<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, AtomicUsize, AtomicPtr};

/// 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<AtomicPtr<libc::c_void>>>,
    /// A unique identifier for this context
    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, AtomicPtr::new(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.is_finished())
    }
    /// 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(AtomicPtr::new(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 ptr in mem.drain(0..) {
            let m = ptr.load(atomic::Ordering::SeqCst);
            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?
    start: AtomicUsize,
    end: usize,
    /// 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: AtomicPtr<libc::c_void>,
    /// Tracks how many chunks we've given out so far to threads
    chunks_launched: AtomicUsize,
    /// Tracks how many of the chunks we gave out are completed. A group is finished
    /// only when all chunks are done and start >= total tasks, call `is_finished` to check.
    ///
    /// I'm unsure whether or semaphore/condvar 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?
    /// TODO: We can't just have the last chunk executed mark the group as done
    /// because earlier chunks might still be running! We need to mark ourselves
    chunks_finished: AtomicUsize,
}

impl Group {
    /// Create a new task group for execution of the function
    pub fn new(total: (i32, i32, i32), data: AtomicPtr<libc::c_void>, fcn: ISPCTaskFn) -> Group {
        Group { start: AtomicUsize::new(0), end: (total.0 * total.1 * total.2) as usize,
                total: total, data: data, fcn: fcn,
                chunks_launched: AtomicUsize::new(0), chunks_finished: AtomicUsize::new(0) }
    }
    /// Get an iterator over `chunk_size` chunks of tasks to be executed for this group
    pub fn chunks(&self, chunk_size: usize) -> GroupChunks {
        GroupChunks { group: self, chunk_size: chunk_size }
    }
    /// Check if all tasks for this group have been completed
    pub fn is_finished(&self) -> bool {
        let finished = self.chunks_finished.load(atomic::Ordering::SeqCst);
        let launched = self.chunks_launched.load(atomic::Ordering::SeqCst);
        let start = self.start.load(atomic::Ordering::SeqCst);
        // This shouldn't happen, if it does some bad threading voodoo is afoot
        assert!(finished <= launched);
        finished == launched && start >= self.end
    }
    /// Check if this group has tasks left to execute
    fn has_tasks(&self) -> bool {
        let start = self.start.load(atomic::Ordering::SeqCst);
        start < self.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: usize) -> Option<Chunk> {
        let start = self.start.fetch_add(desired_tasks, atomic::Ordering::SeqCst);
        if start < self.end {
            // Give the chunk 4 tasks or whatever remain
            let c = Some(Chunk::new(self, start, cmp::min(start + desired_tasks, self.end)));
            self.chunks_launched.fetch_add(1, atomic::Ordering::SeqCst);
            c
        } else {
            None
        }
    }
}

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

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: AtomicPtr<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: usize, end: usize) -> Chunk {
        let d = AtomicPtr::new(group.data.load(atomic::Ordering::SeqCst));
        Chunk { start: start as i32, end: end as i32, total: group.total,
                fcn: group.fcn, data: d, 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;
        let data = self.data.load(atomic::Ordering::SeqCst);
        for t in self.start..self.end {
            let id = self.task_indices(t);
            (self.fcn)(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);
        }
        // Tell the group this chunk is done
        self.group.chunks_finished.fetch_add(1, atomic::Ordering::SeqCst);
    }
    /// 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>Address clippy comment I missed<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, AtomicUsize, AtomicPtr};

/// 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<AtomicPtr<libc::c_void>>>,
    /// A unique identifier for this context
    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, AtomicPtr::new(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.is_finished())
    }
    /// 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(AtomicPtr::new(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 ptr in mem.drain(0..) {
            let m = ptr.load(atomic::Ordering::SeqCst);
            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?
    start: AtomicUsize,
    end: usize,
    /// 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: AtomicPtr<libc::c_void>,
    /// Tracks how many chunks we've given out so far to threads
    chunks_launched: AtomicUsize,
    /// Tracks how many of the chunks we gave out are completed. A group is finished
    /// only when all chunks are done and start >= total tasks, call `is_finished` to check.
    ///
    /// I'm unsure whether or semaphore/condvar 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?
    /// TODO: We can't just have the last chunk executed mark the group as done
    /// because earlier chunks might still be running! We need to mark ourselves
    chunks_finished: AtomicUsize,
}

impl Group {
    /// Create a new task group for execution of the function
    pub fn new(total: (i32, i32, i32), data: AtomicPtr<libc::c_void>, fcn: ISPCTaskFn) -> Group {
        Group { start: AtomicUsize::new(0), end: (total.0 * total.1 * total.2) as usize,
                total: total, data: data, fcn: fcn,
                chunks_launched: AtomicUsize::new(0), chunks_finished: AtomicUsize::new(0) }
    }
    /// Get an iterator over `chunk_size` chunks of tasks to be executed for this group
    pub fn chunks(&self, chunk_size: usize) -> GroupChunks {
        GroupChunks { group: self, chunk_size: chunk_size }
    }
    /// Check if all tasks for this group have been completed
    pub fn is_finished(&self) -> bool {
        let finished = self.chunks_finished.load(atomic::Ordering::SeqCst);
        let launched = self.chunks_launched.load(atomic::Ordering::SeqCst);
        let start = self.start.load(atomic::Ordering::SeqCst);
        // This shouldn't happen, if it does some bad threading voodoo is afoot
        assert!(finished <= launched);
        finished == launched && start >= self.end
    }
    /// Check if this group has tasks left to execute
    fn has_tasks(&self) -> bool {
        let start = self.start.load(atomic::Ordering::SeqCst);
        start < self.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: usize) -> Option<Chunk> {
        let start = self.start.fetch_add(desired_tasks, atomic::Ordering::SeqCst);
        if start < self.end {
            // Give the chunk 4 tasks or whatever remain
            let c = Some(Chunk::new(self, start, cmp::min(start + desired_tasks, self.end)));
            self.chunks_launched.fetch_add(1, atomic::Ordering::SeqCst);
            c
        } else {
            None
        }
    }
}

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

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: AtomicPtr<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: usize, end: usize) -> Chunk {
        let d = AtomicPtr::new(group.data.load(atomic::Ordering::SeqCst));
        Chunk { start: start as i32, end: end as i32, total: group.total,
                fcn: group.fcn, data: d, 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;
        let data = self.data.load(atomic::Ordering::SeqCst);
        for t in self.start..self.end {
            let id = self.task_indices(t);
            (self.fcn)(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);
        }
        // Tell the group this chunk is done
        self.group.chunks_finished.fetch_add(1, atomic::Ordering::SeqCst);
    }
    /// 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>use crate::prelude::*;

fn codegen_print(fx: &mut FunctionCx<'_, '_, impl cranelift_module::Backend>, msg: &str) {
    let puts = fx
        .module
        .declare_function(
            "puts",
            Linkage::Import,
            &Signature {
                call_conv: CallConv::triple_default(fx.triple()),
                params: vec![AbiParam::new(pointer_ty(fx.tcx))],
                returns: vec![],
            },
        )
        .unwrap();
    let puts = fx.module.declare_func_in_func(puts, &mut fx.bcx.func);
    #[cfg(debug_assertions)]
    {
        fx.add_entity_comment(puts, "puts");
    }

    let symbol_name = fx.tcx.symbol_name(fx.instance);
    let real_msg = format!("trap at {:?} ({}): {}\0", fx.instance, symbol_name, msg);
    let mut data_ctx = DataContext::new();
    data_ctx.define(real_msg.as_bytes().to_vec().into_boxed_slice());
    let msg_id = fx
        .module
        .declare_data(
            &(symbol_name.name.as_str().to_string() + msg),
            Linkage::Local,
            false,
            None,
        )
        .unwrap();

    // Ignore DuplicateDefinition error, as the data will be the same
    let _ = fx.module.define_data(msg_id, &data_ctx);

    let local_msg_id = fx.module.declare_data_in_func(msg_id, fx.bcx.func);
    #[cfg(debug_assertions)]
    {
        fx.add_entity_comment(local_msg_id, msg);
    }
    let msg_ptr = fx.bcx.ins().global_value(pointer_ty(fx.tcx), local_msg_id);
    fx.bcx.ins().call(puts, &[msg_ptr]);
}

/// Use this when `rustc_codegen_llvm` would insert a call to the panic handler.
///
/// Trap code: user0
pub fn trap_panic(
    fx: &mut FunctionCx<'_, '_, impl cranelift_module::Backend>,
    msg: impl AsRef<str>,
) {
    codegen_print(fx, msg.as_ref());
    fx.bcx.ins().trap(TrapCode::User(0));
}

/// Use this for example when a function call should never return. This will fill the current block,
/// so you can **not** add instructions to it afterwards.
///
/// Trap code: user65535
pub fn trap_unreachable(
    fx: &mut FunctionCx<'_, '_, impl cranelift_module::Backend>,
    msg: impl AsRef<str>,
) {
    codegen_print(fx, msg.as_ref());
    fx.bcx.ins().trap(TrapCode::User(!0));
}

/// Use this when something is unimplemented, but `libcore` or `libstd` requires it to codegen.
/// Unlike `trap_unreachable` this will not fill the current block, so you **must** add instructions
/// to it afterwards.
///
/// Trap code: user65535
pub fn trap_unimplemented(
    fx: &mut FunctionCx<'_, '_, impl cranelift_module::Backend>,
    msg: impl AsRef<str>,
) {
    codegen_print(fx, msg.as_ref());
    let true_ = fx.bcx.ins().iconst(types::I32, 1);
    fx.bcx.ins().trapnz(true_, TrapCode::User(!0));
}

/// Like `trap_unreachable` but returns a fake value of the specified type.
///
/// Trap code: user65535
pub fn trap_unreachable_ret_value<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl cranelift_module::Backend>,
    dest_layout: TyLayout<'tcx>,
    msg: impl AsRef<str>,
) -> CValue<'tcx> {
    trap_unimplemented(fx, msg);
    CValue::by_ref(Pointer::const_addr(fx, 0), dest_layout)
}
<commit_msg>Use TrapCode::UnreachableCodeReached in trap_unreachable<commit_after>use crate::prelude::*;

