<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.

/*! The Rust Runtime, including the task scheduler and I/O

The `rt` module provides the private runtime infrastructure necessary
to support core language features like the exchange and local heap,
the garbage collector, logging, local data and unwinding. It also
implements the default task scheduler and task model. Initialization
routines are provided for setting up runtime resources in common
configurations, including that used by `rustc` when generating
executables.

It is intended that the features provided by `rt` can be factored in a
way such that the core library can be built with different 'profiles'
for different use cases, e.g. excluding the task scheduler. A number
of runtime features though are critical to the functioning of the
language and an implementation must be provided regardless of the
execution environment.

Of foremost importance is the global exchange heap, in the module
`global_heap`. Very little practical Rust code can be written without
access to the global heap. Unlike most of `rt` the global heap is
truly a global resource and generally operates independently of the
rest of the runtime.

All other runtime features are task-local, including the local heap,
the garbage collector, local storage, logging and the stack unwinder.

The relationship between `rt` and the rest of the core library is
not entirely clear yet and some modules will be moving into or
out of `rt` as development proceeds.

Several modules in `core` are clients of `rt`:

* `core::task` - The user-facing interface to the Rust task model.
* `core::task::local_data` - The interface to local data.
* `core::gc` - The garbage collector.
* `core::unstable::lang` - Miscellaneous lang items, some of which rely on `core::rt`.
* `core::condition` - Uses local data.
* `core::cleanup` - Local heap destruction.
* `core::io` - In the future `core::io` will use an `rt` implementation.
* `core::logging`
* `core::pipes`
* `core::comm`
* `core::stackwalk`

*/

#[doc(hidden)];
#[deny(unused_imports)];
#[deny(unused_mut)];
#[deny(unused_variable)];
#[deny(unused_unsafe)];

use cell::Cell;
use clone::Clone;
use container::Container;
use iter::Times;
use iterator::{Iterator, IteratorUtil};
use option::{Some, None};
use ptr::RawPtr;
use rt::local::Local;
use rt::sched::{Scheduler, Shutdown};
use rt::sleeper_list::SleeperList;
use rt::task::{Task, SchedTask, GreenTask, Sched};
use rt::thread::Thread;
use rt::work_queue::WorkQueue;
use rt::uv::uvio::UvEventLoop;
use unstable::atomics::{AtomicInt, SeqCst};
use unstable::sync::UnsafeAtomicRcBox;
use vec::{OwnedVector, MutableVector};

/// The global (exchange) heap.
pub mod global_heap;

/// Implementations of language-critical runtime features like @.
pub mod task;

/// Facilities related to task failure, killing, and death.
mod kill;

/// The coroutine task scheduler, built on the `io` event loop.
mod sched;

/// Synchronous I/O.
pub mod io;

/// The EventLoop and internal synchronous I/O interface.
mod rtio;

/// libuv and default rtio implementation.
pub mod uv;

/// The Local trait for types that are accessible via thread-local
/// or task-local storage.
pub mod local;

/// A parallel work-stealing deque.
mod work_queue;

/// A parallel queue.
mod message_queue;

/// A parallel data structure for tracking sleeping schedulers.
mod sleeper_list;

/// Stack segments and caching.
mod stack;

/// CPU context swapping.
mod context;

/// Bindings to system threading libraries.
mod thread;

/// The runtime configuration, read from environment variables
pub mod env;

/// The local, managed heap
pub mod local_heap;

/// The Logger trait and implementations
pub mod logging;

/// Tools for testing the runtime
pub mod test;

/// Reference counting
pub mod rc;

/// A simple single-threaded channel type for passing buffered data between
/// scheduler and task context
pub mod tube;

/// Simple reimplementation of core::comm
pub mod comm;

/// Routines for select()ing on pipes.
pub mod select;

// FIXME #5248 shouldn't be pub
/// The runtime needs to be able to put a pointer into thread-local storage.
pub mod local_ptr;

// FIXME #5248: The import in `sched` doesn't resolve unless this is pub!
/// Bindings to pthread/windows thread-local storage.
pub mod thread_local_storage;

pub mod metrics;

// FIXME #5248 shouldn't be pub
/// Just stuff
pub mod util;

// Global command line argument storage
pub mod args;

// Support for dynamic borrowck
pub mod borrowck;

/// Set up a default runtime configuration, given compiler-supplied arguments.
///
/// This is invoked by the `start` _language item_ (unstable::lang) to
/// run a Rust executable.
///
/// # Arguments
///
/// * `argc` & `argv` - The argument vector. On Unix this information is used
///   by os::args.
/// * `crate_map` - Runtime information about the executing crate, mostly for logging
///
/// # Return value
///
/// The return value is used as the process return code. 0 on success, 101 on error.
pub fn start(argc: int, argv: **u8, crate_map: *u8, main: ~fn()) -> int {

    init(argc, argv, crate_map);
    let exit_code = run(main);
    cleanup();

    return exit_code;
}

/// Like `start` but creates an additional scheduler on the current thread,
/// which in most cases will be the 'main' thread, and pins the main task to it.
///
/// This is appropriate for running code that must execute on the main thread,
/// such as the platform event loop and GUI.
pub fn start_on_main_thread(argc: int, argv: **u8, crate_map: *u8, main: ~fn()) -> int {
    init(argc, argv, crate_map);
    let exit_code = run_on_main_thread(main);
    cleanup();

    return exit_code;
}

/// One-time runtime initialization.
///
/// Initializes global state, including frobbing
/// the crate's logging flags, registering GC
/// metadata, and storing the process arguments.
pub fn init(argc: int, argv: **u8, crate_map: *u8) {
    // XXX: Derefing these pointers is not safe.
    // Need to propagate the unsafety to `start`.
    unsafe {
        args::init(argc, argv);
        logging::init(crate_map);
        rust_update_gc_metadata(crate_map);
    }

    extern {
        fn rust_update_gc_metadata(crate_map: *u8);
    }
}

/// One-time runtime cleanup.
pub fn cleanup() {
    args::cleanup();
}

/// Execute the main function in a scheduler.
///
/// Configures the runtime according to the environment, by default
/// using a task scheduler with the same number of threads as cores.
/// Returns a process exit code.
pub fn run(main: ~fn()) -> int {
    run_(main, false)
}

pub fn run_on_main_thread(main: ~fn()) -> int {
    run_(main, true)
}

fn run_(main: ~fn(), use_main_sched: bool) -> int {
    static DEFAULT_ERROR_CODE: int = 101;

    let nscheds = util::default_sched_threads();

    let main = Cell::new(main);

    // The shared list of sleeping schedulers. Schedulers wake each other
    // occassionally to do new work.
    let sleepers = SleeperList::new();
    // The shared work queue. Temporary until work stealing is implemented.
    let work_queue = WorkQueue::new();

    // The schedulers.
    let mut scheds = ~[];
    // Handles to the schedulers. When the main task ends these will be
    // sent the Shutdown message to terminate the schedulers.
    let mut handles = ~[];

    do nscheds.times {
        rtdebug!("inserting a regular scheduler");

        // Every scheduler is driven by an I/O event loop.
        let loop_ = ~UvEventLoop::new();
        let mut sched = ~Scheduler::new(loop_, work_queue.clone(), sleepers.clone());
        let handle = sched.make_handle();

        scheds.push(sched);
        handles.push(handle);
    }

    // If we need a main-thread task then create a main thread scheduler
    // that will reject any task that isn't pinned to it
    let main_sched = if use_main_sched {

        // Create a friend handle.
        let mut friend_sched = scheds.pop();
        let friend_handle = friend_sched.make_handle();
        scheds.push(friend_sched);

        let main_loop = ~UvEventLoop::new();
        let mut main_sched = ~Scheduler::new_special(main_loop,
                                                     work_queue.clone(),
                                                     sleepers.clone(),
                                                     false,
                                                     Some(friend_handle));
        let main_handle = main_sched.make_handle();
        handles.push(main_handle);
        Some(main_sched)
    } else {
        None
    };

    // Create a shared cell for transmitting the process exit
    // code from the main task to this function.
    let exit_code = UnsafeAtomicRcBox::new(AtomicInt::new(0));
    let exit_code_clone = exit_code.clone();

    // When the main task exits, after all the tasks in the main
    // task tree, shut down the schedulers and set the exit code.
    let handles = Cell::new(handles);
    let on_exit: ~fn(bool) = |exit_success| {

        let mut handles = handles.take();
        for handle in handles.mut_iter() {
            handle.send(Shutdown);
        }

        unsafe {
            let exit_code = if exit_success {
                use rt::util;

                // If we're exiting successfully, then return the global
                // exit status, which can be set programmatically.
                util::get_exit_status()
            } else {
                DEFAULT_ERROR_CODE
            };
            (*exit_code_clone.get()).store(exit_code, SeqCst);
        }
    };

    let mut threads = ~[];

    let on_exit = Cell::new(on_exit);

    if !use_main_sched {

        // In the case where we do not use a main_thread scheduler we
        // run the main task in one of our threads.

        let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool,
                                            main.take());
        main_task.death.on_exit = Some(on_exit.take());
        let main_task_cell = Cell::new(main_task);

        let sched = scheds.pop();
        let sched_cell = Cell::new(sched);
        let thread = do Thread::start {
            let sched = sched_cell.take();
            sched.bootstrap(main_task_cell.take());
        };
        threads.push(thread);
    }

    // Run each remaining scheduler in a thread.
    while !scheds.is_empty() {
        rtdebug!("creating regular schedulers");
        let sched = scheds.pop();
        let sched_cell = Cell::new(sched);
        let thread = do Thread::start {
            let mut sched = sched_cell.take();
            let bootstrap_task = ~do Task::new_root(&mut sched.stack_pool) || {
                rtdebug!("boostraping a non-primary scheduler");
            };
            sched.bootstrap(bootstrap_task);
        };
        threads.push(thread);
    }

    // If we do have a main thread scheduler, run it now.

    if use_main_sched {

        rtdebug!("about to create the main scheduler task");

        let mut main_sched = main_sched.get();

        let home = Sched(main_sched.make_handle());
        let mut main_task = ~Task::new_root_homed(&mut main_sched.stack_pool,
                                                  home, main.take());
        main_task.death.on_exit = Some(on_exit.take());
        rtdebug!("boostrapping main_task");

        main_sched.bootstrap(main_task);
    }

    rtdebug!("waiting for threads");

    // Wait for schedulers
    for thread in threads.consume_iter() {
        thread.join();
    }

    // Return the exit code
    unsafe {
        (*exit_code.get()).load(SeqCst)
    }
}

/// Possible contexts in which Rust code may be executing.
/// Different runtime services are available depending on context.
/// Mostly used for determining if we're using the new scheduler
/// or the old scheduler.
#[deriving(Eq)]
pub enum RuntimeContext {
    // Only the exchange heap is available
    GlobalContext,
    // The scheduler may be accessed
    SchedulerContext,
    // Full task services, e.g. local heap, unwinding
    TaskContext,
    // Running in an old-style task
    OldTaskContext
}

/// Determine the current RuntimeContext
pub fn context() -> RuntimeContext {

    use task::rt::rust_task;

    if unsafe { rust_try_get_task().is_not_null() } {
        return OldTaskContext;
    } else if Local::exists::<Task>() {
        // In this case we know it is a new runtime context, but we
        // need to check which one. Going to try borrowing task to
        // check. Task should always be in TLS, so hopefully this
        // doesn't conflict with other ops that borrow.
        return do Local::borrow::<Task,RuntimeContext> |task| {
            match task.task_type {
                SchedTask => SchedulerContext,
                GreenTask(_) => TaskContext
            }
        };
    } else {
        return GlobalContext;
    }

    extern {
        #[rust_stack]
        pub fn rust_try_get_task() -> *rust_task;
    }
}

