<commit_before>//! Defines structs for operating on ISPC task groups and getting chunks
//! of a task to be scheduled on to threads

use libc;
use aligned_alloc;

use std::cmp;
use std::iter::Iterator;
use std::sync::{Mutex, RwLock, Arc};
use std::sync::atomic::{self, AtomicBool, ATOMIC_BOOL_INIT};

/// A pointer to an ISPC task function.
///
/// The ISPC task function pointer is:
/// ```c
/// void (*TaskFuncPtr)(void *data, int threadIndex, int threadCount,
///                     int taskIndex, int taskCount,
///                     int taskIndex0, int taskIndex1, int taskIndex2,
///                     int taskCount0, int taskCount1, int taskCount2);
/// ```
pub type ISPCTaskFn = extern "C" fn(data: *mut libc::c_void, thread_idx: libc::c_int, thread_cnt: libc::c_int,
                                    task_idx: libc::c_int, task_cnt: libc::c_int, task_idx0: libc::c_int,
                                    task_idx1: libc::c_int, task_idx2: libc::c_int, task_cnt0: libc::c_int,
                                    task_cnt1: libc::c_int, task_cnt2: libc::c_int);

/// A list of all task groups spawned by a function in some launch context which
/// will be sync'd at an explicit `sync` call or function exit.
///
/// **Note:** A Context is done if and only if ISPCSync has been called with
/// its handle and all of its tasks are finished. Until ISPCSync is called on the
/// Context's handle more tasks could be launched.
///
/// Additionally, because we're not really able to associate a call to ISPCAlloc
/// with a specific Group care must be taken that the Context is not dropped
/// until ISPCSync has been called on its handle and all Groups within have
/// completed execution.
#[derive(Debug)]
pub struct Context {
    /// Task groups launched by this function
    /// TODO: Must be protected by a Reader-Writer lock, though I don't think we'd want to
    /// protect each Group, it'd be an RwLock<Vec<Group>>
    /// PROBLEM: If we're accessing this from multiple threads and have other threads
    /// working on the group when we want to push a new group on we'll get stuck until those
    /// tasks finish because they'll have a read lock on the vec to access the Group safely.
    /// I guess an easy fix would be to push groups behind Arcs? But then how would the
    /// Chunk get the Arc?
    tasks: RwLock<Vec<Arc<Group>>>,
    /// The memory allocated for the various task group's parameters
    mem: Mutex<Vec<*mut libc::c_void>>,
    pub id: usize,
}

impl Context {
    /// Create a new list of tasks for some function with id `id`
    pub fn new(id: usize) -> Context {
        Context { tasks: RwLock::new(Vec::new()), mem: Mutex::new(Vec::new()), id: id }
    }
    /// Add a task group for execution that was launched in this context
    pub fn launch(&self, total: (i32, i32, i32), data: *mut libc::c_void, fcn: ISPCTaskFn) {
        self.tasks.write().unwrap().push(Arc::new(Group::new(total, data, fcn)));
    }
    /// Check if all tasks currently in the task list are completed
    ///
    /// **Note:** A Context is done if and only if ISPCSync has been called with
    /// its handle and all of its tasks are finished. Until ISPCSync is called on the
    /// Context's handle more tasks could be launched.
    /// TODO: With this design we're essentially requiring the thread waiting on the context
    /// to busy wait since we provide no condition variable to block on.
    pub fn current_tasks_done(&self) -> bool {
        self.tasks.read().unwrap()
            .iter().fold(true, |done, t| {
            done && t.finished.load(atomic::Ordering::SeqCst)
        })
    }
    /// Allocate some memory for this Context's task groups, returns a pointer to the allocated memory.
    pub unsafe fn alloc(&self, size: usize, align: usize) -> *mut libc::c_void {
        // TODO: The README for this lib mentions it may be slow. Maybe use some other allocator?
        let ptr = aligned_alloc::aligned_alloc(size as usize, align as usize) as *mut libc::c_void;
        let mut mem = self.mem.lock().unwrap();
        mem.push(ptr);
        ptr
    }
    /// An iterator over the **current** groups in the context which have remaining tasks to
    /// run on a thread. If more task groups are added before this iterator has returned
    /// None those will appear as well.
    pub fn iter(&self) -> ContextIter {
        ContextIter { context: self }
    }
    /// Get a Group with tasks remaining to be executed, returns None if there
    /// are no groups left to run in this context.
    ///
    /// Note that you can't assume that the Group you get back is guaranteed
    /// to have tasks remaining since between the time of checking that the
    /// group has outstanding tasks and getting the group back to call `chunks`
    /// those remaining tasks may have been taken by another threaad.
    fn get_unscheduled_group(&self) -> Option<Arc<Group>> {
        let tasks = self.tasks.read().unwrap();
        for group in tasks.iter() {
            if group.has_tasks() {
                return Some(group.clone());
            }
        }
        None
    }
}

impl Drop for Context {
    /// Release memory for all the tasks in this context
    ///
    /// **Note:** that because we're not really able to associate a call to ISPCAlloc
    /// with a specific Group care must be taken that the Context is not dropped
    /// until ISPCSync has been called on its handle and all Groups within have
    /// completed execution.
    fn drop(&mut self) {
        let mut mem = self.mem.lock().unwrap();
        for m in mem.drain(0..) {
            unsafe { aligned_alloc::aligned_free(m as *mut ()); }
        }
    }
}

/// An iterator over the **current** groups in the context which have remaining tasks to
/// run on a thread. If more task groups are added before this iterator has returned
/// None those will appear as well.
pub struct ContextIter<'a> {
    context: &'a Context,
}

impl<'a> Iterator for ContextIter<'a> {
    type Item = Arc<Group>;

    /// Get a Group with tasks remaining to be executed, returns None if there
    /// are no groups left to run in this context.
    ///
    /// Note that you can't assume that the Group you get back is guaranteed
    /// to have tasks remaining since between the time of checking that the
    /// group has outstanding tasks and getting the group back to call `chunks`
    /// those remaining tasks may have been taken by another threaad.
    fn next(&mut self) -> Option<Arc<Group>> {
        self.context.get_unscheduled_group()
    }
}

/// A group of tasks spawned by a call to `launch` in ISPC
#[derive(Debug)]
pub struct Group {
    /// Current starting index to execute the remaining tasks in this group
    /// TODO: Protect start by a mutex since it will be modified by `get_chunk`
    /// which would get a chunk of tasks to be executed along with a copy of the
    /// total, fcn ptr and data. This would be wrapped in to a struct, `Chunk` which
    /// would expose next() and behave like an iterator to go through the chunk of tasks
    /// and run them. Right now we just schedule tasks like in a nested for loop,
    /// would some tiled scheduling be better?
    pub start: RwLock<i32>,
    /// Total number of tasks scheduled in this group
    pub total: (i32, i32, i32),
    /// Function to run for this task
    pub fcn: ISPCTaskFn,
    /// Data pointer to user params to pass to the function
    pub data: *mut libc::c_void,
    /// Whether all tasks have been completed or not, TODO: should become
    /// an atomic or semaphore
    /// I'm unsure whether an atomic or semaphore would be the better choice here
    /// The TASK_LIST would want to send an alert when new tasks are pushed so in
    /// Sync we could wait on the context to finish?
    finished: AtomicBool,
}

impl Group {
    /// Create a new task group for execution of the function
    pub fn new(total: (i32, i32, i32), data: *mut libc::c_void, fcn: ISPCTaskFn) -> Group {
        Group { start: RwLock::new(0), total: total, data: data, fcn: fcn, finished: ATOMIC_BOOL_INIT }
    }
    pub fn chunks(&self, chunk_size: i32) -> GroupChunks {
        GroupChunks { group: self, chunk_size: chunk_size }
    }
    pub fn is_finished(&self) -> bool {
        self.finished.load(atomic::Ordering::SeqCst)
    }
    fn mark_finished(&self) {
        self.finished.store(true, atomic::Ordering::SeqCst)
    }
    /// Check if this group has tasks left to execute
    fn has_tasks(&self) -> bool {
        let end = self.total.0 * self.total.1 * self.total.2;
        let start = self.start.read().unwrap();
        *start < end
    }
    /// Get a chunk of tasks from the group to run if there are any tasks left to run
    ///
    /// `desired_tasks` specifies the number of tasks we'd like the chunk to contain,
    /// though you may get fewer if there aren't that many tasks left. If the chunk
    /// you get is the last chunk to be executed (`chunk.end == total.0 * total.1 * total.2`)
    /// you must mark this group as finished upon completing execution of the chunk
    fn get_chunk(&self, desired_tasks: i32) -> Option<Chunk> {
        let end = self.total.0 * self.total.1 * self.total.2;
        let mut start = self.start.write().unwrap();
        if *start < end {
            // Give the chunk 4 tasks or whatever remain
            let c = Some(Chunk::new(self, *start, cmp::min(*start + desired_tasks, end)));
            *start += desired_tasks;
            c
        } else {
            None
        }
    }
}

/// An iterator over chunks of tasks to be executed in a Group
pub struct GroupChunks<'a> {
    group: &'a Group,
    chunk_size: i32,
}

impl<'a> Iterator for GroupChunks<'a> {
    type Item = Chunk<'a>;

    /// Get the next chunk of tasks to be executed
    fn next(&mut self) -> Option<Chunk<'a>> {
        self.group.get_chunk(self.chunk_size)
    }
}

/// A chunk of tasks from a Group to be executed
///
/// Executes task in the range [start, end)
#[derive(Debug)]
pub struct Chunk<'a> {
    /// The next task to be executed in this chunk
    start: i32,
    /// The last task to be executed in this chunk
    end: i32,
    /// Total number of tasks scheduled in the group this chunk came from
    total: (i32, i32, i32),
    /// Function to run for this task
    fcn: ISPCTaskFn,
    /// Data pointer to user params to pass to the function
    data: *mut libc::c_void,
    /// The group this chunk is running tasks from
    group: &'a Group,
}

impl<'a> Chunk<'a> {
    /// Create a new chunk to execute tasks in the group from [start, end)
    pub fn new(group: &'a Group, start: i32, end: i32) -> Chunk {
        Chunk { start: start, end: end, total: group.total,
                fcn: group.fcn, data: group.data, group: group
        }
    }
    /// Execute all tasks in this chunk
    pub fn execute(&self, thread_id: i32, total_threads: i32) {
        let total_tasks = self.total.0 * self.total.1 * self.total.2;
        for t in self.start..self.end {
            let id = self.task_indices(t);
            (self.fcn)(self.data, thread_id as libc::c_int, total_threads as libc::c_int,
                       t as libc::c_int, total_tasks as libc::c_int,
                       id.0 as libc::c_int, id.1 as libc::c_int, id.2 as libc::c_int,
                       self.total.0 as libc::c_int, self.total.1 as libc::c_int,
                       self.total.2 as libc::c_int);
        }
        // If this chunk finished the group mark the group as finished
        if self.is_last() {
            self.group.mark_finished();
        }
    }
    /// Check if this is the last chunk in the group
    pub fn is_last(&self) -> bool {
        self.end == self.total.0 * self.total.1 * self.total.2
    }
    /// Get the global task id for the task index
    fn task_indices(&self, id: i32) -> (i32, i32, i32) {
        (id % self.total.0, (id / self.total.0) % self.total.1, id / (self.total.0 * self.total.1))
    }
}

<commit_msg>Better naming<commit_after>//! Defines structs for operating on ISPC task groups and getting chunks
//! of a task to be scheduled on to threads

use libc;
use aligned_alloc;

use std::cmp;
use std::iter::Iterator;
use std::sync::{Mutex, RwLock, Arc};
use std::sync::atomic::{self, AtomicBool, ATOMIC_BOOL_INIT};