fn codegen_print(fx: &mut FunctionCx<'_, '_, impl cranelift_module::Backend>, msg: &str) {
    let puts = fx
        .module
        .declare_function(
            "puts",
            Linkage::Import,
            &Signature {
                call_conv: CallConv::triple_default(fx.triple()),
                params: vec![AbiParam::new(pointer_ty(fx.tcx))],
                returns: vec![],
            },
        )
        .unwrap();
    let puts = fx.module.declare_func_in_func(puts, &mut fx.bcx.func);
    #[cfg(debug_assertions)]
    {
        fx.add_entity_comment(puts, "puts");
    }

    let symbol_name = fx.tcx.symbol_name(fx.instance);
    let real_msg = format!("trap at {:?} ({}): {}\0", fx.instance, symbol_name, msg);
    let mut data_ctx = DataContext::new();
    data_ctx.define(real_msg.as_bytes().to_vec().into_boxed_slice());
    let msg_id = fx
        .module
        .declare_data(
            &(symbol_name.name.as_str().to_string() + msg),
            Linkage::Local,
            false,
            None,
        )
        .unwrap();

    // Ignore DuplicateDefinition error, as the data will be the same
    let _ = fx.module.define_data(msg_id, &data_ctx);

    let local_msg_id = fx.module.declare_data_in_func(msg_id, fx.bcx.func);
    #[cfg(debug_assertions)]
    {
        fx.add_entity_comment(local_msg_id, msg);
    }
    let msg_ptr = fx.bcx.ins().global_value(pointer_ty(fx.tcx), local_msg_id);
    fx.bcx.ins().call(puts, &[msg_ptr]);
}

/// Use this when `rustc_codegen_llvm` would insert a call to the panic handler.
///
/// Trap code: user0
pub fn trap_panic(
    fx: &mut FunctionCx<'_, '_, impl cranelift_module::Backend>,
    msg: impl AsRef<str>,
) {
    codegen_print(fx, msg.as_ref());
    fx.bcx.ins().trap(TrapCode::User(0));
}

/// Use this for example when a function call should never return. This will fill the current block,
/// so you can **not** add instructions to it afterwards.
///
/// Trap code: user65535
pub fn trap_unreachable(
    fx: &mut FunctionCx<'_, '_, impl cranelift_module::Backend>,
    msg: impl AsRef<str>,
) {
    codegen_print(fx, msg.as_ref());
    fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
}

/// Use this when something is unimplemented, but `libcore` or `libstd` requires it to codegen.
/// Unlike `trap_unreachable` this will not fill the current block, so you **must** add instructions
/// to it afterwards.
///
/// Trap code: user65535
pub fn trap_unimplemented(
    fx: &mut FunctionCx<'_, '_, impl cranelift_module::Backend>,
    msg: impl AsRef<str>,
) {
    codegen_print(fx, msg.as_ref());
    let true_ = fx.bcx.ins().iconst(types::I32, 1);
    fx.bcx.ins().trapnz(true_, TrapCode::User(!0));
}

/// Like `trap_unreachable` but returns a fake value of the specified type.
///
/// Trap code: user65535
pub fn trap_unreachable_ret_value<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl cranelift_module::Backend>,
    dest_layout: TyLayout<'tcx>,
    msg: impl AsRef<str>,
) -> CValue<'tcx> {
    trap_unimplemented(fx, msg);
    CValue::by_ref(Pointer::const_addr(fx, 0), dest_layout)
}
<|endoftext|>


<commit_before>use std::fs;
use std::io;
use std::iter;

// Specify indent size?

pub fn tree() -> Result<(), io::Error>{
    return print_dir_recursive(".", 0);
}

fn print_dir_recursive(path : &str, indent_level : usize)
        -> Result<(), io::Error>{
    let indent : String = iter::repeat("   |").take(indent_level).collect();

    let paths = try!(fs::read_dir(path));
    for entry in paths {
        let entry_name = try!(entry).path();
        let entry_name = entry_name.to_str().unwrap();
        println!("{}- {}", indent, entry_name);
        print_dir_recursive(entry_name, indent_level + 1);
    }
    return Ok(());
}
<commit_msg>Added comment about lifetime issue<commit_after>use std::fs;
use std::io;
use std::iter;

// Specify indent size?

pub fn tree() -> Result<(), io::Error>{
    return print_dir_recursive(".", 0);
}

fn print_dir_recursive(path : &str, indent_level : usize)
        -> Result<(), io::Error>{
    let indent : String = iter::repeat("   |").take(indent_level).collect();

    let paths = try!(fs::read_dir(path));
    for entry in paths {
        // For some reason, try!(entry).path().to_str().unwrap() complains about
        // some lifetime issue? I don't understand this yet.
        let entry_name = try!(entry).path();
        let entry_name = entry_name.to_str().unwrap();
        println!("{}- {}", indent, entry_name);
        print_dir_recursive(entry_name, indent_level + 1);
    }
    return Ok(());
}
<|endoftext|>


<commit_before>use urlparse::{Query, parse_qs, urlparse, urlunparse};

/// Re-encode a query string for Rust
fn encode_querystring(query: Query) -> Option<String> {
  let mut query_components: Vec<String> = vec![];
  for (key, value) in query {
    for v in value.iter() {
      query_components.push(format!("{}={}", key, v));
    }
  }
  if query_components.len() > 0 {
    Some(query_components.join("&"))
  } else {
    None
  }
}

/// Strip tracking junk and URL suffixes.
pub fn tidy_url(url: &str) -> String {
    let mut parsed_url = urlparse(url);

    // Always get the desktop version of Twitter URLs
    if parsed_url.netloc == "mobile.twitter.com" {
        parsed_url.netloc = String::from("twitter.com");
    }

    // Remove any tracking junk from Amazon URLs so they're not a
    // ridiculous length
    if parsed_url.netloc == "www.amazon.co.uk" {
        parsed_url.query = None;
        let mut new_path = String::from("");
        for component in parsed_url.path.split("ref=") {
            new_path = String::from(component);
            break;
        }
        parsed_url.path = new_path;
    }

    // Strip tracking junk from Medium, Mashable and Buzzfeed
    if (parsed_url.netloc == "medium.com") ||
       (parsed_url.netloc == "www.buzzfeed.com") ||
       (parsed_url.netloc == "mashable.com") {
            parsed_url.fragment = None;
    }

    // Remove '#notes' from Tumblr URLs
    if parsed_url.netloc.ends_with("tumblr.com") {
        let new_fragment: Option<String> = match parsed_url.fragment {
            Some(fragment) => {
                if fragment == "notes" {
                    None
                } else {
                    Some(fragment)
                }
            }
            None => None,
        };
        parsed_url.fragment = new_fragment;
    }

  // Remove &feature=youtu.be from YouTube URLs
  if parsed_url.netloc.ends_with("youtube.com") {
    parsed_url.query = match parsed_url.query {
      Some(qs) => {
        let mut query = parse_qs(&qs);
        query.remove("feature");
        encode_querystring(query)
      },
      None => None,
    };
  }

  // Remove any UTM tracking parameters from URLs
  parsed_url.query = match parsed_url.query {
    Some(qs) => {
      let mut query = parse_qs(&qs);
      let utm_keys: Vec<_> = query
        .keys()
        .filter(|key| key.starts_with("utm_"))
        .map(|k| k.clone())
        .collect();
      for key in utm_keys {
        query.remove(&key);
      }
      encode_querystring(query)
    },
    None => None
  };

  urlunparse(parsed_url)
}

macro_rules! tidy_url_tests {
    ($($name:ident: $value:expr,)*) => {
    $(
        #[test]
        fn $name() {
            let (input, expected) = $value;
            assert_eq!(expected, tidy_url(input));
        }
    )*
    }
}