#[test]
fn test_context() {
    use unstable::run_in_bare_thread;

    assert_eq!(context(), OldTaskContext);
    do run_in_bare_thread {
        assert_eq!(context(), GlobalContext);
    }
}
<commit_msg>std::rt: Remove the test for context()<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.

/*! The Rust Runtime, including the task scheduler and I/O

The `rt` module provides the private runtime infrastructure necessary
to support core language features like the exchange and local heap,
the garbage collector, logging, local data and unwinding. It also
implements the default task scheduler and task model. Initialization
routines are provided for setting up runtime resources in common
configurations, including that used by `rustc` when generating
executables.

It is intended that the features provided by `rt` can be factored in a
way such that the core library can be built with different 'profiles'
for different use cases, e.g. excluding the task scheduler. A number
of runtime features though are critical to the functioning of the
language and an implementation must be provided regardless of the
execution environment.

Of foremost importance is the global exchange heap, in the module
`global_heap`. Very little practical Rust code can be written without
access to the global heap. Unlike most of `rt` the global heap is
truly a global resource and generally operates independently of the
rest of the runtime.

All other runtime features are task-local, including the local heap,
the garbage collector, local storage, logging and the stack unwinder.

The relationship between `rt` and the rest of the core library is
not entirely clear yet and some modules will be moving into or
out of `rt` as development proceeds.

Several modules in `core` are clients of `rt`:

* `core::task` - The user-facing interface to the Rust task model.
* `core::task::local_data` - The interface to local data.
* `core::gc` - The garbage collector.
* `core::unstable::lang` - Miscellaneous lang items, some of which rely on `core::rt`.
* `core::condition` - Uses local data.
* `core::cleanup` - Local heap destruction.
* `core::io` - In the future `core::io` will use an `rt` implementation.
* `core::logging`
* `core::pipes`
* `core::comm`
* `core::stackwalk`

*/

#[doc(hidden)];
#[deny(unused_imports)];
#[deny(unused_mut)];
#[deny(unused_variable)];
#[deny(unused_unsafe)];

use cell::Cell;
use clone::Clone;
use container::Container;
use iter::Times;
use iterator::{Iterator, IteratorUtil};
use option::{Some, None};
use ptr::RawPtr;
use rt::local::Local;
use rt::sched::{Scheduler, Shutdown};
use rt::sleeper_list::SleeperList;
use rt::task::{Task, SchedTask, GreenTask, Sched};
use rt::thread::Thread;
use rt::work_queue::WorkQueue;
use rt::uv::uvio::UvEventLoop;
use unstable::atomics::{AtomicInt, SeqCst};
use unstable::sync::UnsafeAtomicRcBox;
use vec::{OwnedVector, MutableVector};

/// The global (exchange) heap.
pub mod global_heap;

/// Implementations of language-critical runtime features like @.
pub mod task;

/// Facilities related to task failure, killing, and death.
mod kill;

/// The coroutine task scheduler, built on the `io` event loop.
mod sched;

/// Synchronous I/O.
pub mod io;

/// The EventLoop and internal synchronous I/O interface.
mod rtio;

/// libuv and default rtio implementation.
pub mod uv;

/// The Local trait for types that are accessible via thread-local
/// or task-local storage.
pub mod local;

/// A parallel work-stealing deque.
mod work_queue;

/// A parallel queue.
mod message_queue;

/// A parallel data structure for tracking sleeping schedulers.
mod sleeper_list;

/// Stack segments and caching.
mod stack;

/// CPU context swapping.
mod context;

/// Bindings to system threading libraries.
mod thread;

/// The runtime configuration, read from environment variables
pub mod env;

/// The local, managed heap
pub mod local_heap;

/// The Logger trait and implementations
pub mod logging;

/// Tools for testing the runtime
pub mod test;

/// Reference counting
pub mod rc;

/// A simple single-threaded channel type for passing buffered data between
/// scheduler and task context
pub mod tube;

/// Simple reimplementation of core::comm
pub mod comm;

/// Routines for select()ing on pipes.
pub mod select;

// FIXME #5248 shouldn't be pub
/// The runtime needs to be able to put a pointer into thread-local storage.
pub mod local_ptr;

// FIXME #5248: The import in `sched` doesn't resolve unless this is pub!
/// Bindings to pthread/windows thread-local storage.
pub mod thread_local_storage;

pub mod metrics;

// FIXME #5248 shouldn't be pub
/// Just stuff
pub mod util;

// Global command line argument storage
pub mod args;

// Support for dynamic borrowck
pub mod borrowck;

/// Set up a default runtime configuration, given compiler-supplied arguments.
///
/// This is invoked by the `start` _language item_ (unstable::lang) to
/// run a Rust executable.
///
/// # Arguments
///
/// * `argc` & `argv` - The argument vector. On Unix this information is used
///   by os::args.
/// * `crate_map` - Runtime information about the executing crate, mostly for logging
///
/// # Return value
///
/// The return value is used as the process return code. 0 on success, 101 on error.
pub fn start(argc: int, argv: **u8, crate_map: *u8, main: ~fn()) -> int {

    init(argc, argv, crate_map);
    let exit_code = run(main);
    cleanup();

    return exit_code;
}

/// Like `start` but creates an additional scheduler on the current thread,
/// which in most cases will be the 'main' thread, and pins the main task to it.
///
/// This is appropriate for running code that must execute on the main thread,
/// such as the platform event loop and GUI.
pub fn start_on_main_thread(argc: int, argv: **u8, crate_map: *u8, main: ~fn()) -> int {
    init(argc, argv, crate_map);
    let exit_code = run_on_main_thread(main);
    cleanup();

    return exit_code;
}

/// One-time runtime initialization.
///
/// Initializes global state, including frobbing
/// the crate's logging flags, registering GC
/// metadata, and storing the process arguments.
pub fn init(argc: int, argv: **u8, crate_map: *u8) {
    // XXX: Derefing these pointers is not safe.
    // Need to propagate the unsafety to `start`.
    unsafe {
        args::init(argc, argv);
        logging::init(crate_map);
        rust_update_gc_metadata(crate_map);
    }

    extern {
        fn rust_update_gc_metadata(crate_map: *u8);
    }
}

/// One-time runtime cleanup.
pub fn cleanup() {
    args::cleanup();
}

/// Execute the main function in a scheduler.
///
/// Configures the runtime according to the environment, by default
/// using a task scheduler with the same number of threads as cores.
/// Returns a process exit code.
pub fn run(main: ~fn()) -> int {
    run_(main, false)
}

pub fn run_on_main_thread(main: ~fn()) -> int {
    run_(main, true)
}

fn run_(main: ~fn(), use_main_sched: bool) -> int {
    static DEFAULT_ERROR_CODE: int = 101;

    let nscheds = util::default_sched_threads();

    let main = Cell::new(main);

    // The shared list of sleeping schedulers. Schedulers wake each other
    // occassionally to do new work.
    let sleepers = SleeperList::new();
    // The shared work queue. Temporary until work stealing is implemented.
    let work_queue = WorkQueue::new();

    // The schedulers.
    let mut scheds = ~[];
    // Handles to the schedulers. When the main task ends these will be
    // sent the Shutdown message to terminate the schedulers.
    let mut handles = ~[];

    do nscheds.times {
        rtdebug!("inserting a regular scheduler");

        // Every scheduler is driven by an I/O event loop.
        let loop_ = ~UvEventLoop::new();
        let mut sched = ~Scheduler::new(loop_, work_queue.clone(), sleepers.clone());
        let handle = sched.make_handle();

        scheds.push(sched);
        handles.push(handle);
    }

    // If we need a main-thread task then create a main thread scheduler
    // that will reject any task that isn't pinned to it
    let main_sched = if use_main_sched {

        // Create a friend handle.
        let mut friend_sched = scheds.pop();
        let friend_handle = friend_sched.make_handle();
        scheds.push(friend_sched);

        let main_loop = ~UvEventLoop::new();
        let mut main_sched = ~Scheduler::new_special(main_loop,
                                                     work_queue.clone(),
                                                     sleepers.clone(),
                                                     false,
                                                     Some(friend_handle));
        let main_handle = main_sched.make_handle();
        handles.push(main_handle);
        Some(main_sched)
    } else {
        None
    };

    // Create a shared cell for transmitting the process exit
    // code from the main task to this function.
    let exit_code = UnsafeAtomicRcBox::new(AtomicInt::new(0));
    let exit_code_clone = exit_code.clone();

    // When the main task exits, after all the tasks in the main
    // task tree, shut down the schedulers and set the exit code.
    let handles = Cell::new(handles);
    let on_exit: ~fn(bool) = |exit_success| {

        let mut handles = handles.take();
        for handle in handles.mut_iter() {
            handle.send(Shutdown);
        }

        unsafe {
            let exit_code = if exit_success {
                use rt::util;

                // If we're exiting successfully, then return the global
                // exit status, which can be set programmatically.
                util::get_exit_status()
            } else {
                DEFAULT_ERROR_CODE
            };
            (*exit_code_clone.get()).store(exit_code, SeqCst);
        }
    };

    let mut threads = ~[];

    let on_exit = Cell::new(on_exit);

    if !use_main_sched {

        // In the case where we do not use a main_thread scheduler we
        // run the main task in one of our threads.

        let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool,
                                            main.take());
        main_task.death.on_exit = Some(on_exit.take());
        let main_task_cell = Cell::new(main_task);

        let sched = scheds.pop();
        let sched_cell = Cell::new(sched);
        let thread = do Thread::start {
            let sched = sched_cell.take();
            sched.bootstrap(main_task_cell.take());
        };
        threads.push(thread);
    }

    // Run each remaining scheduler in a thread.
    while !scheds.is_empty() {
        rtdebug!("creating regular schedulers");
        let sched = scheds.pop();
        let sched_cell = Cell::new(sched);
        let thread = do Thread::start {
            let mut sched = sched_cell.take();
            let bootstrap_task = ~do Task::new_root(&mut sched.stack_pool) || {
                rtdebug!("boostraping a non-primary scheduler");
            };
            sched.bootstrap(bootstrap_task);
        };
        threads.push(thread);
    }

    // If we do have a main thread scheduler, run it now.

    if use_main_sched {

        rtdebug!("about to create the main scheduler task");

        let mut main_sched = main_sched.get();

        let home = Sched(main_sched.make_handle());
        let mut main_task = ~Task::new_root_homed(&mut main_sched.stack_pool,
                                                  home, main.take());
        main_task.death.on_exit = Some(on_exit.take());
        rtdebug!("boostrapping main_task");

        main_sched.bootstrap(main_task);
    }

    rtdebug!("waiting for threads");

    // Wait for schedulers
    for thread in threads.consume_iter() {
        thread.join();
    }

    // Return the exit code
    unsafe {
        (*exit_code.get()).load(SeqCst)
    }
}

/// Possible contexts in which Rust code may be executing.
/// Different runtime services are available depending on context.
/// Mostly used for determining if we're using the new scheduler
/// or the old scheduler.
#[deriving(Eq)]
pub enum RuntimeContext {
    // Only the exchange heap is available
    GlobalContext,
    // The scheduler may be accessed
    SchedulerContext,
    // Full task services, e.g. local heap, unwinding
    TaskContext,
    // Running in an old-style task
    OldTaskContext
}

/// Determine the current RuntimeContext
pub fn context() -> RuntimeContext {

    use task::rt::rust_task;

    if unsafe { rust_try_get_task().is_not_null() } {
        return OldTaskContext;
    } else if Local::exists::<Task>() {
        // In this case we know it is a new runtime context, but we
        // need to check which one. Going to try borrowing task to
        // check. Task should always be in TLS, so hopefully this
        // doesn't conflict with other ops that borrow.
        return do Local::borrow::<Task,RuntimeContext> |task| {
            match task.task_type {
                SchedTask => SchedulerContext,
                GreenTask(_) => TaskContext
            }
        };
    } else {
        return GlobalContext;
    }

    extern {
        #[rust_stack]
        pub fn rust_try_get_task() -> *rust_task;
    }
}
<|endoftext|>


