<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: #13994: port to the sized deallocation API when available
// FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias`
//                and `nonnull`

use core::ptr::RawPtr;
#[cfg(not(test))] use core::raw;
#[cfg(stage0, not(test))] use util;

/// 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, size: uint, align: uint,
                         old_size: uint) -> *mut u8 {
    imp::reallocate(ptr, size, align, old_size)
}

/// 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, size: uint, align: uint,
                                 old_size: uint) -> bool {
    imp::reallocate_inplace(ptr, size, align, old_size)
}

/// 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) {
    // FIXME(14395) This is only required for DST ~[T], it should be removed once
    // we fix that representation to not use null pointers.
    if ptr.is_null() {
        return;
    }
    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();
}

// The compiler never calls `exchange_free` on Box<ZeroSizeType>, so zero-size
// allocations can point to this `static`. It would be incorrect to use a null
// pointer, due to enums assuming types like unique pointers are never null.
pub static mut EMPTY: uint = 12345;

/// 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 *const uint 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);
}

// FIXME: #7496
#[cfg(stage0, not(test))]
#[lang="closure_exchange_malloc"]
#[inline]
#[allow(deprecated)]
unsafe fn closure_exchange_malloc(drop_glue: fn(*mut u8), size: uint,
                                  align: uint) -> *mut u8 {
    let total_size = util::get_box_size(size, align);
    let p = allocate(total_size, 8);

    let alloc = p as *mut raw::Box<()>;
    (*alloc).drop_glue = drop_glue;

    alloc as *mut u8
}

// FIXME: #7496
#[cfg(not(stage0), not(test))]
#[lang="closure_exchange_malloc"]
#[inline]
#[allow(deprecated)]
unsafe fn closure_exchange_malloc(drop_glue: fn(*mut u8), size: uint,
                                  align: uint) -> *mut u8 {
    let p = allocate(size, align);

    let alloc = p as *mut raw::Box<()>;
    (*alloc).drop_glue = drop_glue;

    alloc as *mut u8
}

// 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(target_arch = "arm")]
#[cfg(target_arch = "mips")]
#[cfg(target_arch = "mipsel")]
static MIN_ALIGN: uint = 8;
#[cfg(target_arch = "x86")]
#[cfg(target_arch = "x86_64")]
static MIN_ALIGN: uint = 16;

#[cfg(jemalloc)]
mod imp {
    use core::option::{None, Option};
    use core::ptr::{RawPtr, mut_null, 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_dallocx(ptr: *mut c_void, 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(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, size: uint, align: uint,
                             _old_size: 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, size: uint, align: uint,
                                     _old_size: uint) -> bool {
        let flags = align_to_flags(align);
        je_xallocx(ptr as *mut c_void, size as size_t, 0, flags) == size as size_t
    }

    #[inline]
    pub unsafe fn deallocate(ptr: *mut u8, _size: uint, align: uint) {
        let flags = align_to_flags(align);
        je_dallocx(ptr as *mut c_void, 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, mut_null(), null())
        }
    }
}

#[cfg(not(jemalloc), unix)]
mod imp {
    use core::cmp;
    use core::mem;
    use core::ptr;
    use libc;
    use libc_heap;
    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 {
            libc_heap::malloc_raw(size)
        } 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, size: uint, align: uint,
                             old_size: uint) -> *mut u8 {
        if align <= MIN_ALIGN {
            libc_heap::realloc_raw(ptr, size)
        } 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, _size: uint, _align: uint,
                                     _old_size: uint) -> bool {
        false
    }

    #[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(not(jemalloc), windows)]
mod imp {
    use libc::{c_void, size_t};
    use libc;
    use libc_heap;
    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 {
            libc_heap::malloc_raw(size)
        } 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, size: uint, align: uint,
                             _old_size: uint) -> *mut u8 {
        if align <= MIN_ALIGN {
            libc_heap::realloc_raw(ptr, size)
        } 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, _size: uint, _align: uint,
                                     _old_size: uint) -> bool {
        false
    }

    #[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 bench {
    extern crate test;
    use self::test::Bencher;

    #[bench]
    fn alloc_owned_small(b: &mut Bencher) {
        b.iter(|| {
            box 10i
        })
    }
}
<commit_msg>implement sized deallocation<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: #13994: port to the sized deallocation API when available
// FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias`
//                and `nonnull`

use core::ptr::RawPtr;
#[cfg(not(test))] use core::raw;
#[cfg(stage0, not(test))] use util;

/// 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, size: uint, align: uint,
                         old_size: uint) -> *mut u8 {
    imp::reallocate(ptr, size, align, old_size)
}

/// 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, size: uint, align: uint,
                                 old_size: uint) -> bool {
    imp::reallocate_inplace(ptr, size, align, old_size)
}

/// 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) {
    // FIXME(14395) This is only required for DST ~[T], it should be removed once
    // we fix that representation to not use null pointers.
    if ptr.is_null() {
        return;
    }
    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();
}

// The compiler never calls `exchange_free` on Box<ZeroSizeType>, so zero-size
// allocations can point to this `static`. It would be incorrect to use a null
// pointer, due to enums assuming types like unique pointers are never null.
pub static mut EMPTY: uint = 12345;

/// 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 *const uint 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);
}

// FIXME: #7496
#[cfg(stage0, not(test))]
#[lang="closure_exchange_malloc"]
#[inline]
#[allow(deprecated)]
unsafe fn closure_exchange_malloc(drop_glue: fn(*mut u8), size: uint,
                                  align: uint) -> *mut u8 {
    let total_size = util::get_box_size(size, align);
    let p = allocate(total_size, 8);

    let alloc = p as *mut raw::Box<()>;
    (*alloc).drop_glue = drop_glue;

    alloc as *mut u8
}

// FIXME: #7496
#[cfg(not(stage0), not(test))]
#[lang="closure_exchange_malloc"]
#[inline]
#[allow(deprecated)]
unsafe fn closure_exchange_malloc(drop_glue: fn(*mut u8), size: uint,
                                  align: uint) -> *mut u8 {
    let p = allocate(size, align);

    let alloc = p as *mut raw::Box<()>;
    (*alloc).drop_glue = drop_glue;

    alloc as *mut u8
}

// 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(target_arch = "arm")]
#[cfg(target_arch = "mips")]
#[cfg(target_arch = "mipsel")]
static MIN_ALIGN: uint = 8;
#[cfg(target_arch = "x86")]
#[cfg(target_arch = "x86_64")]
static MIN_ALIGN: uint = 16;

#[cfg(jemalloc)]
mod imp {
    use core::option::{None, Option};
    use core::ptr::{RawPtr, mut_null, 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;
        #[cfg(stage0)]
        fn je_dallocx(ptr: *mut c_void, flags: c_int);
        #[cfg(not(stage0))]
        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(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, size: uint, align: uint,
                             _old_size: 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, size: uint, align: uint,
                                     _old_size: uint) -> bool {
        let flags = align_to_flags(align);
        je_xallocx(ptr as *mut c_void, size as size_t, 0, flags) == size as size_t
    }

    #[inline]
    #[cfg(stage0)]
    pub unsafe fn deallocate(ptr: *mut u8, _size: uint, align: uint) {
        let flags = align_to_flags(align);
        je_dallocx(ptr as *mut c_void, flags)
    }

    #[inline]
    #[cfg(not(stage0))]
    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, mut_null(), null())
        }
    }
}

#[cfg(not(jemalloc), unix)]
mod imp {
    use core::cmp;
    use core::mem;
    use core::ptr;
    use libc;
    use libc_heap;
    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 {
            libc_heap::malloc_raw(size)
        } 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, size: uint, align: uint,
                             old_size: uint) -> *mut u8 {
        if align <= MIN_ALIGN {
            libc_heap::realloc_raw(ptr, size)
        } 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, _size: uint, _align: uint,
                                     _old_size: uint) -> bool {
        false
    }

    #[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(not(jemalloc), windows)]
mod imp {
    use libc::{c_void, size_t};
    use libc;
    use libc_heap;
    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 {
            libc_heap::malloc_raw(size)
        } 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, size: uint, align: uint,
                             _old_size: uint) -> *mut u8 {
        if align <= MIN_ALIGN {
            libc_heap::realloc_raw(ptr, size)
        } 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, _size: uint, _align: uint,
                                     _old_size: uint) -> bool {
        false
    }

    #[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 bench {
    extern crate test;
    use self::test::Bencher;

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


<commit_before>use std::path::{Path, PathBuf};
use std::borrow::Cow;
use std::env;
use std::io;
use std::fs;
use std::process::Command;
use std::fmt::{self, Display};

use itertools::Itertools;

use errors::*;
use rust_install::{temp, utils, dist};
use override_db::OverrideDB;
use toolchain::Toolchain;