tidy_url_tests! {
    url_tw_0:  ("https://mobile.twitter.com/Breaking911/status/822589852596191235",
                "https://twitter.com/Breaking911/status/822589852596191235"),
    url_tw_1:  ("https://twitter.com/elise3aum/status/822903824268533762",
                "https://twitter.com/elise3aum/status/822903824268533762"),

    url_az_0:  ("https://www.amazon.co.uk/dp/B01DFKBL68/ref=gw_aucc_comb_AB_clean_2?pf_rd_r=N1MF2PWADRHS55427ETG&pf_rd_p=c11a2c11-c670-46ff-87a1-c1eef4fad652",
                "https://www.amazon.co.uk/dp/B01DFKBL68/"),

    url_md_0:  ("https://medium.com/@anildash/forget-why-its-time-to-get-to-work-c49ac5f0da20#.sjyskxdsz",
                "https://medium.com/@anildash/forget-why-its-time-to-get-to-work-c49ac5f0da20"),

    url_tm_0:  ("http://azurelunatic.tumblr.com/post/155525051123/things-about-hufflepuffs-539#notes",
                "http://azurelunatic.tumblr.com/post/155525051123/things-about-hufflepuffs-539"),

    url_8:   ("https://www.buzzfeed.com/katienotopoulos/the-end-of-apple-man#.biqmkzz8kn",
              "https://www.buzzfeed.com/katienotopoulos/the-end-of-apple-man"),
    url_9:   ("http://mashable.com/2016/03/21/apple-liam-recycling-robot/#b9y4lv3m4qqX",
              "http://mashable.com/2016/03/21/apple-liam-recycling-robot/"),

  youtube_plain_video: (
    "https://www.youtube.com/watch?v=zB4I68XVPzQ",
    "https://www.youtube.com/watch?v=zB4I68XVPzQ",
  ),

  youtube_with_timestamp: (
    "https://www.youtube.com/watch?v=D68cUzqcTrg&feature=youtu.be#t=1m",
    "https://www.youtube.com/watch?v=D68cUzqcTrg#t=1m",
  ),

  youtube_with_trailing_feature: (
    "https://www.youtube.com/watch?v=PbJqNa0_Oz0&feature=youtu.be",
    "https://www.youtube.com/watch?v=PbJqNa0_Oz0",
  ),

  youtube_with_leading_feature: (
    "https://www.youtube.com/watch?feature=youtu.be&v=oPo4n9tBPsk",
    "https://www.youtube.com/watch?v=oPo4n9tBPsk",
  ),

  youtube_with_only_feature: (
    "https://www.youtube.com/watch?feature=youtu.be",
    "https://www.youtube.com/watch",
  ),

  youtube_channel: (
    "https://www.youtube.com/user/TheQIElves",
    "https://www.youtube.com/user/TheQIElves"
  ),

  single_utm_tracker: (
    "https://example.com?utm_medium=social",
    "https://example.com",
  ),

  multiple_utm_tracker: (
    "https://example.com?utm_medium=social&utm_source=twitter",
    "https://example.com",
  ),

  multiple_utm_tracker_with_others: (
    "https://example.com?utm_medium=social&foo=bar&utm_source=twitter&bar=baz",
    "https://example.com?foo=bar&bar=baz",
  ),
}
<commit_msg>Remove potentially flakey URL test<commit_after>use urlparse::{Query, parse_qs, urlparse, urlunparse};

/// Re-encode a query string for Rust
fn encode_querystring(query: Query) -> Option<String> {
  let mut query_components: Vec<String> = vec![];
  for (key, value) in query {
    for v in value.iter() {
      query_components.push(format!("{}={}", key, v));
    }
  }
  if query_components.len() > 0 {
    Some(query_components.join("&"))
  } else {
    None
  }
}

/// Strip tracking junk and URL suffixes.
pub fn tidy_url(url: &str) -> String {
    let mut parsed_url = urlparse(url);

    // Always get the desktop version of Twitter URLs
    if parsed_url.netloc == "mobile.twitter.com" {
        parsed_url.netloc = String::from("twitter.com");
    }

    // Remove any tracking junk from Amazon URLs so they're not a
    // ridiculous length
    if parsed_url.netloc == "www.amazon.co.uk" {
        parsed_url.query = None;
        let mut new_path = String::from("");
        for component in parsed_url.path.split("ref=") {
            new_path = String::from(component);
            break;
        }
        parsed_url.path = new_path;
    }

    // Strip tracking junk from Medium, Mashable and Buzzfeed
    if (parsed_url.netloc == "medium.com") ||
       (parsed_url.netloc == "www.buzzfeed.com") ||
       (parsed_url.netloc == "mashable.com") {
            parsed_url.fragment = None;
    }

    // Remove '#notes' from Tumblr URLs
    if parsed_url.netloc.ends_with("tumblr.com") {
        let new_fragment: Option<String> = match parsed_url.fragment {
            Some(fragment) => {
                if fragment == "notes" {
                    None
                } else {
                    Some(fragment)
                }
            }
            None => None,
        };
        parsed_url.fragment = new_fragment;
    }

  // Remove &feature=youtu.be from YouTube URLs
  if parsed_url.netloc.ends_with("youtube.com") {
    parsed_url.query = match parsed_url.query {
      Some(qs) => {
        let mut query = parse_qs(&qs);
        query.remove("feature");
        encode_querystring(query)
      },
      None => None,
    };
  }

  // Remove any UTM tracking parameters from URLs
  parsed_url.query = match parsed_url.query {
    Some(qs) => {
      let mut query = parse_qs(&qs);
      let utm_keys: Vec<_> = query
        .keys()
        .filter(|key| key.starts_with("utm_"))
        .map(|k| k.clone())
        .collect();
      for key in utm_keys {
        query.remove(&key);
      }
      encode_querystring(query)
    },
    None => None
  };

  urlunparse(parsed_url)
}

macro_rules! tidy_url_tests {
    ($($name:ident: $value:expr,)*) => {
    $(
        #[test]
        fn $name() {
            let (input, expected) = $value;
            assert_eq!(expected, tidy_url(input));
        }
    )*
    }
}

tidy_url_tests! {
    url_tw_0:  ("https://mobile.twitter.com/Breaking911/status/822589852596191235",
                "https://twitter.com/Breaking911/status/822589852596191235"),
    url_tw_1:  ("https://twitter.com/elise3aum/status/822903824268533762",
                "https://twitter.com/elise3aum/status/822903824268533762"),

    url_az_0:  ("https://www.amazon.co.uk/dp/B01DFKBL68/ref=gw_aucc_comb_AB_clean_2?pf_rd_r=N1MF2PWADRHS55427ETG&pf_rd_p=c11a2c11-c670-46ff-87a1-c1eef4fad652",
                "https://www.amazon.co.uk/dp/B01DFKBL68/"),

    url_md_0:  ("https://medium.com/@anildash/forget-why-its-time-to-get-to-work-c49ac5f0da20#.sjyskxdsz",
                "https://medium.com/@anildash/forget-why-its-time-to-get-to-work-c49ac5f0da20"),

    url_tm_0:  ("http://azurelunatic.tumblr.com/post/155525051123/things-about-hufflepuffs-539#notes",
                "http://azurelunatic.tumblr.com/post/155525051123/things-about-hufflepuffs-539"),

    url_8:   ("https://www.buzzfeed.com/katienotopoulos/the-end-of-apple-man#.biqmkzz8kn",
              "https://www.buzzfeed.com/katienotopoulos/the-end-of-apple-man"),
    url_9:   ("http://mashable.com/2016/03/21/apple-liam-recycling-robot/#b9y4lv3m4qqX",
              "http://mashable.com/2016/03/21/apple-liam-recycling-robot/"),

  youtube_plain_video: (
    "https://www.youtube.com/watch?v=zB4I68XVPzQ",
    "https://www.youtube.com/watch?v=zB4I68XVPzQ",
  ),

  youtube_with_timestamp: (
    "https://www.youtube.com/watch?v=D68cUzqcTrg&feature=youtu.be#t=1m",
    "https://www.youtube.com/watch?v=D68cUzqcTrg#t=1m",
  ),

  youtube_with_trailing_feature: (
    "https://www.youtube.com/watch?v=PbJqNa0_Oz0&feature=youtu.be",
    "https://www.youtube.com/watch?v=PbJqNa0_Oz0",
  ),

  youtube_with_leading_feature: (
    "https://www.youtube.com/watch?feature=youtu.be&v=oPo4n9tBPsk",
    "https://www.youtube.com/watch?v=oPo4n9tBPsk",
  ),

  youtube_with_only_feature: (
    "https://www.youtube.com/watch?feature=youtu.be",
    "https://www.youtube.com/watch",
  ),

  youtube_channel: (
    "https://www.youtube.com/user/TheQIElves",
    "https://www.youtube.com/user/TheQIElves"
  ),

  single_utm_tracker: (
    "https://example.com?utm_medium=social",
    "https://example.com",
  ),

  multiple_utm_tracker: (
    "https://example.com?utm_medium=social&utm_source=twitter",
    "https://example.com",
  ),

  multiple_utm_tracker_with_others: (
    "https://example.com?utm_medium=social&foo=bar&utm_source=twitter",
    "https://example.com?foo=bar",
  ),
}
<|endoftext|>


<commit_before>use std::sync::{RwLock, LockResult, RwLockWriteGuard, RwLockReadGuard, PoisonError};
use std::ops::{Deref, DerefMut};

pub struct LoggingRwLock<T: ?Sized> {
    lock: RwLock<T>,
}

impl <T> LoggingRwLock<T> {
    pub fn new(t: T) -> LoggingRwLock<T> {
        LoggingRwLock {
            lock: RwLock::new(t),
        }
    }
}

impl<T: ?Sized> LoggingRwLock<T> {
    pub fn write(&self, site: u32) -> LockResult<LoggingRwLockWriteGuard<T>> {
       debug!("write() called at line {}", site);
       match self.lock.write() {
           Ok(locked) => {
               Ok(LoggingRwLockWriteGuard{guard: locked})
           },
           Err(locked) => {
               Err(PoisonError::new(LoggingRwLockWriteGuard{guard: locked.into_inner()}))
           },
       }
    }