<commit_before>extern crate texture_atlas;

use texture_atlas::{Atlas, AtlasGenerator, AtlasRect};
use texture_atlas::gen::{BinaryTreeGenerator, PassthroughGenerator};
use texture_atlas::util::Rect;

// TODO: Consider using this function in the lib by default.
fn smoke_atlas<T: AtlasRect>(atlas: &Atlas<T>)
{
	// If the rect generates more bins than rects, something is wrong.
	assert!(atlas.bin_count() <= atlas.rect_count());
	atlas.bin_list();

	// Make sure no bins repeat textures.
	let mut counter = atlas.bin_list().len();
	let mut checker = vec![false; counter];
	for bin in atlas.bin_list()
	{
		for part in bin.parts()
		{
			let rect_index = part.rect_index;
			if checker[rect_index] == true
			{
				panic!("Bin contains rect already in another bin");
			}
			checker[rect_index] = true;
			counter -= 1;
		}
	}
	if counter != 0
	{
		panic!("Atlas does not include all rects");
	}

	// TODO: Make sure atlases do not overlap rects.
}

fn smoke<T: AtlasGenerator>(generator: &T)
{
	const ATLAS_WIDTH: u32 = 256;
	const ATLAS_HEIGHT: u32 = 128;

	const RECT_LARGE_WIDTH: u32 = 192;
	const RECT_LARGE_HEIGHT: u32 = 96;

	let rect_large = Rect::new(RECT_LARGE_WIDTH, RECT_LARGE_HEIGHT);

	// Empty rect list should generate no bins.
	let list_empty: Vec<Rect> = Vec::new();
	let atlas = Atlas::with_max(generator, &list_empty, ATLAS_WIDTH, ATLAS_HEIGHT);
	assert_eq!(atlas.bin_count(), 0);

	// Single item rect list should always generate one bin.
	let list_single = vec![rect_large];
	let atlas = Atlas::with_max(generator, &list_single, ATLAS_WIDTH, ATLAS_HEIGHT);
	assert_eq!(atlas.bin_count(), 1);

	// Having two large items means you cannot fit everything, so two bins.
	let list_large = vec![rect_large, rect_large];
	let atlas = Atlas::with_max(generator, &list_large, ATLAS_WIDTH, ATLAS_HEIGHT);
	assert_eq!(atlas.bin_count(), 2);
	smoke_atlas(&atlas);
}

#[test]
fn test_passthrough()
{
	smoke(&PassthroughGenerator);
}

#[test]
fn test_binary_tree()
{
	smoke(&BinaryTreeGenerator);

	// TODO: Better tests specific to this generator.
}
<commit_msg>Lint with Clippy<commit_after>extern crate texture_atlas;

use texture_atlas::{Atlas, AtlasGenerator, AtlasRect};
use texture_atlas::gen::{BinaryTreeGenerator, PassthroughGenerator};
use texture_atlas::util::Rect;

// TODO: Consider using this function in the lib by default.
fn smoke_atlas<T: AtlasRect>(atlas: &Atlas<T>)
{
	// If the rect generates more bins than rects, something is wrong.
	assert!(atlas.bin_count() <= atlas.rect_count());
	atlas.bin_list();

	// Make sure no bins repeat textures.
	let mut counter = atlas.bin_list().len();
	let mut checker = vec![false; counter];
	for bin in atlas.bin_list()
	{
		for part in bin.parts()
		{
			let rect_index = part.rect_index;
			if checker[rect_index]
			{
				panic!("Bin contains rect already in another bin");
			}
			checker[rect_index] = true;
			counter -= 1;
		}
	}
	if counter != 0
	{
		panic!("Atlas does not include all rects");
	}

	// TODO: Make sure atlases do not overlap rects.
}

fn smoke<T: AtlasGenerator>(generator: &T)
{
	const ATLAS_WIDTH: u32 = 256;
	const ATLAS_HEIGHT: u32 = 128;

	const RECT_LARGE_WIDTH: u32 = 192;
	const RECT_LARGE_HEIGHT: u32 = 96;

	let rect_large = Rect::new(RECT_LARGE_WIDTH, RECT_LARGE_HEIGHT);

	// Empty rect list should generate no bins.
	let list_empty: Vec<Rect> = Vec::new();
	let atlas = Atlas::with_max(generator, &list_empty, ATLAS_WIDTH, ATLAS_HEIGHT);
	assert_eq!(atlas.bin_count(), 0);

	// Single item rect list should always generate one bin.
	let list_single = vec![rect_large];
	let atlas = Atlas::with_max(generator, &list_single, ATLAS_WIDTH, ATLAS_HEIGHT);
	assert_eq!(atlas.bin_count(), 1);

	// Having two large items means you cannot fit everything, so two bins.
	let list_large = vec![rect_large, rect_large];
	let atlas = Atlas::with_max(generator, &list_large, ATLAS_WIDTH, ATLAS_HEIGHT);
	assert_eq!(atlas.bin_count(), 2);
	smoke_atlas(&atlas);
}

#[test]
fn test_passthrough()
{
	smoke(&PassthroughGenerator);
}

#[test]
fn test_binary_tree()
{
	smoke(&BinaryTreeGenerator);

	// TODO: Better tests specific to this generator.
}
<|endoftext|>


<commit_before>use neb::ram::types;
use neb::ram::chunk;

pub const CHUNK_SIZE: usize = 2048;

macro_rules! test_nums {
    (
        $t:ident, $io:ident
    ) => (
        mod $t {
            use neb::ram::types;
            use neb::ram::chunk::Chunks;
            use std;
            use rand;
            use super::CHUNK_SIZE;
            #[test]
            fn test () {
                let rand_num = rand::random::<$t>();
                let test_data = vec![std::$t::MIN, std::$t::MAX, rand_num, 0 as $t, 1 as $t, 2 as $t, 127 as $t];
                let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
                let counts = CHUNK_SIZE / types::$io::size(0) as usize;
                for d in test_data {
                    for i in 0..counts {
                        let addr = chunk.addr + i * types::$io::size(0);
                        types::$io::write(d, addr);
                        assert!(types::$io::read(addr) == d);
                    }
                    for i in 0..counts {
                        let addr = chunk.addr + i * types::$io::size(0);
                        assert!(types::$io::read(addr) == d);
                    }
                }
            }
        }
    );
}

test_nums!(i8, i8_io);
test_nums!(i16, i16_io);
test_nums!(i32, i32_io);
test_nums!(i64, i64_io);

test_nums!(u8, u8_io);
test_nums!(u16, u16_io);
test_nums!(u32, u32_io);
test_nums!(u64, u64_io);

test_nums!(isize, isize_io);
test_nums!(usize, usize_io);
test_nums!(f32, f32_io);
test_nums!(f64, f64_io);

mod pos2d32 {
    use neb::ram::types;
    use neb::ram::chunk::Chunks;
    use std;
    use rand;
    use super::CHUNK_SIZE;
    #[test]
    fn test () {
        let test_data = vec![
            types::Pos2d32 {x: std::f32::MIN, y: std::f32::MAX},
            types::Pos2d32 {x: rand::random::<f32>(), y: rand::random::<f32>()}
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::pos2d32_io::size(0) as usize;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk.addr + i * types::pos2d32_io::size(0);
                types::pos2d32_io::write(&d, addr);
                assert!(types::pos2d32_io::read(addr) == d);
            }
            for i in 0..counts {
                let addr = chunk.addr + i * types::pos2d32_io::size(0);
                assert!(types::pos2d32_io::read(addr) == d);
            }
        }
    }
}

mod pos2d64 {
    use neb::ram::types;
    use neb::ram::chunk::Chunks;
    use std;
    use rand;
    use super::CHUNK_SIZE;
    #[test]
    fn test () {
        let test_data = vec![
            types::Pos2d64 {x: std::f64::MIN, y: std::f64::MAX},
            types::Pos2d64 {x: rand::random::<f64>(), y: rand::random::<f64>()}
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::pos2d64_io::size(0) as usize;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk.addr + i * types::pos2d64_io::size(0);
                types::pos2d64_io::write(&d, addr);
                assert!(types::pos2d64_io::read(addr) == d);
            }
            for i in 0..counts {
                let addr = chunk.addr + i * types::pos2d64_io::size(0);
                assert!(types::pos2d64_io::read(addr) == d);
            }
        }
    }
}

mod pos3d32 {
    use neb::ram::types;
    use neb::ram::chunk::Chunks;
    use std;
    use rand;
    use super::CHUNK_SIZE;
    #[test]
    fn test () {
        let test_data = vec![
            types::Pos3d32 {x: std::f32::MIN, y: std::f32::MAX, z: rand::random::<f32>()},
            types::Pos3d32 {x: rand::random::<f32>(), y: rand::random::<f32>(), z: rand::random::<f32>()}
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::pos3d32_io::size(0) as usize;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk.addr + i * types::pos3d32_io::size(0);
                types::pos3d32_io::write(&d, addr);
                assert!(types::pos3d32_io::read(addr) == d);
            }
            for i in 0..counts {
                let addr = chunk.addr + i * types::pos3d32_io::size(0);
                assert!(types::pos3d32_io::read(addr) == d);
            }
        }
    }
}

mod pos3d64 {
    use neb::ram::types;
    use neb::ram::chunk::Chunks;
    use std;
    use rand;
    use super::CHUNK_SIZE;
    #[test]
    fn test () {
        let test_data = vec![
            types::Pos3d64 {x: std::f64::MIN, y: std::f64::MAX, z: rand::random::<f64>()},
            types::Pos3d64 {x: rand::random::<f64>(), y: rand::random::<f64>(), z: rand::random::<f64>()}
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::pos3d64_io::size(0) as usize;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk.addr + i * types::pos3d64_io::size(0);
                types::pos3d64_io::write(&d, addr);
                assert!(types::pos3d64_io::read(addr) == d);
            }
            for i in 0..counts {
                let addr = chunk.addr + i * types::pos3d64_io::size(0);
                assert!(types::pos3d64_io::read(addr) == d);
            }
        }
    }
}

mod uuid {
    use neb::ram::types;
    use neb::ram::types::Id;
    use neb::ram::chunk::Chunks;
    use super::CHUNK_SIZE;
    #[test]
    fn test () {
        let test_data = vec![Id {higher: 1, lower: 2}];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::id_io::size(0) as usize;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk.addr + i * types::id_io::size(0);
                types::id_io::write(&d, addr);
                assert!(types::id_io::read(addr) == d);
            }
            for i in 0..counts {
                let addr = chunk.addr + i * types::id_io::size(0);
                assert!(types::id_io::read(addr) == d);
            }
        }
    }
}