pub const METADATA_VERSION: &'static str = "2";

pub enum OverrideReason {
	Environment,
	OverrideDB(PathBuf),
}

impl Display for OverrideReason {
	fn fmt(&self, f: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
		match *self {
			OverrideReason::Environment =>
				write!(f, "environment override by MULTIRUST_TOOLCHAIN"),
			OverrideReason::OverrideDB(ref path) =>
				write!(f, "directory override due to '{}'", path.display()),
		}
	}
}

pub struct Cfg {
	pub multirust_dir: PathBuf,
	pub version_file: PathBuf,
	pub override_db: OverrideDB,
	pub default_file: PathBuf,
	pub toolchains_dir: PathBuf,
	pub update_hash_dir: PathBuf,
	pub temp_cfg: temp::Cfg,
	pub gpg_key: Cow<'static, str>,
	pub env_override: Option<String>,
	pub dist_root_url: Cow<'static, str>,
	pub notify_handler: SharedNotifyHandler,
}

impl Cfg {
	pub fn from_env(notify_handler: SharedNotifyHandler) -> Result<Self> {
		// Get absolute home directory
		let data_dir = try!(utils::get_local_data_path());

		// Set up the multirust home directory
		let multirust_dir = env::var_os("MULTIRUST_HOME")
			.and_then(utils::if_not_empty)
			.map(PathBuf::from)
			.unwrap_or_else(|| data_dir.join(".multirust"));

		try!(utils::ensure_dir_exists("home", &multirust_dir, ntfy!(&notify_handler)));

		// Data locations
		let version_file = multirust_dir.join("version");
		let override_db = OverrideDB::new(multirust_dir.join("overrides"));
		let default_file = multirust_dir.join("default");
		let toolchains_dir = multirust_dir.join("toolchains");
		let update_hash_dir = multirust_dir.join("update-hashes");

		let notify_clone = notify_handler.clone();
		let temp_cfg = temp::Cfg::new(
			multirust_dir.join("tmp"),
			shared_ntfy!(move |n: temp::Notification| {
				notify_clone.call(Notification::Temp(n));
			}),
		);

		// GPG key
		let gpg_key = if let Some(path) = env::var_os("MULTIRUST_GPG_KEY").and_then(utils::if_not_empty) {
			Cow::Owned(try!(utils::read_file("public key", Path::new(&path))))
		} else {
			Cow::Borrowed(include_str!("rust-key.gpg.ascii"))
		};

		// Environment override
		let env_override = env::var("MULTIRUST_TOOLCHAIN")
			.ok().and_then(utils::if_not_empty);

		let dist_root_url = env::var("MULTIRUST_DIST_ROOT")
			.ok().and_then(utils::if_not_empty)
			.map(Cow::Owned)
			.unwrap_or(Cow::Borrowed(dist::DEFAULT_DIST_ROOT));

		Ok(Cfg {
			multirust_dir: multirust_dir,
			version_file: version_file,
			override_db: override_db,
			default_file: default_file,
			toolchains_dir: toolchains_dir,
			update_hash_dir: update_hash_dir,
			temp_cfg: temp_cfg,
			gpg_key: gpg_key,
			notify_handler: notify_handler,
			env_override: env_override,
			dist_root_url: dist_root_url,
		})
	}

	pub fn set_default(&self, toolchain: &str) -> Result<()> {
		let work_file = try!(self.temp_cfg.new_file());

		try!(utils::write_file("temp", &work_file, toolchain));

		try!(utils::rename_file("default", &*work_file, &self.default_file));

		self.notify_handler.call(Notification::SetDefaultToolchain(toolchain));

		Ok(())
	}

	pub fn get_toolchain(&self, name: &str, create_parent: bool) -> Result<Toolchain> {
		if create_parent {
			try!(utils::ensure_dir_exists("toolchains", &self.toolchains_dir, ntfy!(&self.notify_handler)));
		}

		Ok(Toolchain::from(self, name))
	}

	pub fn verify_toolchain(&self, name: &str) -> Result<Toolchain> {
		let toolchain = try!(self.get_toolchain(name, false));
		try!(toolchain.verify());
		Ok(toolchain)
	}

	pub fn get_hash_file(&self, toolchain: &str, create_parent: bool) -> Result<PathBuf> {
		if create_parent {
			try!(utils::ensure_dir_exists("update-hash", &self.update_hash_dir, ntfy!(&self.notify_handler)));
		}

		Ok(self.update_hash_dir.join(toolchain))
	}

	pub fn which_binary(&self, path: &Path, binary: &str) -> Result<Option<PathBuf>> {

		if let Some((toolchain, _)) = try!(self.find_override_toolchain_or_default(path)) {
			Ok(Some(toolchain.prefix().binary_file(binary)))
		} else {
			Ok(None)
		}
	}

	pub fn upgrade_data(&self) -> Result<bool> {
		if !utils::is_file(&self.version_file) {
			return Ok(false);
		}

		let current_version = try!(utils::read_file("version", &self.version_file));

		self.notify_handler.call(Notification::UpgradingMetadata(&current_version, METADATA_VERSION));

		match &*current_version {
			"2" => {
				// Current version. Do nothing
				Ok(false)
			},
			"1" => {
				// Ignore errors. These files may not exist.
				let _ = fs::remove_dir_all(self.multirust_dir.join("available-updates"));
				let _ = fs::remove_dir_all(self.multirust_dir.join("update-sums"));
				let _ = fs::remove_dir_all(self.multirust_dir.join("channel-sums"));
				let _ = fs::remove_dir_all(self.multirust_dir.join("manifests"));

				try!(utils::write_file("version", &self.version_file, METADATA_VERSION));

				Ok(true)
			}
			_ => {
				Err(Error::UnknownMetadataVersion(current_version))
			}
		}
	}

	pub fn delete_data(&self) -> Result<()> {
		if utils::path_exists(&self.multirust_dir) {
			Ok(try!(utils::remove_dir("home", &self.multirust_dir, ntfy!(&self.notify_handler))))
		} else {
			Ok(())
		}
	}

	pub fn find_default(&self) -> Result<Option<Toolchain>> {
		if !utils::is_file(&self.default_file) {
			return Ok(None);
		}

		let name = try!(utils::read_file("default", &self.default_file));
		if name.is_empty() {
			return Ok(None);
		}

		let toolchain = try!(self.verify_toolchain(&name));

		Ok(Some(toolchain))
	}

	pub fn find_override(&self, path: &Path) -> Result<Option<(Toolchain, OverrideReason)>> {
		if let Some(ref name) = self.env_override {
			let toolchain = try!(self.verify_toolchain(name));

			return Ok(Some((toolchain, OverrideReason::Environment)));
		}

		if let Some((name, reason_path)) = try!(self.override_db.find(path, self.notify_handler.as_ref())) {
			let toolchain = try!(self.verify_toolchain(&name));
			return Ok(Some((toolchain, OverrideReason::OverrideDB(reason_path))));
		}

		Ok(None)
	}

	pub fn find_override_toolchain_or_default(&self, path: &Path) -> Result<Option<(Toolchain, Option<OverrideReason>)>> {
		Ok(if let Some((toolchain, reason)) = try!(self.find_override(path)) {
			Some((toolchain, Some(reason)))
		} else {
			try!(self.find_default()).map(|toolchain| (toolchain, None))
		})
	}

	pub fn list_toolchains(&self) -> Result<Vec<String>> {
		if utils::is_directory(&self.toolchains_dir) {
			let toolchains: Vec<_> = try!(utils::read_dir("toolchains", &self.toolchains_dir))
				.filter_map(io::Result::ok)
				.filter_map(|e| e.file_name().into_string().ok())
				.collect();

			Ok(toolchains)
		} else {
			Ok(Vec::new())
		}
	}

	pub fn update_all_channels(&self) -> Result<Vec<(String, Result<()>)>> {
		let mut toolchains = try!(self.list_toolchains());
		toolchains.sort();

		Ok(toolchains.into_iter()
			.merge(["beta", "nightly", "stable"].into_iter().map(|s| (*s).to_owned()))
			.dedup()
			.filter(|name| dist::ToolchainDesc::from_str(&name).map(|d| d.is_tracking()) == Some(true))
			.map(|name| {
				let result = self.get_toolchain(&name, true).and_then(|t| t.install_from_dist());
				if let Err(ref e) = result {
					self.notify_handler.call(Notification::NonFatalError(e));
				}
				(name, result)
			})
			.collect())
	}

	pub fn check_metadata_version(&self) -> Result<bool> {
		try!(utils::assert_is_directory(&self.multirust_dir));

		if !utils::is_file(&self.version_file) {
			self.notify_handler.call(Notification::WritingMetadataVersion(METADATA_VERSION));

			try!(utils::write_file("metadata version", &self.version_file, METADATA_VERSION));

			Ok(true)
		} else {
			let current_version = try!(utils::read_file("metadata version", &self.version_file));

			self.notify_handler.call(Notification::ReadMetadataVersion(&current_version));

			Ok(&*current_version == METADATA_VERSION)
		}
	}