/// A pointer to an ISPC task function.
///
/// The ISPC task function pointer is:
/// ```c
/// void (*TaskFuncPtr)(void *data, int threadIndex, int threadCount,
///                     int taskIndex, int taskCount,
///                     int taskIndex0, int taskIndex1, int taskIndex2,
///                     int taskCount0, int taskCount1, int taskCount2);
/// ```
pub type ISPCTaskFn = extern "C" fn(data: *mut libc::c_void, thread_idx: libc::c_int, thread_cnt: libc::c_int,
                                    task_idx: libc::c_int, task_cnt: libc::c_int, task_idx0: libc::c_int,
                                    task_idx1: libc::c_int, task_idx2: libc::c_int, task_cnt0: libc::c_int,
                                    task_cnt1: libc::c_int, task_cnt2: libc::c_int);

/// A list of all task groups spawned by a function in some launch context which
/// will be sync'd at an explicit `sync` call or function exit.
///
/// **Note:** A Context is done if and only if ISPCSync has been called with
/// its handle and all of its tasks are finished. Until ISPCSync is called on the
/// Context's handle more tasks could be launched.
///
/// Additionally, because we're not really able to associate a call to ISPCAlloc
/// with a specific Group care must be taken that the Context is not dropped
/// until ISPCSync has been called on its handle and all Groups within have
/// completed execution.
#[derive(Debug)]
pub struct Context {
    /// Task groups launched by this function
    /// TODO: Must be protected by a Reader-Writer lock, though I don't think we'd want to
    /// protect each Group, it'd be an RwLock<Vec<Group>>
    /// PROBLEM: If we're accessing this from multiple threads and have other threads
    /// working on the group when we want to push a new group on we'll get stuck until those
    /// tasks finish because they'll have a read lock on the vec to access the Group safely.
    /// I guess an easy fix would be to push groups behind Arcs? But then how would the
    /// Chunk get the Arc?
    tasks: RwLock<Vec<Arc<Group>>>,
    /// The memory allocated for the various task group's parameters
    mem: Mutex<Vec<*mut libc::c_void>>,
    pub id: usize,
}

impl Context {
    /// Create a new list of tasks for some function with id `id`
    pub fn new(id: usize) -> Context {
        Context { tasks: RwLock::new(Vec::new()), mem: Mutex::new(Vec::new()), id: id }
    }
    /// Add a task group for execution that was launched in this context
    pub fn launch(&self, total: (i32, i32, i32), data: *mut libc::c_void, fcn: ISPCTaskFn) {
        self.tasks.write().unwrap().push(Arc::new(Group::new(total, data, fcn)));
    }
    /// Check if all tasks currently in the task list are completed
    ///
    /// **Note:** A Context is done if and only if ISPCSync has been called with
    /// its handle and all of its tasks are finished. Until ISPCSync is called on the
    /// Context's handle more tasks could be launched.
    /// TODO: With this design we're essentially requiring the thread waiting on the context
    /// to busy wait since we provide no condition variable to block on.
    pub fn current_tasks_done(&self) -> bool {
        self.tasks.read().unwrap()
            .iter().fold(true, |done, t| {
            done && t.finished.load(atomic::Ordering::SeqCst)
        })
    }
    /// Allocate some memory for this Context's task groups, returns a pointer to the allocated memory.
    pub unsafe fn alloc(&self, size: usize, align: usize) -> *mut libc::c_void {
        // TODO: The README for this lib mentions it may be slow. Maybe use some other allocator?
        let ptr = aligned_alloc::aligned_alloc(size as usize, align as usize) as *mut libc::c_void;
        let mut mem = self.mem.lock().unwrap();
        mem.push(ptr);
        ptr
    }
    /// An iterator over the **current** groups in the context which have remaining tasks to
    /// run on a thread. If more task groups are added before this iterator has returned
    /// None those will appear as well.
    pub fn iter(&self) -> ContextIter {
        ContextIter { context: self }
    }
    /// Get a Group with tasks remaining to be executed, returns None if there
    /// are no groups left to run in this context.
    ///
    /// Note that you can't assume that the Group you get back is guaranteed
    /// to have tasks remaining since between the time of checking that the
    /// group has outstanding tasks and getting the group back to call `chunks`
    /// those remaining tasks may have been taken by another threaad.
    fn get_active_group(&self) -> Option<Arc<Group>> {
        let tasks = self.tasks.read().unwrap();
        for group in tasks.iter() {
            if group.has_tasks() {
                return Some(group.clone());
            }
        }
        None
    }
}

impl Drop for Context {
    /// Release memory for all the tasks in this context
    ///
    /// **Note:** that because we're not really able to associate a call to ISPCAlloc
    /// with a specific Group care must be taken that the Context is not dropped
    /// until ISPCSync has been called on its handle and all Groups within have
    /// completed execution.
    fn drop(&mut self) {
        let mut mem = self.mem.lock().unwrap();
        for m in mem.drain(0..) {
            unsafe { aligned_alloc::aligned_free(m as *mut ()); }
        }
    }
}

/// An iterator over the **current** groups in the context which have remaining tasks to
/// run on a thread. If more task groups are added before this iterator has returned
/// None those will appear as well.
pub struct ContextIter<'a> {
    context: &'a Context,
}

impl<'a> Iterator for ContextIter<'a> {
    type Item = Arc<Group>;

    /// Get a Group with tasks remaining to be executed, returns None if there
    /// are no groups left to run in this context.
    ///
    /// Note that you can't assume that the Group you get back is guaranteed
    /// to have tasks remaining since between the time of checking that the
    /// group has outstanding tasks and getting the group back to call `chunks`
    /// those remaining tasks may have been taken by another threaad.
    fn next(&mut self) -> Option<Arc<Group>> {
        self.context.get_active_group()
    }
}

/// A group of tasks spawned by a call to `launch` in ISPC
#[derive(Debug)]
pub struct Group {
    /// Current starting index to execute the remaining tasks in this group
    /// TODO: Protect start by a mutex since it will be modified by `get_chunk`
    /// which would get a chunk of tasks to be executed along with a copy of the
    /// total, fcn ptr and data. This would be wrapped in to a struct, `Chunk` which
    /// would expose next() and behave like an iterator to go through the chunk of tasks
    /// and run them. Right now we just schedule tasks like in a nested for loop,
    /// would some tiled scheduling be better?
    pub start: RwLock<i32>,
    /// Total number of tasks scheduled in this group
    pub total: (i32, i32, i32),
    /// Function to run for this task
    pub fcn: ISPCTaskFn,
    /// Data pointer to user params to pass to the function
    pub data: *mut libc::c_void,
    /// Whether all tasks have been completed or not, TODO: should become
    /// an atomic or semaphore
    /// I'm unsure whether an atomic or semaphore would be the better choice here
    /// The TASK_LIST would want to send an alert when new tasks are pushed so in
    /// Sync we could wait on the context to finish?
    finished: AtomicBool,
}

impl Group {
    /// Create a new task group for execution of the function
    pub fn new(total: (i32, i32, i32), data: *mut libc::c_void, fcn: ISPCTaskFn) -> Group {
        Group { start: RwLock::new(0), total: total, data: data, fcn: fcn, finished: ATOMIC_BOOL_INIT }
    }
    pub fn chunks(&self, chunk_size: i32) -> GroupChunks {
        GroupChunks { group: self, chunk_size: chunk_size }
    }
    pub fn is_finished(&self) -> bool {
        self.finished.load(atomic::Ordering::SeqCst)
    }
    fn mark_finished(&self) {
        self.finished.store(true, atomic::Ordering::SeqCst)
    }
    /// Check if this group has tasks left to execute
    fn has_tasks(&self) -> bool {
        let end = self.total.0 * self.total.1 * self.total.2;
        let start = self.start.read().unwrap();
        *start < end
    }
    /// Get a chunk of tasks from the group to run if there are any tasks left to run
    ///
    /// `desired_tasks` specifies the number of tasks we'd like the chunk to contain,
    /// though you may get fewer if there aren't that many tasks left. If the chunk
    /// you get is the last chunk to be executed (`chunk.end == total.0 * total.1 * total.2`)
    /// you must mark this group as finished upon completing execution of the chunk
    fn get_chunk(&self, desired_tasks: i32) -> Option<Chunk> {
        let end = self.total.0 * self.total.1 * self.total.2;
        let mut start = self.start.write().unwrap();
        if *start < end {
            // Give the chunk 4 tasks or whatever remain
            let c = Some(Chunk::new(self, *start, cmp::min(*start + desired_tasks, end)));
            *start += desired_tasks;
            c
        } else {
            None
        }
    }
}

/// An iterator over chunks of tasks to be executed in a Group
pub struct GroupChunks<'a> {
    group: &'a Group,
    chunk_size: i32,
}

impl<'a> Iterator for GroupChunks<'a> {
    type Item = Chunk<'a>;

    /// Get the next chunk of tasks to be executed
    fn next(&mut self) -> Option<Chunk<'a>> {
        self.group.get_chunk(self.chunk_size)
    }
}

/// A chunk of tasks from a Group to be executed
///
/// Executes task in the range [start, end)
#[derive(Debug)]
pub struct Chunk<'a> {
    /// The next task to be executed in this chunk
    start: i32,
    /// The last task to be executed in this chunk
    end: i32,
    /// Total number of tasks scheduled in the group this chunk came from
    total: (i32, i32, i32),
    /// Function to run for this task
    fcn: ISPCTaskFn,
    /// Data pointer to user params to pass to the function
    data: *mut libc::c_void,
    /// The group this chunk is running tasks from
    group: &'a Group,
}

impl<'a> Chunk<'a> {
    /// Create a new chunk to execute tasks in the group from [start, end)
    pub fn new(group: &'a Group, start: i32, end: i32) -> Chunk {
        Chunk { start: start, end: end, total: group.total,
                fcn: group.fcn, data: group.data, group: group
        }
    }
    /// Execute all tasks in this chunk
    pub fn execute(&self, thread_id: i32, total_threads: i32) {
        let total_tasks = self.total.0 * self.total.1 * self.total.2;
        for t in self.start..self.end {
            let id = self.task_indices(t);
            (self.fcn)(self.data, thread_id as libc::c_int, total_threads as libc::c_int,
                       t as libc::c_int, total_tasks as libc::c_int,
                       id.0 as libc::c_int, id.1 as libc::c_int, id.2 as libc::c_int,
                       self.total.0 as libc::c_int, self.total.1 as libc::c_int,
                       self.total.2 as libc::c_int);
        }
        // If this chunk finished the group mark the group as finished
        if self.is_last() {
            self.group.mark_finished();
        }
    }
    /// Check if this is the last chunk in the group
    pub fn is_last(&self) -> bool {
        self.end == self.total.0 * self.total.1 * self.total.2
    }
    /// Get the global task id for the task index
    fn task_indices(&self, id: i32) -> (i32, i32, i32) {
        (id % self.total.0, (id / self.total.0) % self.total.1, id / (self.total.0 * self.total.1))
    }
}

<|endoftext|>


<commit_before>// If `src` can be promoted to `$dst`, then it must be Ok to cast `dst` back to
// `$src`
macro_rules! promote_and_back {
    ($($src:ident => $($dst:ident),+);+;) => {
        mod demoting_to {
            $(
                mod $src {
                    mod from {
                        use crate::From;

                        $(
                            quickcheck! {
                                fn $dst(src: $src) -> bool {
                                    $src::cast($dst::cast(src)).is_ok()
                                }
                            }
                         )+
                    }
                }
             )+
        }
    }
}