mod string {
    use neb::ram::types;
    use neb::ram::chunk::Chunks;
    use std::string::String;
    use super::CHUNK_SIZE;
    #[test]
    fn test () {
        let test_data = vec![
            "", "ಬಾ ಇಲ್ಲಿ ಸಂಭವಿಸ", "中文测试文本", "Hello Test", "💖"
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let mut addr = chunk.addr;
        for d in test_data.clone() {
            let test_str = String::from(d);
            types::string_io::write(&test_str, addr);
            let len = types::string_io::size(addr);
            let dec_str = types::string_io::read(addr);
            assert!(dec_str == test_str);
            println!("{}", dec_str);
            addr += len;
        }
        addr = chunk.addr;
        for d in test_data.clone() {
            let test_str = String::from(d);
            let len = types::string_io::size(addr);
            assert!(types::string_io::read(addr) == test_str);
            addr += len;
        }
    }
}

#[test]
fn array_len_type () {
    assert_eq!(types::u16_io::size(0), types::get_size(types::ARRAY_LEN_TYPE_ID, 0))
}

#[test]
fn null_type () {
    assert_eq!(types::u8_io::size(0), types::get_size(types::NULL_TYPE_ID, 0))
}<commit_msg>_in map tests<commit_after>use neb::ram::types;
use neb::ram::chunk;

pub const CHUNK_SIZE: usize = 2048;

macro_rules! test_nums {
    (
        $t:ident, $io:ident
    ) => (
        mod $t {
            use neb::ram::types;
            use neb::ram::chunk::Chunks;
            use std;
            use rand;
            use super::CHUNK_SIZE;
            #[test]
            fn test () {
                let rand_num = rand::random::<$t>();
                let test_data = vec![std::$t::MIN, std::$t::MAX, rand_num, 0 as $t, 1 as $t, 2 as $t, 127 as $t];
                let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
                let counts = CHUNK_SIZE / types::$io::size(0) as usize;
                for d in test_data {
                    for i in 0..counts {
                        let addr = chunk.addr + i * types::$io::size(0);
                        types::$io::write(d, addr);
                        assert!(types::$io::read(addr) == d);
                    }
                    for i in 0..counts {
                        let addr = chunk.addr + i * types::$io::size(0);
                        assert!(types::$io::read(addr) == d);
                    }
                }
            }
        }
    );
}

test_nums!(i8, i8_io);
test_nums!(i16, i16_io);
test_nums!(i32, i32_io);
test_nums!(i64, i64_io);

test_nums!(u8, u8_io);
test_nums!(u16, u16_io);
test_nums!(u32, u32_io);
test_nums!(u64, u64_io);

test_nums!(isize, isize_io);
test_nums!(usize, usize_io);
test_nums!(f32, f32_io);
test_nums!(f64, f64_io);

mod pos2d32 {
    use neb::ram::types;
    use neb::ram::chunk::Chunks;
    use std;
    use rand;
    use super::CHUNK_SIZE;
    #[test]
    fn test () {
        let test_data = vec![
            types::Pos2d32 {x: std::f32::MIN, y: std::f32::MAX},
            types::Pos2d32 {x: rand::random::<f32>(), y: rand::random::<f32>()}
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::pos2d32_io::size(0) as usize;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk.addr + i * types::pos2d32_io::size(0);
                types::pos2d32_io::write(&d, addr);
                assert!(types::pos2d32_io::read(addr) == d);
            }
            for i in 0..counts {
                let addr = chunk.addr + i * types::pos2d32_io::size(0);
                assert!(types::pos2d32_io::read(addr) == d);
            }
        }
    }
}

mod pos2d64 {
    use neb::ram::types;
    use neb::ram::chunk::Chunks;
    use std;
    use rand;
    use super::CHUNK_SIZE;
    #[test]
    fn test () {
        let test_data = vec![
            types::Pos2d64 {x: std::f64::MIN, y: std::f64::MAX},
            types::Pos2d64 {x: rand::random::<f64>(), y: rand::random::<f64>()}
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::pos2d64_io::size(0) as usize;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk.addr + i * types::pos2d64_io::size(0);
                types::pos2d64_io::write(&d, addr);
                assert!(types::pos2d64_io::read(addr) == d);
            }
            for i in 0..counts {
                let addr = chunk.addr + i * types::pos2d64_io::size(0);
                assert!(types::pos2d64_io::read(addr) == d);
            }
        }
    }
}

mod pos3d32 {
    use neb::ram::types;
    use neb::ram::chunk::Chunks;
    use std;
    use rand;
    use super::CHUNK_SIZE;
    #[test]
    fn test () {
        let test_data = vec![
            types::Pos3d32 {x: std::f32::MIN, y: std::f32::MAX, z: rand::random::<f32>()},
            types::Pos3d32 {x: rand::random::<f32>(), y: rand::random::<f32>(), z: rand::random::<f32>()}
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::pos3d32_io::size(0) as usize;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk.addr + i * types::pos3d32_io::size(0);
                types::pos3d32_io::write(&d, addr);
                assert!(types::pos3d32_io::read(addr) == d);
            }
            for i in 0..counts {
                let addr = chunk.addr + i * types::pos3d32_io::size(0);
                assert!(types::pos3d32_io::read(addr) == d);
            }
        }
    }
}

mod pos3d64 {
    use neb::ram::types;
    use neb::ram::chunk::Chunks;
    use std;
    use rand;
    use super::CHUNK_SIZE;
    #[test]
    fn test () {
        let test_data = vec![
            types::Pos3d64 {x: std::f64::MIN, y: std::f64::MAX, z: rand::random::<f64>()},
            types::Pos3d64 {x: rand::random::<f64>(), y: rand::random::<f64>(), z: rand::random::<f64>()}
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::pos3d64_io::size(0) as usize;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk.addr + i * types::pos3d64_io::size(0);
                types::pos3d64_io::write(&d, addr);
                assert!(types::pos3d64_io::read(addr) == d);
            }
            for i in 0..counts {
                let addr = chunk.addr + i * types::pos3d64_io::size(0);
                assert!(types::pos3d64_io::read(addr) == d);
            }
        }
    }
}

mod uuid {
    use neb::ram::types;
    use neb::ram::types::Id;
    use neb::ram::chunk::Chunks;
    use super::CHUNK_SIZE;
    #[test]
    fn test () {
        let test_data = vec![Id {higher: 1, lower: 2}];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::id_io::size(0) as usize;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk.addr + i * types::id_io::size(0);
                types::id_io::write(&d, addr);
                assert!(types::id_io::read(addr) == d);
            }
            for i in 0..counts {
                let addr = chunk.addr + i * types::id_io::size(0);
                assert!(types::id_io::read(addr) == d);
            }
        }
    }
}

mod string {
    use neb::ram::types;
    use neb::ram::chunk::Chunks;
    use std::string::String;
    use super::CHUNK_SIZE;
    #[test]
    fn test () {
        let test_data = vec![
            "", "ಬಾ ಇಲ್ಲಿ ಸಂಭವಿಸ", "中文测试文本", "Hello Test", "💖"
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let mut addr = chunk.addr;
        for d in test_data.clone() {
            let test_str = String::from(d);
            types::string_io::write(&test_str, addr);
            let len = types::string_io::size(addr);
            let dec_str = types::string_io::read(addr);
            assert!(dec_str == test_str);
            println!("{}", dec_str);
            addr += len;
        }
        addr = chunk.addr;
        for d in test_data.clone() {
            let test_str = String::from(d);
            let len = types::string_io::size(addr);
            assert!(types::string_io::read(addr) == test_str);
            addr += len;
        }
    }
}

#[test]
fn array_len_type () {
    assert_eq!(types::u16_io::size(0), types::get_size(types::ARRAY_LEN_TYPE_ID, 0))
}

#[test]
fn null_type () {
    assert_eq!(types::u8_io::size(0), types::get_size(types::NULL_TYPE_ID, 0))
}

#[test]
fn _in_map() {
    let mut map2 = types::Map::new();
    map2.insert(&String::from("a"), types::Value::I32(1));
    map2.insert(&String::from("b"), types::Value::I64(2));

    let mut map = types::Map::new();
    map.insert(&String::from("A"), types::Value::I32(1));
    map.insert(&String::from("B"), types::Value::Map(map2));

    assert_eq!(map.get(&String::from("A")).unwrap().I32().unwrap(), 1);
    assert_eq!(map.get_in(vec!["B", "a"]).unwrap().I32().unwrap(), 1);

    map.set_in(vec!["B", "a"], types::Value::I32(20)).unwrap();
    assert_eq!(map.get_in(vec!["B", "a"]).unwrap().I32().unwrap(), 20);

    map.update_in(vec!["B", "b"], |value: &mut types::Value| {
        assert_eq!(value.I64().unwrap(), 2);
        *value = types::Value::I64(30);
    });
    assert_eq!(map.get_in(vec!["B", "b"]).unwrap().I64().unwrap(), 30);
}<|endoftext|>


<commit_before>#![feature(core)]
#![feature(io)]

//! #Introduction
//! This crate focuses on geting system information.
//!
//! For now it supports Linux, Mac OS X and Windows.
//! And now it can get information of kernel/cpu/memory/disk/load/hostname and so on.
//!

use std::ffi;
use std::str;
use std::io::Read;
use std::fs::File;
use std::sync::{Once, ONCE_INIT};
use std::mem;

/// System load average value.
#[repr(C)]
pub struct LoadAvg {
    /// Average load within one minite.
    pub one: f64,
    /// Average load within five minites.
    pub five: f64,
    /// Average load within fifteen minites.
    pub fifteen: f64
}

/// System memory information.
#[repr(C)]
pub struct MemInfo {
    /// Total physical memory.
    pub total: u64,
    pub free:  u64,
    pub avail: u64,

    pub buffers: u64,
    pub cached:  u64,

    /// Total swap memory.
    pub swap_total: u64,
    pub swap_free:  u64
}

/// System momory information.
#[repr(C)]
pub struct DiskInfo {
    pub total: u64,
    pub free: u64
}

extern {
    fn get_os_type() -> *const i8;
    fn get_os_release() -> *const i8;

    fn get_cpu_num() -> u32;
    fn get_cpu_speed() -> u64;

    fn get_loadavg() -> LoadAvg;
    fn get_proc_total() -> u64;

    fn get_mem_info() -> MemInfo;
    fn get_disk_info() -> DiskInfo;
}

/// Get operation system type.
///
/// Such as "Linux", "Darwin", "Windows".
pub fn os_type() -> Result<String, String> {
    static mut OS_TYPE: &'static str = "";
    static OS_TYPE_INIT: Once = ONCE_INIT;
    if cfg!(unix) || cfg!(windows) {
        unsafe {
            OS_TYPE_INIT.call_once(|| {
                if cfg!(target_os = "linux") {
                    let mut f = File::open("/proc/sys/kernel/ostype").unwrap();
                    let mut s = String::new();
                    let _ = f.read_to_string(&mut s).unwrap();
                    s.pop();  // pop '\n'
                    OS_TYPE = mem::copy_lifetime(OS_TYPE, s.as_slice());
                    mem::forget(s);
                } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
                    OS_TYPE = str::from_utf8(ffi::CStr::from_ptr(get_os_type())
                                   .to_bytes()).unwrap()
                }
            });
            Ok(OS_TYPE.to_string())
        }
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get operation system release version.
///
/// Such as "3.19.0-gentoo"
pub fn os_release() -> Result<String, String> {
    static mut OS_RELEASE: &'static str = "";
    static OS_RELEASE_INIT: Once = ONCE_INIT;
    if cfg!(unix) || cfg!(windows) {
        unsafe {
            OS_RELEASE_INIT.call_once(|| {
                if cfg!(target_os = "linux") {
                    let mut f = File::open("/proc/sys/kernel/osrelease").unwrap();
                    let mut s = String::new();
                    let _ = f.read_to_string(&mut s).unwrap();
                    s.pop();
                    OS_RELEASE = std::mem::copy_lifetime(OS_RELEASE, s.as_slice());
                    mem::forget(s);
                } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
                    OS_RELEASE = str::from_utf8(
                        ffi::CStr::from_ptr(get_os_release()).to_bytes()).unwrap();
                }
            });
            Ok(OS_RELEASE.to_string())
        }
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get cpu num quantity.
///
/// Notice, it returns the logical cpu quantity.
pub fn cpu_num() -> Result<u32, String> {
    static mut CPU_NUM: u32 = 0;
    static CPU_NUM_INIT: Once = ONCE_INIT;
    if cfg!(unix) || cfg!(windows) {
        unsafe {
            CPU_NUM_INIT.call_once(|| {
                CPU_NUM = get_cpu_num();
            });
            Ok(CPU_NUM)
        }
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get cpu speed.
///
/// Such as 2500, that is 2500 MHz.
pub fn cpu_speed() -> Result<u64, String> {
    static mut CPU_SPEED: u64 = 0;
    static CPU_SPEED_INIT: Once = ONCE_INIT;
    if cfg!(unix) || cfg!(windows) {
        unsafe {
            CPU_SPEED_INIT.call_once(|| {
                CPU_SPEED = if cfg!(target_os = "linux") {
                    // /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq
                    let mut f = File::open("/proc/cpuinfo").unwrap();
                    let mut s = String::new();
                    let _ = f.read_to_string(&mut s).unwrap();
                    let mut lines = s.as_slice().split('\n');
                    for _ in 0..7 {
                        lines.next();
                    }
                    let mut words = lines.next().unwrap().split(':');
                    words.next();
                    let s = words.next().unwrap().trim().trim_right_matches('\n');
                    s.parse::<f64>().unwrap() as u64
                } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
                    get_cpu_speed()
                } else { 0 };
            });
            Ok(CPU_SPEED)
        }
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get system load average value.
///
/// Notice, on windows, one/five/fifteen of the LoadAvg returned are the current load.
pub fn loadavg() -> Result<LoadAvg, String> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/loadavg").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        let mut words = s.as_slice().split(' ');
        let one = words.next().unwrap().parse::<f64>().unwrap();
        let five = words.next().unwrap().parse::<f64>().unwrap();
        let fifteen = words.next().unwrap().parse::<f64>().unwrap();
        Ok(LoadAvg { one: one, five: five, fifteen: fifteen} )
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_loadavg() })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get current processes quantity.
///
/// Notice, it temporarily does not support Windows.
pub fn proc_total() -> Result<u64, String> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/loadavg").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        Ok({
            let mut words = s.as_slice().splitn(3, ' ');
            for _ in 0..3 {
                words.next();
            }
            let mut words = words.next().unwrap().split('/');
            words.next();
            let mut words = words.next().unwrap().split(' ');
            words.next().unwrap().parse::<u64>().unwrap()
        })
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_proc_total() })
    } else {
        Err("Unsupported system".to_string())
    }
}