	pub fn toolchain_for_dir(&self, path: &Path) -> Result<(Toolchain, Option<OverrideReason>)> {
		self.find_override_toolchain_or_default(path)
			.and_then(|r| r.ok_or(Error::NoDefaultToolchain))
	}

	pub fn create_command_for_dir(&self, path: &Path, binary: &str) -> Result<Command> {
		let (toolchain, _) = try!(self.toolchain_for_dir(path));
		toolchain.create_command(binary)
	}

	pub fn doc_path_for_dir(&self, path: &Path, relative: &str) -> Result<PathBuf> {
		let (toolchain, _) = try!(self.toolchain_for_dir(path));
		toolchain.doc_path(relative)
	}

	pub fn open_docs_for_dir(&self, path: &Path, relative: &str) -> Result<()> {
		let (toolchain, _) = try!(self.toolchain_for_dir(path));
		toolchain.open_docs(relative)
	}
}
<commit_msg>Trim default toolchain name<commit_after>use std::path::{Path, PathBuf};
use std::borrow::Cow;
use std::env;
use std::io;
use std::fs;
use std::process::Command;
use std::fmt::{self, Display};

use itertools::Itertools;

use errors::*;
use rust_install::{temp, utils, dist};
use override_db::OverrideDB;
use toolchain::Toolchain;

pub const METADATA_VERSION: &'static str = "2";

pub enum OverrideReason {
	Environment,
	OverrideDB(PathBuf),
}

impl Display for OverrideReason {
	fn fmt(&self, f: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
		match *self {
			OverrideReason::Environment =>
				write!(f, "environment override by MULTIRUST_TOOLCHAIN"),
			OverrideReason::OverrideDB(ref path) =>
				write!(f, "directory override due to '{}'", path.display()),
		}
	}
}

pub struct Cfg {
	pub multirust_dir: PathBuf,
	pub version_file: PathBuf,
	pub override_db: OverrideDB,
	pub default_file: PathBuf,
	pub toolchains_dir: PathBuf,
	pub update_hash_dir: PathBuf,
	pub temp_cfg: temp::Cfg,
	pub gpg_key: Cow<'static, str>,
	pub env_override: Option<String>,
	pub dist_root_url: Cow<'static, str>,
	pub notify_handler: SharedNotifyHandler,
}

impl Cfg {
	pub fn from_env(notify_handler: SharedNotifyHandler) -> Result<Self> {
		// Get absolute home directory
		let data_dir = try!(utils::get_local_data_path());

		// Set up the multirust home directory
		let multirust_dir = env::var_os("MULTIRUST_HOME")
			.and_then(utils::if_not_empty)
			.map(PathBuf::from)
			.unwrap_or_else(|| data_dir.join(".multirust"));

		try!(utils::ensure_dir_exists("home", &multirust_dir, ntfy!(&notify_handler)));

		// Data locations
		let version_file = multirust_dir.join("version");
		let override_db = OverrideDB::new(multirust_dir.join("overrides"));
		let default_file = multirust_dir.join("default");
		let toolchains_dir = multirust_dir.join("toolchains");
		let update_hash_dir = multirust_dir.join("update-hashes");

		let notify_clone = notify_handler.clone();
		let temp_cfg = temp::Cfg::new(
			multirust_dir.join("tmp"),
			shared_ntfy!(move |n: temp::Notification| {
				notify_clone.call(Notification::Temp(n));
			}),
		);

		// GPG key
		let gpg_key = if let Some(path) = env::var_os("MULTIRUST_GPG_KEY").and_then(utils::if_not_empty) {
			Cow::Owned(try!(utils::read_file("public key", Path::new(&path))))
		} else {
			Cow::Borrowed(include_str!("rust-key.gpg.ascii"))
		};

		// Environment override
		let env_override = env::var("MULTIRUST_TOOLCHAIN")
			.ok().and_then(utils::if_not_empty);

		let dist_root_url = env::var("MULTIRUST_DIST_ROOT")
			.ok().and_then(utils::if_not_empty)
			.map(Cow::Owned)
			.unwrap_or(Cow::Borrowed(dist::DEFAULT_DIST_ROOT));

		Ok(Cfg {
			multirust_dir: multirust_dir,
			version_file: version_file,
			override_db: override_db,
			default_file: default_file,
			toolchains_dir: toolchains_dir,
			update_hash_dir: update_hash_dir,
			temp_cfg: temp_cfg,
			gpg_key: gpg_key,
			notify_handler: notify_handler,
			env_override: env_override,
			dist_root_url: dist_root_url,
		})
	}

	pub fn set_default(&self, toolchain: &str) -> Result<()> {
		let work_file = try!(self.temp_cfg.new_file());

		try!(utils::write_file("temp", &work_file, toolchain));

		try!(utils::rename_file("default", &*work_file, &self.default_file));

		self.notify_handler.call(Notification::SetDefaultToolchain(toolchain));

		Ok(())
	}

	pub fn get_toolchain(&self, name: &str, create_parent: bool) -> Result<Toolchain> {
		if create_parent {
			try!(utils::ensure_dir_exists("toolchains", &self.toolchains_dir, ntfy!(&self.notify_handler)));
		}

		Ok(Toolchain::from(self, name))
	}

	pub fn verify_toolchain(&self, name: &str) -> Result<Toolchain> {
		let toolchain = try!(self.get_toolchain(name, false));
		try!(toolchain.verify());
		Ok(toolchain)
	}

	pub fn get_hash_file(&self, toolchain: &str, create_parent: bool) -> Result<PathBuf> {
		if create_parent {
			try!(utils::ensure_dir_exists("update-hash", &self.update_hash_dir, ntfy!(&self.notify_handler)));
		}

		Ok(self.update_hash_dir.join(toolchain))
	}

	pub fn which_binary(&self, path: &Path, binary: &str) -> Result<Option<PathBuf>> {

		if let Some((toolchain, _)) = try!(self.find_override_toolchain_or_default(path)) {
			Ok(Some(toolchain.prefix().binary_file(binary)))
		} else {
			Ok(None)
		}
	}

	pub fn upgrade_data(&self) -> Result<bool> {
		if !utils::is_file(&self.version_file) {
			return Ok(false);
		}

		let current_version = try!(utils::read_file("version", &self.version_file));

		self.notify_handler.call(Notification::UpgradingMetadata(&current_version, METADATA_VERSION));

		match &*current_version {
			"2" => {
				// Current version. Do nothing
				Ok(false)
			},
			"1" => {
				// Ignore errors. These files may not exist.
				let _ = fs::remove_dir_all(self.multirust_dir.join("available-updates"));
				let _ = fs::remove_dir_all(self.multirust_dir.join("update-sums"));
				let _ = fs::remove_dir_all(self.multirust_dir.join("channel-sums"));
				let _ = fs::remove_dir_all(self.multirust_dir.join("manifests"));

				try!(utils::write_file("version", &self.version_file, METADATA_VERSION));

				Ok(true)
			}
			_ => {
				Err(Error::UnknownMetadataVersion(current_version))
			}
		}
	}

	pub fn delete_data(&self) -> Result<()> {
		if utils::path_exists(&self.multirust_dir) {
			Ok(try!(utils::remove_dir("home", &self.multirust_dir, ntfy!(&self.notify_handler))))
		} else {
			Ok(())
		}
	}

	pub fn find_default(&self) -> Result<Option<Toolchain>> {
		if !utils::is_file(&self.default_file) {
			return Ok(None);
		}
		let content = try!(utils::read_file("default", &self.default_file));
		let name = content.trim_matches('\n');
		if name.is_empty() {
			return Ok(None);
		}

		let toolchain = try!(self.verify_toolchain(name));

		Ok(Some(toolchain))
	}

	pub fn find_override(&self, path: &Path) -> Result<Option<(Toolchain, OverrideReason)>> {
		if let Some(ref name) = self.env_override {
			let toolchain = try!(self.verify_toolchain(name));

			return Ok(Some((toolchain, OverrideReason::Environment)));
		}

		if let Some((name, reason_path)) = try!(self.override_db.find(path, self.notify_handler.as_ref())) {
			let toolchain = try!(self.verify_toolchain(&name));
			return Ok(Some((toolchain, OverrideReason::OverrideDB(reason_path))));
		}

		Ok(None)
	}

	pub fn find_override_toolchain_or_default(&self, path: &Path) -> Result<Option<(Toolchain, Option<OverrideReason>)>> {
		Ok(if let Some((toolchain, reason)) = try!(self.find_override(path)) {
			Some((toolchain, Some(reason)))
		} else {
			try!(self.find_default()).map(|toolchain| (toolchain, None))
		})
	}