#[cfg(target_pointer_width = "32")]
promote_and_back! {
    i8    => f32, f64,     i16, i32, isize, i64, i128                            ;
    i16   => f32, f64,          i32, isize, i64, i128                            ;
    i32   => f32, f64,                      i64, i128                            ;
    isize => f32, f64,                      i64, i128                            ;
    i64   => f32, f64,                           i128                            ;
    u8    => f32, f64,     i16, i32, isize, i64, i128, u16, u32, usize, u64, u128;
    u16   => f32, f64,          i32, isize, i64, i128,      u32, usize, u64, u128;
    u32   => f32, f64,                      i64, i128,                  u64, u128;
    usize => f32, f64,                      i64, i128,                  u64, u128;
    u64   => f32, f64,                           i128,                       u128;
}

#[cfg(target_pointer_width = "64")]
promote_and_back! {
    i8    => f32, f64,     i16, i32, i64, isize, i128                            ;
    i16   => f32, f64,          i32, i64, isize, i128                            ;
    i32   => f32, f64,               i64, isize, i128                            ;
    i64   => f32, f64,                           i128                            ;
    isize => f32, f64,                           i128                            ;
    u8    => f32, f64,     i16, i32, i64, isize, i128, u16, u32, u64, usize, u128;
    u16   => f32, f64,          i32, i64, isize, i128,      u32, u64, usize, u128;
    u32   => f32, f64,               i64, isize, i128,           u64, usize, u128;
    u64   => f32, f64,                           i128,                       u128;
    usize => f32, f64,                           i128,                       u128;
}

// TODO uncomment this.
/*
promote_and_back! {
    i128  => f32, f64            ;
    u128  => f32, f64            ;
}*/

// If it's Ok to cast `src` to `$dst`, it must also be Ok to cast `dst` back to
// `$src`
macro_rules! symmetric_cast_between {
    ($($src:ident => $($dst:ident),+);+;) => {
        mod symmetric_cast_between {
            $(
                mod $src {
                    mod and {
                        use quickcheck::TestResult;

                        use crate::From;

                        $(
                            quickcheck! {
                                fn $dst(src: $src) -> TestResult {
                                    if let Ok(dst) = $dst::cast(src) {
                                        TestResult::from_bool(
                                            $src::cast(dst).is_ok())
                                    } else {
                                        TestResult::discard()
                                    }
                                }
                            }
                         )+
                    }
                }
             )+
        }
    }
}

#[cfg(target_pointer_width = "32")]
symmetric_cast_between! {
    u8    =>           i8                      ;
    u16   =>           i8, i16                 ;
    u32   =>           i8, i16, i32            ;
    usize =>           i8, i16, i32            ;
    u64   =>           i8, i16, i32, i64, isize;
}

#[cfg(target_pointer_width = "64")]
symmetric_cast_between! {
    u8    =>           i8                            ;
    u16   =>           i8, i16                       ;
    u32   =>           i8, i16, i32                  ;
    u64   =>           i8, i16, i32, i64, isize      ;
    usize =>           i8, i16, i32, i64, isize      ;
    u128  =>           i8, i16, i32, i64, isize, i128;
}

macro_rules! from_float {
    ($($src:ident => $($dst:ident),+);+;) => {
        $(
            mod $src {
                mod inf {
                    mod to {
                        use crate::{Error, From};

                        $(
                            #[test]
                            fn $dst() {
                                let _0: $src = 0.;
                                let _1: $src = 1.;
                                let inf = _1 / _0;
                                let neg_inf = -_1 / _0;

                                assert_eq!($dst::cast(inf),
                                           Err(Error::Infinite));
                                assert_eq!($dst::cast(neg_inf),
                                           Err(Error::Infinite));
                            }
                         )+
                    }
                }

                mod nan {
                    mod to {
                        use crate::{Error, From};

                        $(
                            #[test]
                            fn $dst() {
                                let _0: $src = 0.;
                                let nan = _0 / _0;

                                assert_eq!($dst::cast(nan),
                                           Err(Error::NaN));
                            }
                         )+
                    }
                }
            }
         )+
    }
}

from_float! {
    f32 => i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize;
    f64 => i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize;
}

#[test]
fn test_fl_conversion() {
    use crate::u128;
    assert_eq!(u128(42.0f32), Ok(42));
}

#[test]
fn gh16() {
    assert_eq!(super::u64(-0.01_f64), Ok(0));
    assert_eq!(super::u64(-0.99_f32), Ok(0));

    assert_eq!(super::u32(-0.99_f64), Ok(0));
    assert_eq!(super::u32(-0.01_f32), Ok(0));

    assert_eq!(super::u64(0.01_f64), Ok(0));
    assert_eq!(super::u64(0.99_f32), Ok(0));

    assert_eq!(super::u32(0.99_f64), Ok(0));
    assert_eq!(super::u32(0.01_f32), Ok(0));
}

#[test]
fn gh15() {
    assert_eq!(super::u32(32_f32.exp2()), Err(super::Error::Overflow));
    assert_eq!(super::u32(32_f64.exp2()), Err(super::Error::Overflow));

    assert_eq!(super::u64(64_f32.exp2()), Err(super::Error::Overflow));
    assert_eq!(super::u64(64_f64.exp2()), Err(super::Error::Overflow));

    assert_eq!(super::u8(8_f32.exp2()), Err(super::Error::Overflow));
    assert_eq!(super::u8(8_f64.exp2()), Err(super::Error::Overflow));

    assert_eq!(super::u16(16_f32.exp2()), Err(super::Error::Overflow));
    assert_eq!(super::u16(16_f64.exp2()), Err(super::Error::Overflow));
}

#[test]
fn gh23_lossless_integer_max_min_to_float() {
    // f32::MANTISSA_DIGITS = 24
    assert_eq!(Ok(u8::MAX), super::u8(255f32));
    assert_eq!(Ok(u16::MAX), super::u16(65_535f32));

    // f64::MANTISSA_DIGITS = 53
    assert_eq!(Ok(u8::MAX), super::u8(255f64));
    assert_eq!(Ok(u16::MAX), super::u16(65_535f64));
    assert_eq!(Ok(u32::MAX), super::u32(4_294_967_295f64));

    // also check negative values (not part of the original bug)
    assert_eq!(Ok(i8::MIN), super::i8(-128f32));
    assert_eq!(Ok(i16::MIN), super::i16(-32_768f32));

    assert_eq!(Ok(i8::MIN), super::i8(-128f64));
    assert_eq!(Ok(i16::MIN), super::i16(-32_768f64));
    assert_eq!(Ok(i32::MIN), super::i32(-2_147_483_648f64));
}
<commit_msg>fix promote and back tests<commit_after>// If `src` can be promoted to `$dst`, then it must be Ok to cast `dst` back to
// `$src`
macro_rules! promote_and_back {
    ($($src:ident => $($dst:ident),+);+;) => {
        mod demoting_to {
            $(
                mod $src {
                    mod from {
                        use crate::From;

                        $(
                            quickcheck! {
                                fn $dst(src: $src) -> bool {
                                    $src::cast($dst::cast(src)).is_ok()
                                }
                            }
                         )+
                    }
                }
             )+
        }
    }
}

#[cfg(target_pointer_width = "32")]
promote_and_back! {
    i8    => f32, f64,     i16, i32, isize, i64, i128                            ;
    i16   => f32, f64,          i32, isize, i64, i128                            ;
    i32   =>      f64,                      i64, i128                            ;
    isize =>      f64,                      i64, i128                            ;
    i64   =>                                     i128                            ;
    u8    => f32, f64,     i16, i32, isize, i64, i128, u16, u32, usize, u64, u128;
    u16   => f32, f64,          i32, isize, i64, i128,      u32, usize, u64, u128;
    u32   =>      f64,                      i64, i128,                  u64, u128;
    usize =>      f64,                      i64, i128,                  u64, u128;
    u64   =>                                     i128,                       u128;
}

#[cfg(target_pointer_width = "64")]
promote_and_back! {
    i8    => f32, f64,     i16, i32, i64, isize, i128                            ;
    i16   => f32, f64,          i32, i64, isize, i128                            ;
    i32   =>      f64,               i64, isize, i128                            ;
    i64   =>                                     i128                            ;
    isize =>                                     i128                            ;
    u8    => f32, f64,     i16, i32, i64, isize, i128, u16, u32, u64, usize, u128;
    u16   => f32, f64,          i32, i64, isize, i128,      u32, u64, usize, u128;
    u32   =>      f64,               i64, isize, i128,           u64, usize, u128;
    u64   =>                                     i128,                       u128;
    usize =>                                     i128,                       u128;
}

// If it's Ok to cast `src` to `$dst`, it must also be Ok to cast `dst` back to
// `$src`
macro_rules! symmetric_cast_between {
    ($($src:ident => $($dst:ident),+);+;) => {
        mod symmetric_cast_between {
            $(
                mod $src {
                    mod and {
                        use quickcheck::TestResult;

                        use crate::From;

                        $(
                            quickcheck! {
                                fn $dst(src: $src) -> TestResult {
                                    if let Ok(dst) = $dst::cast(src) {
                                        TestResult::from_bool(
                                            $src::cast(dst).is_ok())
                                    } else {
                                        TestResult::discard()
                                    }
                                }
                            }
                         )+
                    }
                }
             )+
        }
    }
}

#[cfg(target_pointer_width = "32")]
symmetric_cast_between! {
    u8    =>           i8                      ;
    u16   =>           i8, i16                 ;
    u32   =>           i8, i16, i32            ;
    usize =>           i8, i16, i32            ;
    u64   =>           i8, i16, i32, i64, isize;
}

#[cfg(target_pointer_width = "64")]
symmetric_cast_between! {
    u8    =>           i8                            ;
    u16   =>           i8, i16                       ;
    u32   =>           i8, i16, i32                  ;
    u64   =>           i8, i16, i32, i64, isize      ;
    usize =>           i8, i16, i32, i64, isize      ;
    u128  =>           i8, i16, i32, i64, isize, i128;
}

macro_rules! from_float {
    ($($src:ident => $($dst:ident),+);+;) => {
        $(
            mod $src {
                mod inf {
                    mod to {
                        use crate::{Error, From};

                        $(
                            #[test]
                            fn $dst() {
                                let _0: $src = 0.;
                                let _1: $src = 1.;
                                let inf = _1 / _0;
                                let neg_inf = -_1 / _0;

                                assert_eq!($dst::cast(inf),
                                           Err(Error::Infinite));
                                assert_eq!($dst::cast(neg_inf),
                                           Err(Error::Infinite));
                            }
                         )+
                    }
                }

                mod nan {
                    mod to {
                        use crate::{Error, From};

                        $(
                            #[test]
                            fn $dst() {
                                let _0: $src = 0.;
                                let nan = _0 / _0;

                                assert_eq!($dst::cast(nan),
                                           Err(Error::NaN));
                            }
                         )+
                    }
                }
            }
         )+
    }
}

from_float! {
    f32 => i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize;
    f64 => i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize;
}

#[test]
fn test_fl_conversion() {
    use crate::u128;
    assert_eq!(u128(42.0f32), Ok(42));
}

#[test]
fn gh16() {
    assert_eq!(super::u64(-0.01_f64), Ok(0));
    assert_eq!(super::u64(-0.99_f32), Ok(0));

    assert_eq!(super::u32(-0.99_f64), Ok(0));
    assert_eq!(super::u32(-0.01_f32), Ok(0));

    assert_eq!(super::u64(0.01_f64), Ok(0));
    assert_eq!(super::u64(0.99_f32), Ok(0));

    assert_eq!(super::u32(0.99_f64), Ok(0));
    assert_eq!(super::u32(0.01_f32), Ok(0));
}