// Analyse number from line.
fn get_mem_num(line: &str) -> u64 {
    let mut line = line.splitn(1, ' ');
    line.next();
    line.next().unwrap().trim_left().split(' ').next().unwrap()
        .parse::<u64>().unwrap()
}

/// Get memory information.
///
/// On Mac OS X and Windows, the buffers and cached variables of the MemInfo returned are zero.
pub fn mem_info() -> Result<MemInfo, String> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/meminfo").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        let mut lines = s.as_slice().split('\n');
        let total = get_mem_num(lines.next().unwrap());
        let free = get_mem_num(lines.next().unwrap());
        let avail = get_mem_num(lines.next().unwrap());
        let buffers = get_mem_num(lines.next().unwrap());
        let cached = get_mem_num(lines.next().unwrap());
        let swap_total = {
            for _ in 0..9 {
                lines.next();
            }
            get_mem_num(lines.next().unwrap())
        };
        let swap_free = get_mem_num(lines.next().unwrap());

        Ok(MemInfo{ total: total, free: free, avail: avail,
                    buffers: buffers, cached: cached,
                    swap_total: swap_total, swap_free: swap_free})
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_mem_info() })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get disk information.
///
/// Notice, it just calculate current disk on Windows.
pub fn disk_info() -> Result<DiskInfo, String> {
    if cfg!(target_os = "linux") ||
        cfg!(target_os = "macos") ||
        cfg!(target_os = "windows")
    {
        Ok(unsafe { get_disk_info() })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get hostname.
pub fn hostname() -> Result<String, String> {
    use std::process::Command;
    if cfg!(unix) {
        let output = match Command::new("hostname").output() {
            Ok(o)  => o,
            Err(e) => return Err(format!("failed to execute process: {}", e)),
        };
        let mut s = String::from_utf8(output.stdout).unwrap();
        s.pop();  // pop '\n'
        Ok(s)
    } else if cfg!(windows) {
        let output = match Command::new("hostname").output() {
            Ok(o)  => o,
            Err(e) => return Err(format!("failed to execute process: {}", e)),
        };
        let mut s = String::from_utf8(output.stdout).unwrap();
        s.pop();  // pop '\n'
        Ok(s)
    } else {
        Err("Unsupported system".to_string())
    }
}

<commit_msg>fix for nightly rustc<commit_after>#![feature(core)]

//! #Introduction
//! This crate focuses on geting system information.
//!
//! For now it supports Linux, Mac OS X and Windows.
//! And now it can get information of kernel/cpu/memory/disk/load/hostname and so on.
//!

use std::ffi;
use std::str;
use std::io::Read;
use std::fs::File;
use std::sync::{Once, ONCE_INIT};
use std::mem;

/// System load average value.
#[repr(C)]
pub struct LoadAvg {
    /// Average load within one minite.
    pub one: f64,
    /// Average load within five minites.
    pub five: f64,
    /// Average load within fifteen minites.
    pub fifteen: f64
}

/// System memory information.
#[repr(C)]
pub struct MemInfo {
    /// Total physical memory.
    pub total: u64,
    pub free:  u64,
    pub avail: u64,

    pub buffers: u64,
    pub cached:  u64,

    /// Total swap memory.
    pub swap_total: u64,
    pub swap_free:  u64
}

/// System momory information.
#[repr(C)]
pub struct DiskInfo {
    pub total: u64,
    pub free: u64
}

extern {
    fn get_os_type() -> *const i8;
    fn get_os_release() -> *const i8;

    fn get_cpu_num() -> u32;
    fn get_cpu_speed() -> u64;

    fn get_loadavg() -> LoadAvg;
    fn get_proc_total() -> u64;

    fn get_mem_info() -> MemInfo;
    fn get_disk_info() -> DiskInfo;
}

/// Get operation system type.
///
/// Such as "Linux", "Darwin", "Windows".
pub fn os_type() -> Result<String, String> {
    static mut OS_TYPE: &'static str = "";
    static OS_TYPE_INIT: Once = ONCE_INIT;
    if cfg!(unix) || cfg!(windows) {
        unsafe {
            OS_TYPE_INIT.call_once(|| {
                if cfg!(target_os = "linux") {
                    let mut f = File::open("/proc/sys/kernel/ostype").unwrap();
                    let mut s = String::new();
                    let _ = f.read_to_string(&mut s).unwrap();
                    s.pop();  // pop '\n'
                    OS_TYPE = mem::copy_lifetime(OS_TYPE, s.as_slice());
                    mem::forget(s);
                } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
                    OS_TYPE = str::from_utf8(ffi::CStr::from_ptr(get_os_type())
                                   .to_bytes()).unwrap()
                }
            });
            Ok(OS_TYPE.to_string())
        }
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get operation system release version.
///
/// Such as "3.19.0-gentoo"
pub fn os_release() -> Result<String, String> {
    static mut OS_RELEASE: &'static str = "";
    static OS_RELEASE_INIT: Once = ONCE_INIT;
    if cfg!(unix) || cfg!(windows) {
        unsafe {
            OS_RELEASE_INIT.call_once(|| {
                if cfg!(target_os = "linux") {
                    let mut f = File::open("/proc/sys/kernel/osrelease").unwrap();
                    let mut s = String::new();
                    let _ = f.read_to_string(&mut s).unwrap();
                    s.pop();
                    OS_RELEASE = std::mem::copy_lifetime(OS_RELEASE, s.as_slice());
                    mem::forget(s);
                } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
                    OS_RELEASE = str::from_utf8(
                        ffi::CStr::from_ptr(get_os_release()).to_bytes()).unwrap();
                }
            });
            Ok(OS_RELEASE.to_string())
        }
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get cpu num quantity.
///
/// Notice, it returns the logical cpu quantity.
pub fn cpu_num() -> Result<u32, String> {
    static mut CPU_NUM: u32 = 0;
    static CPU_NUM_INIT: Once = ONCE_INIT;
    if cfg!(unix) || cfg!(windows) {
        unsafe {
            CPU_NUM_INIT.call_once(|| {
                CPU_NUM = get_cpu_num();
            });
            Ok(CPU_NUM)
        }
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get cpu speed.
///
/// Such as 2500, that is 2500 MHz.
pub fn cpu_speed() -> Result<u64, String> {
    static mut CPU_SPEED: u64 = 0;
    static CPU_SPEED_INIT: Once = ONCE_INIT;
    if cfg!(unix) || cfg!(windows) {
        unsafe {
            CPU_SPEED_INIT.call_once(|| {
                CPU_SPEED = if cfg!(target_os = "linux") {
                    // /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq
                    let mut f = File::open("/proc/cpuinfo").unwrap();
                    let mut s = String::new();
                    let _ = f.read_to_string(&mut s).unwrap();
                    let mut lines = s.as_slice().split('\n');
                    for _ in 0..7 {
                        lines.next();
                    }
                    let mut words = lines.next().unwrap().split(':');
                    words.next();
                    let s = words.next().unwrap().trim().trim_right_matches('\n');
                    s.parse::<f64>().unwrap() as u64
                } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
                    get_cpu_speed()
                } else { 0 };
            });
            Ok(CPU_SPEED)
        }
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get system load average value.
///
/// Notice, on windows, one/five/fifteen of the LoadAvg returned are the current load.
pub fn loadavg() -> Result<LoadAvg, String> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/loadavg").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        let mut words = s.as_slice().split(' ');
        let one = words.next().unwrap().parse::<f64>().unwrap();
        let five = words.next().unwrap().parse::<f64>().unwrap();
        let fifteen = words.next().unwrap().parse::<f64>().unwrap();
        Ok(LoadAvg { one: one, five: five, fifteen: fifteen} )
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_loadavg() })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get current processes quantity.
///
/// Notice, it temporarily does not support Windows.
pub fn proc_total() -> Result<u64, String> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/loadavg").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        Ok({
            let mut words = s.as_slice().splitn(3, ' ');
            for _ in 0..3 {
                words.next();
            }
            let mut words = words.next().unwrap().split('/');
            words.next();
            let mut words = words.next().unwrap().split(' ');
            words.next().unwrap().parse::<u64>().unwrap()
        })
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_proc_total() })
    } else {
        Err("Unsupported system".to_string())
    }
}

// Analyse number from line.
fn get_mem_num(line: &str) -> u64 {
    let mut line = line.splitn(1, ' ');
    line.next();
    line.next().unwrap().trim_left().split(' ').next().unwrap()
        .parse::<u64>().unwrap()
}