	pub fn list_toolchains(&self) -> Result<Vec<String>> {
		if utils::is_directory(&self.toolchains_dir) {
			let toolchains: Vec<_> = try!(utils::read_dir("toolchains", &self.toolchains_dir))
				.filter_map(io::Result::ok)
				.filter_map(|e| e.file_name().into_string().ok())
				.collect();

			Ok(toolchains)
		} else {
			Ok(Vec::new())
		}
	}

	pub fn update_all_channels(&self) -> Result<Vec<(String, Result<()>)>> {
		let mut toolchains = try!(self.list_toolchains());
		toolchains.sort();

		Ok(toolchains.into_iter()
			.merge(["beta", "nightly", "stable"].into_iter().map(|s| (*s).to_owned()))
			.dedup()
			.filter(|name| dist::ToolchainDesc::from_str(&name).map(|d| d.is_tracking()) == Some(true))
			.map(|name| {
				let result = self.get_toolchain(&name, true).and_then(|t| t.install_from_dist());
				if let Err(ref e) = result {
					self.notify_handler.call(Notification::NonFatalError(e));
				}
				(name, result)
			})
			.collect())
	}

	pub fn check_metadata_version(&self) -> Result<bool> {
		try!(utils::assert_is_directory(&self.multirust_dir));

		if !utils::is_file(&self.version_file) {
			self.notify_handler.call(Notification::WritingMetadataVersion(METADATA_VERSION));

			try!(utils::write_file("metadata version", &self.version_file, METADATA_VERSION));

			Ok(true)
		} else {
			let current_version = try!(utils::read_file("metadata version", &self.version_file));

			self.notify_handler.call(Notification::ReadMetadataVersion(&current_version));

			Ok(&*current_version == METADATA_VERSION)
		}
	}

	pub fn toolchain_for_dir(&self, path: &Path) -> Result<(Toolchain, Option<OverrideReason>)> {
		self.find_override_toolchain_or_default(path)
			.and_then(|r| r.ok_or(Error::NoDefaultToolchain))
	}

	pub fn create_command_for_dir(&self, path: &Path, binary: &str) -> Result<Command> {
		let (toolchain, _) = try!(self.toolchain_for_dir(path));
		toolchain.create_command(binary)
	}

	pub fn doc_path_for_dir(&self, path: &Path, relative: &str) -> Result<PathBuf> {
		let (toolchain, _) = try!(self.toolchain_for_dir(path));
		toolchain.doc_path(relative)
	}

	pub fn open_docs_for_dir(&self, path: &Path, relative: &str) -> Result<()> {
		let (toolchain, _) = try!(self.toolchain_for_dir(path));
		toolchain.open_docs(relative)
	}
}
<|endoftext|>


<commit_before><commit_msg>yes in Rust<commit_after>use std::env;

#[allow(while_true)]
fn main() {
    let args: Vec<String> = env::args().collect();

    match args.len() {
        1 => {
            while true {
                println!("yes");
            }
        },
        _ => {
            while true {
                println!("{}", args[1]);
            }
        },
    }
}
<|endoftext|>


<commit_before><commit_msg>Forgot to add the file<commit_after>use std::ptr;
use std::cast;
use ffi::*;

pub struct EventQueue
{
	priv allegro_queue: *mut ALLEGRO_EVENT_QUEUE
}

impl EventQueue
{
	pub fn new() -> Option<EventQueue>
	{
		unsafe
		{
			let q = al_create_event_queue();
			if ptr::is_null(q)
			{
				None
			}
			else
			{
				Some(EventQueue{ allegro_queue: q })
			}
		}
	}

	pub fn register_event_source(&self, src: &EventSource)
	{
		unsafe
		{
			al_register_event_source(self.allegro_queue, src.allegro_source);
		}
	}

	pub fn wait_for_event(&self) -> Event
	{
		unsafe
		{
			let mut e = ALLEGRO_EVENT{ data: [0, ..72] };
			al_wait_for_event(self.allegro_queue, &mut e);

			match *e._type() as u32
			{
				ALLEGRO_EVENT_DISPLAY_CLOSE =>
				{
					DisplayClose{ source: cast::transmute((*e.display()).source), timestamp: (*e.display()).timestamp as f64}
				},
				_ => NoEvent
			}
		}
	}
}

impl Drop for EventQueue
{
	fn drop(&self)
	{
		unsafe
		{
			al_destroy_event_queue(self.allegro_queue);
		}
	}
}

pub struct EventSource
{
	priv allegro_source: *mut ALLEGRO_EVENT_SOURCE
}

impl EventSource
{
	pub fn get_event_source(&self) -> *mut ALLEGRO_EVENT_SOURCE
	{
		self.allegro_source
	}
}

pub enum Event
{
	NoEvent,
	DisplayClose
	{
		source: *mut ALLEGRO_EVENT_SOURCE,
		timestamp: f64
	}
}

mod private
{
	use ffi::*;

	pub fn event_source_ref(source: *mut ALLEGRO_EVENT_SOURCE) -> super::EventSource
	{
		super::EventSource{ allegro_source: source }
	}
}
<|endoftext|>


<commit_before>#![feature(alloc)]
#![feature(asm)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(core_simd)]
#![feature(core_slice_ext)]
#![feature(core_str_ext)]
#![feature(convert)]
#![feature(fnbox)]
#![feature(fundamental)]
#![feature(lang_items)]
#![feature(no_std)]
#![feature(rc_unique)]
#![feature(unboxed_closures)]
#![feature(unsafe_no_drop_flag)]
#![feature(vec_from_raw_buf)]
#![feature(vec_push_all)]
#![no_std]

extern crate alloc;

extern crate collections;

#[macro_use]
extern crate mopa;

use core::mem::size_of;

use alloc::rc::*;

use common::debug::*;
use common::pio::*;
use common::memory::*;
use common::string::*;
use common::url::*;

use drivers::keyboard::*;
use drivers::mouse::*;
use drivers::pci::*;
use drivers::ps2::*;
use drivers::serial::*;

use graphics::bmp::*;

use programs::filemanager::*;
use programs::session::*;

use schemes::file::*;
use schemes::http::*;
use schemes::memory::*;
use schemes::pci::*;
use schemes::random::*;

mod common {
    pub mod debug;
    pub mod elf;
    pub mod memory;
    pub mod pci;
    pub mod pio;
    pub mod random;
    pub mod string;
    pub mod url;
}

mod drivers {
    pub mod disk;
    pub mod keyboard;
    pub mod mouse;
    pub mod pci;
    pub mod ps2;
    pub mod serial;
}

mod filesystems {
    pub mod unfs;
}

mod graphics {
    pub mod bmp;
    pub mod color;
    pub mod display;
    pub mod point;
    pub mod size;
    pub mod window;
}

mod network {
    pub mod arp;
    pub mod common;
    pub mod ethernet;
    pub mod icmp;
    pub mod intel8254x;
    pub mod ipv4;
    pub mod rtl8139;
    pub mod tcp;
    pub mod udp;
}

mod programs {
    pub mod editor;
    pub mod executor;
    pub mod filemanager;
    pub mod session;
    pub mod viewer;
}

mod schemes {
    pub mod file;
    pub mod http;
    pub mod ide;
    pub mod memory;
    pub mod pci;
    pub mod random;
}

mod usb {
    pub mod xhci;
}

static mut session_ptr: *mut Session = 0 as *mut Session;

unsafe fn init(){
    serial_init();

    dd(size_of::<usize>() * 8);
    d(" bits");
    dl();

    page_init();
    cluster_init();

    session_ptr = alloc(size_of::<Session>()) as *mut Session;
    *session_ptr = Session::new();
    let session = &mut *session_ptr;

    session.items.insert(0, Rc::new(FileManager::new()));

    keyboard_init();
    mouse_init();

    session.modules.push(Rc::new(PS2));
    session.modules.push(Rc::new(Serial::new(0x3F8, 0x4)));

    pci_init(session);

    session.modules.push(Rc::new(FileScheme));
    session.modules.push(Rc::new(HTTPScheme));
    session.modules.push(Rc::new(MemoryScheme));
    session.modules.push(Rc::new(PCIScheme));
    session.modules.push(Rc::new(RandomScheme));

    session.on_url_wrapped(&URL::from_string("file:///background.bmp".to_string()), box |response: String|{
        if response.data as usize > 0 {
            (*session_ptr).display.background = BMP::from_data(response.data as usize);
        }
    });
}