#[test]
fn gh15() {
    assert_eq!(super::u32(32_f32.exp2()), Err(super::Error::Overflow));
    assert_eq!(super::u32(32_f64.exp2()), Err(super::Error::Overflow));

    assert_eq!(super::u64(64_f32.exp2()), Err(super::Error::Overflow));
    assert_eq!(super::u64(64_f64.exp2()), Err(super::Error::Overflow));

    assert_eq!(super::u8(8_f32.exp2()), Err(super::Error::Overflow));
    assert_eq!(super::u8(8_f64.exp2()), Err(super::Error::Overflow));

    assert_eq!(super::u16(16_f32.exp2()), Err(super::Error::Overflow));
    assert_eq!(super::u16(16_f64.exp2()), Err(super::Error::Overflow));
}

#[test]
fn gh23_lossless_integer_max_min_to_float() {
    // f32::MANTISSA_DIGITS = 24
    assert_eq!(Ok(u8::MAX), super::u8(255f32));
    assert_eq!(Ok(u16::MAX), super::u16(65_535f32));

    // f64::MANTISSA_DIGITS = 53
    assert_eq!(Ok(u8::MAX), super::u8(255f64));
    assert_eq!(Ok(u16::MAX), super::u16(65_535f64));
    assert_eq!(Ok(u32::MAX), super::u32(4_294_967_295f64));

    // also check negative values (not part of the original bug)
    assert_eq!(Ok(i8::MIN), super::i8(-128f32));
    assert_eq!(Ok(i16::MIN), super::i16(-32_768f32));

    assert_eq!(Ok(i8::MIN), super::i8(-128f64));
    assert_eq!(Ok(i16::MIN), super::i16(-32_768f64));
    assert_eq!(Ok(i32::MIN), super::i32(-2_147_483_648f64));
}
<|endoftext|>


<commit_before>use super::{Puppetfile, Module, ModuleInfo, Version};
use semver;