/// Get memory information.
///
/// On Mac OS X and Windows, the buffers and cached variables of the MemInfo returned are zero.
pub fn mem_info() -> Result<MemInfo, String> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/meminfo").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        let mut lines = s.as_slice().split('\n');
        let total = get_mem_num(lines.next().unwrap());
        let free = get_mem_num(lines.next().unwrap());
        let avail = get_mem_num(lines.next().unwrap());
        let buffers = get_mem_num(lines.next().unwrap());
        let cached = get_mem_num(lines.next().unwrap());
        let swap_total = {
            for _ in 0..9 {
                lines.next();
            }
            get_mem_num(lines.next().unwrap())
        };
        let swap_free = get_mem_num(lines.next().unwrap());

        Ok(MemInfo{ total: total, free: free, avail: avail,
                    buffers: buffers, cached: cached,
                    swap_total: swap_total, swap_free: swap_free})
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_mem_info() })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get disk information.
///
/// Notice, it just calculate current disk on Windows.
pub fn disk_info() -> Result<DiskInfo, String> {
    if cfg!(target_os = "linux") ||
        cfg!(target_os = "macos") ||
        cfg!(target_os = "windows")
    {
        Ok(unsafe { get_disk_info() })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get hostname.
pub fn hostname() -> Result<String, String> {
    use std::process::Command;
    if cfg!(unix) {
        let output = match Command::new("hostname").output() {
            Ok(o)  => o,
            Err(e) => return Err(format!("failed to execute process: {}", e)),
        };
        let mut s = String::from_utf8(output.stdout).unwrap();
        s.pop();  // pop '\n'
        Ok(s)
    } else if cfg!(windows) {
        let output = match Command::new("hostname").output() {
            Ok(o)  => o,
            Err(e) => return Err(format!("failed to execute process: {}", e)),
        };
        let mut s = String::from_utf8(output.stdout).unwrap();
        s.pop();  // pop '\n'
        Ok(s)
    } else {
        Err("Unsupported system".to_string())
    }
}

<|endoftext|>


<commit_before>//! Logging scopes for slog-rs
//!
//! Logging scopes are convinience functionality for slog-rs to free user from manually passing
//! `Logger` objects around.
//!
//! Set of macros is also provided as an alternative to original `slog` crate macros, for logging
//! directly to `Logger` of the current logging scope.
//!
//! Note: Part of a `slog` logging philosophy is ability to freely express logging contexts
//! according to logical structure, rather than code structure. By using logging scopes the logging
//! context is tied to code flow again, which is less expressive.
//!
//! It is generally advised **NOT** to use `slog_scope` in libraries. Read more in
//! [slog-rs FAQ](https://github.com/slog-rs/slog/wiki/FAQ#do-i-have-to-pass-logger-around)
//!
//! ```
//! #[macro_use(slog_o, slog_info, slog_log, slog_record, slog_record_static, slog_b, slog_kv)]
//! extern crate slog;
//! #[macro_use]
//! extern crate slog_scope;
//! extern crate slog_term;
//!
//! use slog::Drain;
//!
//! fn foo() {
//!     slog_info!(slog_scope::logger(), "foo");
//!     info!("foo"); // Same as above, but more ergonomic.
//! }
//!
//! fn main() {
//!     let plain = slog_term::PlainSyncDecorator::new(std::io::stdout());
//!     let log = slog::Logger::root(
//!         slog_term::FullFormat::new(plain)
//!         .build().fuse(), slog_o!()
//!     );
//!
//!     slog_scope::set_global_logger(log);
//!     slog_scope::scope(slog_scope::logger().new(slog_o!("scope" => "1")),
//!         || foo()
//!     );
//! }

#![warn(missing_docs)]

#[macro_use(o)]
extern crate slog;
#[macro_use]
extern crate lazy_static;
extern crate crossbeam;

use slog::*;

use std::sync::Arc;
use std::cell::RefCell;
use crossbeam::sync::ArcCell;

/// Log a critical level message using current scope logger
#[macro_export]
macro_rules! crit( ($($args:tt)+) => { slog_crit![$crate::logger(), $($args)+]; };);
/// Log a error level message using current scope logger
#[macro_export]
macro_rules! error( ($($args:tt)+) => { slog_error![$crate::logger(), $($args)+]; };);
/// Log a warning level message using current scope logger
#[macro_export]
macro_rules! warn( ($($args:tt)+) => { slog_warn![$crate::logger(), $($args)+]; };);
/// Log a info level message using current scope logger
#[macro_export]
macro_rules! info( ($($args:tt)+) => { slog_info![$crate::logger(), $($args)+]; };);
/// Log a debug level message using current scope logger
#[macro_export]
macro_rules! debug( ($($args:tt)+) => { slog_debug![$crate::logger(), $($args)+]; };);
/// Log a trace level message using current scope logger
#[macro_export]
macro_rules! trace( ($($args:tt)+) => { slog_trace![$crate::logger(), $($args)+]; };);

thread_local! {
    static TL_SCOPES: RefCell<Vec<slog::Logger>> = RefCell::new(Vec::with_capacity(8))
}

lazy_static! {
    static ref GLOBAL_LOGGER : ArcCell<slog::Logger> = ArcCell::new(
        Arc::new(
            slog::Logger::root(slog::Discard, o!())
        )
    );
}

/// Guard resetting global logger
///
/// On drop it will reset global logger to `slog::Discard`.
/// This will `drop` any existing global logger.
#[must_use]
pub struct GlobalLoggerGuard {
    canceled : bool,
}

impl GlobalLoggerGuard {

    fn new() -> Self {
        GlobalLoggerGuard {
            canceled: false,
        }
    }

    /// Cancel resetting global logger
    pub fn cancel_reset(mut self) {
        self.canceled = true;
    }
}

impl Drop for GlobalLoggerGuard {
    fn drop(&mut self) {
        if !self.canceled {
            let _ = GLOBAL_LOGGER.set(
                Arc::new(
                    slog::Logger::root(slog::Discard, o!())
                    )
                );
        }
    }
}

/// Set global `Logger` that is returned by calls like `logger()` outside of any logging scope.
pub fn set_global_logger(l: slog::Logger) -> GlobalLoggerGuard {
    let _ = GLOBAL_LOGGER.set(Arc::new(l));

    GlobalLoggerGuard::new()
}

struct ScopeGuard;

impl ScopeGuard {
    fn new(logger: slog::Logger) -> Self {
        TL_SCOPES.with(|s| { s.borrow_mut().push(logger); });

        ScopeGuard
    }
}

impl Drop for ScopeGuard {
    fn drop(&mut self) {
        TL_SCOPES.with(|s| { s.borrow_mut().pop().expect("TL_SCOPES should contain a logger"); })
    }
}

/// Access the `Logger` for the current logging scope
pub fn logger() -> Logger {
    TL_SCOPES.with(|s| {
        let s = s.borrow();
        match s.last() {
            Some(logger) => logger.clone(),
            None => (*GLOBAL_LOGGER.get()).clone(),
        }
    })
}

/// Execute code in a logging scope
///
/// Logging scopes allow using a `slog::Logger` without explicitly
/// passing it in the code.
///
/// At any time current active `Logger` for a given thread can be retrived
/// with `logger()` call.
///
/// Logging scopes can be nested and are panic safe.
///
/// `logger` is the `Logger` to use during the duration of `f`.
/// `with_current_logger` can be used to build it as a child of currently active
/// logger.
///
/// `f` is a code to be executed in the logging scope.
///
/// Note: Thread scopes are thread-local. Each newly spawned thread starts
/// with a global logger, as a current logger.
pub fn scope<SF, R>(logger: slog::Logger, f: SF) -> R
    where SF: FnOnce() -> R
{
    let _guard = ScopeGuard::new(logger);
    f()
}
<commit_msg>Fix the example in documentation<commit_after>//! Logging scopes for slog-rs
//!
//! Logging scopes are convinience functionality for slog-rs to free user from manually passing
//! `Logger` objects around.
//!
//! Set of macros is also provided as an alternative to original `slog` crate macros, for logging
//! directly to `Logger` of the current logging scope.
//!
//! Note: Part of a `slog` logging philosophy is ability to freely express logging contexts
//! according to logical structure, rather than code structure. By using logging scopes the logging
//! context is tied to code flow again, which is less expressive.
//!
//! It is generally advised **NOT** to use `slog_scope` in libraries. Read more in
//! [slog-rs FAQ](https://github.com/slog-rs/slog/wiki/FAQ#do-i-have-to-pass-logger-around)
//!
//! ```
//! #[macro_use(slog_o, slog_info, slog_log, slog_record, slog_record_static, slog_b, slog_kv)]
//! extern crate slog;
//! #[macro_use]
//! extern crate slog_scope;
//! extern crate slog_term;
//!
//! use slog::Drain;
//!
//! fn foo() {
//!     slog_info!(slog_scope::logger(), "foo");
//!     info!("foo"); // Same as above, but more ergonomic.
//! }
//!
//! fn main() {
//!     let plain = slog_term::PlainSyncDecorator::new(std::io::stdout());
//!     let log = slog::Logger::root(
//!         slog_term::FullFormat::new(plain)
//!         .build().fuse(), slog_o!()
//!     );
//!
//!     // Make sure to save the guard, see documentation for more information
//!     let _guard = slog_scope::set_global_logger(log);
//!     slog_scope::scope(slog_scope::logger().new(slog_o!("scope" => "1")),
//!         || foo()
//!     );
//! }

#![warn(missing_docs)]

#[macro_use(o)]
extern crate slog;
#[macro_use]
extern crate lazy_static;
extern crate crossbeam;

use slog::*;

use std::sync::Arc;
use std::cell::RefCell;
use crossbeam::sync::ArcCell;

/// Log a critical level message using current scope logger
#[macro_export]
macro_rules! crit( ($($args:tt)+) => { slog_crit![$crate::logger(), $($args)+]; };);
/// Log a error level message using current scope logger
#[macro_export]
macro_rules! error( ($($args:tt)+) => { slog_error![$crate::logger(), $($args)+]; };);
/// Log a warning level message using current scope logger
#[macro_export]
macro_rules! warn( ($($args:tt)+) => { slog_warn![$crate::logger(), $($args)+]; };);
/// Log a info level message using current scope logger
#[macro_export]
macro_rules! info( ($($args:tt)+) => { slog_info![$crate::logger(), $($args)+]; };);
/// Log a debug level message using current scope logger
#[macro_export]
macro_rules! debug( ($($args:tt)+) => { slog_debug![$crate::logger(), $($args)+]; };);
/// Log a trace level message using current scope logger
#[macro_export]
macro_rules! trace( ($($args:tt)+) => { slog_trace![$crate::logger(), $($args)+]; };);

thread_local! {
    static TL_SCOPES: RefCell<Vec<slog::Logger>> = RefCell::new(Vec::with_capacity(8))
}

lazy_static! {
    static ref GLOBAL_LOGGER : ArcCell<slog::Logger> = ArcCell::new(
        Arc::new(
            slog::Logger::root(slog::Discard, o!())
        )
    );
}

/// Guard resetting global logger
///
/// On drop it will reset global logger to `slog::Discard`.
/// This will `drop` any existing global logger.
#[must_use]
pub struct GlobalLoggerGuard {
    canceled : bool,
}

impl GlobalLoggerGuard {

    fn new() -> Self {
        GlobalLoggerGuard {
            canceled: false,
        }
    }

    /// Cancel resetting global logger
    pub fn cancel_reset(mut self) {
        self.canceled = true;
    }
}

impl Drop for GlobalLoggerGuard {
    fn drop(&mut self) {
        if !self.canceled {
            let _ = GLOBAL_LOGGER.set(
                Arc::new(
                    slog::Logger::root(slog::Discard, o!())
                    )
                );
        }
    }
}

/// Set global `Logger` that is returned by calls like `logger()` outside of any logging scope.
pub fn set_global_logger(l: slog::Logger) -> GlobalLoggerGuard {
    let _ = GLOBAL_LOGGER.set(Arc::new(l));

    GlobalLoggerGuard::new()
}

struct ScopeGuard;

impl ScopeGuard {
    fn new(logger: slog::Logger) -> Self {
        TL_SCOPES.with(|s| { s.borrow_mut().push(logger); });

        ScopeGuard
    }
}

impl Drop for ScopeGuard {
    fn drop(&mut self) {
        TL_SCOPES.with(|s| { s.borrow_mut().pop().expect("TL_SCOPES should contain a logger"); })
    }
}

/// Access the `Logger` for the current logging scope
pub fn logger() -> Logger {
    TL_SCOPES.with(|s| {
        let s = s.borrow();
        match s.last() {
            Some(logger) => logger.clone(),
            None => (*GLOBAL_LOGGER.get()).clone(),
        }
    })
}

/// Execute code in a logging scope
///
/// Logging scopes allow using a `slog::Logger` without explicitly
/// passing it in the code.
///
/// At any time current active `Logger` for a given thread can be retrived
/// with `logger()` call.
///
/// Logging scopes can be nested and are panic safe.
///
/// `logger` is the `Logger` to use during the duration of `f`.
/// `with_current_logger` can be used to build it as a child of currently active
/// logger.
///
/// `f` is a code to be executed in the logging scope.
///
/// Note: Thread scopes are thread-local. Each newly spawned thread starts
/// with a global logger, as a current logger.
pub fn scope<SF, R>(logger: slog::Logger, f: SF) -> R
    where SF: FnOnce() -> R
{
    let _guard = ScopeGuard::new(logger);
    f()
}
<|endoftext|>


<commit_before>extern crate rosc;
extern crate byteorder;

use byteorder::{ByteOrder, BigEndian};
use std::{mem, iter};
use std::ascii::AsciiExt;

use rosc::{types, errors, decoder, utils};

#[test]
fn test_decode_no_args() {
    // message to build: /some/valid/address/4 ,
    let raw_addr = "/some/valid/address/4";
    let addr = to_osc_string(raw_addr.as_bytes());
    let type_tags = to_osc_string(b",");
    let merged: Vec<u8> = addr.into_iter()
                              .chain(type_tags.into_iter())
                              .collect();
    let osc_packet: Result<types::OscPacket, errors::OscError> = decoder::decode(&merged);
    assert!(osc_packet.is_ok());
    match osc_packet {
        Ok(types::OscPacket::Message(msg)) => {
            assert_eq!(raw_addr, msg.addr);
            assert!(msg.args.is_none());
        }
        Ok(_) => panic!("Expected an OscMessage!"),
        Err(e) => panic!(e),
    }
}

#[test]
fn test_decode_args() {
    // /another/valid/address/123 ,fdih 3.1415 3.14159265359 12345678i32
    // -1234567891011
    let raw_addr = "/another/valid/address/123";
    let addr = to_osc_string(raw_addr.as_bytes());
    // args
    let f = 3.1415f32;
    let mut f_bytes: [u8; 4] = [0u8; 4];
    BigEndian::write_f32(&mut f_bytes, f);
    assert_eq!(BigEndian::read_f32(&f_bytes), f);

    let d = 3.14159265359f64;
    let mut d_bytes: [u8; 8] = [0u8; 8];
    BigEndian::write_f64(&mut d_bytes, d);
    assert_eq!(BigEndian::read_f64(&d_bytes), d);

    let i = 12345678i32;
    let i_bytes: [u8; 4] = unsafe { mem::transmute(i.to_be()) };

    let l = -1234567891011i64;
    let h_bytes: [u8; 8] = unsafe { mem::transmute(l.to_be()) };

    let blob_size: [u8; 4] = unsafe { mem::transmute(6u32.to_be()) };
    let blob: Vec<u8> = vec![1u8, 2u8, 3u8, 4u8, 5u8, 6u8];

    let s = "I am an osc test string.";
    assert!(s.is_ascii());

    // Osc strings are null terminated like in C!
    let s_bytes: Vec<u8> = to_osc_string(s.as_bytes());

    let type_tags = to_osc_string(b",fdsihb");

    let args: Vec<u8> = f_bytes.iter()
                               .chain(d_bytes.iter())
                               .chain(s_bytes.iter())
                               .chain(i_bytes.iter())
                               .chain(h_bytes.iter())
                               .chain(blob_size.iter())
                               .chain(blob.iter())
                               .chain(vec![0u8, 0u8].iter())
                               .map(|x| *x)
                               .collect::<Vec<u8>>();

    let merged: Vec<u8> = addr.into_iter()
                              .chain(type_tags.into_iter())
                              .chain(args)
                              .collect::<Vec<u8>>();

    let osc_packet: Result<types::OscPacket, errors::OscError> = decoder::decode(&merged);
    match osc_packet {
        Ok(types::OscPacket::Message(msg)) => {
            assert_eq!(raw_addr, msg.addr);
            for arg in msg.args.unwrap() {
                match arg {
                    types::OscType::Int(x) => assert_eq!(i, x),
                    types::OscType::Long(x) => assert_eq!(l, x),
                    types::OscType::Float(x) => assert_eq!(f, x),
                    types::OscType::Double(x) => assert_eq!(d, x),
                    types::OscType::String(x) => assert_eq!(s, x),
                    types::OscType::Blob(x) => assert_eq!(blob, x),
                    _ => panic!(),
                }
            }
        }
        Ok(_) => panic!("Expected an OscMessage!"),
        Err(e) => panic!(e),
    }
}

/// Nul terminates the data and pads with zero bytes to a length that is a multiple of 4.
fn to_osc_string(data: &[u8]) -> Vec<u8> {
    let mut v: Vec<u8> = data.iter()
                             .cloned()
                             .chain(iter::once(0u8))
                             .collect();
    // v;
    let pad_len: usize = utils::pad(v.len() as u64) as usize;
    while v.len() < pad_len {
        v.push(0u8);
    }
    v
}<commit_msg>Move OSC blob argument to check if padding works<commit_after>extern crate rosc;
extern crate byteorder;

use byteorder::{ByteOrder, BigEndian};
use std::{mem, iter};
use std::ascii::AsciiExt;

use rosc::{types, errors, decoder, utils};

#[test]
fn test_decode_no_args() {
    // message to build: /some/valid/address/4 ,
    let raw_addr = "/some/valid/address/4";
    let addr = to_osc_string(raw_addr.as_bytes());
    let type_tags = to_osc_string(b",");
    let merged: Vec<u8> = addr.into_iter()
                              .chain(type_tags.into_iter())
                              .collect();
    let osc_packet: Result<types::OscPacket, errors::OscError> = decoder::decode(&merged);
    assert!(osc_packet.is_ok());
    match osc_packet {
        Ok(types::OscPacket::Message(msg)) => {
            assert_eq!(raw_addr, msg.addr);
            assert!(msg.args.is_none());
        }
        Ok(_) => panic!("Expected an OscMessage!"),
        Err(e) => panic!(e),
    }
}

#[test]
fn test_decode_args() {
    // /another/valid/address/123 ,fdih 3.1415 3.14159265359 12345678i32
    // -1234567891011
    let raw_addr = "/another/valid/address/123";
    let addr = to_osc_string(raw_addr.as_bytes());
    // args
    let f = 3.1415f32;
    let mut f_bytes: [u8; 4] = [0u8; 4];
    BigEndian::write_f32(&mut f_bytes, f);
    assert_eq!(BigEndian::read_f32(&f_bytes), f);

    let d = 3.14159265359f64;
    let mut d_bytes: [u8; 8] = [0u8; 8];
    BigEndian::write_f64(&mut d_bytes, d);
    assert_eq!(BigEndian::read_f64(&d_bytes), d);

    let i = 12345678i32;
    let i_bytes: [u8; 4] = unsafe { mem::transmute(i.to_be()) };

    let l = -1234567891011i64;
    let h_bytes: [u8; 8] = unsafe { mem::transmute(l.to_be()) };

    let blob_size: [u8; 4] = unsafe { mem::transmute(6u32.to_be()) };
    let blob: Vec<u8> = vec![1u8, 2u8, 3u8, 4u8, 5u8, 6u8];

    let s = "I am an osc test string.";
    assert!(s.is_ascii());

    // Osc strings are null terminated like in C!
    let s_bytes: Vec<u8> = to_osc_string(s.as_bytes());

    let type_tags = to_osc_string(b",fdsibh");

    let args: Vec<u8> = f_bytes.iter()
                               .chain(d_bytes.iter())
                               .chain(s_bytes.iter())
                               .chain(i_bytes.iter())
                               .chain(blob_size.iter())
                               .chain(blob.iter())
                               .chain(vec![0u8, 0u8].iter())
                               .chain(h_bytes.iter())
                               .map(|x| *x)
                               .collect::<Vec<u8>>();

    let merged: Vec<u8> = addr.into_iter()
                              .chain(type_tags.into_iter())
                              .chain(args)
                              .collect::<Vec<u8>>();

    let osc_packet: Result<types::OscPacket, errors::OscError> = decoder::decode(&merged);
    match osc_packet {
        Ok(types::OscPacket::Message(msg)) => {
            assert_eq!(raw_addr, msg.addr);
            for arg in msg.args.unwrap() {
                match arg {
                    types::OscType::Int(x) => assert_eq!(i, x),
                    types::OscType::Long(x) => assert_eq!(l, x),
                    types::OscType::Float(x) => assert_eq!(f, x),
                    types::OscType::Double(x) => assert_eq!(d, x),
                    types::OscType::String(x) => assert_eq!(s, x),
                    types::OscType::Blob(x) => assert_eq!(blob, x),
                    _ => panic!(),
                }
            }
        }
        Ok(_) => panic!("Expected an OscMessage!"),
        Err(e) => panic!(e),
    }
}

/// Nul terminates the data and pads with zero bytes to a length that is a multiple of 4.
fn to_osc_string(data: &[u8]) -> Vec<u8> {
    let mut v: Vec<u8> = data.iter()
                             .cloned()
                             .chain(iter::once(0u8))
                             .collect();
    // v;
    let pad_len: usize = utils::pad(v.len() as u64) as usize;
    while v.len() < pad_len {
        v.push(0u8);
    }
    v
}<|endoftext|>


<commit_before>extern crate rand;

use self::rand::Rng;

use core::world::dungeon::map::{self, Measurable, tile, Tile};

use super::{AI, RANDOM_TRIES};
use core::creature::{Actions, Creature, Actor, Stats};

///
/// SmellerAI is an AI that follows insect smells
///
/// NOTE: This is a proof of concept AI
///
#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct SmellerAI;

impl SmellerAI {
  pub fn new() -> Self {
    SmellerAI {}
  }
}

impl AI for SmellerAI {

  ///
  /// Walk around randomly until it picks up a scent
  ///
  fn take_turn(&mut self, map: &map::Grid<Tile>, _player: &Creature, me: &mut Actor, _stats: &mut Stats) -> Actions {

    let mut state = Actions::Wait;

    let mut x = me.pos.x as usize;
    let mut y = me.pos.y as usize;

    let mut tx : isize = -1;
    let mut ty : isize = -1;
    let mut scent_val : isize = 0;

    // Represents how far the ai can smell
    let mut scent_range = 2;

    me.prev_pos = me.pos.clone();

    // Avoid OOB Errors
    if x < 2 || x > map.width() - 2 || y < 2 || y > map.height() - 2 {
      // NOTE: scent_range one 1 has weird behaviors...
      scent_range = 1;
    }

    for sx in x-scent_range..x+scent_range {
      for sy in y-scent_range..y+scent_range {
        // Scents[1] refers to the insectoid smell via the c-like enum
        // not the best solution
        if map[sx][sy].scents[1].val as isize > scent_val && (sx, sy) != (x, y) {
          tx = sx as isize;
          ty = sy as isize;
          scent_val = map[sx][sy].scents[1].val as isize;
        }
      }
    }

    // If a scent has been picked up behave like a tracker and move towards that tile
    if scent_val > 0 && scent_val < 80{

      // Move x
      if x < tx as usize {
        x += 1;
        state = Actions::Move;
      } else if x > tx as usize {
        x -= 1;
        state = Actions::Move;
      }

      // Check
      if !tile::walkable(&map[x][y]) {
        x = tx as usize;
        state = Actions::Move;
      }

      // Move y
      if y < ty as usize{
        y += 1;
      } else if y > ty as usize {
        y -= 1;
      }

      // Check
      if !tile::walkable(&map[x][y]) {
        y = ty as usize;
        state = Actions::Move;
      }

      me.pos.x = x as isize;
      me.pos.y = y as isize;

    } else {

      // Otherwise behave like a simple ai and walk around randomly
      loop {

        let mut rng = rand::thread_rng();
        let dice : usize;
        state = Actions::Move;

        let mut count : usize = 0;

        count += 1;
        x = me.pos.x as usize;
        y = me.pos.y as usize;
        dice = rng.gen_range(1, 5);

        // Match dice for movement
        match dice {
          1 => x += 1,
          2 => x -= 1,
          3 => y += 1,
          4 => y -= 1,
          _ => unreachable!("SimpleAI - Unreachable dice state reached in movement")
        }

        // Since the only thing this thing can do is move, there is no need to match the dice again to determine state

        // If we find a good tile, great, otherwise keep trying until we get tired of it
        if tile::walkable(&map[x][y]) {
          break;
        } else if count > RANDOM_TRIES {
          x = me.pos.x as usize;
          y = me.pos.y as usize;
          state = Actions::Wait;
          break;
        }

      }

      me.pos.x = x as isize;
      me.pos.y = y as isize;

    }

    return state;

  }

  ///
  /// Allow Box<AI> cloning
  ///
  fn box_clone(&self) -> Box<dyn AI> {
    Box::new((*self).clone())
  }

}<commit_msg>Fix smeller bug at map boundary<commit_after>extern crate rand;

use self::rand::Rng;

use core::world::dungeon::map::{self, Measurable, tile, Tile};

use super::{AI, RANDOM_TRIES};
use core::creature::{Actions, Creature, Actor, Stats};

///
/// SmellerAI is an AI that follows insect smells
///
/// NOTE: This is a proof of concept AI
///
#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct SmellerAI;

impl SmellerAI {
  pub fn new() -> Self {
    SmellerAI {}
  }
}

impl AI for SmellerAI {

  ///
  /// Walk around randomly until it picks up a scent
  ///
  fn take_turn(&mut self, map: &map::Grid<Tile>, _player: &Creature, me: &mut Actor, _stats: &mut Stats) -> Actions {

    let mut state = Actions::Wait;

    let mut x = me.pos.x as usize;
    let mut y = me.pos.y as usize;

    let mut tx : isize = -1;
    let mut ty : isize = -1;
    let mut scent_val : isize = 0;

    // Represents how far the ai can smell
    let mut scent_range = 2;

    me.prev_pos = me.pos.clone();

    // Avoid OOB Errors
    if x <= 2 || x > map.width() - 2 || y <= 2 || y > map.height() - 2 {
      // NOTE: scent_range one 1 has weird behaviors...
      scent_range = 1;
    }

    for sx in x-scent_range..x+scent_range {
      for sy in y-scent_range..y+scent_range {
        // Scents[1] refers to the insectoid smell via the c-like enum
        // not the best solution
        if map[sx][sy].scents[1].val as isize > scent_val && (sx, sy) != (x, y) {
          tx = sx as isize;
          ty = sy as isize;
          scent_val = map[sx][sy].scents[1].val as isize;
        }
      }
    }

    // If a scent has been picked up behave like a tracker and move towards that tile
    if scent_val > 0 && scent_val < 80{

      // Move x
      if x < tx as usize {
        x += 1;
        state = Actions::Move;
      } else if x > tx as usize {
        x -= 1;
        state = Actions::Move;
      }

      // Check
      if !tile::walkable(&map[x][y]) {
        x = tx as usize;
        state = Actions::Move;
      }

      // Move y
      if y < ty as usize{
        y += 1;
      } else if y > ty as usize {
        y -= 1;
      }

      // Check
      if !tile::walkable(&map[x][y]) {
        y = ty as usize;
        state = Actions::Move;
      }

      me.pos.x = x as isize;
      me.pos.y = y as isize;

    } else {

      // Otherwise behave like a simple ai and walk around randomly
      loop {

        let mut rng = rand::thread_rng();
        let dice : usize;
        state = Actions::Move;

        let mut count : usize = 0;

        count += 1;
        x = me.pos.x as usize;
        y = me.pos.y as usize;
        dice = rng.gen_range(1, 5);

        // Match dice for movement
        match dice {
          1 => x += 1,
          2 => x -= 1,
          3 => y += 1,
          4 => y -= 1,
          _ => unreachable!("SimpleAI - Unreachable dice state reached in movement")
        }

        // Since the only thing this thing can do is move, there is no need to match the dice again to determine state

        // If we find a good tile, great, otherwise keep trying until we get tired of it
        if tile::walkable(&map[x][y]) {
          break;
        } else if count > RANDOM_TRIES {
          x = me.pos.x as usize;
          y = me.pos.y as usize;
          state = Actions::Wait;
          break;
        }

      }

      me.pos.x = x as isize;
      me.pos.y = y as isize;

    }

    return state;

  }

  ///
  /// Allow Box<AI> cloning
  ///
  fn box_clone(&self) -> Box<dyn AI> {
    Box::new((*self).clone())
  }

}<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt;

use iron::{Request, Response, Handler, IronResult, IronError};
use iron::status;
use iron::method::Method;

type PickerHandlers = Vec<(Option<Method>, Box<Handler>)>;

/// `MethodPicker` provides an interface to apply different handlers for different http methods as
/// middleware for the Iron framework.
pub struct MethodPicker {
	handlers: PickerHandlers
}

impl MethodPicker {
    /// Construct new `MethodPicker`.
    ///
    /// ```
    /// # use iron_mountrouter::MethodPicker;
    /// let picker = MethodPicker::new();
    /// ```
	pub fn new() -> MethodPicker {
		MethodPicker {
			handlers: PickerHandlers::new()
		}
	}

	/// Adds new handler to picker
	///
	/// `method` is any Iron's http method.
	///
	/// `handler` will be used for specified method
	pub fn add<H: Handler>(&mut self, method: Method, handler: H) -> &mut MethodPicker {
		self.handlers.push((Some(method), Box::new(handler)));
		self
	}

	/// Adds new handler for GET http method to picker
	pub fn get<H: Handler>(&mut self, handler: H) -> &mut MethodPicker {
		self.handlers.push((Some(Method::Get), Box::new(handler)));
		self
	}

	/// Adds new handler for POST http method to picker
	pub fn post<H: Handler>(&mut self, handler: H) -> &mut MethodPicker {
		self.handlers.push((Some(Method::Post), Box::new(handler)));
		self
	}

	/// Adds new handler for PUT http method to picker
	pub fn put<H: Handler>(&mut self, handler: H) -> &mut MethodPicker {
		self.handlers.push((Some(Method::Put), Box::new(handler)));
		self
	}

	/// Adds new handler for DELETE http method to picker
	pub fn delete<H: Handler>(&mut self, handler: H) -> &mut MethodPicker {
		self.handlers.push((Some(Method::Delete), Box::new(handler)));
		self
	}

	/// Adds new handler for HEAD http method to picker
	pub fn head<H: Handler>(&mut self, handler: H) -> &mut MethodPicker {
		self.handlers.push((Some(Method::Head), Box::new(handler)));
		self
	}

	/// Adds new handler for PATCH http method to picker
	pub fn patch<H: Handler>(&mut self, handler: H) -> &mut MethodPicker {
		self.handlers.push((Some(Method::Patch), Box::new(handler)));
		self
	}

	/// Adds new handler for OPTIONS http method to picker
	pub fn options<H: Handler>(&mut self, handler: H) -> &mut MethodPicker {
		self.handlers.push((Some(Method::Options), Box::new(handler)));
		self
	}

	/// Adds default handler to picker which will be used if no method matched
	pub fn default<H: Handler>(&mut self, handler: H) -> &mut MethodPicker {
		self.handlers.push((None, Box::new(handler)));
		self
	}
}

impl Handler for MethodPicker {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
    	for &(ref method, ref handler) in self.handlers.iter() {
    		match method {
    			&Some(ref m) => if *m == req.method {
    				return handler.handle(req);
    			},
    			&None => return handler.handle(req)
    		}
    	}
    	Err(IronError::new(NoMethod, status::NotFound))
    }
}

/// `NoMethod` is error type returned to Iron if no handler was matched in MethodPicker
#[derive(Debug)]
pub struct NoMethod;

impl fmt::Display for NoMethod {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("No matching method found.")
    }
}