#[no_mangle]
pub unsafe fn kernel(interrupt: u32) {
    match interrupt {
        0x20 => (), //timer
        0x21 => (*session_ptr).on_irq(0x1), //keyboard
        0x23 => (*session_ptr).on_irq(0x3), // serial 2 and 4
        0x24 => (*session_ptr).on_irq(0x4), // serial 1 and 3
        0x29 => (*session_ptr).on_irq(0x9), //pci
        0x2A => (*session_ptr).on_irq(0xA), //pci
        0x2B => (*session_ptr).on_irq(0xB), //pci
        0x2C => (*session_ptr).on_irq(0xC), //mouse
        0x2E => (*session_ptr).on_irq(0xE), //disk
        0x2F => (*session_ptr).on_irq(0xF), //disk
        0xFF => { // main loop
            init();

            loop {
                (*session_ptr).on_poll();
                (*session_ptr).redraw();
                asm!("sti");
                asm!("hlt");
                asm!("cli"); // TODO: Allow preempting
            }
        },
        0x0 => {
            d("Divide by zero exception\n");
        },
        0x1 => {
            d("Debug exception\n");
        },
        0x2 => {
            d("Non-maskable interrupt\n");
        },
        0x3 => {
            d("Breakpoint exception\n");
        },
        0x4 => {
            d("Overflow exception\n");
        },
        0x5 => {
            d("Bound range exceeded exception\n");
        },
        0x6 => {
            d("Invalid opcode exception\n");
        },
        0x7 => {
            d("Device not available exception\n");
        },
        0x8 => {
            d("Double fault\n");
        },
        0xA => {
            d("Invalid TSS exception\n");
        },
        0xB => {
            d("Segment not present exception\n");
        },
        0xC => {
            d("Stack-segment fault\n");
        },
        0xD => {
            d("General protection fault\n");
        },
        0xE => {
            d("Page fault\n");
        },
        0x10 => {
            d("x87 floating-point exception\n");
        },
        0x11 => {
            d("Alignment check exception\n");
        },
        0x12 => {
            d("Machine check exception\n");
        },
        0x13 => {
            d("SIMD floating-point exception\n");
        },
        0x14 => {
            d("Virtualization exception\n");
        },
        0x1E => {
            d("Security exception\n");
        },
        _ => {
            d("I: ");
            dh(interrupt as usize);
            dl();
        }
    }

    if interrupt >= 0x20 && interrupt < 0x30 {
        if interrupt >= 0x28 {
            outb(0xA0, 0x20);
        }

        outb(0x20, 0x20);
    }
}

#[no_mangle]
pub extern "C" fn memmove(dst: *mut u8, src: *const u8, len: isize){
    unsafe {
        if src < dst {
            let mut i = len;
            while i > 0 {
                i -= 1;
                *dst.offset(i) = *src.offset(i);
            }
        }else{
            let mut i = 0;
            while i < len {
                *dst.offset(i) = *src.offset(i);
                i += 1;
            }
        }
    }
}

#[no_mangle]
pub extern "C" fn memcpy(dst: *mut u8, src: *const u8, len: isize){
    unsafe {
        let mut i = 0;
        while i < len {
            *dst.offset(i) = *src.offset(i);
            i += 1;
        }
    }
}

#[no_mangle]
pub extern "C" fn memset(src: *mut u8, c: i32, len: isize) {
    unsafe {
        let mut i = 0;
        while i < len {
            *src.offset(i) = c as u8;
            i += 1;
        }
    }
}
<commit_msg>impl panic<commit_after>#![feature(alloc)]
#![feature(asm)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(core_simd)]
#![feature(core_slice_ext)]
#![feature(core_str_ext)]
#![feature(convert)]
#![feature(fnbox)]
#![feature(fundamental)]
#![feature(lang_items)]
#![feature(no_std)]
#![feature(rc_unique)]
#![feature(unboxed_closures)]
#![feature(unsafe_no_drop_flag)]
#![feature(vec_from_raw_buf)]
#![feature(vec_push_all)]
#![no_std]

extern crate alloc;

extern crate collections;

#[macro_use]
extern crate mopa;

use core::fmt;
use core::mem::size_of;

use alloc::rc::*;

use common::debug::*;
use common::pio::*;
use common::memory::*;
use common::string::*;
use common::url::*;

use drivers::keyboard::*;
use drivers::mouse::*;
use drivers::pci::*;
use drivers::ps2::*;
use drivers::serial::*;

use graphics::bmp::*;

use programs::filemanager::*;
use programs::session::*;

use schemes::file::*;
use schemes::http::*;
use schemes::memory::*;
use schemes::pci::*;
use schemes::random::*;

mod common {
    pub mod debug;
    pub mod elf;
    pub mod memory;
    pub mod pci;
    pub mod pio;
    pub mod random;
    pub mod string;
    pub mod url;
}

mod drivers {
    pub mod disk;
    pub mod keyboard;
    pub mod mouse;
    pub mod pci;
    pub mod ps2;
    pub mod serial;
}

mod filesystems {
    pub mod unfs;
}

mod graphics {
    pub mod bmp;
    pub mod color;
    pub mod display;
    pub mod point;
    pub mod size;
    pub mod window;
}

mod network {
    pub mod arp;
    pub mod common;
    pub mod ethernet;
    pub mod icmp;
    pub mod intel8254x;
    pub mod ipv4;
    pub mod rtl8139;
    pub mod tcp;
    pub mod udp;
}

mod programs {
    pub mod editor;
    pub mod executor;
    pub mod filemanager;
    pub mod session;
    pub mod viewer;
}

mod schemes {
    pub mod file;
    pub mod http;
    pub mod ide;
    pub mod memory;
    pub mod pci;
    pub mod random;
}

mod usb {
    pub mod xhci;
}

static mut session_ptr: *mut Session = 0 as *mut Session;

unsafe fn init(){
    serial_init();

    dd(size_of::<usize>() * 8);
    d(" bits");
    dl();

    page_init();
    cluster_init();

    session_ptr = alloc(size_of::<Session>()) as *mut Session;
    *session_ptr = Session::new();
    let session = &mut *session_ptr;

    session.items.insert(0, Rc::new(FileManager::new()));

    keyboard_init();
    mouse_init();

    session.modules.push(Rc::new(PS2));
    session.modules.push(Rc::new(Serial::new(0x3F8, 0x4)));

    pci_init(session);

    session.modules.push(Rc::new(FileScheme));
    session.modules.push(Rc::new(HTTPScheme));
    session.modules.push(Rc::new(MemoryScheme));
    session.modules.push(Rc::new(PCIScheme));
    session.modules.push(Rc::new(RandomScheme));

    session.on_url_wrapped(&URL::from_string("file:///background.bmp".to_string()), box |response: String|{
        if response.data as usize > 0 {
            (*session_ptr).display.background = BMP::from_data(response.data as usize);
        }
    });
}

#[no_mangle]
pub unsafe fn kernel(interrupt: u32) {
    match interrupt {
        0x20 => (), //timer
        0x21 => (*session_ptr).on_irq(0x1), //keyboard
        0x23 => (*session_ptr).on_irq(0x3), // serial 2 and 4
        0x24 => (*session_ptr).on_irq(0x4), // serial 1 and 3
        0x29 => (*session_ptr).on_irq(0x9), //pci
        0x2A => (*session_ptr).on_irq(0xA), //pci
        0x2B => (*session_ptr).on_irq(0xB), //pci
        0x2C => (*session_ptr).on_irq(0xC), //mouse
        0x2E => (*session_ptr).on_irq(0xE), //disk
        0x2F => (*session_ptr).on_irq(0xF), //disk
        0xFF => { // main loop
            init();

            loop {
                (*session_ptr).on_poll();
                (*session_ptr).redraw();
                asm!("sti");
                asm!("hlt");
                asm!("cli"); // TODO: Allow preempting
            }
        },
        0x0 => {
            d("Divide by zero exception\n");
        },
        0x1 => {
            d("Debug exception\n");
        },
        0x2 => {
            d("Non-maskable interrupt\n");
        },
        0x3 => {
            d("Breakpoint exception\n");
        },
        0x4 => {
            d("Overflow exception\n");
        },
        0x5 => {
            d("Bound range exceeded exception\n");
        },
        0x6 => {
            d("Invalid opcode exception\n");
        },
        0x7 => {
            d("Device not available exception\n");
        },
        0x8 => {
            d("Double fault\n");
        },
        0xA => {
            d("Invalid TSS exception\n");
        },
        0xB => {
            d("Segment not present exception\n");
        },
        0xC => {
            d("Stack-segment fault\n");
        },
        0xD => {
            d("General protection fault\n");
        },
        0xE => {
            d("Page fault\n");
        },
        0x10 => {
            d("x87 floating-point exception\n");
        },
        0x11 => {
            d("Alignment check exception\n");
        },
        0x12 => {
            d("Machine check exception\n");
        },
        0x13 => {
            d("SIMD floating-point exception\n");
        },
        0x14 => {
            d("Virtualization exception\n");
        },
        0x1E => {
            d("Security exception\n");
        },
        _ => {
            d("I: ");
            dh(interrupt as usize);
            dl();
        }
    }

    if interrupt >= 0x20 && interrupt < 0x30 {
        if interrupt >= 0x28 {
            outb(0xA0, 0x20);
        }

        outb(0x20, 0x20);
    }
}

