<commit_before>use prolog::ast::*;
use prolog::heap_iter::*;
use prolog::machine::machine_state::MachineState;

use std::cell::Cell;
use std::collections::{HashMap, HashSet};
use std::rc::Rc;

#[derive(Clone)]
pub enum TokenOrRedirect {
    Atom(ClauseName),
    Redirect,
    Open,
    Close,
    Comma,
    OpenList(Rc<Cell<bool>>),
    CloseList(Rc<Cell<bool>>),
    HeadTailSeparator,
    Space
}

pub trait HCValueFormatter {
    // this function belongs to the display predicate formatter, which it uses
    // to format all clauses.
    fn format_struct(&self, arity: usize, name: ClauseName, state_stack: &mut Vec<TokenOrRedirect>)
    {
        state_stack.push(TokenOrRedirect::Close);

        for _ in 0 .. arity {
            state_stack.push(TokenOrRedirect::Redirect);
            state_stack.push(TokenOrRedirect::Comma);
        }

        state_stack.pop();
        state_stack.push(TokenOrRedirect::Open);

        state_stack.push(TokenOrRedirect::Atom(name));
    }

    // this can be overloaded to handle special cases, falling back on the default of
    // format_struct when convenient.
    fn format_clause(&self, usize, ClauseType, &mut Vec<TokenOrRedirect>);
}

pub trait HCValueOutputter {
    type Output;

    fn new() -> Self;
    fn append(&mut self, &str);
    fn begin_new_var(&mut self);
    fn result(self) -> Self::Output;
    fn ends_with(&self, &str) -> bool;
    fn len(&self) -> usize;
    fn truncate(&mut self, usize);
}

pub struct PrinterOutputter {
    contents: String
}

impl HCValueOutputter for PrinterOutputter {
    type Output = String;

    fn new() -> Self {
        PrinterOutputter { contents: String::new() }
    }

    fn append(&mut self, contents: &str) {
        self.contents += contents;
    }

    fn begin_new_var(&mut self) {
        if self.contents.len() != 0 {
            self.contents += ", ";
        }
    }

    fn result(self) -> Self::Output {
        self.contents
    }

    fn ends_with(&self, s: &str) -> bool {
        self.contents.ends_with(s)
    }

    fn len(&self) -> usize {
        self.contents.len()
    }

    fn truncate(&mut self, len: usize) {
        self.contents.truncate(len);
    }
}

// the 'classic' display corresponding to the display predicate.
pub struct DisplayFormatter {}

impl HCValueFormatter for DisplayFormatter {
    fn format_clause(&self, arity: usize, ct: ClauseType, state_stack: &mut Vec<TokenOrRedirect>)
    {
        if ct.fixity().is_some() {
            let mut new_name = String::from("'");
            new_name += ct.name().as_str();
            new_name += "'";

            self.format_struct(arity, ct.name(), state_stack);
        } else {
            self.format_struct(arity, ct.name(), state_stack);
        }
    }
}

pub struct TermFormatter {}

impl HCValueFormatter for TermFormatter {
    fn format_clause(&self, arity: usize, ct: ClauseType, state_stack: &mut Vec<TokenOrRedirect>)
    {
        if let Some(fixity) = ct.fixity() {
            match fixity {
                Fixity::Post => {
                    state_stack.push(TokenOrRedirect::Atom(ct.name()));
                    state_stack.push(TokenOrRedirect::Space);
                    state_stack.push(TokenOrRedirect::Redirect);
                },
                Fixity::Pre => {
                    state_stack.push(TokenOrRedirect::Redirect);
                    state_stack.push(TokenOrRedirect::Space);
                    state_stack.push(TokenOrRedirect::Atom(ct.name()));
                },
                Fixity::In => {
                    state_stack.push(TokenOrRedirect::Redirect);
                    state_stack.push(TokenOrRedirect::Space);
                    state_stack.push(TokenOrRedirect::Atom(ct.name()));
                    state_stack.push(TokenOrRedirect::Space);
                    state_stack.push(TokenOrRedirect::Redirect);
                }
            }
        } else {
            self.format_struct(arity, ct.name(), state_stack);
        }
    }
}

type ReverseHeapVarDict<'a> = HashMap<Addr, Rc<Var>>;

pub struct HCPrinter<'a, Formatter, Outputter> {
    formatter:    Formatter,
    outputter:    Outputter,
    machine_st:   &'a MachineState,
    state_stack:  Vec<TokenOrRedirect>,
    heap_locs:    ReverseHeapVarDict<'a>,
    printed_vars: HashSet<Addr>
}

fn reverse_heap_locs<'a>(machine_st: &'a MachineState, heap_locs: &'a HeapVarDict)
                         -> ReverseHeapVarDict<'a>
{
    heap_locs.iter().map(|(var, var_addr)| {
        (machine_st.store(machine_st.deref(var_addr.clone())), var.clone())
    }).collect()
}

impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
    HCPrinter<'a, Formatter, Outputter>
{
    pub fn new(machine_st: &'a MachineState, fmt: Formatter, output: Outputter) -> Self
    {
        HCPrinter { formatter: fmt,
                    outputter: output,
                    machine_st,
                    state_stack: vec![],
                    heap_locs: ReverseHeapVarDict::new(),
                    printed_vars: HashSet::new() }
    }

    pub fn from_heap_locs(machine_st: &'a MachineState, fmt: Formatter,
                          output: Outputter, heap_locs: &'a HeapVarDict)
                          -> Self
    {
        let mut printer = Self::new(machine_st, fmt, output);

        printer.heap_locs = reverse_heap_locs(machine_st, heap_locs);
        printer
    }

    fn print_offset(&mut self, addr: Addr) {
        match addr {
            Addr::HeapCell(h) | Addr::Lis(h) | Addr::Str(h) =>
                self.outputter.append(format!("_{}", h).as_str()),
            Addr::StackCell(fr, sc) =>
                self.outputter.append(format!("s_{}_{}", fr, sc).as_str()),
            _ => {}
        }
    }

    fn check_for_seen(&mut self, iter: &mut HCPreOrderIterator) -> Option<HeapCellValue> {
        iter.stack().last().cloned().and_then(|addr| {
            let addr = self.machine_st.store(self.machine_st.deref(addr));

            match self.heap_locs.get(&addr).cloned() {
                Some(var) => if !self.printed_vars.contains(&addr) {
                    self.printed_vars.insert(addr);
                    return iter.next();
                } else {
                    iter.stack().pop();
                    self.outputter.append(var.as_str());

                    return None;
                },
                None => if self.machine_st.is_cyclic_term(addr.clone()) {
                    if self.printed_vars.contains(&addr) {
                        iter.stack().pop();
                        self.print_offset(addr);

                        None
                    } else {
                        self.printed_vars.insert(addr);
                        iter.next()
                    }
                } else {
                    iter.next()
                }
            }
        })
    }

    fn handle_heap_term(&mut self, iter: &mut HCPreOrderIterator)
    {
        let heap_val = match self.check_for_seen(iter) {
            Some(heap_val) => heap_val,
            _ => return
        };

        match heap_val {
            HeapCellValue::NamedStr(arity, name, fixity) => {
                let ct = ClauseType::from(name, arity, fixity);
                self.formatter.format_clause(arity, ct, &mut self.state_stack)
            },
            HeapCellValue::Addr(Addr::Con(Constant::EmptyList)) =>
                if !self.at_cdr("") {
                    self.outputter.append("[]");
                },
            HeapCellValue::Addr(Addr::Con(c)) =>
                self.outputter.append(format!("{}", c).as_str()),
            HeapCellValue::Addr(Addr::Lis(_)) => {
                let cell = Rc::new(Cell::new(true));

                self.state_stack.push(TokenOrRedirect::CloseList(cell.clone()));

                self.state_stack.push(TokenOrRedirect::Redirect);
                self.state_stack.push(TokenOrRedirect::HeadTailSeparator); // bar
                self.state_stack.push(TokenOrRedirect::Redirect);

                self.state_stack.push(TokenOrRedirect::OpenList(cell));
            },
            HeapCellValue::Addr(addr) => self.print_offset(addr)
        }
    }

    fn at_cdr(&mut self, tr: &str) -> bool {
        let len = self.outputter.len();

        if self.outputter.ends_with(" | ") {
            self.outputter.truncate(len - 3);
            self.outputter.append(tr);

            true
        } else {
            false
        }
    }

    pub fn print(mut self, addr: Addr) -> Outputter {
        let mut iter = HCPreOrderIterator::new(&self.machine_st, addr);

        loop {
            if let Some(loc_data) = self.state_stack.pop() {
                match loc_data {
                    TokenOrRedirect::Space =>
                        self.outputter.append(" "),
                    TokenOrRedirect::Atom(atom) =>
                        self.outputter.append(atom.as_str()),
                    TokenOrRedirect::Redirect =>
                        self.handle_heap_term(&mut iter),
                    TokenOrRedirect::Close =>
                        self.outputter.append(")"),
                    TokenOrRedirect::Open =>
                        self.outputter.append("("),
                    TokenOrRedirect::OpenList(delimit) =>
                        if !self.at_cdr(", ") {
                            self.outputter.append("[");
                        } else {
                            delimit.set(false);
                        },
                    TokenOrRedirect::CloseList(delimit) =>
                        if delimit.get() {
                            self.outputter.append("]");
                        },
                    TokenOrRedirect::HeadTailSeparator =>
                        self.outputter.append(" | "),
                    TokenOrRedirect::Comma =>
                        self.outputter.append(", ")
                }
            } else if !iter.stack().is_empty() {
                self.handle_heap_term(&mut iter);
            } else {
                break;
            }
        }

        self.outputter
    }
}
<commit_msg>record cyclic terms in printer<commit_after>use prolog::ast::*;
use prolog::heap_iter::*;
use prolog::machine::machine_state::MachineState;

use std::cell::Cell;
use std::collections::{HashMap, HashSet};
use std::rc::Rc;

#[derive(Clone)]
pub enum TokenOrRedirect {
    Atom(ClauseName),
    Redirect,
    Open,
    Close,
    Comma,
    OpenList(Rc<Cell<bool>>),
    CloseList(Rc<Cell<bool>>),
    HeadTailSeparator,
    Space
}

pub trait HCValueFormatter {
    // this function belongs to the display predicate formatter, which it uses
    // to format all clauses.
    fn format_struct(&self, arity: usize, name: ClauseName, state_stack: &mut Vec<TokenOrRedirect>)
    {
        state_stack.push(TokenOrRedirect::Close);

        for _ in 0 .. arity {
            state_stack.push(TokenOrRedirect::Redirect);
            state_stack.push(TokenOrRedirect::Comma);
        }

        state_stack.pop();
        state_stack.push(TokenOrRedirect::Open);

        state_stack.push(TokenOrRedirect::Atom(name));
    }

    // this can be overloaded to handle special cases, falling back on the default of
    // format_struct when convenient.
    fn format_clause(&self, usize, ClauseType, &mut Vec<TokenOrRedirect>);
}

pub trait HCValueOutputter {
    type Output;

    fn new() -> Self;
    fn append(&mut self, &str);
    fn begin_new_var(&mut self);
    fn result(self) -> Self::Output;
    fn ends_with(&self, &str) -> bool;
    fn len(&self) -> usize;
    fn truncate(&mut self, usize);
}

pub struct PrinterOutputter {
    contents: String
}

impl HCValueOutputter for PrinterOutputter {
    type Output = String;

    fn new() -> Self {
        PrinterOutputter { contents: String::new() }
    }

    fn append(&mut self, contents: &str) {
        self.contents += contents;
    }

    fn begin_new_var(&mut self) {
        if self.contents.len() != 0 {
            self.contents += ", ";
        }
    }

    fn result(self) -> Self::Output {
        self.contents
    }

    fn ends_with(&self, s: &str) -> bool {
        self.contents.ends_with(s)
    }

    fn len(&self) -> usize {
        self.contents.len()
    }

    fn truncate(&mut self, len: usize) {
        self.contents.truncate(len);
    }
}

// the 'classic' display corresponding to the display predicate.
pub struct DisplayFormatter {}

impl HCValueFormatter for DisplayFormatter {
    fn format_clause(&self, arity: usize, ct: ClauseType, state_stack: &mut Vec<TokenOrRedirect>)
    {
        if ct.fixity().is_some() {
            let mut new_name = String::from("'");
            new_name += ct.name().as_str();
            new_name += "'";

            self.format_struct(arity, ct.name(), state_stack);
        } else {
            self.format_struct(arity, ct.name(), state_stack);
        }
    }
}

pub struct TermFormatter {}

impl HCValueFormatter for TermFormatter {
    fn format_clause(&self, arity: usize, ct: ClauseType, state_stack: &mut Vec<TokenOrRedirect>)
    {
        if let Some(fixity) = ct.fixity() {
            match fixity {
                Fixity::Post => {
                    state_stack.push(TokenOrRedirect::Atom(ct.name()));
                    state_stack.push(TokenOrRedirect::Space);
                    state_stack.push(TokenOrRedirect::Redirect);
                },
                Fixity::Pre => {
                    state_stack.push(TokenOrRedirect::Redirect);
                    state_stack.push(TokenOrRedirect::Space);
                    state_stack.push(TokenOrRedirect::Atom(ct.name()));
                },
                Fixity::In => {
                    state_stack.push(TokenOrRedirect::Redirect);
                    state_stack.push(TokenOrRedirect::Space);
                    state_stack.push(TokenOrRedirect::Atom(ct.name()));
                    state_stack.push(TokenOrRedirect::Space);
                    state_stack.push(TokenOrRedirect::Redirect);
                }
            }
        } else {
            self.format_struct(arity, ct.name(), state_stack);
        }
    }
}

type ReverseHeapVarDict<'a> = HashMap<Addr, Rc<Var>>;

pub struct HCPrinter<'a, Formatter, Outputter> {
    formatter:    Formatter,
    outputter:    Outputter,
    machine_st:   &'a MachineState,
    state_stack:  Vec<TokenOrRedirect>,
    heap_locs:    ReverseHeapVarDict<'a>,
    printed_vars: HashSet<Addr>
}

fn reverse_heap_locs<'a>(machine_st: &'a MachineState, heap_locs: &'a HeapVarDict)
                         -> ReverseHeapVarDict<'a>
{
    heap_locs.iter().map(|(var, var_addr)| {
        (machine_st.store(machine_st.deref(var_addr.clone())), var.clone())
    }).collect()
}

impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
    HCPrinter<'a, Formatter, Outputter>
{
    pub fn new(machine_st: &'a MachineState, fmt: Formatter, output: Outputter) -> Self
    {
        HCPrinter { formatter: fmt,
                    outputter: output,
                    machine_st,
                    state_stack: vec![],
                    heap_locs: ReverseHeapVarDict::new(),
                    printed_vars: HashSet::new() }
    }

    pub fn from_heap_locs(machine_st: &'a MachineState, fmt: Formatter,
                          output: Outputter, heap_locs: &'a HeapVarDict)
                          -> Self
    {
        let mut printer = Self::new(machine_st, fmt, output);

        printer.heap_locs = reverse_heap_locs(machine_st, heap_locs);
        printer
    }

    fn offset_as_string(&self, addr: Addr) -> Option<String> {
        match addr {
            Addr::HeapCell(h) | Addr::Lis(h) | Addr::Str(h) =>
                Some(format!("_{}", h)),
            Addr::StackCell(fr, sc) =>
                Some(format!("s_{}_{}", fr, sc)),
            _ => None
        }
    }

    fn print_offset(&mut self, addr: Addr) {
        self.offset_as_string(addr).map(|s| self.outputter.append(s.as_str()));
    }

    fn check_for_seen(&mut self, iter: &mut HCPreOrderIterator) -> Option<HeapCellValue> {
        iter.stack().last().cloned().and_then(|addr| {
            let addr = self.machine_st.store(self.machine_st.deref(addr));

            match self.heap_locs.get(&addr).cloned() {
                Some(var) => if !self.printed_vars.contains(&addr) {
                    self.printed_vars.insert(addr);
                    return iter.next();
                } else {
                    iter.stack().pop();
                    self.outputter.append(var.as_str());

                    return None;
                },
                None => if self.machine_st.is_cyclic_term(addr.clone()) {
                    if self.printed_vars.contains(&addr) {
                        iter.stack().pop();
                        self.print_offset(addr);

                        None
                    } else {
                        if let Some(s) = self.offset_as_string(addr.clone()) {
                            let var = Rc::new(s);
                            self.heap_locs.insert(addr.clone(), var);
                        }

                        self.printed_vars.insert(addr);
                        iter.next()
                    }
                } else {
                    iter.next()
                }
            }
        })
    }

    fn handle_heap_term(&mut self, iter: &mut HCPreOrderIterator)
    {
        let heap_val = match self.check_for_seen(iter) {
            Some(heap_val) => heap_val,
            _ => return
        };

        match heap_val {
            HeapCellValue::NamedStr(arity, name, fixity) => {
                let ct = ClauseType::from(name, arity, fixity);
                self.formatter.format_clause(arity, ct, &mut self.state_stack)
            },
            HeapCellValue::Addr(Addr::Con(Constant::EmptyList)) =>
                if !self.at_cdr("") {
                    self.outputter.append("[]");
                },
            HeapCellValue::Addr(Addr::Con(c)) =>
                self.outputter.append(format!("{}", c).as_str()),
            HeapCellValue::Addr(Addr::Lis(_)) => {
                let cell = Rc::new(Cell::new(true));

                self.state_stack.push(TokenOrRedirect::CloseList(cell.clone()));

                self.state_stack.push(TokenOrRedirect::Redirect);
                self.state_stack.push(TokenOrRedirect::HeadTailSeparator); // bar
                self.state_stack.push(TokenOrRedirect::Redirect);

                self.state_stack.push(TokenOrRedirect::OpenList(cell));
            },
            HeapCellValue::Addr(addr) => self.print_offset(addr)
        }
    }

    fn at_cdr(&mut self, tr: &str) -> bool {
        let len = self.outputter.len();

        if self.outputter.ends_with(" | ") {
            self.outputter.truncate(len - 3);
            self.outputter.append(tr);

            true
        } else {
            false
        }
    }

    pub fn print(mut self, addr: Addr) -> Outputter {
        let mut iter = HCPreOrderIterator::new(&self.machine_st, addr);

        loop {
            if let Some(loc_data) = self.state_stack.pop() {
                match loc_data {
                    TokenOrRedirect::Space =>
                        self.outputter.append(" "),
                    TokenOrRedirect::Atom(atom) =>
                        self.outputter.append(atom.as_str()),
                    TokenOrRedirect::Redirect =>
                        self.handle_heap_term(&mut iter),
                    TokenOrRedirect::Close =>
                        self.outputter.append(")"),
                    TokenOrRedirect::Open =>
                        self.outputter.append("("),
                    TokenOrRedirect::OpenList(delimit) =>
                        if !self.at_cdr(", ") {
                            self.outputter.append("[");
                        } else {
                            delimit.set(false);
                        },
                    TokenOrRedirect::CloseList(delimit) =>
                        if delimit.get() {
                            self.outputter.append("]");
                        },
                    TokenOrRedirect::HeadTailSeparator =>
                        self.outputter.append(" | "),
                    TokenOrRedirect::Comma =>
                        self.outputter.append(", ")
                }
            } else if !iter.stack().is_empty() {
                self.handle_heap_term(&mut iter);
            } else {
                break;
            }
        }

        self.outputter
    }
}
<|endoftext|>


<commit_before>use au = gfx::geometry;
use newcss::values::*;
use geom::point::Point2D;
use geom::rect::Rect;
use gfx::display_list::DisplayList;
use gfx::geometry::Au;
use layout::box::RenderBox;
use layout::context::LayoutContext;
use layout::flow::{FlowContext, FlowTree, InlineBlockFlow, BlockFlow, RootFlow};
use layout::display_list_builder::DisplayListBuilder;
use util::tree;

struct RootFlowData {
    mut box: Option<@RenderBox>
}

fn RootFlowData() -> RootFlowData {
    RootFlowData {
        box: None
    }
}

trait RootLayout {
    pure fn starts_root_flow() -> bool;

    fn bubble_widths_root(@self, ctx: &LayoutContext);
    fn assign_widths_root(@self, ctx: &LayoutContext);
    fn assign_height_root(@self, ctx: &LayoutContext);
    fn build_display_list_root(@self, a: &DisplayListBuilder, b: &Rect<Au>,
                               c: &Point2D<Au>, d: &mut DisplayList);
}

impl FlowContext : RootLayout {

    pure fn starts_root_flow() -> bool {
        match self {
            RootFlow(*) => true,
            _ => false
        }
    }

    /* defer to the block algorithm */
    fn bubble_widths_root(@self, ctx: &LayoutContext) {
        assert self.starts_root_flow();
        self.bubble_widths_block(ctx)
    }

    fn assign_widths_root(@self, ctx: &LayoutContext) {
        assert self.starts_root_flow();

        self.d().position = copy ctx.screen_size;
        self.assign_widths_block(ctx)
    }

    fn assign_height_root(@self, ctx: &LayoutContext) {
        assert self.starts_root_flow();

        self.assign_height_block(ctx);
    }

    fn build_display_list_root(@self, builder: &DisplayListBuilder, dirty: &Rect<Au>,
                               offset: &Point2D<Au>, list: &mut DisplayList) {
        assert self.starts_root_flow();

        self.build_display_list_block(builder, dirty, offset, list);
    }
}
<commit_msg>Force root flow's box size to coincide with the viewport if child flows have less combined height than the viewport height.<commit_after>use au = gfx::geometry;
use newcss::values::*;
use geom::point::Point2D;
use geom::rect::Rect;
use gfx::display_list::DisplayList;
use gfx::geometry::Au;
use layout::box::RenderBox;
use layout::context::LayoutContext;
use layout::flow::{FlowContext, FlowTree, InlineBlockFlow, BlockFlow, RootFlow};
use layout::display_list_builder::DisplayListBuilder;
use util::tree;

struct RootFlowData {
    mut box: Option<@RenderBox>
}

fn RootFlowData() -> RootFlowData {
    RootFlowData {
        box: None
    }
}

trait RootLayout {
    pure fn starts_root_flow() -> bool;

    fn bubble_widths_root(@self, ctx: &LayoutContext);
    fn assign_widths_root(@self, ctx: &LayoutContext);
    fn assign_height_root(@self, ctx: &LayoutContext);
    fn build_display_list_root(@self, a: &DisplayListBuilder, b: &Rect<Au>,
                               c: &Point2D<Au>, d: &mut DisplayList);
}

impl FlowContext : RootLayout {

    pure fn starts_root_flow() -> bool {
        match self {
            RootFlow(*) => true,
            _ => false
        }
    }

    /* defer to the block algorithm */
    fn bubble_widths_root(@self, ctx: &LayoutContext) {
        assert self.starts_root_flow();
        self.bubble_widths_block(ctx)
    }

    fn assign_widths_root(@self, ctx: &LayoutContext) {
        assert self.starts_root_flow();

        self.d().position.origin = Au::zero_point();
        self.d().position.size.width = ctx.screen_size.size.width;

        self.assign_widths_block(ctx)
    }

    fn assign_height_root(@self, ctx: &LayoutContext) {
        assert self.starts_root_flow();

        // this is essentially the same as assign_height_block(), except
        // the root adjusts self height to at least cover the viewport.
        let mut cur_y = Au(0);

        for FlowTree.each_child(self) |child_ctx| {
            child_ctx.d().position.origin.y = cur_y;
            cur_y += child_ctx.d().position.size.height;
        }

        self.d().position.size.height = Au::max(ctx.screen_size.size.height, cur_y);

        do self.with_block_box |box| {
            box.d().position.origin.y = Au(0);
            box.d().position.size.height = Au::max(ctx.screen_size.size.height, cur_y);
            let (_used_top, _used_bot) = box.get_used_height();
        }
    }

    fn build_display_list_root(@self, builder: &DisplayListBuilder, dirty: &Rect<Au>,
                               offset: &Point2D<Au>, list: &mut DisplayList) {
        assert self.starts_root_flow();

        self.build_display_list_block(builder, dirty, offset, list);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015-2016 Ivo Wetzel

// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::net;
use std::fmt;
use std::thread;
use std::time::Duration;
use std::io::Error;
use std::sync::mpsc::{channel, Receiver, Sender, TryRecvError};
use super::super::traits::socket::Socket;

/// Non-blocking abstraction over a UDP socket.
///
/// The non-blocking behavior is implement by using a internal reader thread.
pub struct UdpSocket {
    socket: net::UdpSocket,
    reader_thread: Option<thread::JoinHandle<()>>,
    udp_receiver: Receiver<(net::SocketAddr, Vec<u8>)>,
    close_sender: Sender<()>
}

impl UdpSocket {

    /// Tries to create a new UDP socket by binding to the specified address.
    pub fn new<T: net::ToSocketAddrs>(
        address: T, max_packet_size: usize

    ) -> Result<Self, Error> {

        // Create the send socket
        let sender = try!(net::UdpSocket::bind(address));

        // Clone the socket handle for use inside the reader thread
        let reader = try!(sender.try_clone());
        try!(reader.set_read_timeout(Some(Duration::from_millis(10))));

        // Create communication channels
        let (s_udp, r_udp) = channel::<(net::SocketAddr, Vec<u8>)>();
        let (s_close, r_close) = channel::<()>();

        // Create Reader Thread
        let reader_thread = thread::spawn(move|| {

            // Allocate buffer for the maximum packet size
            let mut buffer = Vec::with_capacity(max_packet_size);
            for _ in 0..max_packet_size {
                buffer.push(0);
            }

            loop {

                // Receive packets...
                if let Ok((len, src)) = reader.recv_from(&mut buffer) {

                    // Copy only the actual number of bytes and send them
                    // along with the source address
                    s_udp.send((src, buffer[..len].to_vec())).ok();

                // ...until shutdown is received
                } else if let Ok(_) = r_close.try_recv() {
                    break;
                }

            }

        });

        // Return the combined structure
        Ok(UdpSocket {
            socket: sender,
            reader_thread: Some(reader_thread),
            udp_receiver: r_udp,
            close_sender: s_close
        })

    }

}

impl Socket for UdpSocket {

    /// Attempts to return a incoming packet on this socket without blocking.
    fn try_recv(&self) -> Result<(net::SocketAddr, Vec<u8>), TryRecvError> {
        self.udp_receiver.try_recv()
    }

    /// Send data on the socket to the given address. On success, returns the
    /// number of bytes written.
    fn send_to(
        &mut self, data: &[u8], addr: net::SocketAddr)

    -> Result<usize, Error> {
        self.socket.send_to(data, addr)
    }

    /// Returns the socket address of the underlying `net::UdpSocket`.
    fn local_addr(&self) -> Result<net::SocketAddr, Error> {
        self.socket.local_addr()
    }

    /// Shuts down the socket by stopping its internal reader thread.
    fn shutdown(&mut self) {

        // Only shutdown if we still got a reader thread
        if let Some(reader_thread) = self.reader_thread.take() {

            // Notify the reader thread to exit
            self.close_sender.send(()).unwrap();

            // Finally wait for the reader thread to exit cleanly
            reader_thread.join().unwrap();

        }

    }

}

impl Drop for UdpSocket {
    fn drop(&mut self) {
        // Make sure to exit the internal thread cleanly
        self.shutdown();
    }
}

impl fmt::Debug for UdpSocket {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "UdpSocket({:?})", self.socket)
    }
}

<commit_msg>Clean up creation of initial udp packet receive buffer.<commit_after>// Copyright (c) 2015-2016 Ivo Wetzel

// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::net;
use std::fmt;
use std::iter;
use std::thread;
use std::time::Duration;
use std::io::Error;
use std::sync::mpsc::{channel, Receiver, Sender, TryRecvError};
use super::super::traits::socket::Socket;

/// Non-blocking abstraction over a UDP socket.
///
/// The non-blocking behavior is implement by using a internal reader thread.
pub struct UdpSocket {
    socket: net::UdpSocket,
    reader_thread: Option<thread::JoinHandle<()>>,
    udp_receiver: Receiver<(net::SocketAddr, Vec<u8>)>,
    close_sender: Sender<()>
}

impl UdpSocket {

    /// Tries to create a new UDP socket by binding to the specified address.
    pub fn new<T: net::ToSocketAddrs>(
        address: T, max_packet_size: usize

    ) -> Result<Self, Error> {

        // Create the send socket
        let sender = try!(net::UdpSocket::bind(address));

        // Clone the socket handle for use inside the reader thread
        let reader = try!(sender.try_clone());

        // Configure read timeout so we can eventually exit our receive loop
        try!(reader.set_read_timeout(Some(Duration::from_millis(10))));

        // Create communication channels
        let (s_udp, r_udp) = channel::<(net::SocketAddr, Vec<u8>)>();
        let (s_close, r_close) = channel::<()>();

        // Create Reader Thread
        let reader_thread = thread::spawn(move|| {

            // Allocate buffer for the maximum packet size
            let mut buffer: Vec<u8> = iter::repeat(0).take(max_packet_size).collect();
            loop {

                // Receive packets...
                if let Ok((len, src)) = reader.recv_from(&mut buffer) {

                    // Copy only the actual number of bytes and send them
                    // along with the source address
                    s_udp.send((src, buffer[..len].to_vec())).ok();

                // ...until shutdown is received
                } else if let Ok(_) = r_close.try_recv() {
                    break;
                }

            }

        });

        // Return the combined structure
        Ok(UdpSocket {
            socket: sender,
            reader_thread: Some(reader_thread),
            udp_receiver: r_udp,
            close_sender: s_close
        })

    }

}

impl Socket for UdpSocket {

    /// Attempts to return a incoming packet on this socket without blocking.
    fn try_recv(&self) -> Result<(net::SocketAddr, Vec<u8>), TryRecvError> {
        self.udp_receiver.try_recv()
    }

    /// Send data on the socket to the given address. On success, returns the
    /// number of bytes written.
    fn send_to(
        &mut self, data: &[u8], addr: net::SocketAddr)

    -> Result<usize, Error> {
        self.socket.send_to(data, addr)
    }

    /// Returns the socket address of the underlying `net::UdpSocket`.
    fn local_addr(&self) -> Result<net::SocketAddr, Error> {
        self.socket.local_addr()
    }

    /// Shuts down the socket by stopping its internal reader thread.
    fn shutdown(&mut self) {

        // Only shutdown if we still got a reader thread
        if let Some(reader_thread) = self.reader_thread.take() {

            // Notify the reader thread to exit
            self.close_sender.send(()).unwrap();

            // Finally wait for the reader thread to exit cleanly
            reader_thread.join().unwrap();

        }

    }

}

impl Drop for UdpSocket {
    fn drop(&mut self) {
        // Make sure to exit the internal thread cleanly
        self.shutdown();
    }
}

impl fmt::Debug for UdpSocket {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "UdpSocket({:?})", self.socket)
    }
}

<|endoftext|>


<commit_before>use hyper::{Client, Ok};
use std::io::prelude::*;
use util::logger::log;

/// Scrapes a website
/// The adress may not be https, only http works
pub fn scrape(url: &str, name: &str) -> Option<String> {
    let client = Client::new();
    let mut response = client.get(url).send().unwrap();
    if response.status != Ok {
        log(&format!("Error {}, FAILED scraping from {}", response.status, name));
        return None;
    }
    let mut s = String::new();
    let _ = response.read_to_string(&mut s);
    //log(&format!("Scrapped from {}", name));
    Some(s)
}
<commit_msg>Fix connection timeout panic<commit_after>use hyper::Client;
use std::io::prelude::*;
use util::logger::log;

/// Scrapes a website
/// The adress may not be https, only http works
pub fn scrape(url: &str, name: &str) -> Option<String> {
    let client = Client::new();
    let mut response = match client.get(url).send() {
        Ok(resp) => resp,
        Err(e) => {
            log(&format!("Error {}, FAILED scraping from {}", e, name));
            return None
        },
    };
    if response.status != ::hyper::Ok {
        log(&format!("Error {}, FAILED scraping from {}", response.status, name));
        return None;
    }
    let mut s = String::new();
    let _ = response.read_to_string(&mut s);
    //log(&format!("Scrapped from {}", name));
    Some(s)
}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::Path;

pub fn read_data(path: &str) -> Vec<f64> {
    let p = Path::new(path);
    let f = File::open(p).ok().unwrap();
    let r = BufReader::new(f);

    let data: Vec<f64> = r
        .lines()
        .map(|l| l.ok().unwrap().parse().unwrap())
        .collect();

    data
}

#[derive(Debug, Default)]
pub struct KnownSummary {
    pub src: String,
    pub size: f64,
    pub min: f64,
    pub max: f64,
    pub median: f64,
    pub mean: f64,
    pub lower_quartile: f64,
    pub upper_quartile: f64,
    pub standard_deviation: f64,
    pub standard_error: f64,
    pub variance: f64,
}

impl KnownSummary {
    pub fn new(path: &str) -> Self {
        let p = Path::new(path);
        let f = File::open(p).ok().unwrap();
        let r = BufReader::new(f);

        let mut known = KnownSummary::default();
        let mut keys_read: HashSet<String> = HashSet::new();

        for l in r.lines() {
            let pieces: Vec<String> = l.ok().unwrap().split('\t').map(|s| s.to_string()).collect();
            assert_eq!(pieces.len(), 2, "Invalid line in known answer file");

            let key = pieces[0].to_string();
            let val = pieces[1].to_string();

            match key.as_ref() {
                "src" =>
                    known.src = val,
                "lower_quartile" =>
                    known.lower_quartile = val.parse::<f64>().unwrap(),
                "max" =>
                    known.max = val.parse::<f64>().unwrap(),
                "mean" =>
                    known.mean = val.parse::<f64>().unwrap(),
                "median" =>
                    known.median = val.parse::<f64>().unwrap(),
                "min" =>
                    known.min = val.parse::<f64>().unwrap(),
                "n" =>
                    known.size = val.parse::<f64>().unwrap(),
                "sem" =>
                    known.standard_error = val.parse::<f64>().unwrap(),
                "std" =>
                    known.standard_deviation = val.parse::<f64>().unwrap(),
                "upper_quartile" =>
                    known.upper_quartile = val.parse::<f64>().unwrap(),
                "var" =>
                    known.variance = val.parse::<f64>().unwrap(),
                _ => panic!(),
            }

            keys_read.insert(key.to_string());
        }

        assert_eq!(keys_read.len(), 11, "Missing lines in known answer file");

        known
    }
}

#[derive(Debug, Default)]
pub struct KnownTTest {
    pub src1: String,
    pub src2: String,
    pub t: f64,
}

impl KnownTTest {
    pub fn new(path: &str) -> Self {
        let p = Path::new(path);
        let f = File::open(p).ok().unwrap();
        let r = BufReader::new(f);

        let mut known = KnownTTest::default();
        let mut keys_read: HashSet<String> = HashSet::new();

        for l in r.lines() {
            let pieces: Vec<String> = l.ok().unwrap().split('\t').map(|s| s.to_string()).collect();
            assert_eq!(pieces.len(), 2, "Invalid line in known answer file");

            let key = pieces[0].to_string();
            let val = pieces[1].to_string();

            match key.as_ref() {
                "src1" => known.src1 = val,
                "src2" => known.src2 = val,
                "t" => known.t = val.parse::<f64>().unwrap(),
                _ => panic!(),
            }

            keys_read.insert(key.to_string());
        }

        assert_eq!(keys_read.len(), 3, "Missing lines in known answer file");

        known
    }
}

#[derive(Debug, Default)]
pub struct KnownLR {
    pub src: String,
    pub slope: f64,
    pub intercept: f64,
    pub r: f64,
    pub p: f64,
    pub se: f64,
}

impl KnownLR {
    pub fn new(path: &str) -> Self {
        let p = Path::new(path);
        let f = File::open(p).ok().unwrap();
        let r = BufReader::new(f);

        let mut known = KnownLR::default();
        let mut keys_read: HashSet<String> = HashSet::new();

        for l in r.lines() {
            let pieces: Vec<String> = l.unwrap().split('\t').map(|s| s.to_string()).collect();
            assert_eq!(pieces.len(), 2, "Invalid line in known answer file");

            let key = pieces[0].to_string();
            let val = pieces[1].to_string();

            match key.as_ref() {
                "src" => known.src = val,
                "slope" => known.slope = val.parse::<f64>().unwrap(),
                "intercept" => known.intercept = val.parse::<f64>().unwrap(),
                "r" => known.r = val.parse::<f64>().unwrap(),
                "p" => known.p = val.parse::<f64>().unwrap(),
                "se" => known.se = val.parse::<f64>().unwrap(),
                _ => panic!("Unknown key in known answer file"),
            }

            keys_read.insert(key.to_string());
        }

        assert_eq!(keys_read.len(), 6, "Missing lines in known answer file");

        known
    }
}

macro_rules! assert_appx_eq {
    ($name:expr, $tolerance:expr, $known:expr, $actual:expr) => {
        let d = ($known - $actual).abs();

        let err = format!("{}: {} and {} differ by {} > {}",
                          $name, $known, $actual, d, $tolerance);

        assert!(d < $tolerance, err);
    };
}

#[macro_export]
macro_rules! summary_kat {
    ($test_name:tt, $name:expr) => {
        #[test]
        fn $test_name() {
            use dent::summary::Summarizer;
            use $crate::common::{KnownSummary, read_data};

            let data_path = format!("{}/{}", "support/data", $name);
            let data = read_data(&data_path);
            let summary = Summarizer::new(&data).unwrap();

            let known_path = format!("{}{}", "support/kat/summary_", $name);
            let known = KnownSummary::new(&known_path);

            let precision = 1e-14;

            assert_appx_eq!("Size", precision,
                            known.size, summary.size());
            assert_appx_eq!("Min", precision,
                            known.min, summary.min());
            assert_appx_eq!("Max", precision,
                            known.max, summary.max());
            assert_appx_eq!("Median", precision,
                            known.median, summary.median());
            assert_appx_eq!("Mean", precision,
                            known.mean, summary.mean());
            assert_appx_eq!("Lower quartile", precision,
                            known.lower_quartile, summary.percentile(0.25).unwrap());
            assert_appx_eq!("Upper quartile", precision,
                            known.upper_quartile, summary.percentile(0.75).unwrap());
            assert_appx_eq!("Variance", precision,
                            known.variance, summary.unbiased_variance());
            assert_appx_eq!("Standard deviation", precision,
                            known.standard_deviation, summary.standard_deviation());
            assert_appx_eq!("Standard error", precision,
                            known.standard_error, summary.standard_error());
        }
    }
}

#[macro_export]
macro_rules! t_test_kat {
    ($test_name:tt, $name:expr) => {
        #[test]
        fn $test_name() {
            use dent::summary::Summary;
            use dent::t_test::{SigLevel, welch_t_test};
            use $crate::common::{KnownTTest, read_data};

            let known_path = format!("{}/{}", "support/kat", $name);
            let known = KnownTTest::new(&known_path);

            let data_path1 = format!("{}/{}", "support/data", known.src1);
            let data1 = read_data(&data_path1);
            let summary1 = Summary::new(&data1).unwrap();

            let data_path2 = format!("{}/{}", "support/data", known.src2);
            let data2 = read_data(&data_path2);
            let summary2 = Summary::new(&data2).unwrap();

            let t_test = welch_t_test(&summary1, &summary2, SigLevel::Alpha005);

            let precision = 1e-11 ;

            assert_appx_eq!("T statistic", precision,
                            known.t, t_test.t);
        }

    }
}

#[macro_export]
macro_rules! lr_kat {
    ($test_name:tt, $name:expr) => {
        #[test]
        fn $test_name() {
            use dent::lr::LinearRegression;
            use $crate::common::{KnownLR, read_data};

            let x_path = format!("{}/{}-x", "support/data", $name);
            let x = read_data(&x_path);

            let y_path = format!("{}/{}-y", "support/data", $name);
            let y = read_data(&y_path);

            let lr = LinearRegression::new(&x, &y).unwrap();

            let known_path = format!("{}/{}", "support/kat", $name);
            let known = KnownLR::new(&known_path);

            let precision = 1e-9;

            assert_appx_eq!("Slope", precision, known.slope, lr.slope);
            assert_appx_eq!("Intercept", precision, known.intercept, lr.intercept);
            assert_appx_eq!("R", precision, known.r, lr.r);

            // We dont compute these right now.
            // assert_appx_eq!("P", precision, known.p, lr.p);
            // assert_appx_eq!("Standard Error", precision, known.se, lr.se);
        }
    }
}
<commit_msg>Remove stray newline<commit_after>use std::collections::HashSet;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::Path;

pub fn read_data(path: &str) -> Vec<f64> {
    let p = Path::new(path);
    let f = File::open(p).ok().unwrap();
    let r = BufReader::new(f);

    let data: Vec<f64> = r
        .lines()
        .map(|l| l.ok().unwrap().parse().unwrap())
        .collect();

    data
}

#[derive(Debug, Default)]
pub struct KnownSummary {
    pub src: String,
    pub size: f64,
    pub min: f64,
    pub max: f64,
    pub median: f64,
    pub mean: f64,
    pub lower_quartile: f64,
    pub upper_quartile: f64,
    pub standard_deviation: f64,
    pub standard_error: f64,
    pub variance: f64,
}

impl KnownSummary {
    pub fn new(path: &str) -> Self {
        let p = Path::new(path);
        let f = File::open(p).ok().unwrap();
        let r = BufReader::new(f);

        let mut known = KnownSummary::default();
        let mut keys_read: HashSet<String> = HashSet::new();

        for l in r.lines() {
            let pieces: Vec<String> = l.ok().unwrap().split('\t').map(|s| s.to_string()).collect();
            assert_eq!(pieces.len(), 2, "Invalid line in known answer file");

            let key = pieces[0].to_string();
            let val = pieces[1].to_string();

            match key.as_ref() {
                "src" =>
                    known.src = val,
                "lower_quartile" =>
                    known.lower_quartile = val.parse::<f64>().unwrap(),
                "max" =>
                    known.max = val.parse::<f64>().unwrap(),
                "mean" =>
                    known.mean = val.parse::<f64>().unwrap(),
                "median" =>
                    known.median = val.parse::<f64>().unwrap(),
                "min" =>
                    known.min = val.parse::<f64>().unwrap(),
                "n" =>
                    known.size = val.parse::<f64>().unwrap(),
                "sem" =>
                    known.standard_error = val.parse::<f64>().unwrap(),
                "std" =>
                    known.standard_deviation = val.parse::<f64>().unwrap(),
                "upper_quartile" =>
                    known.upper_quartile = val.parse::<f64>().unwrap(),
                "var" =>
                    known.variance = val.parse::<f64>().unwrap(),
                _ => panic!(),
            }

            keys_read.insert(key.to_string());
        }

        assert_eq!(keys_read.len(), 11, "Missing lines in known answer file");

        known
    }
}

#[derive(Debug, Default)]
pub struct KnownTTest {
    pub src1: String,
    pub src2: String,
    pub t: f64,
}

impl KnownTTest {
    pub fn new(path: &str) -> Self {
        let p = Path::new(path);
        let f = File::open(p).ok().unwrap();
        let r = BufReader::new(f);

        let mut known = KnownTTest::default();
        let mut keys_read: HashSet<String> = HashSet::new();

        for l in r.lines() {
            let pieces: Vec<String> = l.ok().unwrap().split('\t').map(|s| s.to_string()).collect();
            assert_eq!(pieces.len(), 2, "Invalid line in known answer file");

            let key = pieces[0].to_string();
            let val = pieces[1].to_string();

            match key.as_ref() {
                "src1" => known.src1 = val,
                "src2" => known.src2 = val,
                "t" => known.t = val.parse::<f64>().unwrap(),
                _ => panic!(),
            }

            keys_read.insert(key.to_string());
        }

        assert_eq!(keys_read.len(), 3, "Missing lines in known answer file");

        known
    }
}

#[derive(Debug, Default)]
pub struct KnownLR {
    pub src: String,
    pub slope: f64,
    pub intercept: f64,
    pub r: f64,
    pub p: f64,
    pub se: f64,
}

impl KnownLR {
    pub fn new(path: &str) -> Self {
        let p = Path::new(path);
        let f = File::open(p).ok().unwrap();
        let r = BufReader::new(f);

        let mut known = KnownLR::default();
        let mut keys_read: HashSet<String> = HashSet::new();

        for l in r.lines() {
            let pieces: Vec<String> = l.unwrap().split('\t').map(|s| s.to_string()).collect();
            assert_eq!(pieces.len(), 2, "Invalid line in known answer file");

            let key = pieces[0].to_string();
            let val = pieces[1].to_string();

            match key.as_ref() {
                "src" => known.src = val,
                "slope" => known.slope = val.parse::<f64>().unwrap(),
                "intercept" => known.intercept = val.parse::<f64>().unwrap(),
                "r" => known.r = val.parse::<f64>().unwrap(),
                "p" => known.p = val.parse::<f64>().unwrap(),
                "se" => known.se = val.parse::<f64>().unwrap(),
                _ => panic!("Unknown key in known answer file"),
            }

            keys_read.insert(key.to_string());
        }

        assert_eq!(keys_read.len(), 6, "Missing lines in known answer file");

        known
    }
}

macro_rules! assert_appx_eq {
    ($name:expr, $tolerance:expr, $known:expr, $actual:expr) => {
        let d = ($known - $actual).abs();

        let err = format!("{}: {} and {} differ by {} > {}",
                          $name, $known, $actual, d, $tolerance);

        assert!(d < $tolerance, err);
    };
}

#[macro_export]
macro_rules! summary_kat {
    ($test_name:tt, $name:expr) => {
        #[test]
        fn $test_name() {
            use dent::summary::Summarizer;
            use $crate::common::{KnownSummary, read_data};

            let data_path = format!("{}/{}", "support/data", $name);
            let data = read_data(&data_path);
            let summary = Summarizer::new(&data).unwrap();

            let known_path = format!("{}{}", "support/kat/summary_", $name);
            let known = KnownSummary::new(&known_path);

            let precision = 1e-14;

            assert_appx_eq!("Size", precision,
                            known.size, summary.size());
            assert_appx_eq!("Min", precision,
                            known.min, summary.min());
            assert_appx_eq!("Max", precision,
                            known.max, summary.max());
            assert_appx_eq!("Median", precision,
                            known.median, summary.median());
            assert_appx_eq!("Mean", precision,
                            known.mean, summary.mean());
            assert_appx_eq!("Lower quartile", precision,
                            known.lower_quartile, summary.percentile(0.25).unwrap());
            assert_appx_eq!("Upper quartile", precision,
                            known.upper_quartile, summary.percentile(0.75).unwrap());
            assert_appx_eq!("Variance", precision,
                            known.variance, summary.unbiased_variance());
            assert_appx_eq!("Standard deviation", precision,
                            known.standard_deviation, summary.standard_deviation());
            assert_appx_eq!("Standard error", precision,
                            known.standard_error, summary.standard_error());
        }
    }
}

#[macro_export]
macro_rules! t_test_kat {
    ($test_name:tt, $name:expr) => {
        #[test]
        fn $test_name() {
            use dent::summary::Summary;
            use dent::t_test::{SigLevel, welch_t_test};
            use $crate::common::{KnownTTest, read_data};

            let known_path = format!("{}/{}", "support/kat", $name);
            let known = KnownTTest::new(&known_path);

            let data_path1 = format!("{}/{}", "support/data", known.src1);
            let data1 = read_data(&data_path1);
            let summary1 = Summary::new(&data1).unwrap();

            let data_path2 = format!("{}/{}", "support/data", known.src2);
            let data2 = read_data(&data_path2);
            let summary2 = Summary::new(&data2).unwrap();

            let t_test = welch_t_test(&summary1, &summary2, SigLevel::Alpha005);

            let precision = 1e-11 ;

            assert_appx_eq!("T statistic", precision,
                            known.t, t_test.t);
        }
    }
}

#[macro_export]
macro_rules! lr_kat {
    ($test_name:tt, $name:expr) => {
        #[test]
        fn $test_name() {
            use dent::lr::LinearRegression;
            use $crate::common::{KnownLR, read_data};

            let x_path = format!("{}/{}-x", "support/data", $name);
            let x = read_data(&x_path);

            let y_path = format!("{}/{}-y", "support/data", $name);
            let y = read_data(&y_path);

            let lr = LinearRegression::new(&x, &y).unwrap();

            let known_path = format!("{}/{}", "support/kat", $name);
            let known = KnownLR::new(&known_path);

            let precision = 1e-9;

            assert_appx_eq!("Slope", precision, known.slope, lr.slope);
            assert_appx_eq!("Intercept", precision, known.intercept, lr.intercept);
            assert_appx_eq!("R", precision, known.r, lr.r);

            // We dont compute these right now.
            // assert_appx_eq!("P", precision, known.p, lr.p);
            // assert_appx_eq!("Standard Error", precision, known.se, lr.se);
        }
    }
}
<|endoftext|>


<commit_before>#![cfg(feature="quickcheck")]
extern crate quickcheck;

extern crate petgraph;

use petgraph::{Graph, GraphMap, Undirected, Directed, EdgeType, Incoming, Outgoing};
use petgraph::algo::{min_spanning_tree, is_cyclic_undirected, is_isomorphic};
use petgraph::graph::IndexType;

fn prop(g: Graph<(), u32>) -> bool {
    // filter out isolated nodes
    let no_singles = g.filter_map(
        |nx, w| g.neighbors_undirected(nx).next().map(|_| w),
        |_, w| Some(w));
    for i in no_singles.node_indices() {
        assert!(no_singles.neighbors_undirected(i).count() > 0);
    }
    assert_eq!(no_singles.edge_count(), g.edge_count());
    let mst = min_spanning_tree(&no_singles);
    assert!(!is_cyclic_undirected(&mst));
    true
}

fn prop_undir(g: Graph<(), u32, Undirected>) -> bool {
    // filter out isolated nodes
    let no_singles = g.filter_map(
        |nx, w| g.neighbors_undirected(nx).next().map(|_| w),
        |_, w| Some(w));
    for i in no_singles.node_indices() {
        assert!(no_singles.neighbors_undirected(i).count() > 0);
    }
    assert_eq!(no_singles.edge_count(), g.edge_count());
    let mst = min_spanning_tree(&no_singles);
    assert!(!is_cyclic_undirected(&mst));
    true
}

#[test]
fn arbitrary() {
    quickcheck::quickcheck(prop as fn(_) -> bool);
    quickcheck::quickcheck(prop_undir as fn(_) -> bool);
}

#[test]
fn reverse_undirected() {
    fn prop<Ty: EdgeType>(g: Graph<(), (), Ty>) -> bool {
        if g.edge_count() > 30 {
            return true; // iso too slow
        }
        let mut h = g.clone();
        h.reverse();
        is_isomorphic(&g, &h)
    }
    quickcheck::quickcheck(prop as fn(Graph<_, _, Undirected>) -> bool);
}

fn assert_graph_consistent<N, E, Ty, Ix>(g: &Graph<N, E, Ty, Ix>)
    where Ty: EdgeType,
          Ix: IndexType,
{
    assert_eq!(g.node_count(), g.node_indices().count());
    assert_eq!(g.edge_count(), g.edge_indices().count());
    for edge in g.raw_edges() {
        assert!(g.find_edge(edge.source(), edge.target()).is_some(),
                "Edge not in graph! {:?} to {:?}", edge.source(), edge.target());
    }
}

#[test]
fn reverse_directed() {
    fn prop<Ty: EdgeType>(mut g: Graph<(), (), Ty>) -> bool {
        let node_outdegrees = g.node_indices()
                                .map(|i| g.neighbors_directed(i, Outgoing).count())
                                .collect::<Vec<_>>();
        let node_indegrees = g.node_indices()
                                .map(|i| g.neighbors_directed(i, Incoming).count())
                                .collect::<Vec<_>>();

        g.reverse();
        let new_outdegrees = g.node_indices()
                                .map(|i| g.neighbors_directed(i, Outgoing).count())
                                .collect::<Vec<_>>();
        let new_indegrees = g.node_indices()
                                .map(|i| g.neighbors_directed(i, Incoming).count())
                                .collect::<Vec<_>>();
        assert_eq!(node_outdegrees, new_indegrees);
        assert_eq!(node_indegrees, new_outdegrees);
        assert_graph_consistent(&g);
        true
    }
    quickcheck::quickcheck(prop as fn(Graph<_, _, Directed>) -> bool);
}

#[test]
fn retain_nodes() {
    fn prop<Ty: EdgeType>(mut g: Graph<i32, (), Ty>) -> bool {
        // Remove all negative nodes, these should be randomly spread
        let og = g.clone();
        let nodes = g.node_count();
        let num_negs = g.raw_nodes().iter().filter(|n| n.weight < 0).count();
        let mut removed = 0;
        g.retain_nodes(|g, i| {
            let keep = g[i] >= 0;
            if !keep {
                removed += 1;
            }
            keep
        });
        let num_negs_post = g.raw_nodes().iter().filter(|n| n.weight < 0).count();
        let num_pos_post = g.raw_nodes().iter().filter(|n| n.weight >= 0).count();
        assert_eq!(num_negs_post, 0);
        assert_eq!(removed, num_negs);
        assert_eq!(num_negs + g.node_count(), nodes);
        assert_eq!(num_pos_post, g.node_count());
        if og.edge_count() < 30 {
            // check against filter_map
            let filtered = og.filter_map(|_, w| if *w >= 0 { Some(*w) } else { None },
                                         |_, w| Some(*w));
            assert_eq!(g.node_count(), filtered.node_count());
            assert!(is_isomorphic(&filtered, &g));
        }
        true
    }
    quickcheck::quickcheck(prop as fn(Graph<_, _, Directed>) -> bool);
    quickcheck::quickcheck(prop as fn(Graph<_, _, Undirected>) -> bool);
}

#[test]
fn retain_edges() {
    fn prop<Ty: EdgeType>(mut g: Graph<(), i32, Ty>) -> bool {
        // Remove all negative edges, these should be randomly spread
        let og = g.clone();
        let edges = g.edge_count();
        let num_negs = g.raw_edges().iter().filter(|n| n.weight < 0).count();
        let mut removed = 0;
        g.retain_edges(|g, i| {
            let keep = g[i] >= 0;
            if !keep {
                removed += 1;
            }
            keep
        });
        let num_negs_post = g.raw_edges().iter().filter(|n| n.weight < 0).count();
        let num_pos_post = g.raw_edges().iter().filter(|n| n.weight >= 0).count();
        assert_eq!(num_negs_post, 0);
        assert_eq!(removed, num_negs);
        assert_eq!(num_negs + g.edge_count(), edges);
        assert_eq!(num_pos_post, g.edge_count());
        if og.edge_count() < 30 {
            // check against filter_map
            let filtered = og.filter_map(
                |_, w| Some(*w),
                |_, w| if *w >= 0 { Some(*w) } else { None });
            assert_eq!(g.node_count(), filtered.node_count());
            assert!(is_isomorphic(&filtered, &g));
        }
        true
    }
    quickcheck::quickcheck(prop as fn(Graph<_, _, Directed>) -> bool);
    quickcheck::quickcheck(prop as fn(Graph<_, _, Undirected>) -> bool);
}

#[test]
fn graphmap_remove() {
    fn prop(mut g: GraphMap<i8, ()>, a: i8, b: i8) -> bool {
        let contains = g.contains_edge(a, b);
        assert_eq!(contains, g.contains_edge(b, a));
        assert_eq!(g.remove_edge(a, b).is_some(), contains);
        assert!(!g.contains_edge(a, b) &&
            g.neighbors(a).find(|x| *x == b).is_none() &&
            g.neighbors(b).find(|x| *x == a).is_none());
        assert!(g.remove_edge(a, b).is_none());
        true
    }
    quickcheck::quickcheck(prop as fn(_, _, _) -> bool);
}

#[test]
fn graphmap_add_remove() {
    fn prop(mut g: GraphMap<i8, ()>, a: i8, b: i8) -> bool {
        assert_eq!(g.contains_edge(a, b), !g.add_edge(a, b, ()));
        g.remove_edge(a, b);
        !g.contains_edge(a, b) &&
            g.neighbors(a).find(|x| *x == b).is_none() &&
            g.neighbors(b).find(|x| *x == a).is_none()
    }
    quickcheck::quickcheck(prop as fn(_, _, _) -> bool);
}
<commit_msg>Add quickcheck for Graph::remove_edge<commit_after>#![cfg(feature="quickcheck")]
extern crate quickcheck;

extern crate petgraph;

use petgraph::{Graph, GraphMap, Undirected, Directed, EdgeType, Incoming, Outgoing};
use petgraph::algo::{min_spanning_tree, is_cyclic_undirected, is_isomorphic};
use petgraph::graph::{IndexType, node_index};

fn prop(g: Graph<(), u32>) -> bool {
    // filter out isolated nodes
    let no_singles = g.filter_map(
        |nx, w| g.neighbors_undirected(nx).next().map(|_| w),
        |_, w| Some(w));
    for i in no_singles.node_indices() {
        assert!(no_singles.neighbors_undirected(i).count() > 0);
    }
    assert_eq!(no_singles.edge_count(), g.edge_count());
    let mst = min_spanning_tree(&no_singles);
    assert!(!is_cyclic_undirected(&mst));
    true
}

fn prop_undir(g: Graph<(), u32, Undirected>) -> bool {
    // filter out isolated nodes
    let no_singles = g.filter_map(
        |nx, w| g.neighbors_undirected(nx).next().map(|_| w),
        |_, w| Some(w));
    for i in no_singles.node_indices() {
        assert!(no_singles.neighbors_undirected(i).count() > 0);
    }
    assert_eq!(no_singles.edge_count(), g.edge_count());
    let mst = min_spanning_tree(&no_singles);
    assert!(!is_cyclic_undirected(&mst));
    true
}

#[test]
fn arbitrary() {
    quickcheck::quickcheck(prop as fn(_) -> bool);
    quickcheck::quickcheck(prop_undir as fn(_) -> bool);
}

#[test]
fn reverse_undirected() {
    fn prop<Ty: EdgeType>(g: Graph<(), (), Ty>) -> bool {
        if g.edge_count() > 30 {
            return true; // iso too slow
        }
        let mut h = g.clone();
        h.reverse();
        is_isomorphic(&g, &h)
    }
    quickcheck::quickcheck(prop as fn(Graph<_, _, Undirected>) -> bool);
}

fn assert_graph_consistent<N, E, Ty, Ix>(g: &Graph<N, E, Ty, Ix>)
    where Ty: EdgeType,
          Ix: IndexType,
{
    assert_eq!(g.node_count(), g.node_indices().count());
    assert_eq!(g.edge_count(), g.edge_indices().count());
    for edge in g.raw_edges() {
        assert!(g.find_edge(edge.source(), edge.target()).is_some(),
                "Edge not in graph! {:?} to {:?}", edge.source(), edge.target());
    }
}

#[test]
fn reverse_directed() {
    fn prop<Ty: EdgeType>(mut g: Graph<(), (), Ty>) -> bool {
        let node_outdegrees = g.node_indices()
                                .map(|i| g.neighbors_directed(i, Outgoing).count())
                                .collect::<Vec<_>>();
        let node_indegrees = g.node_indices()
                                .map(|i| g.neighbors_directed(i, Incoming).count())
                                .collect::<Vec<_>>();

        g.reverse();
        let new_outdegrees = g.node_indices()
                                .map(|i| g.neighbors_directed(i, Outgoing).count())
                                .collect::<Vec<_>>();
        let new_indegrees = g.node_indices()
                                .map(|i| g.neighbors_directed(i, Incoming).count())
                                .collect::<Vec<_>>();
        assert_eq!(node_outdegrees, new_indegrees);
        assert_eq!(node_indegrees, new_outdegrees);
        assert_graph_consistent(&g);
        true
    }
    quickcheck::quickcheck(prop as fn(Graph<_, _, Directed>) -> bool);
}

#[test]
fn retain_nodes() {
    fn prop<Ty: EdgeType>(mut g: Graph<i32, (), Ty>) -> bool {
        // Remove all negative nodes, these should be randomly spread
        let og = g.clone();
        let nodes = g.node_count();
        let num_negs = g.raw_nodes().iter().filter(|n| n.weight < 0).count();
        let mut removed = 0;
        g.retain_nodes(|g, i| {
            let keep = g[i] >= 0;
            if !keep {
                removed += 1;
            }
            keep
        });
        let num_negs_post = g.raw_nodes().iter().filter(|n| n.weight < 0).count();
        let num_pos_post = g.raw_nodes().iter().filter(|n| n.weight >= 0).count();
        assert_eq!(num_negs_post, 0);
        assert_eq!(removed, num_negs);
        assert_eq!(num_negs + g.node_count(), nodes);
        assert_eq!(num_pos_post, g.node_count());
        if og.edge_count() < 30 {
            // check against filter_map
            let filtered = og.filter_map(|_, w| if *w >= 0 { Some(*w) } else { None },
                                         |_, w| Some(*w));
            assert_eq!(g.node_count(), filtered.node_count());
            assert!(is_isomorphic(&filtered, &g));
        }
        true
    }
    quickcheck::quickcheck(prop as fn(Graph<_, _, Directed>) -> bool);
    quickcheck::quickcheck(prop as fn(Graph<_, _, Undirected>) -> bool);
}

#[test]
fn retain_edges() {
    fn prop<Ty: EdgeType>(mut g: Graph<(), i32, Ty>) -> bool {
        // Remove all negative edges, these should be randomly spread
        let og = g.clone();
        let edges = g.edge_count();
        let num_negs = g.raw_edges().iter().filter(|n| n.weight < 0).count();
        let mut removed = 0;
        g.retain_edges(|g, i| {
            let keep = g[i] >= 0;
            if !keep {
                removed += 1;
            }
            keep
        });
        let num_negs_post = g.raw_edges().iter().filter(|n| n.weight < 0).count();
        let num_pos_post = g.raw_edges().iter().filter(|n| n.weight >= 0).count();
        assert_eq!(num_negs_post, 0);
        assert_eq!(removed, num_negs);
        assert_eq!(num_negs + g.edge_count(), edges);
        assert_eq!(num_pos_post, g.edge_count());
        if og.edge_count() < 30 {
            // check against filter_map
            let filtered = og.filter_map(
                |_, w| Some(*w),
                |_, w| if *w >= 0 { Some(*w) } else { None });
            assert_eq!(g.node_count(), filtered.node_count());
            assert!(is_isomorphic(&filtered, &g));
        }
        true
    }
    quickcheck::quickcheck(prop as fn(Graph<_, _, Directed>) -> bool);
    quickcheck::quickcheck(prop as fn(Graph<_, _, Undirected>) -> bool);
}

#[test]
fn graph_remove_edge() {
    fn prop<Ty: EdgeType>(mut g: Graph<(), (), Ty>, a: u8, b: u8) -> bool {
        let a = node_index(a as usize);
        let b = node_index(b as usize);
        let edge = g.find_edge(a, b);
        if !g.is_directed() {
            assert_eq!(edge.is_some(), g.find_edge(b, a).is_some());
        }
        if let Some(ex) = edge {
            assert!(g.remove_edge(ex).is_some());
        }
        assert_graph_consistent(&g);
        assert!(g.find_edge(a, b).is_none());
        assert!(g.neighbors(a).find(|x| *x == b).is_none());
        if !g.is_directed() {
            assert!(g.neighbors(b).find(|x| *x == a).is_none());
        }
        true
    }
    quickcheck::quickcheck(prop as fn(Graph<_, _, Undirected>, _, _) -> bool);
    quickcheck::quickcheck(prop as fn(Graph<_, _, Directed>, _, _) -> bool);
}

#[test]
fn graphmap_remove() {
    fn prop(mut g: GraphMap<i8, ()>, a: i8, b: i8) -> bool {
        let contains = g.contains_edge(a, b);
        assert_eq!(contains, g.contains_edge(b, a));
        assert_eq!(g.remove_edge(a, b).is_some(), contains);
        assert!(!g.contains_edge(a, b) &&
            g.neighbors(a).find(|x| *x == b).is_none() &&
            g.neighbors(b).find(|x| *x == a).is_none());
        assert!(g.remove_edge(a, b).is_none());
        true
    }
    quickcheck::quickcheck(prop as fn(_, _, _) -> bool);
}

#[test]
fn graphmap_add_remove() {
    fn prop(mut g: GraphMap<i8, ()>, a: i8, b: i8) -> bool {
        assert_eq!(g.contains_edge(a, b), !g.add_edge(a, b, ()));
        g.remove_edge(a, b);
        !g.contains_edge(a, b) &&
            g.neighbors(a).find(|x| *x == b).is_none() &&
            g.neighbors(b).find(|x| *x == a).is_none()
    }
    quickcheck::quickcheck(prop as fn(_, _, _) -> bool);
}
<|endoftext|>


<commit_before>extern crate disqrust;
extern crate disque;
extern crate redis;

use std::time::Duration;
use std::sync::mpsc::{channel, Sender};

use disque::Disque;
use disqrust::{EventLoop, Handler, JobStatus};
use redis::Value;

enum HandlerCall {
    Job(Vec<u8>, String, Vec<u8>),
    Error(Vec<u8>, String, u32, u32),
}

impl HandlerCall {
    fn body(&self) -> Vec<u8> {
        match *self {
            HandlerCall::Job(_, _, ref body) => body.clone(),
            HandlerCall::Error(_, _, _, _) => panic!("getting body for error"),
        }
    }

    fn nack_additional_deliveries(&self) -> (u32, u32) {
        match *self {
            HandlerCall::Job(_, _, _) => panic!("getting nack for job"),
            HandlerCall::Error(_, _, a, b) => (a, b),
        }
    }
}

#[derive(Clone)]
struct MyHandler {
    sender: Sender<HandlerCall>,
    process_job_ret: JobStatus,
    process_error_ret: bool,
}

impl MyHandler {
    fn new(sender: Sender<HandlerCall>, process_job_ret: JobStatus,
            process_error_ret: bool) -> MyHandler {
        MyHandler {
            sender: sender,
            process_job_ret: process_job_ret,
            process_error_ret: process_error_ret,
        }
    }
}

impl Handler for MyHandler {
    fn process_job(&self, queue_name: &[u8], jobid: &String, body: Vec<u8>
            ) -> JobStatus {
        self.sender.send(HandlerCall::Job(queue_name.to_vec(), jobid.clone(),
                    body)).unwrap();
        self.process_job_ret.clone()
    }

    fn process_error(&self, queue_name: &[u8], jobid: &String, nack: u32,
            additional_deliveries: u32) -> bool {
        self.sender.send(HandlerCall::Error(queue_name.to_vec(), jobid.clone(),
                    nack, additional_deliveries)).unwrap();
        self.process_error_ret
    }
}

#[cfg(test)]
fn create_job(queue: &[u8], job: &[u8], nack: bool
        ) -> (Disque, Vec<u8>, Vec<u8>, String) {
    let disque = Disque::open("redis://127.0.0.1:7711/").unwrap();
    let jobid = disque.addjob(queue, job, Duration::from_secs(10), None,
            None, None, None, None, false).unwrap();
    if nack {
        disque.getjob(true, None, &[queue]).unwrap();
        disque.nackjob(jobid.as_bytes()).unwrap();
    }
    (disque, queue.to_vec(), job.to_vec(), jobid)
}

#[test]
fn basic() {
    let (disque, queue, job, _) = create_job(b"basic", b"job67", false);

    let (tx, rx) = channel();
    let handler = MyHandler::new(tx, JobStatus::AckJob, true);
    let mut el = EventLoop::new(disque, 1, handler);
    el.watch_queue(queue.to_vec());
    el.run_times(1);
    el.stop();
    assert_eq!(rx.try_recv().unwrap().body(), job);
    assert!(rx.try_recv().is_err());
}

#[test]
fn error() {
    let (disque, queue, _, _) = create_job(b"error", b"job456", true);

    let (tx, rx) = channel();
    let handler = MyHandler::new(tx, JobStatus::AckJob, false);
    let mut el = EventLoop::new(disque, 1, handler);
    el.watch_queue(queue.to_vec());
    el.run_times(1);
    el.stop();
    assert_eq!(rx.try_recv().unwrap().nack_additional_deliveries(), (1, 0));
    assert!(rx.try_recv().is_err());
}

#[test]
fn error_and_job() {
    let (disque, queue, job, _) = create_job(b"errorandjob", b"job123", true);

    let (tx, rx) = channel();
    let handler = MyHandler::new(tx, JobStatus::AckJob, true);
    let mut el = EventLoop::new(disque, 1, handler);
    el.watch_queue(queue.to_vec());
    el.run_times(1);
    el.stop();
    assert_eq!(rx.try_recv().unwrap().nack_additional_deliveries(), (1, 0));
    assert_eq!(rx.try_recv().unwrap().body(), job);
    assert!(rx.try_recv().is_err());
}

#[test]
fn fastack() {
    let (disque, queue, _, jobid) = create_job(b"fastack", b"job123", false);

    assert!(disque.show(jobid.as_bytes()).unwrap().is_some());

    let (tx, rx) = channel();
    let handler = MyHandler::new(tx, JobStatus::FastAck, true);
    let mut el = EventLoop::new(disque, 1, handler);
    el.watch_queue(queue.to_vec());
    el.run_times(1);
    el.stop();
    rx.try_recv().unwrap();

    let disque = Disque::open("redis://127.0.0.1:7711/").unwrap();
    assert!(disque.show(jobid.as_bytes()).unwrap().is_none());
}

#[test]
fn ackjob() {
    let (disque, queue, _, jobid) = create_job(b"ackjob", b"job123", false);

    assert!(disque.show(jobid.as_bytes()).unwrap().is_some());

    let (tx, rx) = channel();
    let handler = MyHandler::new(tx, JobStatus::AckJob, true);
    let mut el = EventLoop::new(disque, 1, handler);
    el.watch_queue(queue.to_vec());
    el.run_times(1);
    el.stop();
    rx.try_recv().unwrap();

    let disque = Disque::open("redis://127.0.0.1:7711/").unwrap();
    assert!(disque.show(jobid.as_bytes()).unwrap().is_none());
}

#[test]
fn nack() {
    let (disque, queue, _, jobid) = create_job(b"nack", b"job000", false);

    let (tx, rx) = channel();
    let handler = MyHandler::new(tx, JobStatus::NAck, true);
    let mut el = EventLoop::new(disque, 1, handler);
    el.watch_queue(queue.to_vec());

    el.run_times(3);
    el.stop();
    rx.try_recv().unwrap();
    rx.try_recv().unwrap();
    rx.try_recv().unwrap();

    let disque = Disque::open("redis://127.0.0.1:7711/").unwrap();
    assert_eq!(*disque.show(jobid.as_bytes()).unwrap().unwrap().get(
                "nacks").unwrap(),
            Value::Int(3));
    disque.ackjob(jobid.as_bytes()).unwrap();
}

#[test]
fn jobcount_current_node() {
    let (disque, queue, _, _) = create_job(b"ackjob", b"job123", false);

    let (tx, rx) = channel();
    let handler = MyHandler::new(tx, JobStatus::AckJob, true);
    let mut el = EventLoop::new(disque, 1, handler);
    el.watch_queue(queue.to_vec());
    el.run_times(1);

    assert!(el.jobcount_current_node() >= 1);
    el.stop();
    rx.try_recv().unwrap();
}

#[test]
fn change_servers() {
    let disque = Disque::open("redis://127.0.0.1:7711/").unwrap();
    // This test does not apply when there is only one server
    let hello = disque.hello().unwrap();
    if hello.2.len() == 1 {
        return;
    }
    let disque2 = Disque::open(&*format!("redis://{}:{}/",
                hello.2[1].1, hello.2[1].2)).unwrap();

    let (tx, rx) = channel();

    let handler = MyHandler::new(tx, JobStatus::AckJob, true);
    let mut el = EventLoop::new(disque2, 1, handler);
    let oldid = el.current_node_id();
    let queue = b"change_servers";
    let job = b"job";

    el.watch_queue(queue.to_vec());

    let att = 20;
    for _ in 0..att {
        disque.addjob(queue, job, Duration::from_secs(10), None,
                None, None, None, None, false).unwrap();
        el.run_times(1);
        el.do_cycle();
        let newid = el.current_node_id();
        if newid != oldid {
            rx.try_recv().unwrap();
            return;
        }
    }

    panic!("After {} attempts it did not change node", att);
}
<commit_msg>Add queue test<commit_after>#![feature(duration_span)]
extern crate disqrust;
extern crate disque;
extern crate redis;

use std::time::Duration;
use std::sync::mpsc::{channel, Sender};

use disque::Disque;
use disqrust::{EventLoop, Handler, JobStatus};
use redis::Value;

enum HandlerCall {
    Job(Vec<u8>, String, Vec<u8>),
    Error(Vec<u8>, String, u32, u32),
}

impl HandlerCall {
    fn body(&self) -> Vec<u8> {
        match *self {
            HandlerCall::Job(_, _, ref body) => body.clone(),
            HandlerCall::Error(_, _, _, _) => panic!("getting body for error"),
        }
    }

    fn nack_additional_deliveries(&self) -> (u32, u32) {
        match *self {
            HandlerCall::Job(_, _, _) => panic!("getting nack for job"),
            HandlerCall::Error(_, _, a, b) => (a, b),
        }
    }
}

#[derive(Clone)]
struct MyHandler {
    sender: Sender<HandlerCall>,
    process_job_ret: JobStatus,
    process_error_ret: bool,
    sleep: Option<u32>,
}

impl MyHandler {
    fn new(sender: Sender<HandlerCall>, process_job_ret: JobStatus,
            process_error_ret: bool) -> MyHandler {
        MyHandler {
            sender: sender,
            process_job_ret: process_job_ret,
            process_error_ret: process_error_ret,
            sleep: None,
        }
    }

    fn set_sleep(&mut self, sleep: Option<u32>) {
        self.sleep = sleep;
    }
}

impl Handler for MyHandler {
    fn process_job(&self, queue_name: &[u8], jobid: &String, body: Vec<u8>
            ) -> JobStatus {
        if let Some(sleep) = self.sleep {
            std::thread::sleep_ms(sleep);
        }
        self.sender.send(HandlerCall::Job(queue_name.to_vec(), jobid.clone(),
                    body)).unwrap();
        self.process_job_ret.clone()
    }

    fn process_error(&self, queue_name: &[u8], jobid: &String, nack: u32,
            additional_deliveries: u32) -> bool {
        self.sender.send(HandlerCall::Error(queue_name.to_vec(), jobid.clone(),
                    nack, additional_deliveries)).unwrap();
        self.process_error_ret
    }
}

#[cfg(test)]
fn create_job(queue: &[u8], job: &[u8], nack: bool
        ) -> (Disque, Vec<u8>, Vec<u8>, String) {
    let disque = Disque::open("redis://127.0.0.1:7711/").unwrap();
    let jobid = disque.addjob(queue, job, Duration::from_secs(10), None,
            None, None, None, None, false).unwrap();
    if nack {
        disque.getjob(true, None, &[queue]).unwrap();
        disque.nackjob(jobid.as_bytes()).unwrap();
    }
    (disque, queue.to_vec(), job.to_vec(), jobid)
}

#[test]
fn basic() {
    let (disque, queue, job, _) = create_job(b"basic", b"job67", false);

    let (tx, rx) = channel();
    let handler = MyHandler::new(tx, JobStatus::AckJob, true);
    let mut el = EventLoop::new(disque, 1, handler);
    el.watch_queue(queue.to_vec());
    el.run_times(1);
    el.stop();
    assert_eq!(rx.try_recv().unwrap().body(), job);
    assert!(rx.try_recv().is_err());
}

#[test]
fn error() {
    let (disque, queue, _, _) = create_job(b"error", b"job456", true);

    let (tx, rx) = channel();
    let handler = MyHandler::new(tx, JobStatus::AckJob, false);
    let mut el = EventLoop::new(disque, 1, handler);
    el.watch_queue(queue.to_vec());
    el.run_times(1);
    el.stop();
    assert_eq!(rx.try_recv().unwrap().nack_additional_deliveries(), (1, 0));
    assert!(rx.try_recv().is_err());
}

#[test]
fn error_and_job() {
    let (disque, queue, job, _) = create_job(b"errorandjob", b"job123", true);

    let (tx, rx) = channel();
    let handler = MyHandler::new(tx, JobStatus::AckJob, true);
    let mut el = EventLoop::new(disque, 1, handler);
    el.watch_queue(queue.to_vec());
    el.run_times(1);
    el.stop();
    assert_eq!(rx.try_recv().unwrap().nack_additional_deliveries(), (1, 0));
    assert_eq!(rx.try_recv().unwrap().body(), job);
    assert!(rx.try_recv().is_err());
}

#[test]
fn fastack() {
    let (disque, queue, _, jobid) = create_job(b"fastack", b"job123", false);

    assert!(disque.show(jobid.as_bytes()).unwrap().is_some());

    let (tx, rx) = channel();
    let handler = MyHandler::new(tx, JobStatus::FastAck, true);
    let mut el = EventLoop::new(disque, 1, handler);
    el.watch_queue(queue.to_vec());
    el.run_times(1);
    el.stop();
    rx.try_recv().unwrap();

    let disque = Disque::open("redis://127.0.0.1:7711/").unwrap();
    assert!(disque.show(jobid.as_bytes()).unwrap().is_none());
}

#[test]
fn ackjob() {
    let (disque, queue, _, jobid) = create_job(b"ackjob", b"job123", false);

    assert!(disque.show(jobid.as_bytes()).unwrap().is_some());

    let (tx, rx) = channel();
    let handler = MyHandler::new(tx, JobStatus::AckJob, true);
    let mut el = EventLoop::new(disque, 1, handler);
    el.watch_queue(queue.to_vec());
    el.run_times(1);
    el.stop();
    rx.try_recv().unwrap();

    let disque = Disque::open("redis://127.0.0.1:7711/").unwrap();
    assert!(disque.show(jobid.as_bytes()).unwrap().is_none());
}

#[test]
fn nack() {
    let (disque, queue, _, jobid) = create_job(b"nack", b"job000", false);

    let (tx, rx) = channel();
    let handler = MyHandler::new(tx, JobStatus::NAck, true);
    let mut el = EventLoop::new(disque, 1, handler);
    el.watch_queue(queue.to_vec());

    el.run_times(3);
    el.stop();
    rx.try_recv().unwrap();
    rx.try_recv().unwrap();
    rx.try_recv().unwrap();

    let disque = Disque::open("redis://127.0.0.1:7711/").unwrap();
    assert_eq!(*disque.show(jobid.as_bytes()).unwrap().unwrap().get(
                "nacks").unwrap(),
            Value::Int(3));
    disque.ackjob(jobid.as_bytes()).unwrap();
}

#[test]
fn jobcount_current_node() {
    let (disque, queue, _, _) = create_job(b"ackjob", b"job123", false);

    let (tx, rx) = channel();
    let handler = MyHandler::new(tx, JobStatus::AckJob, true);
    let mut el = EventLoop::new(disque, 1, handler);
    el.watch_queue(queue.to_vec());
    el.run_times(1);

    assert!(el.jobcount_current_node() >= 1);
    el.stop();
    rx.try_recv().unwrap();
}

#[test]
fn change_servers() {
    let disque = Disque::open("redis://127.0.0.1:7711/").unwrap();
    // This test does not apply when there is only one server
    let hello = disque.hello().unwrap();
    if hello.2.len() == 1 {
        return;
    }
    let disque2 = Disque::open(&*format!("redis://{}:{}/",
                hello.2[1].1, hello.2[1].2)).unwrap();

    let (tx, rx) = channel();

    let handler = MyHandler::new(tx, JobStatus::AckJob, true);
    let mut el = EventLoop::new(disque2, 1, handler);
    let oldid = el.current_node_id();
    let queue = b"change_servers";
    let job = b"job";

    el.watch_queue(queue.to_vec());

    let att = 20;
    for _ in 0..att {
        disque.addjob(queue, job, Duration::from_secs(10), None,
                None, None, None, None, false).unwrap();
        el.run_times(1);
        el.do_cycle();
        let newid = el.current_node_id();
        if newid != oldid {
            rx.try_recv().unwrap();
            return;
        }
    }

    panic!("After {} attempts it did not change node", att);
}

#[test]
fn queueing() {
    let disque = Disque::open("redis://127.0.0.1:7711/").unwrap();
    // This test does not apply when there is only one server
    let hello = disque.hello().unwrap();
    if hello.2.len() == 1 {
        return;
    }
    let disque2 = Disque::open(&*format!("redis://{}:{}/",
                hello.2[1].1, hello.2[1].2)).unwrap();

    let (tx, rx) = channel();

    let mut handler = MyHandler::new(tx, JobStatus::AckJob, true);
    handler.set_sleep(Some(200));
    let mut el = EventLoop::new(disque2, 1, handler);
    let queue = b"queueing";
    el.watch_queue(queue.to_vec());

    let d = Duration::span(|| {
        disque.addjob(queue, b"job1", Duration::from_secs(10), None,
                None, None, None, None, false).unwrap();
        disque.addjob(queue, b"job2", Duration::from_secs(10), None,
                None, None, None, None, false).unwrap();
        disque.addjob(queue, b"job3", Duration::from_secs(10), None,
                None, None, None, None, false).unwrap();
        el.run_times(3);
        el.stop();
    });
    assert_eq!(rx.try_recv().unwrap().body(), b"job1");
    assert_eq!(rx.try_recv().unwrap().body(), b"job2");
    assert_eq!(rx.try_recv().unwrap().body(), b"job3");
    assert_eq!(d.as_secs(), 0);
    assert!(d.subsec_nanos() >= 600_000_000);
    assert!(d.subsec_nanos() <= 999_999_999);
}
<|endoftext|>