impl Error for NoMethod {
    fn description(&self) -> &str { "No method" }
}<commit_msg>Added macro to create method picker<commit_after>use std::error::Error;
use std::fmt;

use iron::{Request, Response, Handler, IronResult, IronError};
use iron::status;
use iron::method::Method;

type PickerHandlers = Vec<(Option<Method>, Box<Handler>)>;

/// `MethodPicker` provides an interface to apply different handlers for different http methods as
/// middleware for the Iron framework.
pub struct MethodPicker {
	handlers: PickerHandlers
}

impl MethodPicker {
    /// Construct new `MethodPicker`.
    ///
    /// ```
    /// # use iron_mountrouter::MethodPicker;
    /// let picker = MethodPicker::new();
    /// ```
	pub fn new() -> MethodPicker {
		MethodPicker {
			handlers: PickerHandlers::new()
		}
	}

	/// Adds new handler to picker
	///
	/// `method` is any Iron's http method.
	///
	/// `handler` will be used for specified method
	pub fn add<H: Handler>(&mut self, method: Method, handler: H) -> &mut MethodPicker {
		self.handlers.push((Some(method), Box::new(handler)));
		self
	}

	/// Adds new handler for GET http method to picker
	pub fn get<H: Handler>(&mut self, handler: H) -> &mut MethodPicker {
		self.handlers.push((Some(Method::Get), Box::new(handler)));
		self
	}