#[lang = "panic_fmt"]
pub fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: u32) -> !{
    d("PANIC: ");
    d(file);
    d(": ");
    dh(line as usize);
    dl();
    unsafe{
        asm!("cli");
        asm!("hlt");
    }
    loop{}
}

#[no_mangle]
pub extern "C" fn memcmp(a: *mut u8, b: *const u8, len: isize) -> isize {
    unsafe {
        let mut i = 0;
        while i < len {
            let c_a = *a.offset(i);
            let c_b = *b.offset(i);
            if c_a != c_b{
                return c_a as isize - c_b as isize;
            }
            i += 1;
        }
        return 0;
    }
}

#[no_mangle]
pub extern "C" fn memmove(dst: *mut u8, src: *const u8, len: isize){
    unsafe {
        if src < dst {
            let mut i = len;
            while i > 0 {
                i -= 1;
                *dst.offset(i) = *src.offset(i);
            }
        }else{
            let mut i = 0;
            while i < len {
                *dst.offset(i) = *src.offset(i);
                i += 1;
            }
        }
    }
}

#[no_mangle]
pub extern "C" fn memcpy(dst: *mut u8, src: *const u8, len: isize){
    unsafe {
        let mut i = 0;
        while i < len {
            *dst.offset(i) = *src.offset(i);
            i += 1;
        }
    }
}