    pub fn read(&self) -> LockResult<LoggingRwLockReadGuard<T>> {
        debug!("read() called");
        match self.lock.read() {
            Ok(locked) => {
                Ok(LoggingRwLockReadGuard{guard: locked})
            },
            Err(locked) => {
                Err(PoisonError::new(LoggingRwLockReadGuard{guard: locked.into_inner()}))
            },
        }
    }
}

pub struct LoggingRwLockReadGuard<'a, T: ?Sized + 'a> {
    guard: RwLockReadGuard<'a, T>,
}

impl <'rwlock, T: ?Sized> Deref for LoggingRwLockReadGuard<'rwlock, T> {
    type Target = T;
    fn deref(&self) -> &T {
        self.guard.deref()
    }
}
impl <'a, T: ?Sized> Drop for LoggingRwLockReadGuard<'a, T> {
    fn drop(&mut self) {
        debug!("dropping lock");
    }
}

pub struct LoggingRwLockWriteGuard<'a, T: ?Sized + 'a> {
    guard: RwLockWriteGuard<'a, T>,
}

impl <'rwlock, T: ?Sized> Deref for LoggingRwLockWriteGuard<'rwlock, T> {
    type Target = T;
    fn deref(&self) -> &T {
        self.guard.deref()
    }
}
impl <'rwlock, T: ?Sized> DerefMut for LoggingRwLockWriteGuard<'rwlock, T> {
    fn deref_mut(&mut self) -> &mut T {
        self.guard.deref_mut()
    }
}
impl <'a, T: ?Sized> Drop for LoggingRwLockWriteGuard<'a, T> {
    fn drop(&mut self) {
        debug!("dropping write lock");
    }
}
<commit_msg>More goodness for locking wrapper<commit_after>use std::sync::{RwLock, LockResult, RwLockWriteGuard, RwLockReadGuard, PoisonError};
use std::ops::{Deref, DerefMut};
use uuid::Uuid;

pub struct LoggingRwLock<T: ?Sized> {
    uuid: Uuid,
    lock: RwLock<T>,
}

impl <T> LoggingRwLock<T> {
    pub fn new(t: T) -> LoggingRwLock<T> {
        LoggingRwLock {
            lock: RwLock::new(t),
            uuid: Uuid::new_v4(),
        }
    }
}

impl<T: ?Sized> LoggingRwLock<T> {
    pub fn write(&self, site: u32) -> LockResult<LoggingRwLockWriteGuard<T>> {
        let write_uuid = Uuid::new_v4();
        debug!("{} write() called at line {} {}", self.uuid, site, write_uuid);
        match self.lock.write() {
            Ok(locked) => {
                Ok(LoggingRwLockWriteGuard{guard: locked, uuid: write_uuid.clone()})
            },
            Err(locked) => {
                Err(PoisonError::new(LoggingRwLockWriteGuard{guard: locked.into_inner(), uuid: write_uuid.clone()}))
            },
        }
    }

    pub fn read(&self, site: u32) -> LockResult<LoggingRwLockReadGuard<T>> {
        let read_uuid = Uuid::new_v4();
        debug!("{} read() called at line {} {}", self.uuid, site, read_uuid);
        match self.lock.read() {
            Ok(locked) => {
                Ok(LoggingRwLockReadGuard{guard: locked, uuid: read_uuid.clone()})
            },
            Err(locked) => {
                Err(PoisonError::new(LoggingRwLockReadGuard{guard: locked.into_inner(), uuid: read_uuid.clone()}))
            },
        }
    }
}

pub struct LoggingRwLockReadGuard<'a, T: ?Sized + 'a> {
    guard: RwLockReadGuard<'a, T>,
    uuid: Uuid,
}

impl <'rwlock, T: ?Sized> Deref for LoggingRwLockReadGuard<'rwlock, T> {
    type Target = T;
    fn deref(&self) -> &T {
        self.guard.deref()
    }
}
impl <'a, T: ?Sized> Drop for LoggingRwLockReadGuard<'a, T> {
    fn drop(&mut self) {
        debug!("{} dropping lock", self.uuid);
    }
}

pub struct LoggingRwLockWriteGuard<'a, T: ?Sized + 'a> {
    guard: RwLockWriteGuard<'a, T>,
    uuid: Uuid,
}

impl <'rwlock, T: ?Sized> Deref for LoggingRwLockWriteGuard<'rwlock, T> {
    type Target = T;
    fn deref(&self) -> &T {
        self.guard.deref()
    }
}
impl <'rwlock, T: ?Sized> DerefMut for LoggingRwLockWriteGuard<'rwlock, T> {
    fn deref_mut(&mut self) -> &mut T {
        self.guard.deref_mut()
    }
}
impl <'a, T: ?Sized> Drop for LoggingRwLockWriteGuard<'a, T> {
    fn drop(&mut self) {
        debug!("{} dropping write lock", self.uuid);
    }
}
<|endoftext|>


<commit_before>use autoscaling::*;
use visibility::*;
use consumer::*;
use delete::*;
use processor::*;

use rusoto_core::{default_tls_client, Region};

use std::fs::OpenOptions;
use slog;
use slog::Logger;
use slog_json;

use slog::{Drain, FnValue};
use futures_cpupool::CpuPool;
use tokio_timer::*;
use futures::*;
use futures::future::ok;
use std::time::Duration;

use rusoto_sns::{Sns};

use rusoto_sqs::{Sqs, SqsClient, CreateQueueRequest};
use rusoto_credential::{ProvideAwsCredentials, ChainProvider, ProfileProvider};
use rusoto_sns::SnsClient;

use std::sync::{Arc, Mutex};
use std::env;
use hyper;

static mut TIMER: Option<Timer> = None;

const NANOS_PER_MILLI: u32 = 1000_000;
const MILLIS_PER_SEC: u64 = 1000;

pub fn set_timer() {
    unsafe {
        TIMER = Some(Timer::default());
    }
}

pub fn get_timer() -> Timer {
    unsafe {
        TIMER.clone().unwrap().clone()
    }
}

pub fn millis(d: Duration) -> u64 {
    // A proper Duration will not overflow, because MIN and MAX are defined
    // such that the range is exactly i64 milliseconds.
    let secs_part = d.as_secs() * MILLIS_PER_SEC;
    let nanos_part = d.subsec_nanos() / NANOS_PER_MILLI;
    secs_part + nanos_part as u64
}

#[cfg_attr(feature = "flame_it", flame)]
pub fn new_sqs_client<P>(sqs_provider: &P) -> SqsClient<P, hyper::Client>
    where P: ProvideAwsCredentials + Clone + Send + 'static
{
    SqsClient::new(
        default_tls_client().unwrap(),
        sqs_provider.clone(),
        Region::UsEast1
    )
}

#[cfg_attr(feature = "flame_it", flame)]
pub fn new_sns_client<P>(sns_provider: &P) -> SnsClient<P, hyper::Client>
    where P: ProvideAwsCredentials + Clone + Send + 'static
{
    SnsClient::new(
        default_tls_client().unwrap(),
        sns_provider.clone(),
        Region::UsEast1
    )
}