	/// Adds new handler for POST http method to picker
	pub fn post<H: Handler>(&mut self, handler: H) -> &mut MethodPicker {
		self.handlers.push((Some(Method::Post), Box::new(handler)));
		self
	}

	/// Adds new handler for PUT http method to picker
	pub fn put<H: Handler>(&mut self, handler: H) -> &mut MethodPicker {
		self.handlers.push((Some(Method::Put), Box::new(handler)));
		self
	}

	/// Adds new handler for DELETE http method to picker
	pub fn delete<H: Handler>(&mut self, handler: H) -> &mut MethodPicker {
		self.handlers.push((Some(Method::Delete), Box::new(handler)));
		self
	}

	/// Adds new handler for HEAD http method to picker
	pub fn head<H: Handler>(&mut self, handler: H) -> &mut MethodPicker {
		self.handlers.push((Some(Method::Head), Box::new(handler)));
		self
	}

	/// Adds new handler for PATCH http method to picker
	pub fn patch<H: Handler>(&mut self, handler: H) -> &mut MethodPicker {
		self.handlers.push((Some(Method::Patch), Box::new(handler)));
		self
	}

	/// Adds new handler for OPTIONS http method to picker
	pub fn options<H: Handler>(&mut self, handler: H) -> &mut MethodPicker {
		self.handlers.push((Some(Method::Options), Box::new(handler)));
		self
	}

	/// Adds default handler to picker which will be used if no method matched
	pub fn default<H: Handler>(&mut self, handler: H) -> &mut MethodPicker {
		self.handlers.push((None, Box::new(handler)));
		self
	}
}

impl Handler for MethodPicker {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
    	for &(ref method, ref handler) in self.handlers.iter() {
    		match method {
    			&Some(ref m) => if *m == req.method {
    				return handler.handle(req);
    			},
    			&None => return handler.handle(req)
    		}
    	}
    	Err(IronError::new(NoMethod, status::NotFound))
    }
}

/// `NoMethod` is error type returned to Iron if no handler was matched in MethodPicker
#[derive(Debug)]
pub struct NoMethod;

impl fmt::Display for NoMethod {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("No matching method found.")
    }
}

impl Error for NoMethod {
    fn description(&self) -> &str { "No method" }
}

/// Create and populate method picker.
///
/// ```ignore
/// let picker = picker!(get => show,
///                      post => save);
/// ```
#[macro_export]
macro_rules! picker {
    ($($method:ident => $handler:expr),+ $(,)*) => ({
        let mut picker = $crate::MethodPicker::new();
        $(picker.$method($handler);)*
        picker
    });
}<|endoftext|>