#[no_mangle]
pub extern "C" fn memset(src: *mut u8, c: i32, len: isize) {
    unsafe {
        let mut i = 0;
        while i < len {
            *src.offset(i) = c as u8;
            i += 1;
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Run a SPIR-V optimisation pass when compiling shaders<commit_after><|endoftext|>


<commit_before><commit_msg>Remove redundant array bounds checks<commit_after><|endoftext|>


<commit_before><commit_msg>Focus input field when clicked<commit_after><|endoftext|>


<commit_before>use common::memory::*;
use common::scheduler::*;

use drivers::disk::*;

use programs::common::*;

#[derive(Copy, Clone)]
#[repr(packed)]
pub struct Extent{
    pub block: u64,
    pub length: u64
}

#[repr(packed)]
pub struct Header {
    pub signature: [u8; 8],
    pub version: u32,
    pub name: [u8; 244],
    pub extents: [Extent; 16]
}

#[repr(packed)]
pub struct Node {
    pub name: [u8; 256],
    pub extents: [Extent; 16]
}

impl Clone for Node {
    fn clone(&self) -> Node {
        return Node {
            name: self.name,
            extents: self.extents
        };
    }
}

pub struct FileSystem {
    pub disk: Disk,
    pub header: Header,
    pub nodes: Vec<Node>
}

impl FileSystem {
    pub fn from_disk(disk: Disk) -> FileSystem{
        unsafe{
            let header_ptr: *const Header = alloc_type();
            disk.read(1, 1, header_ptr as usize);
            let header = ptr::read(header_ptr);
            unalloc(header_ptr as usize);

            let mut nodes = Vec::new();
            let node_ptr: *const Node = alloc_type();
            for extent in &header.extents {
                if extent.block > 0 {
                    for node_address in extent.block..extent.block + (extent.length + 511)/512 {
                        disk.read(node_address, 1, node_ptr as usize);
                        nodes.push(ptr::read(node_ptr));
                    }
                }
            }
            unalloc(node_ptr as usize);

            return FileSystem {
                disk:disk,
                header: header,
                nodes: nodes
            };
        }
    }

    pub fn valid(&self) -> bool {
        return self.header.signature[0] == 'R' as u8
            && self.header.signature[1] == 'E' as u8
            && self.header.signature[2] == 'D' as u8
            && self.header.signature[3] == 'O' as u8
            && self.header.signature[4] == 'X' as u8
            && self.header.signature[5] == 'F' as u8
            && self.header.signature[6] == 'S' as u8
            && self.header.signature[7] == '\0' as u8
            && self.header.version == 0xFFFFFFFF;
    }

    pub fn node(&self, filename: &String) -> Option<Node>{
        for node in self.nodes.iter() {
            if String::from_c_slice(&node.name) == *filename {
                return Option::Some(node.clone());
            }
        }

        return Option::None;
    }

    pub fn list(&self, directory: &String) -> Vec<String> {
        let mut ret = Vec::<String>::new();

        for node in self.nodes.iter() {
            let node_name = String::from_c_slice(&node.name);
            if node_name.starts_with(directory.clone()) {
                ret.push(node_name.substr(directory.len(), node_name.len() - directory.len()));
            }
        }

        return ret;
    }
}

pub struct FileResource {
    pub node: Node,
    pub vec: Vec<u8>,
    pub seek: usize
}

impl Resource for FileResource {
    fn url(&self) -> URL {
        return URL::from_string(&String::from_c_slice(&self.node.name));
    }

    fn stat(&self) -> ResourceType {
        return ResourceType::File;
    }

    fn read(&mut self, buf: &mut [u8]) -> Option<usize> {
        let mut i = 0;
        while i < buf.len() && self.seek < self.vec.len() {
            match self.vec.get(self.seek) {
                Option::Some(b) => buf[i] = *b,
                Option::None => ()
            }
            self.seek += 1;
            i += 1;
        }
        return Option::Some(i);
    }

    fn write(&mut self, buf: &[u8]) -> Option<usize> {
        let mut i = 0;
        while i < buf.len() && self.seek < self.vec.len() {
            self.vec.set(self.seek, buf[i]);
            self.seek += 1;
            i += 1;
        }
        while i < buf.len() {
            self.vec.push(buf[i]);
            self.seek += 1;
            i += 1;
        }
        return Option::Some(i);
    }

    fn seek(&mut self, pos: ResourceSeek) -> Option<usize> {
        match pos {
            ResourceSeek::Start(offset) => self.seek = offset,
            ResourceSeek::Current(offset) => self.seek = max(0, self.seek as isize + offset) as usize,
            ResourceSeek::End(offset) => self.seek = max(0, self.vec.len() as isize + offset) as usize
        }
        while self.vec.len() < self.seek {
            self.vec.push(0);
        }
        return Option::Some(self.seek);
    }

    fn flush(&mut self) -> bool {
        return false;
    }
}

pub struct FileScheme {
    pub fs: FileSystem
}

impl SessionItem for FileScheme {
    fn scheme(&self) -> String {
        return "file".to_string();
    }

    fn open(&mut self, url: &URL) -> Box<Resource>{
        let path = url.path();
        if path.len() == 0 || path.ends_with("/".to_string()) {
            let mut list = String::new();
            let mut dirs: Vec<String> = Vec::new();

            for file in self.fs.list(&path).iter() {
                let line;
                match file.find("/".to_string()) {
                    Option::Some(index) => {
                        let dirname = file.substr(0, index + 1);
                        let mut found = false;
                        for dir in dirs.iter() {
                            if dirname == *dir {
                                found = true;
                                break;
                            }
                        }
                        if found {
                            line = String::new();
                        }else{
                            line = dirname.clone();
                            dirs.push(dirname);
                        }
                    },
                    Option::None => line = file.clone()
                }
                if line.len() > 0 {
                    if list.len() > 0 {
                        list = list + '\n' + line;
                    }else{
                        list = line;
                    }
                }
            }

            return box VecResource::new(url.clone(), ResourceType::Dir, list.to_utf8());
        }else{
            match self.fs.node(&path) {
                Option::Some(node) => {
                    let mut vec: Vec<u8> = Vec::new();
                    if node.extents[0].block > 0 && node.extents[0].length > 0 {
                        unsafe {
                            let data = alloc(node.extents[0].length as usize);
                            if data > 0 {
                                let reenable = start_no_ints();

                                self.fs.disk.read(node.extents[0].block, ((node.extents[0].length + 511)/512) as u16, data);

                                end_no_ints(reenable);

                                vec = Vec {
                                    data: data as *mut u8,
                                    length: node.extents[0].length as usize
                                };
                            }
                        }
                    }

                    return box FileResource {
                        node: node,
                        vec: vec,
                        seek: 0
                    };
                },
                Option::None => {
                    d("Creating ");
                    path.d();
                    dl();

                    let mut name = [0; 256];
                    for i in 0..256 {
                        //TODO: UTF8
                        let b = path[i] as u8;
                        name[i] = b;
                        if b == 0 {
                            break;
                        }
                    }

                    let node = Node {
                        name: name,
                        extents: [Extent { block: 0, length: 0 }; 16]
                    };

                    //TODO: Sync to disk
                    let mut node_i = 0;
                    while node_i < self.fs.nodes.len() {
                        let mut cmp = 0;

                        if let Option::Some(other_node) = self.fs.nodes.get(node_i) {
                            for i in 0..256 {
                                if other_node.name[i] != node.name[i] {
                                    cmp = other_node.name[i] as isize - node.name[i] as isize;
                                    break;
                                }
                            }
                        }

                        if cmp >= 0 {
                            break;
                        }

                        node_i += 1;
                    }
                    d("Insert at ");
                    dd(node_i);
                    dl();
                    self.fs.nodes.insert(node_i, node.clone());

                    return box FileResource {
                        node: node,
                        vec: Vec::new(),
                        seek: 0
                    };
                }
            }
        }
    }
}
<commit_msg>Remove insert function, for now<commit_after>use common::memory::*;
use common::scheduler::*;

use drivers::disk::*;

use programs::common::*;

#[derive(Copy, Clone)]
#[repr(packed)]
pub struct Extent{
    pub block: u64,
    pub length: u64
}

#[repr(packed)]
pub struct Header {
    pub signature: [u8; 8],
    pub version: u32,
    pub name: [u8; 244],
    pub extents: [Extent; 16]
}

#[repr(packed)]
pub struct Node {
    pub name: [u8; 256],
    pub extents: [Extent; 16]
}

impl Clone for Node {
    fn clone(&self) -> Node {
        return Node {
            name: self.name,
            extents: self.extents
        };
    }
}

pub struct FileSystem {
    pub disk: Disk,
    pub header: Header,
    pub nodes: Vec<Node>
}

impl FileSystem {
    pub fn from_disk(disk: Disk) -> FileSystem{
        unsafe{
            let header_ptr: *const Header = alloc_type();
            disk.read(1, 1, header_ptr as usize);
            let header = ptr::read(header_ptr);
            unalloc(header_ptr as usize);

            let mut nodes = Vec::new();
            let node_ptr: *const Node = alloc_type();
            for extent in &header.extents {
                if extent.block > 0 {
                    for node_address in extent.block..extent.block + (extent.length + 511)/512 {
                        disk.read(node_address, 1, node_ptr as usize);
                        nodes.push(ptr::read(node_ptr));
                    }
                }
            }
            unalloc(node_ptr as usize);

            return FileSystem {
                disk:disk,
                header: header,
                nodes: nodes
            };
        }
    }

    pub fn valid(&self) -> bool {
        return self.header.signature[0] == 'R' as u8
            && self.header.signature[1] == 'E' as u8
            && self.header.signature[2] == 'D' as u8
            && self.header.signature[3] == 'O' as u8
            && self.header.signature[4] == 'X' as u8
            && self.header.signature[5] == 'F' as u8
            && self.header.signature[6] == 'S' as u8
            && self.header.signature[7] == '\0' as u8
            && self.header.version == 0xFFFFFFFF;
    }

    pub fn node(&self, filename: &String) -> Option<Node>{
        for node in self.nodes.iter() {
            if String::from_c_slice(&node.name) == *filename {
                return Option::Some(node.clone());
            }
        }

        return Option::None;
    }

    pub fn list(&self, directory: &String) -> Vec<String> {
        let mut ret = Vec::<String>::new();

        for node in self.nodes.iter() {
            let node_name = String::from_c_slice(&node.name);
            if node_name.starts_with(directory.clone()) {
                ret.push(node_name.substr(directory.len(), node_name.len() - directory.len()));
            }
        }

        return ret;
    }
}

pub struct FileResource {
    pub node: Node,
    pub vec: Vec<u8>,
    pub seek: usize
}

impl Resource for FileResource {
    fn url(&self) -> URL {
        return URL::from_string(&String::from_c_slice(&self.node.name));
    }

    fn stat(&self) -> ResourceType {
        return ResourceType::File;
    }

    fn read(&mut self, buf: &mut [u8]) -> Option<usize> {
        let mut i = 0;
        while i < buf.len() && self.seek < self.vec.len() {
            match self.vec.get(self.seek) {
                Option::Some(b) => buf[i] = *b,
                Option::None => ()
            }
            self.seek += 1;
            i += 1;
        }
        return Option::Some(i);
    }

    fn write(&mut self, buf: &[u8]) -> Option<usize> {
        let mut i = 0;
        while i < buf.len() && self.seek < self.vec.len() {
            self.vec.set(self.seek, buf[i]);
            self.seek += 1;
            i += 1;
        }
        while i < buf.len() {
            self.vec.push(buf[i]);
            self.seek += 1;
            i += 1;
        }
        return Option::Some(i);
    }

    fn seek(&mut self, pos: ResourceSeek) -> Option<usize> {
        match pos {
            ResourceSeek::Start(offset) => self.seek = offset,
            ResourceSeek::Current(offset) => self.seek = max(0, self.seek as isize + offset) as usize,
            ResourceSeek::End(offset) => self.seek = max(0, self.vec.len() as isize + offset) as usize
        }
        while self.vec.len() < self.seek {
            self.vec.push(0);
        }
        return Option::Some(self.seek);
    }

    fn flush(&mut self) -> bool {
        return false;
    }
}

pub struct FileScheme {
    pub fs: FileSystem
}

impl SessionItem for FileScheme {
    fn scheme(&self) -> String {
        return "file".to_string();
    }

    fn open(&mut self, url: &URL) -> Box<Resource>{
        let path = url.path();
        if path.len() == 0 || path.ends_with("/".to_string()) {
            let mut list = String::new();
            let mut dirs: Vec<String> = Vec::new();

            for file in self.fs.list(&path).iter() {
                let line;
                match file.find("/".to_string()) {
                    Option::Some(index) => {
                        let dirname = file.substr(0, index + 1);
                        let mut found = false;
                        for dir in dirs.iter() {
                            if dirname == *dir {
                                found = true;
                                break;
                            }
                        }
                        if found {
                            line = String::new();
                        }else{
                            line = dirname.clone();
                            dirs.push(dirname);
                        }
                    },
                    Option::None => line = file.clone()
                }
                if line.len() > 0 {
                    if list.len() > 0 {
                        list = list + '\n' + line;
                    }else{
                        list = line;
                    }
                }
            }

            return box VecResource::new(url.clone(), ResourceType::Dir, list.to_utf8());
        }else{
            match self.fs.node(&path) {
                Option::Some(node) => {
                    let mut vec: Vec<u8> = Vec::new();
                    if node.extents[0].block > 0 && node.extents[0].length > 0 {
                        unsafe {
                            let data = alloc(node.extents[0].length as usize);
                            if data > 0 {
                                let reenable = start_no_ints();

                                self.fs.disk.read(node.extents[0].block, ((node.extents[0].length + 511)/512) as u16, data);

                                end_no_ints(reenable);

                                vec = Vec {
                                    data: data as *mut u8,
                                    length: node.extents[0].length as usize
                                };
                            }
                        }
                    }

                    return box FileResource {
                        node: node,
                        vec: vec,
                        seek: 0
                    };
                },
                Option::None => {
                    /*
                    d("Creating ");
                    path.d();
                    dl();

                    let mut name = [0; 256];
                    for i in 0..256 {
                        //TODO: UTF8
                        let b = path[i] as u8;
                        name[i] = b;
                        if b == 0 {
                            break;
                        }
                    }

                    let node = Node {
                        name: name,
                        extents: [Extent { block: 0, length: 0 }; 16]
                    };

                    //TODO: Sync to disk
                    let mut node_i = 0;
                    while node_i < self.fs.nodes.len() {
                        let mut cmp = 0;

                        if let Option::Some(other_node) = self.fs.nodes.get(node_i) {
                            for i in 0..256 {
                                if other_node.name[i] != node.name[i] {
                                    cmp = other_node.name[i] as isize - node.name[i] as isize;
                                    break;
                                }
                            }
                        }

                        if cmp >= 0 {
                            break;
                        }

                        node_i += 1;
                    }
                    d("Insert at ");
                    dd(node_i);
                    dl();
                    self.fs.nodes.insert(node_i, node.clone());

                    return box FileResource {
                        node: node,
                        vec: Vec::new(),
                        seek: 0
                    };
                    */
                    return box NoneResource;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Fixed path prefix on random sound response.<commit_after><|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

#![feature(collections, core, io, os, path, rustc_private, std_misc, test)]

extern crate getopts;
extern crate test;

use test::{AutoColor, TestOpts, run_tests_console, TestDesc, TestDescAndFn, DynTestFn, DynTestName};
use test::ShouldFail;
use getopts::{getopts, reqopt};
use std::{os, str, env};
use std::old_io::fs;
use std::old_io::Reader;
use std::old_io::process::{Command, Ignored, CreatePipe, InheritFd, ExitStatus};
use std::old_path::Path;
use std::thunk::Thunk;

#[derive(Clone)]
struct Config {
    source_dir: String,
    filter: Option<String>
}

fn main() {
    let args = env::args();
    let config = parse_config(args.map(|x| x.into_string().unwrap()).collect());
    let opts = test_options(config.clone());
    let tests = find_tests(config);
    match run_tests_console(&opts, tests) {
        Ok(false) => env::set_exit_status(1), // tests failed
        Err(_) => env::set_exit_status(2),    // I/O-related failure
        _ => (),
    }
}

fn parse_config(args: Vec<String>) -> Config {
    let args = args.tail();
    let opts = vec!(reqopt("s", "source-dir", "source-dir", "source-dir"));
    let matches = match getopts(args, opts.as_slice()) {
      Ok(m) => m,
      Err(f) => panic!(format!("{}", f))
    };

    Config {
        source_dir: matches.opt_str("source-dir").unwrap(),
        filter: matches.free.first().map(|s| s.clone())
    }
}

fn test_options(config: Config) -> TestOpts {
    TestOpts {
        filter: config.filter,
        run_ignored: false,
        run_tests: true,
        run_benchmarks: false,
        logfile: None,
        nocapture: false,
        color: AutoColor,
    }
}

fn find_tests(config: Config) -> Vec<TestDescAndFn> {
    let files_res = fs::readdir(&Path::new(config.source_dir));
    let mut files = match files_res {
        Ok(files) => files,
        _ => panic!("Error reading directory."),
    };
    files.retain(|file| file.extension_str() == Some("html") );
    return files.iter().map(|file| make_test(format!("{}", file.display()))).collect();
}

fn make_test(file: String) -> TestDescAndFn {
    TestDescAndFn {
        desc: TestDesc {
            name: DynTestName(file.clone()),
            ignore: false,
            should_fail: ShouldFail::No,
        },
        testfn: DynTestFn(Thunk::new(move || { run_test(file) }))
    }
}

fn run_test(file: String) {
    let path = os::make_absolute(&Path::new(file)).unwrap();
    // FIXME (#1094): not the right way to transform a path
    let infile = format!("file://{}", path.display());
    let stdout = CreatePipe(false, true);
    let stderr = InheritFd(2);
    let args = ["-z", "-f", infile.as_slice()];

    let mut prc = match Command::new(os::self_exe_path().unwrap().join("servo"))
        .args(args.as_slice())
        .stdin(Ignored)
        .stdout(stdout)
        .stderr(stderr)
        .spawn()
    {
        Ok(p) => p,
        _ => panic!("Unable to spawn process."),
    };
    let mut output = Vec::new();
    loop {
        let byte = prc.stdout.as_mut().unwrap().read_byte();
        match byte {
            Ok(byte) => {
                print!("{}", byte as char);
                output.push(byte);
            }
            _ => break
        }
    }

    let out = str::from_utf8(output.as_slice());
    let lines: Vec<&str> = out.unwrap().split('\n').collect();
    for &line in lines.iter() {
        if line.contains("TEST-UNEXPECTED-FAIL") {
            panic!(line.to_string());
        }
    }

    let retval = prc.wait();
    if retval != Ok(ExitStatus(0)) {
        panic!("Servo exited with non-zero status {:?}", retval);
    }
}
<commit_msg>auto merge of #5204 : ehegnes/servo/squelch_contenttest, r=jdm<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

#![feature(collections, core, env, io, os, path, rustc_private, std_misc, test)]

extern crate getopts;
extern crate test;

use test::{AutoColor, TestOpts, run_tests_console, TestDesc, TestDescAndFn, DynTestFn, DynTestName};
use test::ShouldFail;
use getopts::{getopts, reqopt};
use std::{str, env};
use std::old_io::fs;
use std::old_io::Reader;
use std::old_io::process::{Command, Ignored, CreatePipe, InheritFd, ExitStatus};
use std::old_path::Path;
use std::thunk::Thunk;

#[derive(Clone)]
struct Config {
    source_dir: String,
    filter: Option<String>
}

fn main() {
    let args = env::args();
    let config = parse_config(args.map(|x| x.into_string().unwrap()).collect());
    let opts = test_options(config.clone());
    let tests = find_tests(config);
    match run_tests_console(&opts, tests) {
        Ok(false) => env::set_exit_status(1), // tests failed
        Err(_) => env::set_exit_status(2),    // I/O-related failure
        _ => (),
    }
}

fn parse_config(args: Vec<String>) -> Config {
    let args = args.tail();
    let opts = vec!(reqopt("s", "source-dir", "source-dir", "source-dir"));
    let matches = match getopts(args, opts.as_slice()) {
      Ok(m) => m,
      Err(f) => panic!(format!("{}", f))
    };

    Config {
        source_dir: matches.opt_str("source-dir").unwrap(),
        filter: matches.free.first().map(|s| s.clone())
    }
}

fn test_options(config: Config) -> TestOpts {
    TestOpts {
        filter: config.filter,
        run_ignored: false,
        run_tests: true,
        run_benchmarks: false,
        logfile: None,
        nocapture: false,
        color: AutoColor,
    }
}

fn find_tests(config: Config) -> Vec<TestDescAndFn> {
    let files_res = fs::readdir(&Path::new(config.source_dir));
    let mut files = match files_res {
        Ok(files) => files,
        _ => panic!("Error reading directory."),
    };
    files.retain(|file| file.extension_str() == Some("html") );
    return files.iter().map(|file| make_test(format!("{}", file.display()))).collect();
}

fn make_test(file: String) -> TestDescAndFn {
    TestDescAndFn {
        desc: TestDesc {
            name: DynTestName(file.clone()),
            ignore: false,
            should_fail: ShouldFail::No,
        },
        testfn: DynTestFn(Thunk::new(move || { run_test(file) }))
    }
}

fn run_test(file: String) {
    let path = env::current_dir().unwrap().join(&file);
    // FIXME (#1094): not the right way to transform a path
    let infile = format!("file://{}", path.display());
    let stdout = CreatePipe(false, true);
    let stderr = InheritFd(2);
    let args = ["-z", "-f", infile.as_slice()];

    let mut prc_arg = env::current_exe().unwrap();
    let prc_arg = match prc_arg.pop() {
        true => prc_arg.join("servo"),
        _ => panic!("could not pop directory"),
    };
    let mut prc = match Command::new(prc_arg)
        .args(args.as_slice())
        .stdin(Ignored)
        .stdout(stdout)
        .stderr(stderr)
        .spawn()
    {
        Ok(p) => p,
        _ => panic!("Unable to spawn process."),
    };
    let mut output = Vec::new();
    loop {
        let byte = prc.stdout.as_mut().unwrap().read_byte();
        match byte {
            Ok(byte) => {
                print!("{}", byte as char);
                output.push(byte);
            }
            _ => break
        }
    }

    let out = str::from_utf8(output.as_slice());
    let lines: Vec<&str> = out.unwrap().split('\n').collect();
    for &line in lines.iter() {
        if line.contains("TEST-UNEXPECTED-FAIL") {
            panic!(line.to_string());
        }
    }

    let retval = prc.wait();
    if retval != Ok(ExitStatus(0)) {
        panic!("Servo exited with non-zero status {:?}", retval);
    }
}
<|endoftext|>


<commit_before><commit_msg>Add test of anyhow macro tagged dispatch<commit_after>use anyhow::anyhow;
use std::error::Error as StdError;
use std::fmt::{self, Display};
use std::io;

#[derive(Debug)]
enum TestError {
    Io(io::Error),
}

impl Display for TestError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        match self {
            TestError::Io(e) => Display::fmt(e, formatter),
        }
    }
}

impl StdError for TestError {
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        match self {
            TestError::Io(io) => Some(io),
        }
    }
}

#[test]
fn test_literal_source() {
    let error = anyhow!("oh no!");
    assert!(error.source().is_none());
}

#[test]
fn test_variable_source() {
    let msg = "oh no!";
    let error = anyhow!(msg);
    assert!(error.source().is_none());
}

#[test]
fn test_fmt_source() {
    let error = anyhow!("{} {}!", "oh", "no");
    assert!(error.source().is_none());
}

#[test]
fn test_io_source() {
    let io = io::Error::new(io::ErrorKind::Other, "oh no!");
    let error = anyhow!(TestError::Io(io));
    assert_eq!("oh no!", error.source().unwrap().to_string());
}
<|endoftext|>


<commit_before><commit_msg>Add more trace output for Viewer implementation<commit_after><|endoftext|>


<commit_before><commit_msg>Refactor imag-mail to new store iterator interface<commit_after><|endoftext|>


<commit_before><commit_msg>imag-todo: Replace read with typed read<commit_after><|endoftext|>