#[cfg_attr(feature = "flame_it", flame)]
pub fn create_queue<P>(pool: &CpuPool, provider: &P, queue_name: &str, timer: &'static Timer) -> String
    where P: ProvideAwsCredentials + Clone + Send + 'static,
{
    let create_queue_request = CreateQueueRequest {
        attributes: None,
        queue_name: queue_name.to_owned()
    };

    let _provider = provider.clone();
    let _queue_name = queue_name.to_owned();

    let queue_url = timeout_ms! {
        pool.clone(),
        move || {
            ok(SqsClient::new(
                default_tls_client().unwrap(),
                _provider,
                Region::UsEast1
            ).create_queue(&create_queue_request)
                .unwrap_or_else(|e| panic!("Failed to create queue {} with {}", _queue_name, e)))
        },
        5_500,
        timer
    };

    match queue_url {
        Ok(url) => url.queue_url.expect("Queue url was None"),
        _ => panic!("Timeout while trying to create queue: {}", queue_name)
    }
}

#[cfg_attr(feature = "flame_it", flame)]
pub fn get_profile_provider() -> ChainProvider {
    let profile = match env::var("AWS_PROFILE") {
        Ok(val) => val.to_string(),
        Err(_) => "default".to_string(),
    };

    let mut profile_provider = ProfileProvider::new().unwrap();
    profile_provider.set_profile(profile);
    ChainProvider::with_profile_provider(profile_provider)
}

use lru_time_cache::LruCache;

#[derive(Debug)]
pub enum Topic {
    Cached(String),
    Created(String)
}

impl Topic {
    pub fn get(self) -> String {
        match self {
            Topic::Cached(t) | Topic::Created(t) => t,
        }
    }
}

use lru_time_cache::Entry;
use rusoto_sns::CreateTopicInput;

pub struct TopicCreator<SN>
    where SN: Sns + Send + Sync + 'static,
{
    sns_client: Arc<SN>,
    topic_cache: LruCache<String, String>,
}

impl<SN> TopicCreator<SN>
    where SN: Sns + Send + Sync + 'static,
{
    pub fn new(sns_client: Arc<SN>) -> TopicCreator<SN> {
        TopicCreator {
            sns_client,
            topic_cache: LruCache::with_expiry_duration_and_capacity(Duration::from_secs(60 * 60), 500),
        }
    }

    pub fn get_or_create(&mut self, topic_name: &str) -> Result<Topic, String> {
        let entry = self.topic_cache.entry(topic_name.to_owned());

        match entry {
            Entry::Occupied(oc) => {
                Ok(Topic::Cached(oc.into_mut().to_owned()))
            }
            Entry::Vacant(vac) => {
                let create_topic_input = CreateTopicInput {
                    name: topic_name.to_owned()
                };
                let arn_res = self.sns_client.create_topic(&create_topic_input);

                match arn_res {
                    Ok(arn) => {
                        match arn.topic_arn {
                            Some(arn) => {
                                //                                info!("Created topic: {}", arn);
                                vac.insert(arn.clone());
                                Ok(Topic::Created(arn))
                            }
                            None => Err("returned arn was None".to_owned())
                        }
                    }
                    Err(e) => {
                        Err(format!("{}", e))
                    }
                }
            }
        }
    }
}

use processor::{MessageHandlerActor, MessageHandler};

pub fn easy_init<F, P>(new: F, logger: Logger)
    -> impl Consumer
    where P: MessageHandler + Send + 'static,
          F: Fn(MessageHandlerActor) -> P,
{

    set_timer();

    let provider = get_profile_provider();

    let queue_url = "some queue url".to_owned();

    let sqs_client = Arc::new(new_sqs_client(&provider));

    let throttler = MedianThrottler::new(logger.clone());
    let throttler = ThrottlerActor::new(throttler);

    let deleter = MessageDeleterBroker::new(
        |_| {
            MessageDeleter::new(sqs_client.clone(), queue_url.clone(), logger.clone())
        },
        5,
        None
    );

    let deleter = MessageDeleteBuffer::new(deleter, Duration::from_millis(50));
    let deleter = MessageDeleteBufferActor::new(deleter);

    let delete_flusher = DeleteBufferFlusher::new(deleter.clone(), Duration::from_secs(1));
    DeleteBufferFlusherActor::new(delete_flusher.clone());

    let broker = VisibilityTimeoutExtenderBroker::new(
        |_| {
            VisibilityTimeoutExtender::new(sqs_client.clone(),
                                           queue_url.clone(),
                                           deleter.clone(),
                                           throttler.clone(),
                                           logger.clone())
        },
        5,
        None
    );

    let sc = Some(get_short_circuit());
    let buffer = VisibilityTimeoutExtenderBuffer::new(broker, 2, sc.clone());
    let buffer = VisibilityTimeoutExtenderBufferActor::new(buffer);

    let flusher = BufferFlushTimer::new(buffer.clone(), Duration::from_millis(200));
    let _flusher = BufferFlushTimerActor::new(flusher);

    let consumer_throttler = ConsumerThrottler::new(logger.clone());
    let consumer_throttler = ConsumerThrottlerActor::new(consumer_throttler);

    let state_manager = SqsMessageStateManager::new(buffer,
                                                    deleter.clone(),
                                                    logger.clone());

    let state_manager = MessageStateManagerActor::new(state_manager);

    let processor = MessageHandlerBroker::new(
        new,
        1,
        1000,
        state_manager.clone(),
        sc.clone(),
        logger.clone()
    );

    let mut sqs_broker = ConsumerBroker::new(
        |actor| {
            DelayMessageConsumer::new(sqs_client.clone(),
                                      queue_url.clone(),
                                      actor,
                                      state_manager.clone(),
                                      processor.clone(),
                                      throttler.clone(),
                                      logger.clone())
        },
        1,
        None,
        logger.clone()
    );

    consumer_throttler.register_consumer(sqs_broker.clone());

    throttler.register_consumer_throttler(consumer_throttler);

    sqs_broker.consume();

    sqs_broker
}

pub fn init_logger(log_path: &str) -> Logger {
    let file = OpenOptions::new()
        .create(true)
        .write(true)
        .truncate(true)
        .open(log_path)
        .expect(&format!("Failed to create log file {}", log_path));

    slog::Logger::root(
        Mutex::new(slog_json::Json::default(file)).map(slog::Fuse),
        o!("version" => env!("CARGO_PKG_VERSION"),
           "place" =>
              FnValue(move |info| {
                  format!("{}:{} {}",
                          info.file(),
                          info.line(),
                          info.module())
              }))
    )
}<commit_msg>Take number of message consumers as argument to helper.<commit_after>use autoscaling::*;
use visibility::*;
use consumer::*;
use delete::*;
use processor::*;

use rusoto_core::{default_tls_client, Region};

use std::fs::OpenOptions;
use slog;
use slog::Logger;
use slog_json;

use slog::{Drain, FnValue};
use futures_cpupool::CpuPool;
use tokio_timer::*;
use futures::*;
use futures::future::ok;
use std::time::Duration;

use rusoto_sns::{Sns};

use rusoto_sqs::{Sqs, SqsClient, CreateQueueRequest};
use rusoto_credential::{ProvideAwsCredentials, ChainProvider, ProfileProvider};
use rusoto_sns::SnsClient;

use std::sync::{Arc, Mutex};
use std::env;
use hyper;

static mut TIMER: Option<Timer> = None;

const NANOS_PER_MILLI: u32 = 1000_000;
const MILLIS_PER_SEC: u64 = 1000;

pub fn set_timer() {
    unsafe {
        TIMER = Some(Timer::default());
    }
}

pub fn get_timer() -> Timer {
    unsafe {
        TIMER.clone().unwrap().clone()
    }
}

pub fn millis(d: Duration) -> u64 {
    // A proper Duration will not overflow, because MIN and MAX are defined
    // such that the range is exactly i64 milliseconds.
    let secs_part = d.as_secs() * MILLIS_PER_SEC;
    let nanos_part = d.subsec_nanos() / NANOS_PER_MILLI;
    secs_part + nanos_part as u64
}

#[cfg_attr(feature = "flame_it", flame)]
pub fn new_sqs_client<P>(sqs_provider: &P) -> SqsClient<P, hyper::Client>
    where P: ProvideAwsCredentials + Clone + Send + 'static
{
    SqsClient::new(
        default_tls_client().unwrap(),
        sqs_provider.clone(),
        Region::UsEast1
    )
}

#[cfg_attr(feature = "flame_it", flame)]
pub fn new_sns_client<P>(sns_provider: &P) -> SnsClient<P, hyper::Client>
    where P: ProvideAwsCredentials + Clone + Send + 'static
{
    SnsClient::new(
        default_tls_client().unwrap(),
        sns_provider.clone(),
        Region::UsEast1
    )
}

#[cfg_attr(feature = "flame_it", flame)]
pub fn create_queue<P>(pool: &CpuPool, provider: &P, queue_name: &str, timer: &'static Timer) -> String
    where P: ProvideAwsCredentials + Clone + Send + 'static,
{
    let create_queue_request = CreateQueueRequest {
        attributes: None,
        queue_name: queue_name.to_owned()
    };

    let _provider = provider.clone();
    let _queue_name = queue_name.to_owned();

    let queue_url = timeout_ms! {
        pool.clone(),
        move || {
            ok(SqsClient::new(
                default_tls_client().unwrap(),
                _provider,
                Region::UsEast1
            ).create_queue(&create_queue_request)
                .unwrap_or_else(|e| panic!("Failed to create queue {} with {}", _queue_name, e)))
        },
        5_500,
        timer
    };

    match queue_url {
        Ok(url) => url.queue_url.expect("Queue url was None"),
        _ => panic!("Timeout while trying to create queue: {}", queue_name)
    }
}

#[cfg_attr(feature = "flame_it", flame)]
pub fn get_profile_provider() -> ChainProvider {
    let profile = match env::var("AWS_PROFILE") {
        Ok(val) => val.to_string(),
        Err(_) => "default".to_string(),
    };

    let mut profile_provider = ProfileProvider::new().unwrap();
    profile_provider.set_profile(profile);
    ChainProvider::with_profile_provider(profile_provider)
}

use lru_time_cache::LruCache;

#[derive(Debug)]
pub enum Topic {
    Cached(String),
    Created(String)
}

impl Topic {
    pub fn get(self) -> String {
        match self {
            Topic::Cached(t) | Topic::Created(t) => t,
        }
    }
}

use lru_time_cache::Entry;
use rusoto_sns::CreateTopicInput;

pub struct TopicCreator<SN>
    where SN: Sns + Send + Sync + 'static,
{
    sns_client: Arc<SN>,
    topic_cache: LruCache<String, String>,
}

impl<SN> TopicCreator<SN>
    where SN: Sns + Send + Sync + 'static,
{
    pub fn new(sns_client: Arc<SN>) -> TopicCreator<SN> {
        TopicCreator {
            sns_client,
            topic_cache: LruCache::with_expiry_duration_and_capacity(Duration::from_secs(60 * 60), 500),
        }
    }

    pub fn get_or_create(&mut self, topic_name: &str) -> Result<Topic, String> {
        let entry = self.topic_cache.entry(topic_name.to_owned());

        match entry {
            Entry::Occupied(oc) => {
                Ok(Topic::Cached(oc.into_mut().to_owned()))
            }
            Entry::Vacant(vac) => {
                let create_topic_input = CreateTopicInput {
                    name: topic_name.to_owned()
                };
                let arn_res = self.sns_client.create_topic(&create_topic_input);

                match arn_res {
                    Ok(arn) => {
                        match arn.topic_arn {
                            Some(arn) => {
                                //                                info!("Created topic: {}", arn);
                                vac.insert(arn.clone());
                                Ok(Topic::Created(arn))
                            }
                            None => Err("returned arn was None".to_owned())
                        }
                    }
                    Err(e) => {
                        Err(format!("{}", e))
                    }
                }
            }
        }
    }
}

use processor::{MessageHandlerActor, MessageHandler};

pub fn easy_init<F, P>(new: F, processor_count: usize, logger: Logger)
    -> impl Consumer
    where P: MessageHandler + Send + 'static,
          F: Fn(MessageHandlerActor) -> P,
{

    set_timer();

    let provider = get_profile_provider();

    let queue_url = "some queue url".to_owned();

    let sqs_client = Arc::new(new_sqs_client(&provider));

    let throttler = MedianThrottler::new(logger.clone());
    let throttler = ThrottlerActor::new(throttler);

    let deleter = MessageDeleterBroker::new(
        |_| {
            MessageDeleter::new(sqs_client.clone(), queue_url.clone(), logger.clone())
        },
        5,
        None
    );

    let deleter = MessageDeleteBuffer::new(deleter, Duration::from_millis(50));
    let deleter = MessageDeleteBufferActor::new(deleter);

    let delete_flusher = DeleteBufferFlusher::new(deleter.clone(), Duration::from_secs(1));
    DeleteBufferFlusherActor::new(delete_flusher.clone());

    let broker = VisibilityTimeoutExtenderBroker::new(
        |_| {
            VisibilityTimeoutExtender::new(sqs_client.clone(),
                                           queue_url.clone(),
                                           deleter.clone(),
                                           throttler.clone(),
                                           logger.clone())
        },
        5,
        None
    );

    let sc = Some(get_short_circuit());
    let buffer = VisibilityTimeoutExtenderBuffer::new(broker, 2, sc.clone());
    let buffer = VisibilityTimeoutExtenderBufferActor::new(buffer);

    let flusher = BufferFlushTimer::new(buffer.clone(), Duration::from_millis(200));
    let _flusher = BufferFlushTimerActor::new(flusher);

    let consumer_throttler = ConsumerThrottler::new(logger.clone());
    let consumer_throttler = ConsumerThrottlerActor::new(consumer_throttler);

    let state_manager = SqsMessageStateManager::new(buffer,
                                                    deleter.clone(),
                                                    logger.clone());

    let state_manager = MessageStateManagerActor::new(state_manager);

    let processor = MessageHandlerBroker::new(
        new,
        processor_count,
        1000,
        state_manager.clone(),
        sc.clone(),
        logger.clone()
    );

    let mut sqs_broker = ConsumerBroker::new(
        |actor| {
            DelayMessageConsumer::new(sqs_client.clone(),
                                      queue_url.clone(),
                                      actor,
                                      state_manager.clone(),
                                      processor.clone(),
                                      throttler.clone(),
                                      logger.clone())
        },
        1,
        None,
        logger.clone()
    );

    consumer_throttler.register_consumer(sqs_broker.clone());

    throttler.register_consumer_throttler(consumer_throttler);

    sqs_broker.consume();

    sqs_broker
}

pub fn init_logger(log_path: &str) -> Logger {
    let file = OpenOptions::new()
        .create(true)
        .write(true)
        .truncate(true)
        .open(log_path)
        .expect(&format!("Failed to create log file {}", log_path));

    slog::Logger::root(
        Mutex::new(slog_json::Json::default(file)).map(slog::Fuse),
        o!("version" => env!("CARGO_PKG_VERSION"),
           "place" =>
              FnValue(move |info| {
                  format!("{}:{} {}",
                          info.file(),
                          info.line(),
                          info.module())
              }))
    )
}<|endoftext|>


<commit_before>use std::ops::{Index, IndexMut};
use std::default::Default;
use Vector;

#[derive(Clone)]
pub struct Grid<T> {
    data: Vec<T>,
    width: usize,
}

impl<T> Grid<T> {
    pub fn get_width(&self) -> usize {
        self.width
    }

    pub fn get_height(&self) -> usize {
        self.data.len() / self.width
    }
}

impl<T: Default+Clone> Grid<T> {
    pub fn new(width:usize, height:usize) -> Grid<T> {
        Grid{
            data: vec![Default::default(); width * height],
            width: width,
        }
    }
}

impl<T: Clone> Grid<T> {
    pub fn new_filled_with(thing: T, width: usize, height: usize) -> Grid<T> {
        Grid{
            data: vec![thing; width * height],
            width: width,
        }
    }
}

impl<T> Index<(usize, usize)> for Grid<T> {
    type Output= T;

    fn index(&self, (x, y): (usize, usize)) -> &T{
        &self.data[x+y*self.width]
    }
}

impl<T> IndexMut<(usize, usize)> for Grid<T> {
    fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut T {
        &mut self.data[x+y*self.width]
    }
}

pub enum Direction {
    Up,
    Down,
    Left,
    Right,
    Ur,
    Dr,
    Dl,
    Ul,
}

static ORTHOGONAL: [Direction; 4] = [Direction::Up, Direction::Down, Direction::Left, Direction::Right];
static ALL: [Direction; 8] = [Direction::Up, Direction::Down, Direction::Left, Direction::Right, Direction::Dl, Direction::Dr, Direction::Ul, Direction::Ur];

impl Direction {
    pub fn get_vec(&self) -> Vector<isize> {
        use self::Direction::*;
        let vec = match *self {
            Up => Vector::new(0,1),
            Down => Vector::new(0,-1),
            Left => Vector::new(-1,0),
            Right => Vector::new(1,0),
            Ur => Vector::new(1,1),
            Dr => Vector::new(1,-1),
            Dl => Vector::new(-1,-1),
            Ul => Vector::new(-1,1),
        };
        vec
    }

    pub fn get_tuple(&self) -> (isize, isize) {
        use self::Direction::*;
        match *self {
            Up => (0,1),
            Down => (0,-1),
            Left => (-1,0),
            Right => (1,0),
            Ur => (1,1),
            Dr => (1,-1),
            Dl => (-1,-1),
            Ul => (-1,1),
        }
    }

    pub fn get_orthogonal_dirs() -> &'static[Direction] {
        &ORTHOGONAL
    }
    pub fn get_dirs() -> &'static[Direction] {
        &ALL
    }
}