#[test]
fn empty_file() {
    let puppetfile = Puppetfile::parse(r##"forge "https://forge.puppetlabs.com""##);
    assert!(puppetfile.is_ok());
    let parsed = puppetfile.unwrap();
    assert_eq!(
        String::from_str("https://forge.puppetlabs.com"),
        parsed.forge
    );
    assert_eq!(
        vec![],
        parsed.modules
    );
}

#[test]
fn no_version() {
    let puppetfile = Puppetfile::parse(r##"forge "https://forge.puppetlabs.com"

mod 'mayflower/php'
    "##);
    assert!(puppetfile.is_ok());

    let parsed = puppetfile.unwrap();
    assert_eq!(
        String::from_str("https://forge.puppetlabs.com"),
        parsed.forge
    );
    assert_eq!(
        Module { name: String::from_str("mayflower/php"), info: vec![] },
        parsed.modules[0]
    );
}

#[test]
fn git_version() {
    let puppetfile = Puppetfile::parse(r##"forge "https://forge.puppetlabs.com"

mod 'mayflower/php', '1.0.1'
    "##);
    assert!(puppetfile.is_ok());

    let parsed = puppetfile.unwrap();
    assert_eq!(
        String::from_str("https://forge.puppetlabs.com"),
        parsed.forge
    );
    assert_eq!(
        Module {
            name: String::from_str("mayflower/php"),
            info: vec![Version(semver::version::parse("1.0.1").unwrap())]
        },
        parsed.modules[0]
    );
}

#[test]
fn version() {
    let puppetfile = Puppetfile::parse(r##"forge "https://forge.puppetlabs.com"

mod 'mayflower/php',
:git => 'git://github.com/Mayflower/puppet-php.git'
    "##);
    assert!(puppetfile.is_ok());

    let parsed = puppetfile.unwrap();
    assert_eq!(
        String::from_str("https://forge.puppetlabs.com"),
        parsed.forge
    );
    assert_eq!(
        Module {
            name: String::from_str("mayflower/php"),
            info: vec![
                ModuleInfo(String::from_str("git"),
                           String::from_str("git://github.com/Mayflower/puppet-php.git"))
            ]
        },
        parsed.modules[0]
    );
}

#[test]
fn format() {
    let version = Version(semver::version::parse("1.0.0").unwrap());
    assert_eq!(String::from_str("1.0.0"), format!("{}", version));

    let mod_info = ModuleInfo(
        String::from_str("git"),
        String::from_str("git://github.com/Mayflower/puppet-php.git")
    );
    assert_eq!(
        String::from_str(":git => 'git://github.com/Mayflower/puppet-php.git'"),
        format!("{}", mod_info)
    );

    let module = Module {
        name: String::from_str("mayflower/php"),
        info: vec![version, mod_info]
    };
    assert_eq!(
        String::from_str("mod 'mayflower/php', '1.0.0',
  :git => 'git://github.com/Mayflower/puppet-php.git'"),
        format!("{}", module)
    );

    let puppetfile = Puppetfile {
        forge: String::from_str("https://forge.puppetlabs.com"),
        modules: vec![module]
    };
    assert_eq!(
        String::from_str("forge 'https://forge.puppetlabs.com'

mod 'mayflower/php', '1.0.0',
  :git => 'git://github.com/Mayflower/puppet-php.git'
"),
        format!("{}", puppetfile)
    );
}

#[test]
fn version_url() {
    let module = Module { name: String::from_str("mayflower/php"), info: vec![] };
    assert_eq!(
        "https://forge.puppetlabs.com/users/mayflower/modules/php/releases/find.json",
        format!(
            "{}",
            module.version_url(
                String::from_str("https://forge.puppetlabs.com/")
            )
        ).as_slice()
    )
}

#[test]
fn user_name_pair() {
    let module = Module { name: String::from_str("mayflower/php"), info: vec![] };
    assert_eq!(module.user_name_pair(), Some(("mayflower", "php")))
}

#[test]
fn forge_version() {
    let module = Module { name: String::from_str("puppetlabs/nginx"), info: vec![] };
    assert_eq!(
        module.forge_version(String::from_str("https://forge.puppetlabs.com/")),
        semver::version::parse("99.99.99")
    )
}
<commit_msg>fix tests<commit_after>use super::{Puppetfile, Module, ModuleInfo, Version};
use semver;

#[test]
fn empty_file() {
    let puppetfile = Puppetfile::parse(r##"forge "https://forge.puppetlabs.com""##);
    assert!(puppetfile.is_ok());
    let parsed = puppetfile.unwrap();
    assert_eq!(
        String::from_str("https://forge.puppetlabs.com"),
        parsed.forge
    );
    assert_eq!(
        vec![],
        parsed.modules
    );
}

#[test]
fn no_version() {
    let puppetfile = Puppetfile::parse(r##"forge "https://forge.puppetlabs.com"

mod 'mayflower/php'
    "##);
    assert!(puppetfile.is_ok());

    let parsed = puppetfile.unwrap();
    assert_eq!(
        String::from_str("https://forge.puppetlabs.com"),
        parsed.forge
    );
    assert_eq!(
        Module { name: String::from_str("mayflower/php"), info: vec![] },
        parsed.modules[0]
    );
}

#[test]
fn git_version() {
    let puppetfile = Puppetfile::parse(r##"forge "https://forge.puppetlabs.com"

mod 'mayflower/php', '1.0.1'
    "##);
    assert!(puppetfile.is_ok());

    let parsed = puppetfile.unwrap();
    assert_eq!(
        String::from_str("https://forge.puppetlabs.com"),
        parsed.forge
    );
    assert_eq!(
        Module {
            name: String::from_str("mayflower/php"),
            info: vec![Version(semver::Version::parse("1.0.1").unwrap())]
        },
        parsed.modules[0]
    );
}

#[test]
fn version() {
    let puppetfile = Puppetfile::parse(r##"forge "https://forge.puppetlabs.com"

mod 'mayflower/php',
:git => 'git://github.com/Mayflower/puppet-php.git'
    "##);
    assert!(puppetfile.is_ok());

    let parsed = puppetfile.unwrap();
    assert_eq!(
        String::from_str("https://forge.puppetlabs.com"),
        parsed.forge
    );
    assert_eq!(
        Module {
            name: String::from_str("mayflower/php"),
            info: vec![
                ModuleInfo(String::from_str("git"),
                           String::from_str("git://github.com/Mayflower/puppet-php.git"))
            ]
        },
        parsed.modules[0]
    );
}

#[test]
fn format() {
    let version = Version(semver::Version::parse("1.0.0").unwrap());
    assert_eq!(String::from_str("1.0.0"), format!("{}", version));

    let mod_info = ModuleInfo(
        String::from_str("git"),
        String::from_str("git://github.com/Mayflower/puppet-php.git")
    );
    assert_eq!(
        String::from_str(":git => 'git://github.com/Mayflower/puppet-php.git'"),
        format!("{}", mod_info)
    );

    let module = Module {
        name: String::from_str("mayflower/php"),
        info: vec![version, mod_info]
    };
    assert_eq!(
        String::from_str("mod 'mayflower/php', '1.0.0',
  :git => 'git://github.com/Mayflower/puppet-php.git'"),
        format!("{}", module)
    );

    let puppetfile = Puppetfile {
        forge: String::from_str("https://forge.puppetlabs.com"),
        modules: vec![module]
    };
    assert_eq!(
        String::from_str("forge 'https://forge.puppetlabs.com'

mod 'mayflower/php', '1.0.0',
  :git => 'git://github.com/Mayflower/puppet-php.git'
"),
        format!("{}", puppetfile)
    );
}

#[test]
fn version_url() {
    let module = Module { name: String::from_str("mayflower/php"), info: vec![] };
    assert_eq!(
        "https://forge.puppetlabs.com/users/mayflower/modules/php/releases/find.json",
        format!(
            "{}",
            module.version_url(
                String::from_str("https://forge.puppetlabs.com/")
            )
        ).as_slice()
    )
}

#[test]
fn user_name_pair() {
    let module = Module { name: String::from_str("mayflower/php"), info: vec![] };
    assert_eq!(module.user_name_pair(), Some(("mayflower", "php")))
}

#[test]
fn forge_version() {
    let module = Module { name: String::from_str("puppetlabs/nginx"), info: vec![] };
    assert_eq!(
        module.forge_version(String::from_str("https://forge.puppetlabs.com/")),
        semver::Version::parse("99.99.99")
    )
}
<|endoftext|>


<commit_before>#![cfg(test)]
use context::Context;
use lua::{State, Type};
use types::LuaFunction;

#[test]
fn test_thread() {
    use std::thread;
    let mut state = State::new();
    state.open_libs();
    let mut context = Context::new(&mut state);

    // Create a table with a bunch of random numbers
    // Create a median function that finds the median value of the table
    // and a mean function that finds the mean of all the values
    context.do_string("
        t = {}
        math.randomseed(os.time())
        for i = 1, 10000 do
            local v = math.random()
            table.insert(t, v)
        end

        function mean()
            local ret = 0
            print(\"Start mean\")
            for i, v in ipairs(t) do
                ret = ret + v
            end
            ret = ret / #t
            print(\"End mean\")
            return ret
        end
        function median()
            print(\"Start median\")
            local ls = {}
            for i, v in ipairs(t) do
                ls[i] = v
            end
            table.sort(ls)
            local ret = ls[#ls // 2]
            print(\"End median\")
            return ret
        end
    ").unwrap();

    let luathread1 = context.push_thread();
    let luathread2 = context.push_thread();
    {
        let mut state1 = luathread1.as_state(&mut context);
        let mut state2 = luathread2.as_state(&mut context);
        let thread1 = thread::spawn(move || {
            let mut context1 = Context::new(&mut state1);
            let func = context1.push_global("mean")
                .get_value::<LuaFunction>(&mut context1).unwrap();
            let result = func.call_singleret(&mut context1, &[]).unwrap()
                .get_value::<f64>(&mut context1);
            return result.unwrap();
        });
        let thread2 = thread::spawn(move || {
            let mut context2 = Context::new(&mut state2);
            let func = context2.push_global("median")
                .get_value::<LuaFunction>(&mut context2).unwrap();
            let result = func.call_singleret(&mut context2, &[]).unwrap()
                .get_value::<f64>(&mut context2);
            return result.unwrap();
        });

        println!("Mean: {:?}", thread1.join().unwrap());
        println!("Median: {:?}", thread2.join().unwrap());
    }
}

#[test]
fn test_global() {
    let mut state = State::new();
    let mut context = Context::new(&mut state);
    context.set_global("foo", &12);
    assert_eq!(Some(12), context.push_global("foo").get_value(&mut context));
}

#[test]
fn test_table() {
    let mut state = State::new();
    let mut context = Context::new(&mut state);

    let table = context.push_table();
    table.set(&mut context, &"foo", &1.0);

    assert_eq!(Some(1.0), table.get_typed(&mut context, &"foo"));
}

#[test]
fn test_generic() {
    let mut state = State::new();
    let mut context = Context::new(&mut state);
    context.do_string("foo = 1.5").unwrap();
    let value = context.push_global("foo");

    assert_eq!(value.type_of(&mut context), Type::Number);
    assert_eq!(Some(1.5), value.get_value(&mut context));
}

#[test]
fn test_function_call() {
    let mut state = State::new();
    let mut context = Context::new(&mut state);
    context.do_string("function foo(a, b) return a + b; end").unwrap();

    let value:Option<f64> = context.push_global("foo")
        .get_value::<LuaFunction>(&mut context)
        .map(|func| func.call_singleret(&mut context, &[&1.2, &1.2]).unwrap())
        .and_then(|val|val.get_value::<f64>(&mut context));
    // let value = &func.call(&mut context, &[&1.2, &1.2], 1)[0];
    assert_eq!(value, Some(2.4));
}

#[test]
fn test_context_block() {
    let mut state = State::new();
    let mut context = Context::new(&mut state);
    let top = context.get_state().get_top();

    {
        // create a new context with pushed values
        let mut new_context = context.push_context();
        new_context.push_table();
        new_context.push_number(1.0);
        new_context.push_string("wow");
        // values are popped at end of block
    }

    assert_eq!(top, context.get_state().get_top());
}

#[test]
fn test_userdata() {
    struct Foo {
        value: i64
    }
    impl Foo {
        pub fn new() -> Foo {
            Foo {
                value: 0
            }
        }
        pub fn set(&mut self, v: i64) {
            self.value = v;
        }
        pub fn get(&self) -> i64 {
            self.value
        }
    }

    let mut state = State::new();
    let mut context = Context::new(&mut state);
    {
        let mut new_context = context.push_context();
        let udata = {
            let mut foo = Foo::new();
            foo.set(100);
            new_context.push_userdata(foo)
        };
        {
            let foo: &mut Foo = unsafe{udata.get_value(&mut new_context).unwrap()};
            assert_eq!(foo.get(), 100);
        }
    }
}

#[test]
fn test_stack_as_variable() {
    let mut state = State::new();
    let mut context = Context::new(&mut state);

    let b = context.push_integer(15);
    context.set_global("foo", &b);

    assert_eq!(context.push_global("foo").get_value(&mut context), Some(15));
}
<commit_msg>Removed print statements from thread test<commit_after>#![cfg(test)]
use context::Context;
use lua::{State, Type};
use types::LuaFunction;

#[test]
fn test_thread() {
    use std::thread;
    let mut state = State::new();
    state.open_libs();
    let mut context = Context::new(&mut state);

    // Create a table with a bunch of random numbers
    // Create a median function that finds the median value of the table
    // and a mean function that finds the mean of all the values
    context.do_string("
        t = {}
        math.randomseed(os.time())
        for i = 1, 10000 do
            local v = math.random()
            table.insert(t, v)
        end

        function mean()
            local ret = 0
            for i, v in ipairs(t) do
                ret = ret + v
            end
            ret = ret / #t
            return ret
        end
        function median()
            local ls = {}
            for i, v in ipairs(t) do
                ls[i] = v
            end
            table.sort(ls)
            local ret = ls[#ls // 2]
            return ret
        end
    ").unwrap();

    let luathread1 = context.push_thread();
    let luathread2 = context.push_thread();
    {
        let mut state1 = luathread1.as_state(&mut context);
        let mut state2 = luathread2.as_state(&mut context);
        let thread1 = thread::spawn(move || {
            let mut context1 = Context::new(&mut state1);
            let func = context1.push_global("mean")
                .get_value::<LuaFunction>(&mut context1).unwrap();
            let result = func.call_singleret(&mut context1, &[]).unwrap()
                .get_value::<f64>(&mut context1);
            return result.unwrap();
        });
        let thread2 = thread::spawn(move || {
            let mut context2 = Context::new(&mut state2);
            let func = context2.push_global("median")
                .get_value::<LuaFunction>(&mut context2).unwrap();
            let result = func.call_singleret(&mut context2, &[]).unwrap()
                .get_value::<f64>(&mut context2);
            return result.unwrap();
        });

        println!("Mean: {:?}", thread1.join().unwrap());
        println!("Median: {:?}", thread2.join().unwrap());
    }
}

#[test]
fn test_global() {
    let mut state = State::new();
    let mut context = Context::new(&mut state);
    context.set_global("foo", &12);
    assert_eq!(Some(12), context.push_global("foo").get_value(&mut context));
}

#[test]
fn test_table() {
    let mut state = State::new();
    let mut context = Context::new(&mut state);

    let table = context.push_table();
    table.set(&mut context, &"foo", &1.0);

    assert_eq!(Some(1.0), table.get_typed(&mut context, &"foo"));
}

#[test]
fn test_generic() {
    let mut state = State::new();
    let mut context = Context::new(&mut state);
    context.do_string("foo = 1.5").unwrap();
    let value = context.push_global("foo");

    assert_eq!(value.type_of(&mut context), Type::Number);
    assert_eq!(Some(1.5), value.get_value(&mut context));
}

#[test]
fn test_function_call() {
    let mut state = State::new();
    let mut context = Context::new(&mut state);
    context.do_string("function foo(a, b) return a + b; end").unwrap();

    let value:Option<f64> = context.push_global("foo")
        .get_value::<LuaFunction>(&mut context)
        .map(|func| func.call_singleret(&mut context, &[&1.2, &1.2]).unwrap())
        .and_then(|val|val.get_value::<f64>(&mut context));
    // let value = &func.call(&mut context, &[&1.2, &1.2], 1)[0];
    assert_eq!(value, Some(2.4));
}

#[test]
fn test_context_block() {
    let mut state = State::new();
    let mut context = Context::new(&mut state);
    let top = context.get_state().get_top();

    {
        // create a new context with pushed values
        let mut new_context = context.push_context();
        new_context.push_table();
        new_context.push_number(1.0);
        new_context.push_string("wow");
        // values are popped at end of block
    }

    assert_eq!(top, context.get_state().get_top());
}

#[test]
fn test_userdata() {
    struct Foo {
        value: i64
    }
    impl Foo {
        pub fn new() -> Foo {
            Foo {
                value: 0
            }
        }
        pub fn set(&mut self, v: i64) {
            self.value = v;
        }
        pub fn get(&self) -> i64 {
            self.value
        }
    }

    let mut state = State::new();
    let mut context = Context::new(&mut state);
    {
        let mut new_context = context.push_context();
        let udata = {
            let mut foo = Foo::new();
            foo.set(100);
            new_context.push_userdata(foo)
        };
        {
            let foo: &mut Foo = unsafe{udata.get_value(&mut new_context).unwrap()};
            assert_eq!(foo.get(), 100);
        }
    }
}

#[test]
fn test_stack_as_variable() {
    let mut state = State::new();
    let mut context = Context::new(&mut state);

    let b = context.push_integer(15);
    context.set_global("foo", &b);

    assert_eq!(context.push_global("foo").get_value(&mut context), Some(15));
}
<|endoftext|>


<commit_before>use super::{AsStr, Element, XmlReader, XmlWriter};
use super::Event::*;
use super::error::Result;
use std::str::from_utf8;
use std::io::Cursor;

macro_rules! next_eq {
    ($r: expr, $($t:path, $bytes:expr),*) => {
        $(
            match $r.next() {
                Some(Ok($t(ref e))) => {
                    assert!(e.name() == $bytes, "expecting {:?}, found {:?}",
                            from_utf8($bytes), e.content().as_str());
                },
                Some(Ok(e)) => {
                    assert!(false, "expecting {:?}, found {:?}",
                            $t(Element::from_buffer($bytes.to_vec(), 0, $bytes.len(), $bytes.len())), e);
                },
                Some(Err((e, pos))) => {
                    assert!(false, "{:?} at buffer position {}", e, pos);
                },
                p => {
                    assert!(false, "expecting {:?}, found {:?}",
                            $t(Element::from_buffer($bytes.to_vec(), 0, $bytes.len(), $bytes.len())), p);
                }
            }
        )*
    }
}

#[test]
fn test_start() {
    let mut r = XmlReader::from_str("").trim_text(true);
    next_eq!(r, Start, b"a");
}

#[test]
fn test_start_end() {
    let mut r = XmlReader::from_str("").trim_text(true);
    next_eq!(r, Start, b"a", End, b"a");
}

#[test]
fn test_start_end_attr() {
    let mut r = XmlReader::from_str("").trim_text(true);
    next_eq!(r, Start, b"a", End, b"a");
}

#[test]
fn test_start_end_comment() {
    let mut r = XmlReader::from_str(" ").trim_text(true);
    next_eq!(r,
             Start, b"b",
             Start, b"a",
             End, b"a",
             Start, b"a",
             End, b"a",
             Comment, b"t",
             End, b"b"
            );
}

#[test]
fn test_start_txt_end() {
    let mut r = XmlReader::from_str("test").trim_text(true);
    next_eq!(r, Start, b"a", Text, b"test", End, b"a");
}

#[test]
fn test_comment() {
    let mut r = XmlReader::from_str("").trim_text(true);
    next_eq!(r, Comment, b"test");
}

#[test]
fn test_xml_decl() {
    let mut r = XmlReader::from_str("<?xml version=\"1.0\" encoding='utf-8'?>").trim_text(true);
    match r.next() {
        Some(Ok(Decl(ref e))) => {
            match e.version() {
                Ok(v) => assert!(v == b"1.0", "expecting version '1.0', got '{:?}", v.as_str()),
                Err(e) => assert!(false, "{:?}", e),
            }
            match e.encoding() {
                Some(Ok(v)) => assert!(v == b"utf-8", "expecting encoding 'utf-8', got '{:?}",
                                       v.as_str()),
                Some(Err(e)) => assert!(false, "{:?}", e),
                None => assert!(false, "cannot find encoding"),
            }
            match e.standalone() {
                None => assert!(true),
                e => assert!(false, "doesn't expect standalone, got {:?}", e),
            }
        },
        Some(Err((e, pos))) => {
            assert!(false, "{:?} at buffer position {}", e, pos);
        },
        _ => assert!(false, "unable to parse XmlDecl"),
    }
}

#[test]
fn test_trim_test() {
    let txt = "  ";
    let mut r = XmlReader::from_str(&txt).trim_text(true);
    next_eq!(r, Start, b"a",
                Start, b"b",
                End, b"b",
                End, b"a");

    let mut r = XmlReader::from_str(&txt).trim_text(false);
    next_eq!(r, Text, b"",
                Start, b"a",
                Text, b"",
                Start, b"b",
                Text, b"  ",
                End, b"b",
                Text, b"",
                End, b"a");
}

#[test]
fn test_cdata() {
    let mut r = XmlReader::from_str("<![CDATA[test]]>").trim_text(true);
    next_eq!(r, CData, b"test");
}

#[test]
fn test_cdata_open_close() {
    let mut r = XmlReader::from_str("<![CDATA[test <> test]]>").trim_text(true);
    next_eq!(r, CData, b"test <> test");
}

#[test]
fn test_start_attr() {
    let mut r = XmlReader::from_str("").trim_text(true);
    next_eq!(r, Start, b"a");
}

#[test]
fn test_nested() {
    let mut r = XmlReader::from_str("test<c/>").trim_text(true);
    next_eq!(r,
             Start, b"a",
             Start, b"b",
             Text, b"test",
             End, b"b",
             Start, b"c",
             End, b"c",
             End, b"a"
            );
}

#[test]
fn test_writer() {
    let str = r#"<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.github.sample" android:versionName="Lollipop" android:versionCode="5.1"><application android:label="SampleApplication"></application></manifest>"#;
    let reader = XmlReader::from_str(&str).trim_text(true);
    let mut writer = XmlWriter::new(Cursor::new(Vec::new()));
    for event in reader {
        assert!(writer.write(event.unwrap()).is_ok());
    }

    let result = writer.into_inner().into_inner();
    assert_eq!(result, str.as_bytes());
}

#[test]
fn test_write_attrs() {
    let str_from = r#"<source attr="val"></source>"#;
    let expected = r#"<copy attr="val" a="b" c="d" x="y"></copy>"#;
    let reader = XmlReader::from_str(&str_from).trim_text(true);
    let mut writer = XmlWriter::new(Cursor::new(Vec::new()));
    for event in reader {
        let event = event.unwrap();
        let event = match event {
            Start(elem) => {
                let mut attrs = elem.attributes().collect::<Result<Vec<_>>>().unwrap();
                attrs.extend_from_slice(&[(b"a", b"b"), (b"c", b"d")]);
                let mut elem = Element::new("copy").with_attributes(attrs);
                elem.push_attribute("x", "y");
                Start(elem)
            },
            End(_elem) => End(Element::new("copy")),
            _ => event
        };
        assert!(writer.write(event).is_ok());
    }

    let result = writer.into_inner().into_inner();
    assert_eq!(result, expected.as_bytes());
}

#[test]
fn test_buf_position() {
    let mut r = XmlReader::from_str("")
        .trim_text(true).with_check(true);

    match r.next() {
        Some(Err((_, 4))) => assert!(true),
        Some(Err((_, n))) => assert!(false, "expecting buf_pos = 4, found {}", n),
        e => assert!(false, "expecting error, found {:?}", e),
    }

}
<commit_msg>add a namespace test<commit_after>use super::{AsStr, Element, XmlReader, XmlWriter};
use super::Event::*;
use super::error::Result;
use std::str::from_utf8;
use std::io::Cursor;

macro_rules! next_eq {
    ($r: expr, $($t:path, $bytes:expr),*) => {
        $(
            match $r.next() {
                Some(Ok($t(ref e))) => {
                    assert!(e.name() == $bytes, "expecting {:?}, found {:?}",
                            from_utf8($bytes), e.content().as_str());
                },
                Some(Ok(e)) => {
                    assert!(false, "expecting {:?}, found {:?}",
                            $t(Element::from_buffer($bytes.to_vec(), 0, $bytes.len(), $bytes.len())), e);
                },
                Some(Err((e, pos))) => {
                    assert!(false, "{:?} at buffer position {}", e, pos);
                },
                p => {
                    assert!(false, "expecting {:?}, found {:?}",
                            $t(Element::from_buffer($bytes.to_vec(), 0, $bytes.len(), $bytes.len())), p);
                }
            }
        )*
    }
}

#[test]
fn test_start() {
    let mut r = XmlReader::from_str("").trim_text(true);
    next_eq!(r, Start, b"a");
}

#[test]
fn test_start_end() {
    let mut r = XmlReader::from_str("").trim_text(true);
    next_eq!(r, Start, b"a", End, b"a");
}

#[test]
fn test_start_end_attr() {
    let mut r = XmlReader::from_str("").trim_text(true);
    next_eq!(r, Start, b"a", End, b"a");
}

#[test]
fn test_start_end_comment() {
    let mut r = XmlReader::from_str(" ").trim_text(true);
    next_eq!(r,
             Start, b"b",
             Start, b"a",
             End, b"a",
             Start, b"a",
             End, b"a",
             Comment, b"t",
             End, b"b"
            );
}

#[test]
fn test_start_txt_end() {
    let mut r = XmlReader::from_str("test").trim_text(true);
    next_eq!(r, Start, b"a", Text, b"test", End, b"a");
}

#[test]
fn test_comment() {
    let mut r = XmlReader::from_str("").trim_text(true);
    next_eq!(r, Comment, b"test");
}

#[test]
fn test_xml_decl() {
    let mut r = XmlReader::from_str("<?xml version=\"1.0\" encoding='utf-8'?>").trim_text(true);
    match r.next() {
        Some(Ok(Decl(ref e))) => {
            match e.version() {
                Ok(v) => assert!(v == b"1.0", "expecting version '1.0', got '{:?}", v.as_str()),
                Err(e) => assert!(false, "{:?}", e),
            }
            match e.encoding() {
                Some(Ok(v)) => assert!(v == b"utf-8", "expecting encoding 'utf-8', got '{:?}",
                                       v.as_str()),
                Some(Err(e)) => assert!(false, "{:?}", e),
                None => assert!(false, "cannot find encoding"),
            }
            match e.standalone() {
                None => assert!(true),
                e => assert!(false, "doesn't expect standalone, got {:?}", e),
            }
        },
        Some(Err((e, pos))) => {
            assert!(false, "{:?} at buffer position {}", e, pos);
        },
        _ => assert!(false, "unable to parse XmlDecl"),
    }
}

#[test]
fn test_trim_test() {
    let txt = "  ";
    let mut r = XmlReader::from_str(&txt).trim_text(true);
    next_eq!(r, Start, b"a",
                Start, b"b",
                End, b"b",
                End, b"a");

    let mut r = XmlReader::from_str(&txt).trim_text(false);
    next_eq!(r, Text, b"",
                Start, b"a",
                Text, b"",
                Start, b"b",
                Text, b"  ",
                End, b"b",
                Text, b"",
                End, b"a");
}

#[test]
fn test_cdata() {
    let mut r = XmlReader::from_str("<![CDATA[test]]>").trim_text(true);
    next_eq!(r, CData, b"test");
}

#[test]
fn test_cdata_open_close() {
    let mut r = XmlReader::from_str("<![CDATA[test <> test]]>").trim_text(true);
    next_eq!(r, CData, b"test <> test");
}

#[test]
fn test_start_attr() {
    let mut r = XmlReader::from_str("").trim_text(true);
    next_eq!(r, Start, b"a");
}

#[test]
fn test_nested() {
    let mut r = XmlReader::from_str("test<c/>").trim_text(true);
    next_eq!(r,
             Start, b"a",
             Start, b"b",
             Text, b"test",
             End, b"b",
             Start, b"c",
             End, b"c",
             End, b"a"
            );
}

#[test]
fn test_writer() {
    let str = r#"<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.github.sample" android:versionName="Lollipop" android:versionCode="5.1"><application android:label="SampleApplication"></application></manifest>"#;
    let reader = XmlReader::from_str(&str).trim_text(true);
    let mut writer = XmlWriter::new(Cursor::new(Vec::new()));
    for event in reader {
        assert!(writer.write(event.unwrap()).is_ok());
    }

    let result = writer.into_inner().into_inner();
    assert_eq!(result, str.as_bytes());
}

#[test]
fn test_write_attrs() {
    let str_from = r#"<source attr="val"></source>"#;
    let expected = r#"<copy attr="val" a="b" c="d" x="y"></copy>"#;
    let reader = XmlReader::from_str(&str_from).trim_text(true);
    let mut writer = XmlWriter::new(Cursor::new(Vec::new()));
    for event in reader {
        let event = event.unwrap();
        let event = match event {
            Start(elem) => {
                let mut attrs = elem.attributes().collect::<Result<Vec<_>>>().unwrap();
                attrs.extend_from_slice(&[(b"a", b"b"), (b"c", b"d")]);
                let mut elem = Element::new("copy").with_attributes(attrs);
                elem.push_attribute("x", "y");
                Start(elem)
            },
            End(_elem) => End(Element::new("copy")),
            _ => event
        };
        assert!(writer.write(event).is_ok());
    }

    let result = writer.into_inner().into_inner();
    assert_eq!(result, expected.as_bytes());
}

#[test]
fn test_buf_position() {
    let mut r = XmlReader::from_str("")
        .trim_text(true).with_check(true);

    match r.next() {
        Some(Err((_, 4))) => assert!(true),
        Some(Err((_, n))) => assert!(false, "expecting buf_pos = 4, found {}", n),
        e => assert!(false, "expecting error, found {:?}", e),
    }

}

#[test]
fn test_namespace() {
    let mut r = XmlReader::from_str("<myns:b>in namespace!</myns:b>")
        .trim_text(true).namespaced();;

    if let Some(Ok((None, Start(_)))) = r.next() {
    } else {
        assert!(false, "expecting start element with no namespace");
    }

    if let Some(Ok((Some(a), Start(_)))) = r.next() {
        if &*a == b"www1" {
            assert!(true);
        } else {
            assert!(false, "expecting namespace to resolve to 'www1'");
        }
    } else {
        assert!(false, "expecting namespace resolution");
    }
}

<|endoftext|>


<commit_before>use std::rc::Rc;
use std::ops::Deref;

use ::expr::{Expr,Kint,  Kfloat, Type, Proc, Error as E, Result};
use ::env::Env;

pub fn kint(i: Kint) -> Expr {
    Expr::Int(i)
}

pub fn kfloat(f: Kfloat) -> Expr {
    Expr::Float(f)
}

pub fn kcons(car: Expr, cdr: Expr) -> Expr {
    Expr::Cons(Rc::new(car), Rc::new(cdr))
}

pub fn knil() -> Expr {
    Expr::Nil
}

pub fn ksym<S: Into<String>>(s: S) -> Expr {
    Expr::Sym(s.into())
}

pub fn kstr<S: Into<String>>(s: S) -> Expr {
    Expr::Str(s.into())
}

pub fn kproc(p: Proc) -> Expr {
    Expr::Proc(p)
}

pub fn klambda(param: Expr, body: Expr) -> Proc {
    Proc::Lambda(Rc::new(param), Rc::new(body))
}

pub fn kprim<S: Into<String>, F:'static + Fn(&mut Env, &Expr) -> Result<Expr> + Sized>(name: S, f: F) -> Proc{
    Proc::Prim(name.into(), Rc::new(f))
}

pub fn car(cons: &Expr) -> Result<Expr> {
    match cons {
        &Expr::Cons(ref car, _) => Ok(car.deref().clone()),
        arg => Err(E::Type(Type::Cons, arg.clone()))
    }
}

pub fn cdr(cons: &Expr) -> Result<Expr> {
    match cons {
        &Expr::Cons(_, ref cdr) => Ok(cdr.deref().clone()),
        arg => Err(E::Type(Type::Cons, arg.clone()))
    }
}

#[macro_export]
macro_rules! klist {
    ($car: expr, $($cdr: expr), *) => (
        kcons($crate::expr::Expr::from($car), klist!($($cdr),*))
    );
    ($car: expr) => (
        kcons($crate::expr::Expr::from($car), knil())
    );
    () => (
        knil()
    );
}

macro_rules! get_args_one {
    ($v:expr, Int) => (
        match $v {
            &Expr::Int(x) => Ok(x),
            hd => Err(E::Type(Type::Int, hd.clone()))
        }
    );

    ($v:expr, Float) => {
        match $v {
            &Expr::Float(x) => Ok(x),
            hd => Err(E::Type(Type::Float, hd.clone()))
        }
    };
    ($v:expr, Str) => (
        match $v {
            &Expr::Str(ref x) => Ok(x),
            hd => Err(E::Type(Type::Str, hd.clone()))

        }
    );
    ($v:expr, Sym) => (
        match $v {
            &Expr::Sym(ref x) => Ok(x),
            hd => Err(E::Type(Type::Sym, hd.clone()))
        }
    );
    ($v:expr, Nil) => (
        match $v {
            &Expr::Nil => Ok(()),
            hd => Err(E::Type(Type::Nil, hd.clone()))
        }
    );
    ($v:expr, Cons) => (
        match $v {
            &Expr::Cons(ref car, ref cdr) => Ok((car.deref(), cdr.deref())),
            hd => Err(E::Type(Type::Cons, hd.clone()))
        }
    );
    ($v:expr, Proc) => (
        match $v {
            &Expr::Proc(ref p) => Ok(p),
            hd => Err(E::Type(Type::Proc, hd.clone()))
        }
    );
    ($v:expr, Any) => (
        match $v {
            hd => if true {
                Ok(hd)
            } else {
                unreachable!()
            }
        };
    )
}

macro_rules! gen_pattern {
    (($var: pat, $ident: tt) $($other:tt) *) => (
        ($var, gen_pattern!($($other)*))
            );
    () => (())
}

macro_rules! gen_match {
    ($args: expr, ($var: pat, $ident: tt) $($other:tt) *) =>
        (
            match $args {
                &Expr::Cons(ref hd, ref tl) => {
                    let v = try!(get_args_one!(hd.deref(), $ident));
                    (v, gen_match!(tl.deref(), $($other)*))
                },
                &Expr::Nil => return Err(E::ArityShort),
                args => return Err(E::InvalidArgument(args.clone()))
            };
            );
    ($args: expr, ) => (
        match $args {
            &Expr::Nil => (),
            _ => return Err(E::ArityExceed)
        }
        );
}

#[macro_export]
macro_rules! get_args {
    ($args: expr, ($var: pat, $ident: tt) $($other:tt) *) =>
        (
            let gen_pattern!(($var, $ident) $($other)*) = gen_match!($args, ($var, $ident) $($other)*)
            ) ;
    ($args: expr, ) => (
        let () = gen_match!($args,)
        );
    ($args: expr) => (
        let () = gen_match!($args,)
        );
}

pub fn f_foldl<F>(mut env: &mut Env, f: &F, init: &Expr, args: &Expr) -> Result<Expr>
    where F: Fn(&mut Env, &Expr, &Expr) -> Result<Expr>{
    let mut res = init.clone();
    let mut head = args;
    let nil = &Expr::Nil;
    while head != nil {
        match head {
            &Expr::Cons(ref car, ref cdr) => {
                res = try!(f(env, &res, car));
                head = cdr;
            }
            _ => return Err(E::InvalidArgument(args.clone()))
        }
    }
    Ok(res)
}

// fn f_reverse(mut env: &mut Env, args: &Expr) -> Result<Expr> {
//     f_foldl(env, &|_, acc, x| Ok(Expr::Cons(Rc::new(x.clone()), Rc::new(acc))), Expr::Nil, args)
// }

pub fn f_foldr<F>(mut env: &mut Env, f: &F, init: &Expr, args: &Expr) -> Result<Expr>
    where F: Fn(&mut Env, &Expr, &Expr) -> Result<Expr>{
    match args {
        &Expr::Nil => Ok(init.clone()),
        &Expr::Cons(ref car, ref cdr) => {
            let v = try!(f_foldr(env, f, init, cdr));
            f(env, &v, car)
        }
        args => Err(E::InvalidArgument(args.clone()))
    }
}

pub fn f_map<F>(mut env: &mut Env, f: &F, list: &Expr) -> Result<Expr>
    where F: Fn(&mut Env, &Expr) -> Result<Expr>{
    f_foldr(env, &|env, acc, x| Ok(kcons(try!(f(env, x)), acc.clone()))
                 , &Expr::Nil, list)
}

// fn f_iter<F>(mut env: &mut Env, f: &F, list: &Expr) -> Result<Expr>
//     where F: Fn(&mut Env, Expr) -> Result<()>{
//     f_foldr(env, &|env, _, x| {try!(f(env,x.clone())); Ok(Expr::Nil)}
//                  , Expr::Nil, list)
// }

<commit_msg>support optional argument on rust side<commit_after>use std::rc::Rc;
use std::ops::Deref;

use ::expr::{Expr,Kint,  Kfloat, Type, Proc, Error as E, Result};
use ::env::Env;

pub fn kint(i: Kint) -> Expr {
    Expr::Int(i)
}

pub fn kfloat(f: Kfloat) -> Expr {
    Expr::Float(f)
}

pub fn kcons(car: Expr, cdr: Expr) -> Expr {
    Expr::Cons(Rc::new(car), Rc::new(cdr))
}

pub fn knil() -> Expr {
    Expr::Nil
}

pub fn ksym<S: Into<String>>(s: S) -> Expr {
    Expr::Sym(s.into())
}

pub fn kstr<S: Into<String>>(s: S) -> Expr {
    Expr::Str(s.into())
}

pub fn kproc(p: Proc) -> Expr {
    Expr::Proc(p)
}

pub fn klambda(param: Expr, body: Expr) -> Proc {
    Proc::Lambda(Rc::new(param), Rc::new(body))
}

pub fn kprim<S: Into<String>, F:'static + Fn(&mut Env, &Expr) -> Result<Expr> + Sized>(name: S, f: F) -> Proc{
    Proc::Prim(name.into(), Rc::new(f))
}

pub fn car(cons: &Expr) -> Result<Expr> {
    match cons {
        &Expr::Cons(ref car, _) => Ok(car.deref().clone()),
        arg => Err(E::Type(Type::Cons, arg.clone()))
    }
}

pub fn cdr(cons: &Expr) -> Result<Expr> {
    match cons {
        &Expr::Cons(_, ref cdr) => Ok(cdr.deref().clone()),
        arg => Err(E::Type(Type::Cons, arg.clone()))
    }
}

#[macro_export]
macro_rules! klist {
    ($car: expr, $($cdr: expr), *) => (
        kcons($crate::expr::Expr::from($car), klist!($($cdr),*))
    );
    ($car: expr) => (
        kcons($crate::expr::Expr::from($car), knil())
    );
    () => (
        knil()
    );
}

macro_rules! get_args_one {
    ($v:expr, Int) => (
        match $v {
            &Expr::Int(x) => Ok(x),
            hd => Err(E::Type(Type::Int, hd.clone()))
        }
    );

    ($v:expr, Float) => {
        match $v {
            &Expr::Float(x) => Ok(x),
            hd => Err(E::Type(Type::Float, hd.clone()))
        }
    };
    ($v:expr, Str) => (
        match $v {
            &Expr::Str(ref x) => Ok(x),
            hd => Err(E::Type(Type::Str, hd.clone()))

        }
    );
    ($v:expr, Sym) => (
        match $v {
            &Expr::Sym(ref x) => Ok(x),
            hd => Err(E::Type(Type::Sym, hd.clone()))
        }
    );
    ($v:expr, Nil) => (
        match $v {
            &Expr::Nil => Ok(()),
            hd => Err(E::Type(Type::Nil, hd.clone()))
        }
    );
    ($v:expr, Cons) => (
        match $v {
            &Expr::Cons(ref car, ref cdr) => Ok((car.deref(), cdr.deref())),
            hd => Err(E::Type(Type::Cons, hd.clone()))
        }
    );
    ($v:expr, Proc) => (
        match $v {
            &Expr::Proc(ref p) => Ok(p),
            hd => Err(E::Type(Type::Proc, hd.clone()))
        }
    );
    ($v:expr, Any) => (
        match $v {
            hd => if true {
                Ok(hd)
            } else {
                unreachable!()
            }
        };
    )
}

macro_rules! gen_pattern {
    (($var: pat, $ident: tt) $($other:tt) *) => (
        ($var, gen_pattern!($($other)*))
            );
    () => (())
}

macro_rules! gen_match {
    ($args: expr, ($var: pat, $ident: tt) $($other:tt) *) =>
        (
            match $args {
                &Expr::Cons(ref hd, ref tl) => {
                    let v = try!(get_args_one!(hd.deref(), $ident));
                    (v, gen_match!(tl.deref(), $($other)*))
                },
                &Expr::Nil => return Err(E::ArityShort),
                args => return Err(E::InvalidArgument(args.clone()))
            };
            );
    ($args: expr, ($var: pat, opt $ident: tt) $($other:tt) *) =>
        (
            match $args {
                &Expr::Cons(ref hd, ref tl) => {
                    let v = try!(get_args_one!(hd.deref(), $ident));
                    (Some(v), gen_match!(tl.deref(), $($other)*))
                },
                &Expr::Nil => {
                    (None, gen_match!($args, $($other)*))

                },
                args => return Err(E::InvalidArgument(args.clone()))
            };
            );
    ($args: expr, ) => (
        match $args {
            &Expr::Nil => (),
            _ => return Err(E::ArityExceed)
        }
        );
}

#[macro_export]
macro_rules! get_args {
    ($args: expr, ($var: pat, $ident: tt) $($other:tt) *) =>
        (
            let gen_pattern!(($var, $ident) $($other)*) = gen_match!($args, ($var, $ident) $($other)*)
            ) ;
    ($args: expr, ($var: pat, opt $ident: tt) $($other:tt) *) =>
        (
            let gen_pattern!(($var, $ident) $($other)*) = gen_match!($args, ($var, opt $ident) $($other)*)
            ) ;
    ($args: expr, ) => (
        let () = gen_match!($args,)
        );
    ($args: expr) => (
        let () = gen_match!($args,)
        );
}

pub fn f_foldl<F>(mut env: &mut Env, f: &F, init: &Expr, args: &Expr) -> Result<Expr>
    where F: Fn(&mut Env, &Expr, &Expr) -> Result<Expr>{
    let mut res = init.clone();
    let mut head = args;
    let nil = &Expr::Nil;
    while head != nil {
        match head {
            &Expr::Cons(ref car, ref cdr) => {
                res = try!(f(env, &res, car));
                head = cdr;
            }
            _ => return Err(E::InvalidArgument(args.clone()))
        }
    }
    Ok(res)
}

// fn f_reverse(mut env: &mut Env, args: &Expr) -> Result<Expr> {
//     f_foldl(env, &|_, acc, x| Ok(Expr::Cons(Rc::new(x.clone()), Rc::new(acc))), Expr::Nil, args)
// }

pub fn f_foldr<F>(mut env: &mut Env, f: &F, init: &Expr, args: &Expr) -> Result<Expr>
    where F: Fn(&mut Env, &Expr, &Expr) -> Result<Expr>{
    match args {
        &Expr::Nil => Ok(init.clone()),
        &Expr::Cons(ref car, ref cdr) => {
            let v = try!(f_foldr(env, f, init, cdr));
            f(env, &v, car)
        }
        args => Err(E::InvalidArgument(args.clone()))
    }
}

pub fn f_map<F>(mut env: &mut Env, f: &F, list: &Expr) -> Result<Expr>
    where F: Fn(&mut Env, &Expr) -> Result<Expr>{
    f_foldr(env, &|env, acc, x| Ok(kcons(try!(f(env, x)), acc.clone()))
                 , &Expr::Nil, list)
}

// fn f_iter<F>(mut env: &mut Env, f: &F, list: &Expr) -> Result<Expr>
//     where F: Fn(&mut Env, Expr) -> Result<()>{
//     f_foldr(env, &|env, _, x| {try!(f(env,x.clone())); Ok(Expr::Nil)}
//                  , Expr::Nil, list)
// }

<|endoftext|>


<commit_before>use std::io::process::Command;
use std::io::process::Process;
use core::Workspaces;
use window_manager::WindowManager;
use window_system::WindowSystem;
use config::Config;
use window_system::Window;

pub fn run(program: String, args: Option<String>) {
    match match args {
        Some(a) => Command::new(program).arg(a).detached().spawn(),
        None    => Command::new(program).detached().spawn()
    } {
        _ => ()
    }
}

pub fn spawn_pipe(program: String, args: Option<String>) -> Process {
    match args {
        Some(a) => Command::new(program).arg(a).detached().spawn().unwrap(),
        None    => Command::new(program).detached().spawn().unwrap()
    }
}

pub fn spawn_on(workspaces: Workspaces, _: &WindowSystem,
                window: Window, workspace_id: u32) -> Workspaces {
    workspaces.focus_window(window).shift(workspace_id)
}
<commit_msg>fixed util::run<commit_after>use std::io::process::Command;
use std::io::process::Process;
use core::Workspaces;
use window_manager::WindowManager;
use window_system::WindowSystem;
use config::Config;
use window_system::Window;

pub fn run(program: String, args: Option<String>) {
    let arguments : Vec<String> = match args {
        None => Vec::new(),
        Some(ref a) => a.split(' ').map(String::from_str).collect()
    };

    match Command::new(program).args(arguments.as_slice()).detached().spawn() {
        _ => ()
    }
}

pub fn spawn_pipe(program: String, args: Option<String>) -> Process {
    match args {
        Some(a) => Command::new(program).arg(a).detached().spawn().unwrap(),
        None    => Command::new(program).detached().spawn().unwrap()
    }
}

pub fn spawn_on(workspaces: Workspaces, _: &WindowSystem,
                window: Window, workspace_id: u32) -> Workspaces {
    workspaces.focus_window(window).shift(workspace_id)
}
<|endoftext|>


<commit_before>//! A simple connection pool

extern mod extra;

use extra::arc::MutexArc;

use super::{PostgresNotificationIterator,
            PostgresCancelData,
            PostgresConnection,
            NormalPostgresStatement,
            PostgresTransaction,
            SslMode};
use super::error::{PostgresConnectError, PostgresDbError};
use super::types::ToSql;

struct InnerConnectionPool {
    url: ~str,
    ssl: SslMode,
    pool: ~[PostgresConnection],
}

impl InnerConnectionPool {
    fn new_connection(&mut self) -> Option<PostgresConnectError> {
        match PostgresConnection::try_connect(self.url, &self.ssl) {
            Ok(conn) => {
                self.pool.push(conn);
                None
            }
            Err(err) => Some(err)
        }
    }
}

/// A simple fixed-size Postgres connection pool.
///
/// It can be shared across tasks.
#[deriving(Clone)]
pub struct PostgresConnectionPool {
    priv pool: MutexArc<InnerConnectionPool>
}

impl PostgresConnectionPool {
    /// Attempts to create a new pool with the specified number of connections.
    ///
    /// Returns an error if the specified number of connections cannot be
    /// created.
    pub fn try_new(url: &str, ssl: SslMode, pool_size: uint)
            -> Result<PostgresConnectionPool, PostgresConnectError> {
        let mut pool = InnerConnectionPool {
            url: url.to_owned(),
            ssl: ssl,
            pool: ~[],
        };

        for _ in range(0, pool_size) {
            match pool.new_connection() {
                None => (),
                Some(err) => return Err(err)
            }
        }

        Ok(PostgresConnectionPool {
            pool: MutexArc::new(pool)
        })
    }

    /// A convenience function wrapping `try_new`.
    ///
    /// Fails if the pool cannot be created.
    pub fn new(url: &str, ssl: SslMode, pool_size: uint)
            -> PostgresConnectionPool {
        match PostgresConnectionPool::try_new(url, ssl, pool_size) {
            Ok(pool) => pool,
            Err(err) => fail!("Unable to initialize pool: {}", err.to_str())
        }
    }

    /// Retrieves a connection from the pool.
    ///
    /// If all connections are in use, blocks until one becomes available.
    pub fn get_connection(&self) -> PooledPostgresConnection {
        let conn = unsafe {
            self.pool.unsafe_access_cond(|pool, cvar| {
                while pool.pool.is_empty() {
                    cvar.wait();
                }

                pool.pool.pop()
            })
        };

        PooledPostgresConnection {
            pool: self.clone(),
            conn: Some(conn)
        }
    }
}

/// A Postgres connection pulled from a connection pool.
///
/// It will be returned to the pool when it falls out of scope, even due to
/// task failure.
pub struct PooledPostgresConnection {
    priv pool: PostgresConnectionPool,
    // TODO remove the Option wrapper when drop takes self by value
    priv conn: Option<PostgresConnection>
}

impl Drop for PooledPostgresConnection {
    fn drop(&mut self) {
        unsafe {
            self.pool.pool.unsafe_access(|pool| {
                pool.pool.push(self.conn.take_unwrap());
            })
        }
    }
}

impl PooledPostgresConnection {
    /// Like `PostgresConnection::try_prepare`.
    pub fn try_prepare<'a>(&'a self, query: &str)
            -> Result<NormalPostgresStatement<'a>, PostgresDbError> {
        self.conn.get_ref().try_prepare(query)
    }

    /// Like `PostgresConnection::prepare`.
    pub fn prepare<'a>(&'a self, query: &str) -> NormalPostgresStatement<'a> {
        self.conn.get_ref().prepare(query)
    }

    /// Like `PostgresConnection::try_update`.
    pub fn try_update(&self, query: &str, params: &[&ToSql])
            -> Result<uint, PostgresDbError> {
        self.conn.get_ref().try_update(query, params)
    }

    /// Like `PostgresConnection::update`.
    pub fn update(&self, query: &str, params: &[&ToSql]) -> uint {
        self.conn.get_ref().update(query, params)
    }

    /// Like `PostgresConnection::transaction`.
    pub fn transaction<'a>(&'a self) -> PostgresTransaction<'a> {
        self.conn.get_ref().transaction()
    }

    /// Like `PostgresConnection::notifications`.
    pub fn notifications<'a>(&'a self) -> PostgresNotificationIterator<'a> {
        self.conn.get_ref().notifications()
    }

    /// Like `PostgresConnection::cancel_data`.
    pub fn cancel_data(&self) -> PostgresCancelData {
        self.conn.get_ref().cancel_data()
    }
}
<commit_msg>Add failure heading to pool docs<commit_after>//! A simple connection pool

extern mod extra;

use extra::arc::MutexArc;

use super::{PostgresNotificationIterator,
            PostgresCancelData,
            PostgresConnection,
            NormalPostgresStatement,
            PostgresTransaction,
            SslMode};
use super::error::{PostgresConnectError, PostgresDbError};
use super::types::ToSql;

struct InnerConnectionPool {
    url: ~str,
    ssl: SslMode,
    pool: ~[PostgresConnection],
}

impl InnerConnectionPool {
    fn new_connection(&mut self) -> Option<PostgresConnectError> {
        match PostgresConnection::try_connect(self.url, &self.ssl) {
            Ok(conn) => {
                self.pool.push(conn);
                None
            }
            Err(err) => Some(err)
        }
    }
}

/// A simple fixed-size Postgres connection pool.
///
/// It can be shared across tasks.
#[deriving(Clone)]
pub struct PostgresConnectionPool {
    priv pool: MutexArc<InnerConnectionPool>
}

impl PostgresConnectionPool {
    /// Attempts to create a new pool with the specified number of connections.
    ///
    /// Returns an error if the specified number of connections cannot be
    /// created.
    pub fn try_new(url: &str, ssl: SslMode, pool_size: uint)
            -> Result<PostgresConnectionPool, PostgresConnectError> {
        let mut pool = InnerConnectionPool {
            url: url.to_owned(),
            ssl: ssl,
            pool: ~[],
        };

        for _ in range(0, pool_size) {
            match pool.new_connection() {
                None => (),
                Some(err) => return Err(err)
            }
        }

        Ok(PostgresConnectionPool {
            pool: MutexArc::new(pool)
        })
    }

    /// A convenience function wrapping `try_new`.
    ///
    /// # Failure
    ///
    /// Fails if the pool cannot be created.
    pub fn new(url: &str, ssl: SslMode, pool_size: uint)
            -> PostgresConnectionPool {
        match PostgresConnectionPool::try_new(url, ssl, pool_size) {
            Ok(pool) => pool,
            Err(err) => fail!("Unable to initialize pool: {}", err.to_str())
        }
    }

    /// Retrieves a connection from the pool.
    ///
    /// If all connections are in use, blocks until one becomes available.
    pub fn get_connection(&self) -> PooledPostgresConnection {
        let conn = unsafe {
            self.pool.unsafe_access_cond(|pool, cvar| {
                while pool.pool.is_empty() {
                    cvar.wait();
                }

                pool.pool.pop()
            })
        };

        PooledPostgresConnection {
            pool: self.clone(),
            conn: Some(conn)
        }
    }
}

/// A Postgres connection pulled from a connection pool.
///
/// It will be returned to the pool when it falls out of scope, even due to
/// task failure.
pub struct PooledPostgresConnection {
    priv pool: PostgresConnectionPool,
    // TODO remove the Option wrapper when drop takes self by value
    priv conn: Option<PostgresConnection>
}

impl Drop for PooledPostgresConnection {
    fn drop(&mut self) {
        unsafe {
            self.pool.pool.unsafe_access(|pool| {
                pool.pool.push(self.conn.take_unwrap());
            })
        }
    }
}

impl PooledPostgresConnection {
    /// Like `PostgresConnection::try_prepare`.
    pub fn try_prepare<'a>(&'a self, query: &str)
            -> Result<NormalPostgresStatement<'a>, PostgresDbError> {
        self.conn.get_ref().try_prepare(query)
    }

    /// Like `PostgresConnection::prepare`.
    pub fn prepare<'a>(&'a self, query: &str) -> NormalPostgresStatement<'a> {
        self.conn.get_ref().prepare(query)
    }

    /// Like `PostgresConnection::try_update`.
    pub fn try_update(&self, query: &str, params: &[&ToSql])
            -> Result<uint, PostgresDbError> {
        self.conn.get_ref().try_update(query, params)
    }

    /// Like `PostgresConnection::update`.
    pub fn update(&self, query: &str, params: &[&ToSql]) -> uint {
        self.conn.get_ref().update(query, params)
    }

    /// Like `PostgresConnection::transaction`.
    pub fn transaction<'a>(&'a self) -> PostgresTransaction<'a> {
        self.conn.get_ref().transaction()
    }

    /// Like `PostgresConnection::notifications`.
    pub fn notifications<'a>(&'a self) -> PostgresNotificationIterator<'a> {
        self.conn.get_ref().notifications()
    }

    /// Like `PostgresConnection::cancel_data`.
    pub fn cancel_data(&self) -> PostgresCancelData {
        self.conn.get_ref().cancel_data()
    }
}
<|endoftext|>