pub enum Error {
    IndexOutOfBounds,
}
<commit_msg>Implement get_vec using get_tuple<commit_after>use std::ops::{Index, IndexMut};
use std::default::Default;
use Vector;

#[derive(Clone)]
pub struct Grid<T> {
    data: Vec<T>,
    width: usize,
}

impl<T> Grid<T> {
    pub fn get_width(&self) -> usize {
        self.width
    }

    pub fn get_height(&self) -> usize {
        self.data.len() / self.width
    }
}

impl<T: Default+Clone> Grid<T> {
    pub fn new(width:usize, height:usize) -> Grid<T> {
        Grid{
            data: vec![Default::default(); width * height],
            width: width,
        }
    }
}

impl<T: Clone> Grid<T> {
    pub fn new_filled_with(thing: T, width: usize, height: usize) -> Grid<T> {
        Grid{
            data: vec![thing; width * height],
            width: width,
        }
    }
}

impl<T> Index<(usize, usize)> for Grid<T> {
    type Output= T;

    fn index(&self, (x, y): (usize, usize)) -> &T{
        &self.data[x+y*self.width]
    }
}

impl<T> IndexMut<(usize, usize)> for Grid<T> {
    fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut T {
        &mut self.data[x+y*self.width]
    }
}

pub enum Direction {
    Up,
    Down,
    Left,
    Right,
    Ur,
    Dr,
    Dl,
    Ul,
}

static ORTHOGONAL: [Direction; 4] = [Direction::Up, Direction::Down, Direction::Left, Direction::Right];
static ALL: [Direction; 8] = [Direction::Up, Direction::Down, Direction::Left, Direction::Right, Direction::Dl, Direction::Dr, Direction::Ul, Direction::Ur];

impl Direction {
    pub fn get_vec(&self) -> Vector<isize> {
        let (x, y) = self.get_tuple();
        Vector::new(x, y)
    }

    pub fn get_tuple(&self) -> (isize, isize) {
        use self::Direction::*;
        match *self {
            Up => (0,1),
            Down => (0,-1),
            Left => (-1,0),
            Right => (1,0),
            Ur => (1,1),
            Dr => (1,-1),
            Dl => (-1,-1),
            Ul => (-1,1),
        }
    }

    pub fn get_orthogonal_dirs() -> &'static[Direction] {
        &ORTHOGONAL
    }
    pub fn get_dirs() -> &'static[Direction] {
        &ALL
    }
}

pub enum Error {
    IndexOutOfBounds,
}
<|endoftext|>


<commit_before>use std::io::{self, Write};
use adler32::adler32;
use byteorder::{LittleEndian, WriteBytesExt};

use deflate::{deflate, BlockType};
use Options;

pub fn zlib_compress<W>(options: &Options, in_data: &[u8], mut out: W) -> io::Result<()>
    where W: Write
{
    let cmf = 120;  /* CM 8, CINFO 7. See zlib spec.*/
    let flevel = 3;
    let fdict = 0;
    let mut cmfflg = 256 * cmf + fdict * 32 + flevel * 64;
    let fcheck = 31 - cmfflg % 31;
    cmfflg += fcheck;

    try!(out.by_ref().write_u16::<LittleEndian>(cmfflg));

    try!(deflate(options, BlockType::Dynamic, in_data, out.by_ref()));

    let checksum = adler32(io::Cursor::new(&in_data)).expect("Error with adler32");
    out.write_u32::<LittleEndian>(checksum)
}
<commit_msg>Fix Big/Little endianness :(<commit_after>use std::io::{self, Write};
use adler32::adler32;
use byteorder::{BigEndian, WriteBytesExt};

use deflate::{deflate, BlockType};
use Options;

pub fn zlib_compress<W>(options: &Options, in_data: &[u8], mut out: W) -> io::Result<()>
    where W: Write
{
    let cmf = 120;  /* CM 8, CINFO 7. See zlib spec.*/
    let flevel = 3;
    let fdict = 0;
    let mut cmfflg = 256 * cmf + fdict * 32 + flevel * 64;
    let fcheck = 31 - cmfflg % 31;
    cmfflg += fcheck;

    try!(out.by_ref().write_u16::<BigEndian>(cmfflg));

    try!(deflate(options, BlockType::Dynamic, in_data, out.by_ref()));

    let checksum = adler32(io::Cursor::new(&in_data)).expect("Error with adler32");
    out.write_u32::<BigEndian>(checksum)
}
<|endoftext|>


<commit_before>extern crate bytes;
extern crate regex;
extern crate futures;
extern crate httpbis;
extern crate tokio_core;
#[macro_use]
extern crate log;
extern crate env_logger;

mod test_misc;

use futures::future;
use futures::future::Future;
use futures::stream::Stream;

use httpbis::Client;
use test_misc::*;

#[test]
fn smoke() {
    env_logger::init().ok();

    let server = ServerTest::new();

    let client: Client =
        Client::new_plain("::1", server.port, Default::default()).expect("client");

    let mut futures = Vec::new();
    for _ in 0..10 {
        futures.push(client.start_get("/blocks/200000/5", "localhost").collect());
    }

    let r = future::join_all(futures).wait().expect("wait");
    for rr in r {
        assert_eq!(200000 * 5, rr.body.len());
    }
}

#[test]
fn parallel_large() {
    env_logger::init().ok();

    let server = ServerTest::new();

    let client: Client =
        Client::new_plain("::1", server.port, Default::default()).expect("client");

    let mut futures = Vec::new();
    for _ in 0..50 {
        futures.push(client.start_get("/blocks/100000/5", "localhost").collect());
    }

    let r = future::join_all(futures).wait().expect("wait");
    for rr in r {
        assert_eq!(100000 * 5, rr.body.len());
    }
}

#[test]
fn seq_long() {
    env_logger::init().ok();

    let server = ServerTest::new();

    let client: Client =
        Client::new_plain("::1", server.port, Default::default()).expect("client");

    let (headers, parts) = client.start_get("/blocks/100000/100", "localhost").0
        .wait().expect("get");

    assert_eq!(200, headers.status());

    let mut sum_len = 0;
    for b in parts.filter_data().wait() {
        sum_len += b.unwrap().len();
    }

    assert_eq!(100000 * 100, sum_len);
}
<commit_msg>Another smoke test that proves nothing<commit_after>extern crate bytes;
extern crate regex;
extern crate futures;
extern crate httpbis;
extern crate tokio_core;
#[macro_use]
extern crate log;
extern crate env_logger;

use std::sync::Arc;
use std::sync::Mutex;

mod test_misc;

use bytes::Bytes;

use futures::future;
use futures::future::Future;
use futures::stream::Stream;
use futures::sync::mpsc;

use httpbis::Client;
use httpbis::ServerBuilder;
use httpbis::Service;
use httpbis::Response;
use httpbis::Headers;
use httpbis::HttpPartStream;
use test_misc::*;

#[test]
fn smoke() {
    env_logger::init().ok();

    let server = ServerTest::new();

    let client: Client =
        Client::new_plain("::1", server.port, Default::default()).expect("client");

    let mut futures = Vec::new();
    for _ in 0..10 {
        futures.push(client.start_get("/blocks/200000/5", "localhost").collect());
    }

    let r = future::join_all(futures).wait().expect("wait");
    for rr in r {
        assert_eq!(200000 * 5, rr.body.len());
    }
}

#[test]
fn parallel_large() {
    env_logger::init().ok();

    let server = ServerTest::new();

    let client: Client =
        Client::new_plain("::1", server.port, Default::default()).expect("client");

    let mut futures = Vec::new();
    for _ in 0..50 {
        futures.push(client.start_get("/blocks/100000/5", "localhost").collect());
    }

    let r = future::join_all(futures).wait().expect("wait");
    for rr in r {
        assert_eq!(100000 * 5, rr.body.len());
    }
}

#[test]
fn seq_long() {
    env_logger::init().ok();

    let server = ServerTest::new();

    let client: Client =
        Client::new_plain("::1", server.port, Default::default()).expect("client");

    let (headers, parts) = client.start_get("/blocks/100000/100", "localhost").0
        .wait().expect("get");

    assert_eq!(200, headers.status());

    let mut sum_len = 0;
    for b in parts.filter_data().wait() {
        sum_len += b.unwrap().len();
    }

    assert_eq!(100000 * 100, sum_len);
}

#[test]
fn seq_slow() {
    env_logger::init().ok();

    let (tx, rx) = mpsc::unbounded();

    struct Handler {
        rx: Mutex<Option<mpsc::UnboundedReceiver<Bytes>>>,
    }

    impl Service for Handler {
        fn start_request(&self, _headers: Headers, _req: HttpPartStream) -> Response {
            let rx = self.rx.lock().unwrap().take().expect("can be called only once");
            Response::headers_and_bytes_stream(
                Headers::ok_200(),
                rx.map_err(|_| unreachable!()))
        }
    }

    let mut server = ServerBuilder::new_plain();
    server.set_port(0);
    server.service.set_service("/", Arc::new(Handler { rx: Mutex::new(Some(rx)) }));
    let server = server.build().expect("server");

    let client: Client =
        Client::new_plain("::1", server.local_addr().port(), Default::default()).expect("client");

    let (headers, resp) = client.start_get("/gfgfg", "localhost").0.wait().expect("get");

    assert_eq!(200, headers.status());

    let mut resp = resp.filter_data().wait();

    for i in 1..100 {
        let b = vec![(i % 0x100) as u8; i * 1011];
        tx.send(Bytes::from(&b[..])).expect("send");

        let mut c = Vec::new();
        while c.len() != b.len() {
            c.extend(resp.next().unwrap().unwrap());
        }

        assert_eq!(b, c);
    }

    drop(tx);

    if false {
        // TODO
        assert_eq!(None, resp.next().map(|e| format!("{:?}", e)));
    } else {
        assert_eq!(Some(Ok(Bytes::new())), resp.next().map(|r| r.map_err(|e| format!("{:?}", e))));
    }
}
<|endoftext|>


<commit_before>extern crate walkdir;
extern crate itertools;
extern crate cargo_erlangapp;

use cargo_erlangapp::{Target, target_filenames};
use std::ffi::{OsStr};
use std::{env, fs, io};
use std::path::{Path};
use walkdir::WalkDir;
use itertools::Itertools;

const TEST_DIR: &'static str = "tests/testdir";
const APP_DIR: &'static str = "tests/testdir/testapp";

#[test]
fn do_test() {
    test_init();

    invoke_with_args(&["cargo-erlangapp", "build" ]);
    check_build();
    invoke_with_args(&["cargo-erlangapp", "clean" ]);
    check_clean();

    invoke_with_args(&["cargo-erlangapp", "build", "--release" ]);
    check_build();
    invoke_with_args(&["cargo-erlangapp", "clean" ]);
    check_clean();

    invoke_with_args(&["cargo-erlangapp", "build", "--target=x86_64-unknown-linux-gnu" ]);
    check_build();
    invoke_with_args(&["cargo-erlangapp", "clean" ]);
    check_clean();

    invoke_with_args(&["cargo-erlangapp", "test" ]);
    check_clean();
    invoke_with_args(&["cargo-erlangapp", "clean" ]);
    check_clean();

    test_cleanup();
}

fn invoke_with_args(args: &[&str]) {
    let mut appdir = env::current_dir().unwrap();
    appdir.push(TEST_DIR);
    appdir.push("testapp");
    cargo_erlangapp::invoke_with_args(args.into_iter().cloned(), &appdir)
}

fn check_build() {
    check_artifact("bonjourdylib", &Target::Dylib("bonjourdylib".into())).unwrap();
    check_artifact("helloexe", &Target::Bin("helloexe".into())).unwrap();
}

fn check_clean() {
    check_artifact("bonjourdylib", &Target::Dylib("bonjourdylib".into())).unwrap_err();
    check_artifact("helloexe", &Target::Bin("helloexe".into())).unwrap_err();
}

fn check_artifact(cratename: &str, target: &Target) -> Result<String,String> {
    let (dstname, _srcname) = target_filenames(target);
    let targetpath = Path::new(APP_DIR).join("priv").join("crates").join(cratename).join(dstname);
    file_must_exist(&targetpath)
}

fn file_must_exist<S: AsRef<OsStr> + ?Sized>(s: &S) -> Result<String,String> {
    match fs::metadata(s.as_ref())
        .map(|m| m.is_file()).unwrap_or(false) {
        true => Ok(format!("{:?} exists!", s.as_ref())),
        false => Err(format!("{:?} does not exist!", s.as_ref())),
    }
}

fn test_init() {
    test_cleanup();
    copy_all("tests/testapp", TEST_DIR).unwrap();
}

fn test_cleanup() {
    let testdir = Path::new("tests").join("testdir");
    if fs::metadata(&testdir).map(|m| m.is_dir()).unwrap_or(false) {
        fs::remove_dir_all(&testdir).unwrap();
    }
}

fn copy_all<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
    // calculate how many path elements to chop off entry when forming to path
    let chop_cnt = from.as_ref().components().count() - 1;
    for entry in WalkDir::new(from).follow_links(false) {
        let entry = try!(entry);
        let filetype = entry.file_type();
        let compi = entry.path().components().dropping(chop_cnt);
        let to_path = to.as_ref().join(compi.as_path());
        //let to_path = to.as_ref().join(entry.path());
        if filetype.is_dir() {
            try!(fs::create_dir_all(to_path));
        } else if filetype.is_file() {
            try!(fs::copy(entry.path(), to_path));
        }
    }
    Ok(())
}

//testapp_src
//drwxr-xr-x 3 goertzen goertzen 4 Jul 18 09:34 bonjourdylib
//drwxr-xr-x 3 goertzen goertzen 4 Jul 18 09:34 helloexe
//drwxr-xr-x 3 goertzen goertzen 4 Jul 18 09:37 holalib

<commit_msg>add windows compatible paths<commit_after>extern crate walkdir;
extern crate itertools;
extern crate cargo_erlangapp;

use cargo_erlangapp::{Target, target_filenames};
use std::ffi::{OsStr};
use std::{env, fs, io};
use std::path::{Path};
use walkdir::WalkDir;
use itertools::Itertools;

#[cfg(unix)]
const TEST_DIR: &'static str = "tests/testdir";
#[cfg(unix)]
const APP_DIR: &'static str = "tests/testdir/testapp";
#[cfg(unix)]
const APP_SRC: &'static str = "tests/testapp";

#[cfg(windows)]
const TEST_DIR: &'static str = "tests\\testdir";
#[cfg(windows)]
const APP_DIR: &'static str = "tests\\testdir\\testapp";
#[cfg(windows)]
const APP_SRC: &'static str = "tests\\testapp";

#[test]
fn do_test() {
    test_init();

    invoke_with_args(&["cargo-erlangapp", "build" ]);
    check_build();
    invoke_with_args(&["cargo-erlangapp", "clean" ]);
    check_clean();

    invoke_with_args(&["cargo-erlangapp", "build", "--release" ]);
    check_build();
    invoke_with_args(&["cargo-erlangapp", "clean" ]);
    check_clean();

    invoke_with_args(&["cargo-erlangapp", "build", "--target=x86_64-unknown-linux-gnu" ]);
    check_build();
    invoke_with_args(&["cargo-erlangapp", "clean" ]);
    check_clean();

    invoke_with_args(&["cargo-erlangapp", "test" ]);
    check_clean();
    invoke_with_args(&["cargo-erlangapp", "clean" ]);
    check_clean();

    test_cleanup();
}

fn invoke_with_args(args: &[&str]) {
    let mut appdir = env::current_dir().unwrap();
    appdir.push(TEST_DIR);
    appdir.push("testapp");
    cargo_erlangapp::invoke_with_args(args.into_iter().cloned(), &appdir)
}

fn check_build() {
    check_artifact("bonjourdylib", &Target::Dylib("bonjourdylib".into())).unwrap();
    check_artifact("helloexe", &Target::Bin("helloexe".into())).unwrap();
}

fn check_clean() {
    check_artifact("bonjourdylib", &Target::Dylib("bonjourdylib".into())).unwrap_err();
    check_artifact("helloexe", &Target::Bin("helloexe".into())).unwrap_err();
}

fn check_artifact(cratename: &str, target: &Target) -> Result<String,String> {
    let (dstname, _srcname) = target_filenames(target);
    let targetpath = Path::new(APP_DIR).join("priv").join("crates").join(cratename).join(dstname);
    file_must_exist(&targetpath)
}

fn file_must_exist<S: AsRef<OsStr> + ?Sized>(s: &S) -> Result<String,String> {
    match fs::metadata(s.as_ref())
        .map(|m| m.is_file()).unwrap_or(false) {
        true => Ok(format!("{:?} exists!", s.as_ref())),
        false => Err(format!("{:?} does not exist!", s.as_ref())),
    }
}

fn test_init() {
    test_cleanup();
    copy_all(APP_SRC, TEST_DIR).unwrap();
}

fn test_cleanup() {
    let testdir = Path::new("tests").join("testdir");
    if fs::metadata(&testdir).map(|m| m.is_dir()).unwrap_or(false) {
        fs::remove_dir_all(&testdir).unwrap();
    }
}

fn copy_all<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
    // calculate how many path elements to chop off entry when forming to path
    let chop_cnt = from.as_ref().components().count() - 1;
    for entry in WalkDir::new(from).follow_links(false) {
        let entry = try!(entry);
        let filetype = entry.file_type();
        let compi = entry.path().components().dropping(chop_cnt);
        let to_path = to.as_ref().join(compi.as_path());
        //let to_path = to.as_ref().join(entry.path());
        if filetype.is_dir() {
            try!(fs::create_dir_all(to_path));
        } else if filetype.is_file() {
            try!(fs::copy(entry.path(), to_path));
        }
    }
    Ok(())
}

//testapp_src
//drwxr-xr-x 3 goertzen goertzen 4 Jul 18 09:34 bonjourdylib
//drwxr-xr-x 3 goertzen goertzen 4 Jul 18 09:34 helloexe
//drwxr-xr-x 3 goertzen goertzen 4 Jul 18 09:37 holalib

<|endoftext|>


<commit_before>extern crate mosquitto;
use mosquitto::{Client, Qos};

/* The linked code creates a client that connects to a broker at
 * localhost:1883, subscribes to the topics "tick", "control".
 * When received a message on 'tick', it'll be forwarded to tock
 */

/* 1. Start the broker --> mosquitto -c /etc/mosquitto/mosquitto.conf -d
   2. cargo run
   3. mosquitto_sub -t "tock"
   4. mosquitto_pub -t "tick" -m "Hello World"
   5. mosquitto_pub -t "control" -m "halt" --> stop
*/

#[test]
fn test_functionality() {

	/* Set before connect */
	//let client = Client::new("test").keep_alive(30).clean_session(true).auth("root", "admin");
	let mut client = Client::new("test")
					.keep_alive(5)
					.clean_session(true);

	match client.connect("192.168.0.134"){
		Ok(_) => println!("Connection successful --> {:?}", client),
		Err(n) => panic!("Connection error = {:?}", n)
	}

	let i = 100;

	client.onconnect_callback(|a:i32|println!("@@@ On connect callback {}@@@", a + i));

	client.onsubscribe_callback(|mid|println!("Subscribe request received for message {:?}", mid));
	client.subscribe("hello/world", Qos::AtMostOnce);

	client.onpublish_callback(|mid|println!("Publish request received for message {:?}", mid));
	client.publish("hello/world", "Hello World", Qos::AtMostOnce);

	let mut count = 0; //TODO: Weird count print in closure callback
	client.onmesssage_callback(|s|{
									count += 1;
									println!("Message = {:?}, Count = {:?}", s, count);
								   });

	client.loop_forever();
}
<commit_msg>test update<commit_after>extern crate mosquitto;
use mosquitto::{Client, Qos};

/* The linked code creates a client that connects to a broker at
 * localhost:1883, subscribes to the topics "tick", "control".
 * When received a message on 'tick', it'll be forwarded to tock
 */

/* 1. Start the broker --> mosquitto -c /etc/mosquitto/mosquitto.conf -d
   2. cargo run
   3. mosquitto_sub -t "tock"
   4. mosquitto_pub -t "tick" -m "Hello World"
   5. mosquitto_pub -t "control" -m "halt" --> stop
*/

#[test]
fn test_functionality() {

	/* Set before connect */
	//let client = Client::new("test").keep_alive(30).clean_session(true).auth("root", "admin");
	let mut client = Client::new("test")
					.keep_alive(5)
					.clean_session(true);

	let i = 100;

	client.onconnect_callback(|a:i32|println!("@@@ On connect callback {}@@@", a + i));

	match client.connect("192.168.0.134"){
		Ok(_) => println!("Connection successful --> {:?}", client),
		Err(n) => panic!("Connection error = {:?}", n)
	}

	client.onsubscribe_callback(|mid|println!("Subscribe request received for message {:?}", mid));
	client.subscribe("hello/world", Qos::AtMostOnce);

	client.onpublish_callback(|mid|println!("Publish request received for message {:?}", mid));
	client.publish("hello/world", "Hello World", Qos::AtMostOnce);

	let mut count = 0; //TODO: Weird count print in closure callback
	client.onmesssage_callback(|s|{
									count += 1;
									println!("Message = {:?}, Count = {:?}", s, count);
								   });

	client.loop_forever();
}
<|endoftext|>