<commit_before>use std::process::{Command, Stdio};
use std::io::Cursor;
use std::sync::Arc;
use std::time::Duration;

use tokio::prelude::*;
use tokio::prelude::future::Either;
use tokio::timer::timeout;
use tokio_process::CommandExt;
use tokio::{io::{flush, read_exact, write_all}, net::unix::UnixStream};
use bytes::{BytesMut, Buf, BufMut};

use crate::{ExecBackend, UnixSocketBackend};

pub fn exec<'a, T>(
    lang: Arc<ExecBackend>,
    timeout: Option<usize>,
    code: T) -> impl Future<Item = String, Error = String> + 'a
        where T: AsRef<[u8]> + 'a {
    let timeout_arg = timeout
        .map(|t| format!("{}{}", lang.timeout_prefix.as_ref().map(String::as_str).unwrap_or(""), t));
    let timeout_arg_ref = timeout_arg.as_ref().map(String::as_str);
    if let Some(path) = lang.cmdline.iter().nth(0) {
        let mut cmd = Command::new(path);
        cmd.args(lang.cmdline.iter()
            .skip(1)
            .filter_map(|a| if a == "{TIMEOUT}" {
                timeout_arg_ref
            } else {
                Some(a.as_ref())
            }))
            .stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::piped());
        debug!("spawning {:?}", cmd);
        Either::A(cmd.spawn_async()
            .map_err(|e| format!("failed to exec: {}", e))
            .into_future()
            .and_then(|mut child| {
                child.stdin().take().ok_or_else(|| "stdin missing".to_owned()).into_future()
                    .and_then(|stdin|
                        write_all(stdin, code)
                            .map_err(|e| format!("failed to write to stdin: {}", e))
                    )
                    .and_then(|_| child.wait_with_output()
                        .map_err(|e| format!("failed to wait for process: {}", e)))
            })
            .map_err(|e| format!("unknown error in exec: {}", e))
            .map(|o| {
                let mut r = format!("{}{}",
                    String::from_utf8_lossy(&o.stderr),
                    String::from_utf8_lossy(&o.stdout),
                );
                if !o.status.success() {
                    if !r.ends_with('\n') {
                        r.push_str("\n");
                    }
                    if let Some(code) = o.status.code() {
                        r.push_str(&format!("exited with status {}\n", code));
                    } else {
                        r.push_str("exited with unknown failure\n");
                    }
                }
                r
            }))
    } else {
        Either::B(Err("empty cmdline".to_owned()).into_future())
    }
}

macro_rules! persistent {
    ($lang:expr, $connfut:expr, $timeout:expr, $buf:expr) => ({
        let buf = $buf;
        let fut = $connfut
            .map_err(|e| format!("error connecting: {}", e))
            .and_then(move |s| write_all(s, buf)
                .map_err(|e| format!("error writing: {}", e)))
            .and_then(|(s, _)| flush(s)
                .map_err(|e| format!("error flushing: {}", e)))
            .and_then(|s| read_exact(s, [0u8; 4])
                .map_err(|e| format!("error reading result length: {}", e)));
        if let Some(timeout) = $timeout {
            Either::A(fut.timeout(Duration::from_secs(timeout as u64)))
        } else {
            Either::B(fut.map_err(|e| timeout::Error::inner(e)))
        }.then(move |r| match r {
            Ok((s, lenb)) => Either::A(read_exact(s, {
                let outlen = Cursor::new(lenb).get_u32_le() as usize;
                let mut buf = BytesMut::with_capacity(outlen);
                buf.resize(outlen, 0);
                buf
            }).map_err(|e| format!("error reading result: {}", e))
                .map(|(_, ref outb)| String::from_utf8_lossy(outb).into_owned())),
            Err(e) => Either::B(if e.is_elapsed() {
                do_persistent_timeout(&$lang.timeout_cmdline);
                Ok("time limit exceeded".to_owned()).into_future()
            } else {
                Err(format!("error from timeout: {}", e)).into_future()
            })
        })
    });
}

pub fn unix<'a, T, U>(
    lang: Arc<UnixSocketBackend>,
    timeout: Option<usize>,
    context: Option<U>,
    code: T) -> impl Future<Item = String, Error = String> + 'a
        where
            T: AsRef<[u8]>,
            U: AsRef<[u8]> {
    persistent!(lang,
        UnixStream::connect(&lang.socket_addr),
        timeout,
        make_persistent_input(timeout, context, code))
}

fn do_persistent_timeout(cmdline: &Option<Vec<String>>) {
    if let Some(cmdline) = cmdline.as_ref() {
        if let Some(path) = cmdline.iter().nth(0) {
            debug!("timeout kill: launching {:?}", cmdline);
            tokio::spawn(Command::new(path)
                .args(cmdline.iter().skip(1))
                .spawn_async()
                .map_err(|e| error!("failed to exec for timeout kill: {}", e))
                .into_future()
                .and_then(|c| c
                    .map_err(|e| error!("failed to exec for timeout kill: {}", e)))
                    .map(|_| ()));
        }
    }
}

fn make_persistent_input<T, U>(timeout: Option<usize>, context: Option<T>, code: U) -> BytesMut
    where
        T: AsRef<[u8]>,
        U: AsRef<[u8]> {
    let timeout = timeout.unwrap_or(0usize) as u32;
    let contextb = context.as_ref().map(|x| x.as_ref()).unwrap_or(&super::EMPTY_U8);
    let codeb = code.as_ref();
    let contextblen = contextb.len() as u32;
    let codeblen = codeb.len() as u32;

    let mut buf = BytesMut::with_capacity(12usize + contextblen as usize + codeblen as usize);
    buf.put_u32_le(timeout*1000);
    buf.put_u32_le(contextblen);
    buf.put_u32_le(codeblen);
    buf.put(&contextb[..contextblen as usize]);
    buf.put(&codeb[..codeblen as usize]);
    buf
}
<commit_msg>Show signal name if process is signalled<commit_after>use std::process::{Command, Stdio};
use std::io::Cursor;
use std::sync::Arc;
use std::time::Duration;
use std::os::unix::process::ExitStatusExt;

use tokio::prelude::*;
use tokio::prelude::future::Either;
use tokio::timer::timeout;
use tokio_process::CommandExt;
use tokio::{io::{flush, read_exact, write_all}, net::unix::UnixStream};
use bytes::{BytesMut, Buf, BufMut};

use crate::{ExecBackend, UnixSocketBackend};

fn strsig(sig: i32) -> &'static str {
    match sig {
        1 => "Hangup",
        2 => "Interrupt",
        3 => "Quit",
        4 => "Illegal instruction",
        5 => "Trace/breakpoint trap",
        6 => "Aborted",
        7 => "Bus error",
        8 => "Floating point exception",
        9 => "Killed",
        10 => "User defined signal 1",
        11 => "Segmentation fault",
        12 => "User defined signal 2",
        13 => "Broken pipe",
        14 => "Alarm clock",
        15 => "Terminated",
        16 => "Stack fault",
        17 => "Child exited",
        18 => "Continued",
        19 => "Stopped (signal)",
        20 => "Stopped",
        21 => "Stopped (tty input)",
        22 => "Stopped (tty output)",
        23 => "Urgent I/O condition",
        24 => "CPU time limit exceeded",
        25 => "File size limit exceeded",
        26 => "Virtual timer expired",
        27 => "Profiling timer expired",
        28 => "Window changed",
        29 => "I/O possible",
        30 => "Power failure",
        31 => "Bad system call",
        _ => "Unknown signal"
    }
}

fn strsigabbrev(sig: i32) -> &'static str {
    match sig {
        1 => "SIGHUP",
        2 => "SIGINT",
        3 => "SIGQUIT",
        4 => "SIGILL",
        5 => "SIGTRAP",
        6 => "SIGABRT",
        7 => "SIGBUS",
        8 => "SIGFPE",
        9 => "SIGKILL",
        10 => "SIGUSR1",
        11 => "SIGSEGV",
        12 => "SIGUSR2",
        13 => "SIGPIPE",
        14 => "SIGALRM",
        15 => "SIGTERM",
        16 => "SIGSTKFLT",
        17 => "SIGCHLD",
        18 => "SIGCONT",
        19 => "SIGSTOP",
        20 => "SIGTSTP",
        21 => "SIGTTIN",
        22 => "SIGTTOU",
        23 => "SIGURG",
        24 => "SIGXCPU",
        25 => "SIGXFSZ",
        26 => "SIGVTALRM",
        27 => "SIGPROF",
        28 => "SIGWINCH",
        29 => "SIGPOLL",
        30 => "SIGPWR",
        31 => "SIGSYS",
        _ => "(unknown)"
    }
}

pub fn exec<'a, T>(
    lang: Arc<ExecBackend>,
    timeout: Option<usize>,
    code: T) -> impl Future<Item = String, Error = String> + 'a
        where T: AsRef<[u8]> + 'a {
    let timeout_arg = timeout
        .map(|t| format!("{}{}", lang.timeout_prefix.as_ref().map(String::as_str).unwrap_or(""), t));
    let timeout_arg_ref = timeout_arg.as_ref().map(String::as_str);
    if let Some(path) = lang.cmdline.iter().nth(0) {
        let mut cmd = Command::new(path);
        cmd.args(lang.cmdline.iter()
            .skip(1)
            .filter_map(|a| if a == "{TIMEOUT}" {
                timeout_arg_ref
            } else {
                Some(a.as_ref())
            }))
            .stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::piped());
        debug!("spawning {:?}", cmd);
        Either::A(cmd.spawn_async()
            .map_err(|e| format!("failed to exec: {}", e))
            .into_future()
            .and_then(|mut child| {
                child.stdin().take().ok_or_else(|| "stdin missing".to_owned()).into_future()
                    .and_then(|stdin|
                        write_all(stdin, code)
                            .map_err(|e| format!("failed to write to stdin: {}", e))
                    )
                    .and_then(|_| child.wait_with_output()
                        .map_err(|e| format!("failed to wait for process: {}", e)))
            })
            .map_err(|e| format!("unknown error in exec: {}", e))
            .map(|o| {
                let mut r = format!("{}{}",
                    String::from_utf8_lossy(&o.stderr),
                    String::from_utf8_lossy(&o.stdout),
                );
                if !o.status.success() {
                    if !r.ends_with('\n') {
                        r.push_str("\n");
                    }
                    if let Some(code) = o.status.code() {
                        r.push_str(&format!("exited with status {}\n", code));
                    } else if let Some(code) = o.status.signal() {
                        r.push_str(&format!("signalled with {} ({})\n", strsig(code), strsigabbrev(code)));
                    } else {
                        r.push_str("exited with unknown failure\n");
                    }
                }
                r
            }))
    } else {
        Either::B(Err("empty cmdline".to_owned()).into_future())
    }
}

macro_rules! persistent {
    ($lang:expr, $connfut:expr, $timeout:expr, $buf:expr) => ({
        let buf = $buf;
        let fut = $connfut
            .map_err(|e| format!("error connecting: {}", e))
            .and_then(move |s| write_all(s, buf)
                .map_err(|e| format!("error writing: {}", e)))
            .and_then(|(s, _)| flush(s)
                .map_err(|e| format!("error flushing: {}", e)))
            .and_then(|s| read_exact(s, [0u8; 4])
                .map_err(|e| format!("error reading result length: {}", e)));
        if let Some(timeout) = $timeout {
            Either::A(fut.timeout(Duration::from_secs(timeout as u64)))
        } else {
            Either::B(fut.map_err(|e| timeout::Error::inner(e)))
        }.then(move |r| match r {
            Ok((s, lenb)) => Either::A(read_exact(s, {
                let outlen = Cursor::new(lenb).get_u32_le() as usize;
                let mut buf = BytesMut::with_capacity(outlen);
                buf.resize(outlen, 0);
                buf
            }).map_err(|e| format!("error reading result: {}", e))
                .map(|(_, ref outb)| String::from_utf8_lossy(outb).into_owned())),
            Err(e) => Either::B(if e.is_elapsed() {
                do_persistent_timeout(&$lang.timeout_cmdline);
                Ok("time limit exceeded".to_owned()).into_future()
            } else {
                Err(format!("error from timeout: {}", e)).into_future()
            })
        })
    });
}

pub fn unix<'a, T, U>(
    lang: Arc<UnixSocketBackend>,
    timeout: Option<usize>,
    context: Option<U>,
    code: T) -> impl Future<Item = String, Error = String> + 'a
        where
            T: AsRef<[u8]>,
            U: AsRef<[u8]> {
    persistent!(lang,
        UnixStream::connect(&lang.socket_addr),
        timeout,
        make_persistent_input(timeout, context, code))
}

fn do_persistent_timeout(cmdline: &Option<Vec<String>>) {
    if let Some(cmdline) = cmdline.as_ref() {
        if let Some(path) = cmdline.iter().nth(0) {
            debug!("timeout kill: launching {:?}", cmdline);
            tokio::spawn(Command::new(path)
                .args(cmdline.iter().skip(1))
                .spawn_async()
                .map_err(|e| error!("failed to exec for timeout kill: {}", e))
                .into_future()
                .and_then(|c| c
                    .map_err(|e| error!("failed to exec for timeout kill: {}", e)))
                    .map(|_| ()));
        }
    }
}

fn make_persistent_input<T, U>(timeout: Option<usize>, context: Option<T>, code: U) -> BytesMut
    where
        T: AsRef<[u8]>,
        U: AsRef<[u8]> {
    let timeout = timeout.unwrap_or(0usize) as u32;
    let contextb = context.as_ref().map(|x| x.as_ref()).unwrap_or(&super::EMPTY_U8);
    let codeb = code.as_ref();
    let contextblen = contextb.len() as u32;
    let codeblen = codeb.len() as u32;

    let mut buf = BytesMut::with_capacity(12usize + contextblen as usize + codeblen as usize);
    buf.put_u32_le(timeout*1000);
    buf.put_u32_le(contextblen);
    buf.put_u32_le(codeblen);
    buf.put(&contextb[..contextblen as usize]);
    buf.put(&codeb[..codeblen as usize]);
    buf
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate abomonation;
extern crate timely;
extern crate differential_dataflow;
extern crate arrayvec;

use std::fs::File;
use std::io::{BufRead, BufReader};
use std::time::Instant;

use timely::dataflow::*;
use timely::dataflow::operators::*;
use timely::progress::timestamp::RootTimestamp;
use timely::progress::nested::product::Product;

use differential_dataflow::{Collection, AsCollection};

mod types;
mod queries;

use types::*;

fn main() {

    timely::execute_from_args(std::env::args().skip(4), |worker| {

        let index = worker.index();
        let peers = worker.peers();

        let prefix = ::std::env::args().nth(1).unwrap();;
        let logical_batch = ::std::env::args().nth(2).unwrap().parse::<usize>().unwrap();
        let physical_batch = ::std::env::args().nth(3).unwrap().parse::<usize>().unwrap();
        let query: usize = ::std::env::args().nth(4).unwrap().parse().unwrap();
        let seal: bool = ::std::env::args().any(|x| x == "seal-inputs");

        let (mut inputs, probes, used) = worker.dataflow::<usize,_,_>(move |scope| {

            // create new inputs to use in workers!
            let (cust_in, cust) = scope.new_input();
            let (line_in, line) = scope.new_input();
            let (nats_in, nats) = scope.new_input();
            let (ords_in, ords) = scope.new_input();
            let (part_in, part) = scope.new_input();
            let (psup_in, psup) = scope.new_input();
            let (regs_in, regs) = scope.new_input();
            let (supp_in, supp) = scope.new_input();

            let mut collections = Collections::new(
                cust.as_collection(),
                line.as_collection(),
                nats.as_collection(),
                ords.as_collection(),
                part.as_collection(),
                psup.as_collection(),
                regs.as_collection(),
                supp.as_collection(),
            );

            let mut probes = Vec::new();

            match query {
                // 1 => probes.push(queries::query01::query(&mut collections)),
                // 2 => probes.push(queries::query02::query(&mut collections)),
                // 3 => probes.push(queries::query03::query(&mut collections)),
                // 4 => probes.push(queries::query04::query(&mut collections)),
                // 5 => probes.push(queries::query05::query(&mut collections)),
                // 6 => probes.push(queries::query06::query(&mut collections)),
                // 7 => probes.push(queries::query07::query(&mut collections)),
                // 8 => probes.push(queries::query08::query(&mut collections)),
                9 => probes.push(queries::query09::query(&mut collections)),
                // 10 => probes.push(queries::query10::query(&mut collections)),
                // 11 => probes.push(queries::query11::query(&mut collections)),
                // 12 => probes.push(queries::query12::query(&mut collections)),
                // 13 => probes.push(queries::query13::query(&mut collections)),
                // 14 => probes.push(queries::query14::query(&mut collections)),
                // 15 => probes.push(queries::query15::query(&mut collections)),
                // 16 => probes.push(queries::query16::query(&mut collections)),
                // 17 => probes.push(queries::query17::query(&mut collections)),
                // 18 => probes.push(queries::query18::query(&mut collections)),
                // 19 => probes.push(queries::query19::query(&mut collections)),
                // 20 => probes.push(queries::query20::query(&mut collections)),
                // 21 => probes.push(queries::query21::query(&mut collections)),
                // 22 => probes.push(queries::query22::query(&mut collections)),
                _ => panic!("query: {:?} unimplemented", query),
            }

            // return the various input handles, and the list of probes.
            ((cust_in, line_in, Some(nats_in), ords_in, part_in, psup_in, Some(regs_in), supp_in), probes, collections.used)
        });

        // customer.tbl lineitem.tbl    nation.tbl  orders.tbl  part.tbl    partsupp.tbl    region.tbl  supplier.tbl
        let mut customers = if used[0] { load::<Customer>(prefix.as_str(), "customer.tbl", index, peers, logical_batch, physical_batch, 0) } else { Vec::new() };
        let mut lineitems = if used[1] { load::<LineItem>(prefix.as_str(), "lineitem.tbl", index, peers, logical_batch, physical_batch, 1) } else { Vec::new() };
        let mut nations = if used[2] { load::<Nation>(prefix.as_str(), "nation.tbl", index, peers, logical_batch, physical_batch, 2) } else { Vec::new() };
        let mut orders = if used[3] { load::<Order>(prefix.as_str(), "orders.tbl", index, peers, logical_batch, physical_batch, 3) } else { Vec::new() };
        let mut parts = if used[4] { load::<Part>(prefix.as_str(), "part.tbl", index, peers, logical_batch, physical_batch, 4) } else { Vec::new() };
        let mut partsupps = if used[5] { load::<PartSupp>(prefix.as_str(), "partsupp.tbl", index, peers, logical_batch, physical_batch, 5) } else { Vec::new() };
        let mut regions = if used[6] { load::<Region>(prefix.as_str(), "region.tbl", index, peers, logical_batch, physical_batch, 6) } else { Vec::new() };
        let mut suppliers = if used[7] { load::<Supplier>(prefix.as_str(), "supplier.tbl", index, peers, logical_batch, physical_batch, 7) } else { Vec::new() };

        let mut tuples = 0usize;
        tuples += customers.iter().map(|x| x.len()).sum::<usize>();
        tuples += lineitems.iter().map(|x| x.len()).sum::<usize>();
        tuples += nations.iter().map(|x| x.len()).sum::<usize>();
        tuples += orders.iter().map(|x| x.len()).sum::<usize>();
        tuples += parts.iter().map(|x| x.len()).sum::<usize>();
        tuples += partsupps.iter().map(|x| x.len()).sum::<usize>();
        tuples += regions.iter().map(|x| x.len()).sum::<usize>();
        tuples += suppliers.iter().map(|x| x.len()).sum::<usize>();

        // Synchronize before starting the timer.
        let next_round = 1;
        inputs.0.advance_to(next_round);
        inputs.1.advance_to(next_round);
        inputs.2.as_mut().map(|x| x.advance_to(next_round));
        inputs.3.advance_to(next_round);
        inputs.4.advance_to(next_round);
        inputs.5.advance_to(next_round);
        inputs.6.as_mut().map(|x| x.advance_to(next_round));
        inputs.7.advance_to(next_round);
        let time = inputs.0.time().clone();
        worker.step_while(|| probes.iter().all(|p| p.less_than(&time)));

        let timer = Instant::now();
        let mut round = 0;
        while customers.len() > 0 || lineitems.len() > 0 || nations.len() > 0 || orders.len() > 0 || parts.len() > 0 || partsupps.len() > 0 || regions.len() > 0 || suppliers.len() > 0 {

            // introduce physical batch of data for each input with remaining data.
            if let Some(mut data) = customers.pop() { inputs.0.send_batch(&mut data); }
            if let Some(mut data) = lineitems.pop() { inputs.1.send_batch(&mut data); }
            if let Some(mut data) = nations.pop() { inputs.2.as_mut().map(|x| x.send_batch(&mut data)); } else { if seal { inputs.2 = None; } }
            if let Some(mut data) = orders.pop() { inputs.3.send_batch(&mut data); }
            if let Some(mut data) = parts.pop() { inputs.4.send_batch(&mut data); }
            if let Some(mut data) = partsupps.pop() { inputs.5.send_batch(&mut data); }
            if let Some(mut data) = regions.pop() { inputs.6.as_mut().map(|x| x.send_batch(&mut data)); } else { if seal { inputs.6 = None; } }
            if let Some(mut data) = suppliers.pop() { inputs.7.send_batch(&mut data); }

            // catch all inputs up to the same (next) round.
            let next_round = 1 + 8 * (round + 1) * physical_batch;
            inputs.0.advance_to(next_round);
            inputs.1.advance_to(next_round);
            inputs.2.as_mut().map(|x| x.advance_to(next_round));
            inputs.3.advance_to(next_round);
            inputs.4.advance_to(next_round);
            inputs.5.advance_to(next_round);
            inputs.6.as_mut().map(|x| x.advance_to(next_round));
            inputs.7.advance_to(next_round);

            let time = inputs.0.time().clone();
            worker.step_while(|| probes.iter().all(|p| p.less_than(&time)));
            round += 1;
        }

        // Finish outstanding work before stopping the timer.
        let next_round = usize::max_value();
        inputs.0.advance_to(next_round);
        inputs.1.advance_to(next_round);
        inputs.2.as_mut().map(|x| x.advance_to(next_round));
        inputs.3.advance_to(next_round);
        inputs.4.advance_to(next_round);
        inputs.5.advance_to(next_round);
        inputs.6.as_mut().map(|x| x.advance_to(next_round));
        inputs.7.advance_to(next_round);
        let time = inputs.0.time().clone();
        worker.step_while(|| probes.iter().all(|p| p.less_than(&time)));

        let query_name = if query < 10 { format!("q0{}", query) } else { format!("q{}", query) };
        let elapsed = timer.elapsed();
        let nanos = elapsed.as_secs() * 1000000000 + elapsed.subsec_nanos() as u64;
        if index == 0 {
            println!("query: {}, elapsed: {:?}, tuples: {:?}, rate: {:?}", query_name, timer.elapsed(), peers * tuples, ((peers * tuples) as f64) / (nanos as f64 / 1000000000.0));
        }

    }).unwrap();
}

pub struct Collections<G: Scope> {
    customers: Collection<G, Customer, isize>,
    lineitems: Collection<G, LineItem, isize>,
    nations: Collection<G, Nation, isize>,
    orders: Collection<G, Order, isize>,
    parts: Collection<G, Part, isize>,
    partsupps: Collection<G, PartSupp, isize>,
    regions: Collection<G, Region, isize>,
    suppliers: Collection<G, Supplier, isize>,
    used: [bool; 8],
}

impl<G: Scope> Collections<G> {
    fn new(
        customers: Collection<G, Customer, isize>,
        lineitems: Collection<G, LineItem, isize>,
        nations: Collection<G, Nation, isize>,
        orders: Collection<G, Order, isize>,
        parts: Collection<G, Part, isize>,
        partsupps: Collection<G, PartSupp, isize>,
        regions: Collection<G, Region, isize>,
        suppliers: Collection<G, Supplier, isize>,
    ) -> Self {

        Collections {
            customers: customers,
            lineitems: lineitems,
            nations: nations,
            orders: orders,
            parts: parts,
            partsupps: partsupps,
            regions: regions,
            suppliers: suppliers,
            used: [false; 8]
        }
    }

    fn customers(&mut self) -> &Collection<G, Customer, isize> { self.used[0] = true; &self.customers }
    fn lineitems(&mut self) -> &Collection<G, LineItem, isize> { self.used[1] = true; &self.lineitems }
    fn nations(&mut self) -> &Collection<G, Nation, isize> { self.used[2] = true; &self.nations }
    fn orders(&mut self) -> &Collection<G, Order, isize> { self.used[3] = true; &self.orders }
    fn parts(&mut self) -> &Collection<G, Part, isize> { self.used[4] = true; &self.parts }
    fn partsupps(&mut self) -> &Collection<G, PartSupp, isize> { self.used[5] = true; &self.partsupps }
    fn regions(&mut self) -> &Collection<G, Region, isize> { self.used[6] = true; &self.regions }
    fn suppliers(&mut self) -> &Collection<G, Supplier, isize> { self.used[7] = true; &self.suppliers }
}

// Returns a sequence of physical batches of ready-to-go timestamped data. Not clear that `input` can exploit the pre-arrangement yet.
fn load<T>(prefix: &str, name: &str, index: usize, peers: usize, logical_batch: usize, physical_batch: usize, off: usize)
    -> Vec<Vec<(T, Product<RootTimestamp, usize>, isize)>>
where T: for<'a> From<&'a str> {

    let mut result = Vec::new();
    let mut buffer = Vec::new();

    let path = format!("{}{}", prefix, name);

    let items_file = File::open(&path).expect("didn't find items file");
    let mut items_reader =  BufReader::new(items_file);
    let mut count = 0;

    let mut line = String::new();

    while items_reader.read_line(&mut line).unwrap() > 0 {

        if count % peers == index {

            let logical = (8 * count / logical_batch) + off;
            let physical = logical / physical_batch;
            let round = physical / 8;

            while result.len() < round {
                result.push(buffer);
                buffer = Vec::with_capacity(2 + logical_batch * physical_batch / peers);
            }

            let item = T::from(line.as_str());
            buffer.push((item, RootTimestamp::new(logical + 1), 1));
        }

        count += 1;

        line.clear();
    }

    if buffer.len() > 0 {
        result.push(buffer);
    }

    result.reverse();
    result
}
<commit_msg>add queries back in<commit_after>#[macro_use]
extern crate abomonation;
extern crate timely;
extern crate differential_dataflow;
extern crate arrayvec;

use std::fs::File;
use std::io::{BufRead, BufReader};
use std::time::Instant;

use timely::dataflow::*;
use timely::dataflow::operators::*;
use timely::progress::timestamp::RootTimestamp;
use timely::progress::nested::product::Product;

use differential_dataflow::{Collection, AsCollection};

mod types;
mod queries;

use types::*;

fn main() {

    timely::execute_from_args(std::env::args().skip(4), |worker| {

        let index = worker.index();
        let peers = worker.peers();

        let prefix = ::std::env::args().nth(1).unwrap();;
        let logical_batch = ::std::env::args().nth(2).unwrap().parse::<usize>().unwrap();
        let physical_batch = ::std::env::args().nth(3).unwrap().parse::<usize>().unwrap();
        let query: usize = ::std::env::args().nth(4).unwrap().parse().unwrap();
        let seal: bool = ::std::env::args().any(|x| x == "seal-inputs");

        let (mut inputs, probes, used) = worker.dataflow::<usize,_,_>(move |scope| {

            // create new inputs to use in workers!
            let (cust_in, cust) = scope.new_input();
            let (line_in, line) = scope.new_input();
            let (nats_in, nats) = scope.new_input();
            let (ords_in, ords) = scope.new_input();
            let (part_in, part) = scope.new_input();
            let (psup_in, psup) = scope.new_input();
            let (regs_in, regs) = scope.new_input();
            let (supp_in, supp) = scope.new_input();

            let mut collections = Collections::new(
                cust.as_collection(),
                line.as_collection(),
                nats.as_collection(),
                ords.as_collection(),
                part.as_collection(),
                psup.as_collection(),
                regs.as_collection(),
                supp.as_collection(),
            );

            let mut probes = Vec::new();

            match query {
                1 => probes.push(queries::query01::query(&mut collections)),
                2 => probes.push(queries::query02::query(&mut collections)),
                3 => probes.push(queries::query03::query(&mut collections)),
                4 => probes.push(queries::query04::query(&mut collections)),
                5 => probes.push(queries::query05::query(&mut collections)),
                6 => probes.push(queries::query06::query(&mut collections)),
                7 => probes.push(queries::query07::query(&mut collections)),
                8 => probes.push(queries::query08::query(&mut collections)),
                9 => probes.push(queries::query09::query(&mut collections)),
                10 => probes.push(queries::query10::query(&mut collections)),
                11 => probes.push(queries::query11::query(&mut collections)),
                12 => probes.push(queries::query12::query(&mut collections)),
                13 => probes.push(queries::query13::query(&mut collections)),
                14 => probes.push(queries::query14::query(&mut collections)),
                15 => probes.push(queries::query15::query(&mut collections)),
                16 => probes.push(queries::query16::query(&mut collections)),
                17 => probes.push(queries::query17::query(&mut collections)),
                18 => probes.push(queries::query18::query(&mut collections)),
                19 => probes.push(queries::query19::query(&mut collections)),
                20 => probes.push(queries::query20::query(&mut collections)),
                21 => probes.push(queries::query21::query(&mut collections)),
                22 => probes.push(queries::query22::query(&mut collections)),
                _ => panic!("query: {:?} unimplemented", query),
            }

            // return the various input handles, and the list of probes.
            ((cust_in, line_in, Some(nats_in), ords_in, part_in, psup_in, Some(regs_in), supp_in), probes, collections.used)
        });

        // customer.tbl lineitem.tbl    nation.tbl  orders.tbl  part.tbl    partsupp.tbl    region.tbl  supplier.tbl
        let mut customers = if used[0] { load::<Customer>(prefix.as_str(), "customer.tbl", index, peers, logical_batch, physical_batch, 0) } else { Vec::new() };
        let mut lineitems = if used[1] { load::<LineItem>(prefix.as_str(), "lineitem.tbl", index, peers, logical_batch, physical_batch, 1) } else { Vec::new() };
        let mut nations = if used[2] { load::<Nation>(prefix.as_str(), "nation.tbl", index, peers, logical_batch, physical_batch, 2) } else { Vec::new() };
        let mut orders = if used[3] { load::<Order>(prefix.as_str(), "orders.tbl", index, peers, logical_batch, physical_batch, 3) } else { Vec::new() };
        let mut parts = if used[4] { load::<Part>(prefix.as_str(), "part.tbl", index, peers, logical_batch, physical_batch, 4) } else { Vec::new() };
        let mut partsupps = if used[5] { load::<PartSupp>(prefix.as_str(), "partsupp.tbl", index, peers, logical_batch, physical_batch, 5) } else { Vec::new() };
        let mut regions = if used[6] { load::<Region>(prefix.as_str(), "region.tbl", index, peers, logical_batch, physical_batch, 6) } else { Vec::new() };
        let mut suppliers = if used[7] { load::<Supplier>(prefix.as_str(), "supplier.tbl", index, peers, logical_batch, physical_batch, 7) } else { Vec::new() };

        let mut tuples = 0usize;
        tuples += customers.iter().map(|x| x.len()).sum::<usize>();
        tuples += lineitems.iter().map(|x| x.len()).sum::<usize>();
        tuples += nations.iter().map(|x| x.len()).sum::<usize>();
        tuples += orders.iter().map(|x| x.len()).sum::<usize>();
        tuples += parts.iter().map(|x| x.len()).sum::<usize>();
        tuples += partsupps.iter().map(|x| x.len()).sum::<usize>();
        tuples += regions.iter().map(|x| x.len()).sum::<usize>();
        tuples += suppliers.iter().map(|x| x.len()).sum::<usize>();

        // Synchronize before starting the timer.
        let next_round = 1;
        inputs.0.advance_to(next_round);
        inputs.1.advance_to(next_round);
        inputs.2.as_mut().map(|x| x.advance_to(next_round));
        inputs.3.advance_to(next_round);
        inputs.4.advance_to(next_round);
        inputs.5.advance_to(next_round);
        inputs.6.as_mut().map(|x| x.advance_to(next_round));
        inputs.7.advance_to(next_round);
        let time = inputs.0.time().clone();
        worker.step_while(|| probes.iter().all(|p| p.less_than(&time)));

        let timer = Instant::now();
        let mut round = 0;
        while customers.len() > 0 || lineitems.len() > 0 || nations.len() > 0 || orders.len() > 0 || parts.len() > 0 || partsupps.len() > 0 || regions.len() > 0 || suppliers.len() > 0 {

            // introduce physical batch of data for each input with remaining data.
            if let Some(mut data) = customers.pop() { inputs.0.send_batch(&mut data); }
            if let Some(mut data) = lineitems.pop() { inputs.1.send_batch(&mut data); }
            if let Some(mut data) = nations.pop() { inputs.2.as_mut().map(|x| x.send_batch(&mut data)); } else { if seal { inputs.2 = None; } }
            if let Some(mut data) = orders.pop() { inputs.3.send_batch(&mut data); }
            if let Some(mut data) = parts.pop() { inputs.4.send_batch(&mut data); }
            if let Some(mut data) = partsupps.pop() { inputs.5.send_batch(&mut data); }
            if let Some(mut data) = regions.pop() { inputs.6.as_mut().map(|x| x.send_batch(&mut data)); } else { if seal { inputs.6 = None; } }
            if let Some(mut data) = suppliers.pop() { inputs.7.send_batch(&mut data); }

            // catch all inputs up to the same (next) round.
            let next_round = 1 + 8 * (round + 1) * physical_batch;
            inputs.0.advance_to(next_round);
            inputs.1.advance_to(next_round);
            inputs.2.as_mut().map(|x| x.advance_to(next_round));
            inputs.3.advance_to(next_round);
            inputs.4.advance_to(next_round);
            inputs.5.advance_to(next_round);
            inputs.6.as_mut().map(|x| x.advance_to(next_round));
            inputs.7.advance_to(next_round);

            let time = inputs.0.time().clone();
            worker.step_while(|| probes.iter().all(|p| p.less_than(&time)));
            round += 1;
        }

        // Finish outstanding work before stopping the timer.
        let next_round = usize::max_value();
        inputs.0.advance_to(next_round);
        inputs.1.advance_to(next_round);
        inputs.2.as_mut().map(|x| x.advance_to(next_round));
        inputs.3.advance_to(next_round);
        inputs.4.advance_to(next_round);
        inputs.5.advance_to(next_round);
        inputs.6.as_mut().map(|x| x.advance_to(next_round));
        inputs.7.advance_to(next_round);
        let time = inputs.0.time().clone();
        worker.step_while(|| probes.iter().all(|p| p.less_than(&time)));

        let query_name = if query < 10 { format!("q0{}", query) } else { format!("q{}", query) };
        let elapsed = timer.elapsed();
        let nanos = elapsed.as_secs() * 1000000000 + elapsed.subsec_nanos() as u64;
        if index == 0 {
            println!("query: {}, elapsed: {:?}, tuples: {:?}, rate: {:?}", query_name, timer.elapsed(), peers * tuples, ((peers * tuples) as f64) / (nanos as f64 / 1000000000.0));
        }

    }).unwrap();
}

pub struct Collections<G: Scope> {
    customers: Collection<G, Customer, isize>,
    lineitems: Collection<G, LineItem, isize>,
    nations: Collection<G, Nation, isize>,
    orders: Collection<G, Order, isize>,
    parts: Collection<G, Part, isize>,
    partsupps: Collection<G, PartSupp, isize>,
    regions: Collection<G, Region, isize>,
    suppliers: Collection<G, Supplier, isize>,
    used: [bool; 8],
}

impl<G: Scope> Collections<G> {
    fn new(
        customers: Collection<G, Customer, isize>,
        lineitems: Collection<G, LineItem, isize>,
        nations: Collection<G, Nation, isize>,
        orders: Collection<G, Order, isize>,
        parts: Collection<G, Part, isize>,
        partsupps: Collection<G, PartSupp, isize>,
        regions: Collection<G, Region, isize>,
        suppliers: Collection<G, Supplier, isize>,
    ) -> Self {

        Collections {
            customers: customers,
            lineitems: lineitems,
            nations: nations,
            orders: orders,
            parts: parts,
            partsupps: partsupps,
            regions: regions,
            suppliers: suppliers,
            used: [false; 8]
        }
    }

    fn customers(&mut self) -> &Collection<G, Customer, isize> { self.used[0] = true; &self.customers }
    fn lineitems(&mut self) -> &Collection<G, LineItem, isize> { self.used[1] = true; &self.lineitems }
    fn nations(&mut self) -> &Collection<G, Nation, isize> { self.used[2] = true; &self.nations }
    fn orders(&mut self) -> &Collection<G, Order, isize> { self.used[3] = true; &self.orders }
    fn parts(&mut self) -> &Collection<G, Part, isize> { self.used[4] = true; &self.parts }
    fn partsupps(&mut self) -> &Collection<G, PartSupp, isize> { self.used[5] = true; &self.partsupps }
    fn regions(&mut self) -> &Collection<G, Region, isize> { self.used[6] = true; &self.regions }
    fn suppliers(&mut self) -> &Collection<G, Supplier, isize> { self.used[7] = true; &self.suppliers }
}

// Returns a sequence of physical batches of ready-to-go timestamped data. Not clear that `input` can exploit the pre-arrangement yet.
fn load<T>(prefix: &str, name: &str, index: usize, peers: usize, logical_batch: usize, physical_batch: usize, off: usize)
    -> Vec<Vec<(T, Product<RootTimestamp, usize>, isize)>>
where T: for<'a> From<&'a str> {

    let mut result = Vec::new();
    let mut buffer = Vec::new();

    let path = format!("{}{}", prefix, name);

    let items_file = File::open(&path).expect("didn't find items file");
    let mut items_reader =  BufReader::new(items_file);
    let mut count = 0;

    let mut line = String::new();

    while items_reader.read_line(&mut line).unwrap() > 0 {

        if count % peers == index {

            let logical = (8 * count / logical_batch) + off;
            let physical = logical / physical_batch;
            let round = physical / 8;

            while result.len() < round {
                result.push(buffer);
                buffer = Vec::with_capacity(2 + logical_batch * physical_batch / peers);
            }

            let item = T::from(line.as_str());
            buffer.push((item, RootTimestamp::new(logical + 1), 1));
        }

        count += 1;

        line.clear();
    }

    if buffer.len() > 0 {
        result.push(buffer);
    }

    result.reverse();
    result
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![feature(libc, rustc_private, thread_local)]

#[macro_use]
extern crate log;

extern crate compositing;
extern crate devtools;
extern crate net;
extern crate net_traits;
extern crate msg;
extern crate profile;
#[macro_use]
extern crate util;
extern crate script;
extern crate layout;
extern crate gfx;
extern crate libc;
extern crate url;

use compositing::CompositorEventListener;
use compositing::windowing::{WindowEvent, WindowMethods};

#[cfg(not(test))]
use compositing::{CompositorProxy, CompositorTask, Constellation};
#[cfg(not(test))]
use msg::constellation_msg::Msg as ConstellationMsg;
#[cfg(not(test))]
use msg::constellation_msg::ConstellationChan;
#[cfg(not(test))]
use script::dom::bindings::codegen::RegisterBindings;

#[cfg(not(test))]
use net::image_cache_task::{ImageCacheTaskFactory, LoadPlaceholder};
#[cfg(not(test))]
use net::storage_task::StorageTaskFactory;
#[cfg(not(test))]
use net::resource_task::new_resource_task;
#[cfg(not(test))]
use net_traits::image_cache_task::ImageCacheTask;
#[cfg(not(test))]
use net_traits::storage_task::StorageTask;
#[cfg(not(test))]
use gfx::font_cache_task::FontCacheTask;
#[cfg(not(test))]
use profile::mem;
#[cfg(not(test))]
use profile::time;
#[cfg(not(test))]
use util::opts;
#[cfg(not(test))]
use util::taskpool::TaskPool;

#[cfg(not(test))]
use std::rc::Rc;

pub struct Browser {
    compositor: Box<CompositorEventListener + 'static>,
}

impl Browser  {
    #[cfg(not(test))]
    pub fn new<Window>(window: Option<Rc<Window>>) -> Browser
    where Window: WindowMethods + 'static {
        use std::env;

        ::util::opts::set_experimental_enabled(opts::get().enable_experimental);
        let opts = opts::get();
        RegisterBindings::RegisterProxyHandlers();

        let shared_task_pool = TaskPool::new(8);

        let (compositor_proxy, compositor_receiver) =
            WindowMethods::create_compositor_channel(&window);
        let time_profiler_chan = time::Profiler::create(opts.time_profiler_period);
        let mem_profiler_chan = mem::Profiler::create(opts.mem_profiler_period);
        let devtools_chan = opts.devtools_port.map(|port| {
            devtools::start_server(port)
        });

        // Create a Servo instance.
        let resource_task = new_resource_task(opts.user_agent.clone());

        // If we are emitting an output file, then we need to block on
        // image load or we risk emitting an output file missing the
        // image.
        let image_cache_task: ImageCacheTask = if opts.output_file.is_some() {
            ImageCacheTaskFactory::new_sync(resource_task.clone(), shared_task_pool,
                                            time_profiler_chan.clone(), LoadPlaceholder::Preload)
        } else {
            ImageCacheTaskFactory::new(resource_task.clone(), shared_task_pool,
                                       time_profiler_chan.clone(), LoadPlaceholder::Preload)
        };

        let font_cache_task = FontCacheTask::new(resource_task.clone());
        let storage_task: StorageTask = StorageTaskFactory::new();

        let constellation_chan = Constellation::<layout::layout_task::LayoutTask,
                                                 script::script_task::ScriptTask>::start(
                                                      compositor_proxy.clone_compositor_proxy(),
                                                      resource_task,
                                                      image_cache_task,
                                                      font_cache_task,
                                                      time_profiler_chan.clone(),
                                                      mem_profiler_chan.clone(),
                                                      devtools_chan,
                                                      storage_task);

        // Send the URL command to the constellation.
        let cwd = env::current_dir().unwrap();
        for url in opts.urls.iter() {
            let url = match url::Url::parse(&*url) {
                Ok(url) => url,
                Err(url::ParseError::RelativeUrlWithoutBase)
                => url::Url::from_file_path(&*cwd.join(&*url)).unwrap(),
                Err(_) => panic!("URL parsing failed"),
            };

            let ConstellationChan(ref chan) = constellation_chan;
            chan.send(ConstellationMsg::InitLoadUrl(url)).unwrap();
        }

        debug!("preparing to enter main loop");
        let compositor = CompositorTask::create(window,
                                                compositor_proxy,
                                                compositor_receiver,
                                                constellation_chan,
                                                time_profiler_chan,
                                                mem_profiler_chan);

        Browser {
            compositor: compositor,
        }
    }

    pub fn handle_event(&mut self, event: WindowEvent) -> bool {
        self.compositor.handle_event(event)
    }

    pub fn repaint_synchronously(&mut self) {
        self.compositor.repaint_synchronously()
    }

    pub fn pinch_zoom_level(&self) -> f32 {
        self.compositor.pinch_zoom_level()
    }

    pub fn get_title_for_main_frame(&self) {
        self.compositor.get_title_for_main_frame()
    }

    pub fn shutdown(mut self) {
        self.compositor.shutdown();
    }
}

<commit_msg>Fix warnings when building tests<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![feature(libc, rustc_private, thread_local)]
#![cfg_attr(not(test), feature(path))]

#[macro_use]
extern crate log;

extern crate compositing;
extern crate devtools;
extern crate net;
extern crate net_traits;
extern crate msg;
extern crate profile;
#[macro_use]
extern crate util;
extern crate script;
extern crate layout;
extern crate gfx;
extern crate libc;
extern crate url;

use compositing::CompositorEventListener;
use compositing::windowing::WindowEvent;

#[cfg(not(test))]
use compositing::windowing::WindowMethods;
#[cfg(not(test))]
use compositing::{CompositorProxy, CompositorTask, Constellation};
#[cfg(not(test))]
use msg::constellation_msg::Msg as ConstellationMsg;
#[cfg(not(test))]
use msg::constellation_msg::ConstellationChan;
#[cfg(not(test))]
use script::dom::bindings::codegen::RegisterBindings;

#[cfg(not(test))]
use net::image_cache_task::{ImageCacheTaskFactory, LoadPlaceholder};
#[cfg(not(test))]
use net::storage_task::StorageTaskFactory;
#[cfg(not(test))]
use net::resource_task::new_resource_task;
#[cfg(not(test))]
use net_traits::image_cache_task::ImageCacheTask;
#[cfg(not(test))]
use net_traits::storage_task::StorageTask;
#[cfg(not(test))]
use gfx::font_cache_task::FontCacheTask;
#[cfg(not(test))]
use profile::mem;
#[cfg(not(test))]
use profile::time;
#[cfg(not(test))]
use util::opts;
#[cfg(not(test))]
use util::taskpool::TaskPool;

#[cfg(not(test))]
use std::rc::Rc;

pub struct Browser {
    compositor: Box<CompositorEventListener + 'static>,
}

impl Browser  {
    #[cfg(not(test))]
    pub fn new<Window>(window: Option<Rc<Window>>) -> Browser
    where Window: WindowMethods + 'static {
        use std::env;

        ::util::opts::set_experimental_enabled(opts::get().enable_experimental);
        let opts = opts::get();
        RegisterBindings::RegisterProxyHandlers();

        let shared_task_pool = TaskPool::new(8);

        let (compositor_proxy, compositor_receiver) =
            WindowMethods::create_compositor_channel(&window);
        let time_profiler_chan = time::Profiler::create(opts.time_profiler_period);
        let mem_profiler_chan = mem::Profiler::create(opts.mem_profiler_period);
        let devtools_chan = opts.devtools_port.map(|port| {
            devtools::start_server(port)
        });

        // Create a Servo instance.
        let resource_task = new_resource_task(opts.user_agent.clone());

        // If we are emitting an output file, then we need to block on
        // image load or we risk emitting an output file missing the
        // image.
        let image_cache_task: ImageCacheTask = if opts.output_file.is_some() {
            ImageCacheTaskFactory::new_sync(resource_task.clone(), shared_task_pool,
                                            time_profiler_chan.clone(), LoadPlaceholder::Preload)
        } else {
            ImageCacheTaskFactory::new(resource_task.clone(), shared_task_pool,
                                       time_profiler_chan.clone(), LoadPlaceholder::Preload)
        };

        let font_cache_task = FontCacheTask::new(resource_task.clone());
        let storage_task: StorageTask = StorageTaskFactory::new();

        let constellation_chan = Constellation::<layout::layout_task::LayoutTask,
                                                 script::script_task::ScriptTask>::start(
                                                      compositor_proxy.clone_compositor_proxy(),
                                                      resource_task,
                                                      image_cache_task,
                                                      font_cache_task,
                                                      time_profiler_chan.clone(),
                                                      mem_profiler_chan.clone(),
                                                      devtools_chan,
                                                      storage_task);

        // Send the URL command to the constellation.
        let cwd = env::current_dir().unwrap();
        for url in opts.urls.iter() {
            let url = match url::Url::parse(&*url) {
                Ok(url) => url,
                Err(url::ParseError::RelativeUrlWithoutBase)
                => url::Url::from_file_path(&*cwd.join(&*url)).unwrap(),
                Err(_) => panic!("URL parsing failed"),
            };

            let ConstellationChan(ref chan) = constellation_chan;
            chan.send(ConstellationMsg::InitLoadUrl(url)).unwrap();
        }

        debug!("preparing to enter main loop");
        let compositor = CompositorTask::create(window,
                                                compositor_proxy,
                                                compositor_receiver,
                                                constellation_chan,
                                                time_profiler_chan,
                                                mem_profiler_chan);

        Browser {
            compositor: compositor,
        }
    }

    pub fn handle_event(&mut self, event: WindowEvent) -> bool {
        self.compositor.handle_event(event)
    }

    pub fn repaint_synchronously(&mut self) {
        self.compositor.repaint_synchronously()
    }

    pub fn pinch_zoom_level(&self) -> f32 {
        self.compositor.pinch_zoom_level()
    }

    pub fn get_title_for_main_frame(&self) {
        self.compositor.get_title_for_main_frame()
    }

    pub fn shutdown(mut self) {
        self.compositor.shutdown();
    }
}

<|endoftext|>


<commit_before>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A unique pointer type.

#![stable]

use core::any::Any;
use core::clone::Clone;
use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
use core::default::Default;
use core::fmt;
use core::hash::{self, Hash};
use core::marker::Sized;
use core::mem;
use core::option::Option;
use core::ptr::Unique;
use core::raw::TraitObject;
use core::result::Result;
use core::result::Result::{Ok, Err};
use core::ops::{Deref, DerefMut};

/// A value that represents the global exchange heap. This is the default
/// place that the `box` keyword allocates into when no place is supplied.
///
/// The following two examples are equivalent:
///
/// ```rust
/// use std::boxed::HEAP;
///
/// # struct Bar;
/// # impl Bar { fn new(_a: int) { } }
/// let foo = box(HEAP) Bar::new(2);
/// let foo = box Bar::new(2);
/// ```
#[lang = "exchange_heap"]
#[experimental = "may be renamed; uncertain about custom allocator design"]
pub static HEAP: () = ();

/// A type that represents a uniquely-owned value.
#[lang = "owned_box"]
#[stable]
pub struct Box<T>(Unique<T>);

#[stable]
impl<T: Default> Default for Box<T> {
    #[stable]
    fn default() -> Box<T> { box Default::default() }
}

#[stable]
impl<T> Default for Box<[T]> {
    #[stable]
    fn default() -> Box<[T]> { box [] }
}

#[stable]
impl<T: Clone> Clone for Box<T> {
    /// Returns a copy of the owned box.
    #[inline]
    fn clone(&self) -> Box<T> { box {(**self).clone()} }

    /// Performs copy-assignment from `source` by reusing the existing allocation.
    #[inline]
    fn clone_from(&mut self, source: &Box<T>) {
        (**self).clone_from(&(**source));
    }
}

#[stable]
impl<T: ?Sized + PartialEq> PartialEq for Box<T> {
    #[inline]
    fn eq(&self, other: &Box<T>) -> bool { PartialEq::eq(&**self, &**other) }
    #[inline]
    fn ne(&self, other: &Box<T>) -> bool { PartialEq::ne(&**self, &**other) }
}
#[stable]
impl<T: ?Sized + PartialOrd> PartialOrd for Box<T> {
    #[inline]
    fn partial_cmp(&self, other: &Box<T>) -> Option<Ordering> {
        PartialOrd::partial_cmp(&**self, &**other)
    }
    #[inline]
    fn lt(&self, other: &Box<T>) -> bool { PartialOrd::lt(&**self, &**other) }
    #[inline]
    fn le(&self, other: &Box<T>) -> bool { PartialOrd::le(&**self, &**other) }
    #[inline]
    fn ge(&self, other: &Box<T>) -> bool { PartialOrd::ge(&**self, &**other) }
    #[inline]
    fn gt(&self, other: &Box<T>) -> bool { PartialOrd::gt(&**self, &**other) }
}
#[stable]
impl<T: ?Sized + Ord> Ord for Box<T> {
    #[inline]
    fn cmp(&self, other: &Box<T>) -> Ordering {
        Ord::cmp(&**self, &**other)
    }

#[stable]}
impl<T: ?Sized + Eq> Eq for Box<T> {}

#[cfg(stage0)]
impl<S: hash::Writer, T: ?Sized + Hash<S>> Hash<S> for Box<T> {
    #[inline]
    fn hash(&self, state: &mut S) {
        (**self).hash(state);
    }
}
#[cfg(not(stage0))]
impl<S: hash::Hasher, T: ?Sized + Hash<S>> Hash<S> for Box<T> {
    #[inline]
    fn hash(&self, state: &mut S) {
        (**self).hash(state);
    }
}

/// Extension methods for an owning `Any` trait object.
#[unstable = "post-DST and coherence changes, this will not be a trait but \
              rather a direct `impl` on `Box<Any>`"]
pub trait BoxAny {
    /// Returns the boxed value if it is of type `T`, or
    /// `Err(Self)` if it isn't.
    #[stable]
    fn downcast<T: 'static>(self) -> Result<Box<T>, Self>;
}

impl BoxAny for Box<Any> {
    #[inline]
    #[unstable = "method may be renamed with respect to other downcasting \
                  methods"]
    fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
        if self.is::<T>() {
            unsafe {
                // Get the raw representation of the trait object
                let to: TraitObject =
                    mem::transmute::<Box<Any>, TraitObject>(self);

                // Extract the data pointer
                Ok(mem::transmute(to.data))
            }
        } else {
            Err(self)
        }
    }
}

impl<T: ?Sized + fmt::Show> fmt::Show for Box<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Box({:?})", &**self)
    }
}

impl<T: ?Sized + fmt::String> fmt::String for Box<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::String::fmt(&**self, f)
    }
}

impl fmt::Show for Box<Any> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("Box<Any>")
    }
}

#[stable]
impl<T: ?Sized> Deref for Box<T> {
    type Target = T;

    fn deref(&self) -> &T { &**self }
}

#[stable]
impl<T: ?Sized> DerefMut for Box<T> {
    fn deref_mut(&mut self) -> &mut T { &mut **self }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_owned_clone() {
        let a = box 5i;
        let b: Box<int> = a.clone();
        assert!(a == b);
    }

    #[test]
    fn any_move() {
        let a = box 8u as Box<Any>;
        let b = box Test as Box<Any>;

        match a.downcast::<uint>() {
            Ok(a) => { assert!(a == box 8u); }
            Err(..) => panic!()
        }
        match b.downcast::<Test>() {
            Ok(a) => { assert!(a == box Test); }
            Err(..) => panic!()
        }

        let a = box 8u as Box<Any>;
        let b = box Test as Box<Any>;

        assert!(a.downcast::<Box<Test>>().is_err());
        assert!(b.downcast::<Box<uint>>().is_err());
    }

    #[test]
    fn test_show() {
        let a = box 8u as Box<Any>;
        let b = box Test as Box<Any>;
        let a_str = a.to_str();
        let b_str = b.to_str();
        assert_eq!(a_str, "Box<Any>");
        assert_eq!(b_str, "Box<Any>");

        let a = &8u as &Any;
        let b = &Test as &Any;
        let s = format!("{}", a);
        assert_eq!(s, "&Any");
        let s = format!("{}", b);
        assert_eq!(s, "&Any");
    }

    #[test]
    fn deref() {
        fn homura<T: Deref<Target=i32>>(_: T) { }
        homura(box 765i32);
    }
}
<commit_msg>rollup merge of #20710: daboross/fix-stable-before-bracket<commit_after>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A unique pointer type.

#![stable]

use core::any::Any;
use core::clone::Clone;
use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
use core::default::Default;
use core::fmt;
use core::hash::{self, Hash};
use core::marker::Sized;
use core::mem;
use core::option::Option;
use core::ptr::Unique;
use core::raw::TraitObject;
use core::result::Result;
use core::result::Result::{Ok, Err};
use core::ops::{Deref, DerefMut};

/// A value that represents the global exchange heap. This is the default
/// place that the `box` keyword allocates into when no place is supplied.
///
/// The following two examples are equivalent:
///
/// ```rust
/// use std::boxed::HEAP;
///
/// # struct Bar;
/// # impl Bar { fn new(_a: int) { } }
/// let foo = box(HEAP) Bar::new(2);
/// let foo = box Bar::new(2);
/// ```
#[lang = "exchange_heap"]
#[experimental = "may be renamed; uncertain about custom allocator design"]
pub static HEAP: () = ();

/// A type that represents a uniquely-owned value.
#[lang = "owned_box"]
#[stable]
pub struct Box<T>(Unique<T>);

#[stable]
impl<T: Default> Default for Box<T> {
    #[stable]
    fn default() -> Box<T> { box Default::default() }
}

#[stable]
impl<T> Default for Box<[T]> {
    #[stable]
    fn default() -> Box<[T]> { box [] }
}

#[stable]
impl<T: Clone> Clone for Box<T> {
    /// Returns a copy of the owned box.
    #[inline]
    fn clone(&self) -> Box<T> { box {(**self).clone()} }

    /// Performs copy-assignment from `source` by reusing the existing allocation.
    #[inline]
    fn clone_from(&mut self, source: &Box<T>) {
        (**self).clone_from(&(**source));
    }
}

#[stable]
impl<T: ?Sized + PartialEq> PartialEq for Box<T> {
    #[inline]
    fn eq(&self, other: &Box<T>) -> bool { PartialEq::eq(&**self, &**other) }
    #[inline]
    fn ne(&self, other: &Box<T>) -> bool { PartialEq::ne(&**self, &**other) }
}
#[stable]
impl<T: ?Sized + PartialOrd> PartialOrd for Box<T> {
    #[inline]
    fn partial_cmp(&self, other: &Box<T>) -> Option<Ordering> {
        PartialOrd::partial_cmp(&**self, &**other)
    }
    #[inline]
    fn lt(&self, other: &Box<T>) -> bool { PartialOrd::lt(&**self, &**other) }
    #[inline]
    fn le(&self, other: &Box<T>) -> bool { PartialOrd::le(&**self, &**other) }
    #[inline]
    fn ge(&self, other: &Box<T>) -> bool { PartialOrd::ge(&**self, &**other) }
    #[inline]
    fn gt(&self, other: &Box<T>) -> bool { PartialOrd::gt(&**self, &**other) }
}
#[stable]
impl<T: ?Sized + Ord> Ord for Box<T> {
    #[inline]
    fn cmp(&self, other: &Box<T>) -> Ordering {
        Ord::cmp(&**self, &**other)
    }
}
#[stable]
impl<T: ?Sized + Eq> Eq for Box<T> {}

#[cfg(stage0)]
impl<S: hash::Writer, T: ?Sized + Hash<S>> Hash<S> for Box<T> {
    #[inline]
    fn hash(&self, state: &mut S) {
        (**self).hash(state);
    }
}
#[cfg(not(stage0))]
impl<S: hash::Hasher, T: ?Sized + Hash<S>> Hash<S> for Box<T> {
    #[inline]
    fn hash(&self, state: &mut S) {
        (**self).hash(state);
    }
}

/// Extension methods for an owning `Any` trait object.
#[unstable = "post-DST and coherence changes, this will not be a trait but \
              rather a direct `impl` on `Box<Any>`"]
pub trait BoxAny {
    /// Returns the boxed value if it is of type `T`, or
    /// `Err(Self)` if it isn't.
    #[stable]
    fn downcast<T: 'static>(self) -> Result<Box<T>, Self>;
}

impl BoxAny for Box<Any> {
    #[inline]
    #[unstable = "method may be renamed with respect to other downcasting \
                  methods"]
    fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
        if self.is::<T>() {
            unsafe {
                // Get the raw representation of the trait object
                let to: TraitObject =
                    mem::transmute::<Box<Any>, TraitObject>(self);

                // Extract the data pointer
                Ok(mem::transmute(to.data))
            }
        } else {
            Err(self)
        }
    }
}

impl<T: ?Sized + fmt::Show> fmt::Show for Box<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Box({:?})", &**self)
    }
}

impl<T: ?Sized + fmt::String> fmt::String for Box<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::String::fmt(&**self, f)
    }
}

impl fmt::Show for Box<Any> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("Box<Any>")
    }
}

#[stable]
impl<T: ?Sized> Deref for Box<T> {
    type Target = T;

    fn deref(&self) -> &T { &**self }
}

#[stable]
impl<T: ?Sized> DerefMut for Box<T> {
    fn deref_mut(&mut self) -> &mut T { &mut **self }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_owned_clone() {
        let a = box 5i;
        let b: Box<int> = a.clone();
        assert!(a == b);
    }

    #[test]
    fn any_move() {
        let a = box 8u as Box<Any>;
        let b = box Test as Box<Any>;

        match a.downcast::<uint>() {
            Ok(a) => { assert!(a == box 8u); }
            Err(..) => panic!()
        }
        match b.downcast::<Test>() {
            Ok(a) => { assert!(a == box Test); }
            Err(..) => panic!()
        }

        let a = box 8u as Box<Any>;
        let b = box Test as Box<Any>;

        assert!(a.downcast::<Box<Test>>().is_err());
        assert!(b.downcast::<Box<uint>>().is_err());
    }

    #[test]
    fn test_show() {
        let a = box 8u as Box<Any>;
        let b = box Test as Box<Any>;
        let a_str = a.to_str();
        let b_str = b.to_str();
        assert_eq!(a_str, "Box<Any>");
        assert_eq!(b_str, "Box<Any>");

        let a = &8u as &Any;
        let b = &Test as &Any;
        let s = format!("{}", a);
        assert_eq!(s, "&Any");
        let s = format!("{}", b);
        assert_eq!(s, "&Any");
    }

    #[test]
    fn deref() {
        fn homura<T: Deref<Target=i32>>(_: T) { }
        homura(box 765i32);
    }
}
<|endoftext|>


<commit_before>extern crate serde_json;
extern crate zmq;

use std::cell::RefCell;
use std::thread;

use errors::common::CommonError;
use errors::pool::PoolError;
use utils::json::{JsonDecodable, JsonEncodable};
use utils::sequence::SequenceUtils;

struct RemoteAgent {
    socket: zmq::Socket,
    addr: String,
    public_key: String,
    secret_key: String,
    server_key: String,
}

struct AgentWorker {
    cmd_socket: zmq::Socket,
    agent_connections: Vec<RemoteAgent>,
}

struct Agent {
    cmd_socket: zmq::Socket,
    worker: Option<thread::JoinHandle<()>>,
}

impl Drop for Agent {
    fn drop(&mut self) {
        trace!("agent drop >>");
        self.cmd_socket.send_str(AgentWorkerCommand::Exit.to_json().unwrap().as_str(), zmq::DONTWAIT).unwrap(); //TODO
        self.worker.take().unwrap().join().unwrap();
        trace!("agent drop <<");
    }
}

pub struct AgentService {
    agent: RefCell<Option<Agent>>,
}

impl Agent {
    pub fn new() -> Agent {
        let ctx = zmq::Context::new();
        let (send_soc, recv_soc) = _create_zmq_socket_pair("agent", true).unwrap();
        let mut worker = AgentWorker {
            cmd_socket: recv_soc,
            agent_connections: Vec::new(),
        };
        Agent {
            cmd_socket: send_soc,
            worker: Some(thread::spawn(move || { worker.run() }))
        }
    }
}

impl AgentService {
    pub fn new() -> AgentService {
        AgentService { agent: RefCell::new((None)) }
    }

    pub fn connect(&self, sender_did: &str, my_sk: &str, my_pk: &str, endpoint: &str, server_key: &str) -> Result<(), CommonError> {
        let mut agent = self.agent.borrow_mut();
        if agent.is_none() {
            *agent = Some(Agent::new());
        }
        let conn_handle = SequenceUtils::get_next_id();
        let connect_cmd: AgentWorkerCommand = AgentWorkerCommand::Connect(ConnectCmd {
            did: sender_did.to_string(),
            secret_key: my_sk.to_string(),
            public_key: my_pk.to_string(),
            endpoint: endpoint.to_string(),
            server_key: server_key.to_string(),
        });
        agent.as_ref().unwrap().cmd_socket.send_str(connect_cmd.to_json().unwrap().as_str(), zmq::DONTWAIT).unwrap();
        Ok(())
    }
}

impl AgentWorker {
    fn run(&mut self) {
        loop {
            trace!("agent worker poll loop >>");
            self.cmd_socket.poll(zmq::POLLIN, -1).unwrap();
            let s = self.cmd_socket.recv_string(zmq::DONTWAIT).unwrap().unwrap();
            let cmd = AgentWorkerCommand::from_json(s.as_str()).unwrap();
            match cmd {
                AgentWorkerCommand::Connect(cmd) => self.connect(&cmd).unwrap(),
                AgentWorkerCommand::Exit => break,
            }
            info!("received cmd {}", s);
            trace!("agent worker poll loop <<");
        }
        trace!("agent poll finished");
    }

    fn connect(&mut self, cmd: &ConnectCmd) -> Result<(), PoolError> {
        let ra = RemoteAgent::new(cmd.public_key.as_str(), cmd.secret_key.as_str(),
                                  cmd.server_key.as_str(), cmd.endpoint.as_str())
            .map_err(map_err_trace!("RemoteAgent::new failed"))?;
        ra.connect().map_err(map_err_trace!("RemoteAgent::connect failed"))?;
        self.agent_connections.push(ra);
        Ok(())
    }
}

impl RemoteAgent {
    fn new(pub_key: &str, sec_key: &str, ver_key: &str, addr: &str) -> Result<RemoteAgent, zmq::Error> {
        Ok(RemoteAgent {
            socket: zmq::Context::new().socket(zmq::SocketType::DEALER)?,
            public_key: pub_key.to_string(),
            secret_key: sec_key.to_string(),
            server_key: ver_key.to_string(),
            addr: addr.to_string(),
        })
    }

    fn connect(&self) -> Result<(), PoolError> {
        impl From<zmq::EncodeError> for PoolError {
            fn from(err: zmq::EncodeError) -> PoolError {
                PoolError::InvalidState(format!("Invalid data stored RemoteAgent detected while connect {:?}", err))
            }
        }
        self.socket.set_identity(self.public_key.as_bytes()).map_err(map_err_trace!())?;
        self.socket.set_curve_secretkey(self.secret_key.as_str()).map_err(map_err_trace!())?;
        self.socket.set_curve_publickey(self.public_key.as_str()).map_err(map_err_trace!())?;
        self.socket.set_curve_serverkey(self.server_key.as_str()).map_err(map_err_trace!())?;
        self.socket.set_linger(0).map_err(map_err_trace!())?; //TODO set correct timeout
        self.socket.connect(self.addr.as_str()).map_err(map_err_trace!())?;
        self.socket.send_str("DID", zmq::DONTWAIT).map_err(map_err_trace!())?;
        Ok(())
    }
}

#[serde(tag = "cmd")]
#[derive(Serialize, Deserialize, Debug)]
enum AgentWorkerCommand {
    Connect(ConnectCmd),
    Exit,
}

impl JsonEncodable for AgentWorkerCommand {}

impl<'a> JsonDecodable<'a> for AgentWorkerCommand {}

#[derive(Serialize, Deserialize, Debug)]
struct ConnectCmd {
    endpoint: String,
    did: String,
    secret_key: String,
    public_key: String,
    server_key: String,
}

fn _create_zmq_socket_pair(address: &str, connect_and_bind: bool) -> Result<(zmq::Socket, zmq::Socket), zmq::Error> {
    let ctx = zmq::Context::new();
    let recv_soc = ctx.socket(zmq::SocketType::PAIR)?;
    let send_soc = ctx.socket(zmq::SocketType::PAIR)?;
    if connect_and_bind {
        let address = format!("inproc://{}", address);
        recv_soc.bind(&address)?;
        send_soc.connect(&address)?;
    }
    Ok((send_soc, recv_soc))
}

#[cfg(test)]
mod tests {
    use super::*;

    use std::sync::mpsc::channel;

    use utils::timeout::TimeoutUtils;

    #[test]
    fn agent_can_be_dropped() {
        let (sender, receiver) = channel();
        thread::spawn(move || {
            {
                let agent = Agent::new();
            }
            sender.send(true).unwrap();
        });
        receiver.recv_timeout(TimeoutUtils::short_timeout()).expect("drop not finished");
    }

    #[test]
    fn agent_service_connect_works() {
        let (sender, receiver) = channel();
        let (send_soc, recv_soc) = _create_zmq_socket_pair("test_connect", true).unwrap();
        let agent = Agent {
            cmd_socket: send_soc,
            worker: Some(thread::spawn(move || {
                sender.send(recv_soc.recv_string(0).unwrap().unwrap()).unwrap()
            }))
        };
        let agent_service = AgentService {
            agent: RefCell::new(Some(agent)),
        };
        agent_service.connect("sd", "sk", "pk", "ep", "serv").unwrap();
        let expected_cmd = ConnectCmd {
            server_key: "serv".to_string(),
            public_key: "pk".to_string(),
            secret_key: "sk".to_string(),
            endpoint: "ep".to_string(),
            did: "sd".to_string(),
        };
        let str = receiver.recv_timeout(TimeoutUtils::short_timeout()).unwrap();
        assert_eq!(str, AgentWorkerCommand::Connect(expected_cmd).to_json().unwrap());
    }

    #[test]
    fn agent_worker_connect_works() {
        ::utils::logger::LoggerUtils::init();
        let send_key_pair = zmq::CurveKeyPair::new().unwrap();
        let recv_key_pair = zmq::CurveKeyPair::new().unwrap();
        let ctx = zmq::Context::new();
        let recv_soc = ctx.socket(zmq::SocketType::ROUTER).unwrap();
        recv_soc.set_curve_publickey(recv_key_pair.public_key.as_str()).unwrap();
        recv_soc.set_curve_secretkey(recv_key_pair.secret_key.as_str()).unwrap();
        recv_soc.set_curve_server(true).unwrap();
        recv_soc.bind("tcp://127.0.0.1:*").unwrap();
        let addr = recv_soc.get_last_endpoint().unwrap().unwrap();
        info!("addr {}", addr);

        let mut agent_worker = AgentWorker {
            agent_connections: Vec::new(),
            cmd_socket: zmq::Context::new().socket(zmq::SocketType::PAIR).unwrap(),
        };
        let cmd = ConnectCmd {
            endpoint: addr,
            public_key: send_key_pair.public_key.to_string(),
            secret_key: send_key_pair.secret_key.to_string(),
            did: "".to_string(),
            server_key: recv_key_pair.public_key.to_string(),
        };

        agent_worker.connect(&cmd).unwrap();

        assert_eq!(agent_worker.agent_connections.len(), 1);
        recv_soc.recv_string(0).unwrap().unwrap(); //ignore identity
        assert_eq!(recv_soc.recv_string(zmq::DONTWAIT).unwrap().unwrap(), "DID");
    }

    #[test]
    fn remote_agent_connect_works() {
        let dest = "test_agent_connect";
        let addr: String = format!("inproc://{}", dest);
        let (send_soc, recv_soc) = _create_zmq_socket_pair(dest, false).unwrap();
        recv_soc.bind(addr.as_str()).unwrap(); //TODO enable CurveCP
        let send_key_pair = zmq::CurveKeyPair::new().unwrap();
        let recv_key_pair = zmq::CurveKeyPair::new().unwrap();
        let agent = RemoteAgent {
            socket: send_soc,
            addr: addr,
            server_key: recv_key_pair.public_key,
            secret_key: send_key_pair.secret_key,
            public_key: send_key_pair.public_key,
        };
        agent.connect().unwrap();
        assert_eq!(recv_soc.recv_string(zmq::DONTWAIT).unwrap().unwrap(), "DID");
    }

    #[test]
    fn agent_service_static_create_zmq_socket_pair_works() {
        let msg = "msg";
        let sockets = _create_zmq_socket_pair("test_pair", true).unwrap();
        sockets.0.send_str(msg, zmq::DONTWAIT).unwrap();
        assert_eq!(sockets.1.recv_string(zmq::DONTWAIT).unwrap().unwrap(), msg);
    }
}<commit_msg>Fix format of keys in RemoteAgent.<commit_after>extern crate rust_base58;
extern crate serde_json;
extern crate zmq;

use self::rust_base58::FromBase58;
use std::cell::RefCell;
use std::thread;

use errors::common::CommonError;
use errors::pool::PoolError;
use utils::json::{JsonDecodable, JsonEncodable};
use utils::sequence::SequenceUtils;

struct RemoteAgent {
    socket: zmq::Socket,
    addr: String,
    public_key: Vec<u8>,
    secret_key: Vec<u8>,
    server_key: Vec<u8>,
}

struct AgentWorker {
    cmd_socket: zmq::Socket,
    agent_connections: Vec<RemoteAgent>,
}

struct Agent {
    cmd_socket: zmq::Socket,
    worker: Option<thread::JoinHandle<()>>,
}

impl Drop for Agent {
    fn drop(&mut self) {
        trace!("agent drop >>");
        self.cmd_socket.send_str(AgentWorkerCommand::Exit.to_json().unwrap().as_str(), zmq::DONTWAIT).unwrap(); //TODO
        self.worker.take().unwrap().join().unwrap();
        trace!("agent drop <<");
    }
}

pub struct AgentService {
    agent: RefCell<Option<Agent>>,
}

impl Agent {
    pub fn new() -> Agent {
        let ctx = zmq::Context::new();
        let (send_soc, recv_soc) = _create_zmq_socket_pair("agent", true).unwrap();
        let mut worker = AgentWorker {
            cmd_socket: recv_soc,
            agent_connections: Vec::new(),
        };
        Agent {
            cmd_socket: send_soc,
            worker: Some(thread::spawn(move || { worker.run() }))
        }
    }
}

impl AgentService {
    pub fn new() -> AgentService {
        AgentService { agent: RefCell::new((None)) }
    }

    pub fn connect(&self, sender_did: &str, my_sk: &str, my_pk: &str, endpoint: &str, server_key: &str) -> Result<(), CommonError> {
        let mut agent = self.agent.borrow_mut();
        if agent.is_none() {
            *agent = Some(Agent::new());
        }
        let conn_handle = SequenceUtils::get_next_id();
        let connect_cmd: AgentWorkerCommand = AgentWorkerCommand::Connect(ConnectCmd {
            did: sender_did.to_string(),
            secret_key: my_sk.to_string(),
            public_key: my_pk.to_string(),
            endpoint: endpoint.to_string(),
            server_key: server_key.to_string(),
        });
        agent.as_ref().unwrap().cmd_socket.send_str(connect_cmd.to_json().unwrap().as_str(), zmq::DONTWAIT).unwrap();
        Ok(())
    }
}

impl AgentWorker {
    fn run(&mut self) {
        loop {
            trace!("agent worker poll loop >>");
            self.cmd_socket.poll(zmq::POLLIN, -1).unwrap();
            let s = self.cmd_socket.recv_string(zmq::DONTWAIT).unwrap().unwrap();
            let cmd = AgentWorkerCommand::from_json(s.as_str()).unwrap();
            match cmd {
                AgentWorkerCommand::Connect(cmd) => self.connect(&cmd).unwrap(),
                AgentWorkerCommand::Exit => break,
            }
            info!("received cmd {}", s);
            trace!("agent worker poll loop <<");
        }
        trace!("agent poll finished");
    }

    fn connect(&mut self, cmd: &ConnectCmd) -> Result<(), PoolError> {
        let ra = RemoteAgent::new(cmd.public_key.as_str(), cmd.secret_key.as_str(),
                                  cmd.server_key.as_str(), cmd.endpoint.as_str())
            .map_err(map_err_trace!("RemoteAgent::new failed"))?;
        ra.connect().map_err(map_err_trace!("RemoteAgent::connect failed"))?;
        self.agent_connections.push(ra);
        Ok(())
    }
}

impl RemoteAgent {
    fn new(pub_key: &str, sec_key: &str, ver_key: &str, addr: &str) -> Result<RemoteAgent, PoolError> {
        Ok(RemoteAgent {
            socket: zmq::Context::new().socket(zmq::SocketType::DEALER)?,
            public_key: pub_key.from_base58()
                .map_err(PoolError::from_displayable_as_invalid_config)?,
            secret_key: sec_key.from_base58()
                .map_err(PoolError::from_displayable_as_invalid_config)?,
            server_key: ver_key.from_base58()
                .map_err(PoolError::from_displayable_as_invalid_config)?,
            addr: addr.to_string(),
        })
    }

    fn connect(&self) -> Result<(), PoolError> {
        impl From<zmq::EncodeError> for PoolError {
            fn from(err: zmq::EncodeError) -> PoolError {
                PoolError::InvalidState(format!("Invalid data stored RemoteAgent detected while connect {:?}", err))
            }
        }
        self.socket.set_identity(zmq::z85_encode(self.public_key.as_slice())?.as_bytes())
            .map_err(map_err_trace!())?;
        self.socket.set_curve_secretkey(zmq::z85_encode(self.secret_key.as_slice())?.as_str())
            .map_err(map_err_trace!())?;
        self.socket.set_curve_publickey(zmq::z85_encode(self.public_key.as_slice())?.as_str())
            .map_err(map_err_trace!())?;
        self.socket.set_curve_serverkey(zmq::z85_encode(self.server_key.as_slice())?.as_str())
            .map_err(map_err_trace!())?;
        self.socket.set_linger(0).map_err(map_err_trace!())?; //TODO set correct timeout
        self.socket.connect(self.addr.as_str()).map_err(map_err_trace!())?;
        self.socket.send_str("DID", zmq::DONTWAIT).map_err(map_err_trace!())?;
        Ok(())
    }
}

#[serde(tag = "cmd")]
#[derive(Serialize, Deserialize, Debug)]
enum AgentWorkerCommand {
    Connect(ConnectCmd),
    Exit,
}

impl JsonEncodable for AgentWorkerCommand {}

impl<'a> JsonDecodable<'a> for AgentWorkerCommand {}

#[derive(Serialize, Deserialize, Debug)]
struct ConnectCmd {
    endpoint: String,
    did: String,
    secret_key: String,
    public_key: String,
    server_key: String,
}

fn _create_zmq_socket_pair(address: &str, connect_and_bind: bool) -> Result<(zmq::Socket, zmq::Socket), zmq::Error> {
    let ctx = zmq::Context::new();
    let recv_soc = ctx.socket(zmq::SocketType::PAIR)?;
    let send_soc = ctx.socket(zmq::SocketType::PAIR)?;
    if connect_and_bind {
        let address = format!("inproc://{}", address);
        recv_soc.bind(&address)?;
        send_soc.connect(&address)?;
    }
    Ok((send_soc, recv_soc))
}

#[cfg(test)]
mod tests {
    use super::*;

    use std::sync::mpsc::channel;
    use super::rust_base58::ToBase58;

    use utils::timeout::TimeoutUtils;

    #[test]
    fn agent_can_be_dropped() {
        let (sender, receiver) = channel();
        thread::spawn(move || {
            {
                let agent = Agent::new();
            }
            sender.send(true).unwrap();
        });
        receiver.recv_timeout(TimeoutUtils::short_timeout()).expect("drop not finished");
    }

    #[test]
    fn agent_service_connect_works() {
        let (sender, receiver) = channel();
        let (send_soc, recv_soc) = _create_zmq_socket_pair("test_connect", true).unwrap();
        let agent = Agent {
            cmd_socket: send_soc,
            worker: Some(thread::spawn(move || {
                sender.send(recv_soc.recv_string(0).unwrap().unwrap()).unwrap()
            }))
        };
        let agent_service = AgentService {
            agent: RefCell::new(Some(agent)),
        };
        agent_service.connect("sd", "sk", "pk", "ep", "serv").unwrap();
        let expected_cmd = ConnectCmd {
            server_key: "serv".to_string(),
            public_key: "pk".to_string(),
            secret_key: "sk".to_string(),
            endpoint: "ep".to_string(),
            did: "sd".to_string(),
        };
        let str = receiver.recv_timeout(TimeoutUtils::short_timeout()).unwrap();
        assert_eq!(str, AgentWorkerCommand::Connect(expected_cmd).to_json().unwrap());
    }

    #[test]
    fn agent_worker_connect_works() {
        ::utils::logger::LoggerUtils::init();
        let send_key_pair = zmq::CurveKeyPair::new().unwrap();
        let recv_key_pair = zmq::CurveKeyPair::new().unwrap();
        let ctx = zmq::Context::new();
        let recv_soc = ctx.socket(zmq::SocketType::ROUTER).unwrap();
        recv_soc.set_curve_publickey(recv_key_pair.public_key.as_str()).unwrap();
        recv_soc.set_curve_secretkey(recv_key_pair.secret_key.as_str()).unwrap();
        recv_soc.set_curve_server(true).unwrap();
        recv_soc.bind("tcp://127.0.0.1:*").unwrap();
        let addr = recv_soc.get_last_endpoint().unwrap().unwrap();
        info!("addr {}", addr);

        let mut agent_worker = AgentWorker {
            agent_connections: Vec::new(),
            cmd_socket: zmq::Context::new().socket(zmq::SocketType::PAIR).unwrap(),
        };
        let cmd = ConnectCmd {
            endpoint: addr,
            public_key: zmq::z85_decode(send_key_pair.public_key.as_str()).unwrap().to_base58(),
            secret_key: zmq::z85_decode(send_key_pair.secret_key.as_str()).unwrap().to_base58(),
            did: "".to_string(),
            server_key: zmq::z85_decode(recv_key_pair.public_key.as_str()).unwrap().to_base58(),
        };

        agent_worker.connect(&cmd).unwrap();

        assert_eq!(agent_worker.agent_connections.len(), 1);
        recv_soc.recv_string(0).unwrap().unwrap(); //ignore identity
        assert_eq!(recv_soc.recv_string(zmq::DONTWAIT).unwrap().unwrap(), "DID");
    }

    #[test]
    fn remote_agent_connect_works() {
        let dest = "test_agent_connect";
        let addr: String = format!("inproc://{}", dest);
        let (send_soc, recv_soc) = _create_zmq_socket_pair(dest, false).unwrap();
        recv_soc.bind(addr.as_str()).unwrap(); //TODO enable CurveCP
        let send_key_pair = zmq::CurveKeyPair::new().unwrap();
        let recv_key_pair = zmq::CurveKeyPair::new().unwrap();
        let agent = RemoteAgent {
            socket: send_soc,
            addr: addr,
            server_key: zmq::z85_decode(send_key_pair.public_key.as_str()).unwrap(),
            secret_key: zmq::z85_decode(recv_key_pair.secret_key.as_str()).unwrap(),
            public_key: zmq::z85_decode(recv_key_pair.public_key.as_str()).unwrap(),
        };
        agent.connect().unwrap();
        assert_eq!(recv_soc.recv_string(zmq::DONTWAIT).unwrap().unwrap(), "DID");
    }

    #[test]
    fn agent_service_static_create_zmq_socket_pair_works() {
        let msg = "msg";
        let sockets = _create_zmq_socket_pair("test_pair", true).unwrap();
        sockets.0.send_str(msg, zmq::DONTWAIT).unwrap();
        assert_eq!(sockets.1.recv_string(zmq::DONTWAIT).unwrap().unwrap(), msg);
    }
}<|endoftext|>


<commit_before>// High-level bindings to Azure.

import bindgen::{AzCreateColorPattern, AzCreateDrawTargetForCairoSurface};
import bindgen::{AzDrawSurfaceOptions, AzDrawTargetClearRect, AzDrawTargetCreateSourceSurfaceFromData};
import bindgen::{AzDrawTargetDrawSurface, AzDrawTargetFillRect, AzDrawTargetFlush};
import bindgen::{AzDrawTargetStrokeRect, AzFilter, AzReleaseColorPattern, AzReleaseDrawTarget};
import bindgen::{AzReleaseSourceSurface, AzSurfaceFormat};
import cairo_hl::ImageSurface;
import geom::rect::Rect;
import geom::size::Size2D;
import ptr::{addr_of, null};

trait AsAzureRect {
    fn as_azure_rect() -> AzRect;
}

impl AzureExtensions of AsAzureRect for Rect<AzFloat> {
    fn as_azure_rect() -> AzRect {
        {
            x: self.origin.x,
            y: self.origin.y,
            width: self.size.width,
            height: self.size.height
        }
    }
}

trait AsAzureIntSize {
    fn as_azure_int_size() -> AzIntSize;
}

impl AzureExtensions of AsAzureIntSize for Size2D<i32> {
    fn as_azure_int_size() -> AzIntSize {
        {
            width: self.width,
            height: self.height
        }
    }
}

class Color {
    let r: AzFloat;
    let g: AzFloat;
    let b: AzFloat;
    let a: AzFloat;

    new(r: AzFloat, g: AzFloat, b: AzFloat, a: AzFloat) {
        self.r = r;
        self.g = g;
        self.b = b;
        self.a = a;
    }

    fn as_azure_color() -> AzColor {
        { r: self.r, g: self.g, b: self.b, a: self.a }
    }
}

// FIXME: Should have a class hierarchy here starting with Pattern.
class ColorPattern {
    let azure_color_pattern: AzColorPatternRef;

    new(+color: Color) {
        self.azure_color_pattern = AzCreateColorPattern(addr_of(color.as_azure_color()));
    }

    drop {
        AzReleaseColorPattern(self.azure_color_pattern);
    }
}

class StrokeOptions {
    let line_width: AzFloat;
    let miter_limit: AzFloat;
    let fields: uint16_t;

    new(line_width: AzFloat, miter_limit: AzFloat, fields: uint16_t) {
        self.line_width = line_width;
        self.miter_limit = miter_limit;
        self.fields = fields;
    }

    fn as_azure_stroke_options() -> AzStrokeOptions {
        {
            mLineWidth: self.line_width,
            mMiterLimit: self.miter_limit,
            mDashPattern: null(),
            mDashLength: 0,
            mDashOffset: 0.0f as AzFloat,
            fields: 0
        }
    }
}

class DrawOptions {
    let alpha: AzFloat;
    let fields: uint16_t;

    new(alpha: AzFloat, fields: uint16_t) {
        self.alpha = alpha;
        self.fields = fields;
    }

    fn as_azure_draw_options() -> AzDrawOptions {
        {
            mAlpha: self.alpha,
            fields: self.fields
        }
    }
}

enum SurfaceFormat {
    B8G8R8A8,
    R8G8R8X8,
    R5G6B5,
    A8
}

impl extensions for SurfaceFormat {
    fn as_azure_surface_format() -> AzSurfaceFormat {
        self as AzSurfaceFormat
    }
}

enum Filter {
    Linear,
    Point
}

impl extensions for Filter {
    fn as_azure_filter() -> AzFilter {
        self as AzFilter
    }
}

struct DrawSurfaceOptions {
    filter: Filter;
    sampling_bounds: bool;

    new(filter: Filter, sampling_bounds: bool) {
        self.filter = filter;
        self.sampling_bounds = sampling_bounds;
    }

    fn as_azure_draw_surface_options() -> AzDrawSurfaceOptions {
        { fields: ((self.filter as int) | (if self.sampling_bounds { 8 } else { 0 })) as u32 }
    }
}

class DrawTarget {
    let azure_draw_target: AzDrawTargetRef;

    new(&&cairo_surface: ImageSurface) {
        self.azure_draw_target = AzCreateDrawTargetForCairoSurface(cairo_surface.cairo_surface);
    }

    drop {
        AzReleaseDrawTarget(self.azure_draw_target);
    }

    fn flush() {
        AzDrawTargetFlush(self.azure_draw_target);
    }

    fn clear_rect(&&rect: Rect<AzFloat>) {
        AzDrawTargetClearRect(self.azure_draw_target, addr_of(rect.as_azure_rect()));
    }

    fn fill_rect(&&rect: Rect<AzFloat>, &&pattern: ColorPattern) {
        AzDrawTargetFillRect(self.azure_draw_target,
                             addr_of(rect.as_azure_rect()),
                             pattern.azure_color_pattern);
    }

    fn stroke_rect(&&rect: Rect<AzFloat>, &&pattern: ColorPattern, &&stroke_options: StrokeOptions,
                   &&draw_options: DrawOptions) {
        AzDrawTargetStrokeRect(self.azure_draw_target,
                               addr_of(rect.as_azure_rect()),
                               pattern.azure_color_pattern,
                               addr_of(stroke_options.as_azure_stroke_options()),
                               addr_of(draw_options.as_azure_draw_options()));
    }

    fn draw_surface(surface: SourceSurface, dest: Rect<AzFloat>, source: Rect<AzFloat>,
                    surf_options: DrawSurfaceOptions, options: DrawOptions) {

        AzDrawTargetDrawSurface(self.azure_draw_target,
                                surface.azure_source_surface,
                                addr_of(dest.as_azure_rect()),
                                addr_of(source.as_azure_rect()),
                                addr_of(surf_options.as_azure_draw_surface_options()),
                                addr_of(options.as_azure_draw_options()));
    }

    fn create_source_surface_from_data(data: &[u8], size: Size2D<i32>, stride: i32,
                                       format: SurfaceFormat) -> SourceSurface {

        assert data.len() as i32 == stride * size.height;
        let azure_surface =
            AzDrawTargetCreateSourceSurfaceFromData(self.azure_draw_target,
                                                    addr_of(data[0]),
                                                    addr_of(size.as_azure_int_size()),
                                                    stride,
                                                    format.as_azure_surface_format());
        SourceSurface(azure_surface)
    }
}

struct SourceSurface {
    azure_source_surface: AzSourceSurfaceRef;

    new(azure_source_surface: AzSourceSurfaceRef) {
        self.azure_source_surface = azure_source_surface;
    }

    drop {
        AzReleaseSourceSurface(self.azure_source_surface);
    }
}

<commit_msg>Fixed nonresolving imports<commit_after>// High-level bindings to Azure.

import bindgen::{AzCreateColorPattern, AzCreateDrawTargetForCairoSurface};
import AzDrawSurfaceOptions;
import bindgen::AzDrawTargetClearRect;
import bindgen::AzDrawTargetCreateSourceSurfaceFromData;
import bindgen::{AzDrawTargetDrawSurface, AzDrawTargetFillRect, AzDrawTargetFlush};
import bindgen::{AzDrawTargetStrokeRect};
import AzFilter;
import bindgen::{AzReleaseColorPattern, AzReleaseDrawTarget};
import bindgen::AzReleaseSourceSurface;
import AzSurfaceFormat;
import cairo_hl::ImageSurface;
import geom::rect::Rect;
import geom::size::Size2D;
import ptr::{addr_of, null};

trait AsAzureRect {
    fn as_azure_rect() -> AzRect;
}

impl AzureExtensions of AsAzureRect for Rect<AzFloat> {
    fn as_azure_rect() -> AzRect {
        {
            x: self.origin.x,
            y: self.origin.y,
            width: self.size.width,
            height: self.size.height
        }
    }
}

trait AsAzureIntSize {
    fn as_azure_int_size() -> AzIntSize;
}

impl AzureExtensions of AsAzureIntSize for Size2D<i32> {
    fn as_azure_int_size() -> AzIntSize {
        {
            width: self.width,
            height: self.height
        }
    }
}

class Color {
    let r: AzFloat;
    let g: AzFloat;
    let b: AzFloat;
    let a: AzFloat;

    new(r: AzFloat, g: AzFloat, b: AzFloat, a: AzFloat) {
        self.r = r;
        self.g = g;
        self.b = b;
        self.a = a;
    }

    fn as_azure_color() -> AzColor {
        { r: self.r, g: self.g, b: self.b, a: self.a }
    }
}

// FIXME: Should have a class hierarchy here starting with Pattern.
class ColorPattern {
    let azure_color_pattern: AzColorPatternRef;

    new(+color: Color) {
        self.azure_color_pattern = AzCreateColorPattern(addr_of(color.as_azure_color()));
    }

    drop {
        AzReleaseColorPattern(self.azure_color_pattern);
    }
}

class StrokeOptions {
    let line_width: AzFloat;
    let miter_limit: AzFloat;
    let fields: uint16_t;

    new(line_width: AzFloat, miter_limit: AzFloat, fields: uint16_t) {
        self.line_width = line_width;
        self.miter_limit = miter_limit;
        self.fields = fields;
    }

    fn as_azure_stroke_options() -> AzStrokeOptions {
        {
            mLineWidth: self.line_width,
            mMiterLimit: self.miter_limit,
            mDashPattern: null(),
            mDashLength: 0,
            mDashOffset: 0.0f as AzFloat,
            fields: 0
        }
    }
}

class DrawOptions {
    let alpha: AzFloat;
    let fields: uint16_t;

    new(alpha: AzFloat, fields: uint16_t) {
        self.alpha = alpha;
        self.fields = fields;
    }

    fn as_azure_draw_options() -> AzDrawOptions {
        {
            mAlpha: self.alpha,
            fields: self.fields
        }
    }
}

enum SurfaceFormat {
    B8G8R8A8,
    R8G8R8X8,
    R5G6B5,
    A8
}

impl extensions for SurfaceFormat {
    fn as_azure_surface_format() -> AzSurfaceFormat {
        self as AzSurfaceFormat
    }
}

enum Filter {
    Linear,
    Point
}

impl extensions for Filter {
    fn as_azure_filter() -> AzFilter {
        self as AzFilter
    }
}

struct DrawSurfaceOptions {
    filter: Filter;
    sampling_bounds: bool;

    new(filter: Filter, sampling_bounds: bool) {
        self.filter = filter;
        self.sampling_bounds = sampling_bounds;
    }

    fn as_azure_draw_surface_options() -> AzDrawSurfaceOptions {
        { fields: ((self.filter as int) | (if self.sampling_bounds { 8 } else { 0 })) as u32 }
    }
}

class DrawTarget {
    let azure_draw_target: AzDrawTargetRef;

    new(&&cairo_surface: ImageSurface) {
        self.azure_draw_target = AzCreateDrawTargetForCairoSurface(cairo_surface.cairo_surface);
    }

    drop {
        AzReleaseDrawTarget(self.azure_draw_target);
    }

    fn flush() {
        AzDrawTargetFlush(self.azure_draw_target);
    }

    fn clear_rect(&&rect: Rect<AzFloat>) {
        AzDrawTargetClearRect(self.azure_draw_target, addr_of(rect.as_azure_rect()));
    }

    fn fill_rect(&&rect: Rect<AzFloat>, &&pattern: ColorPattern) {
        AzDrawTargetFillRect(self.azure_draw_target,
                             addr_of(rect.as_azure_rect()),
                             pattern.azure_color_pattern);
    }

    fn stroke_rect(&&rect: Rect<AzFloat>, &&pattern: ColorPattern, &&stroke_options: StrokeOptions,
                   &&draw_options: DrawOptions) {
        AzDrawTargetStrokeRect(self.azure_draw_target,
                               addr_of(rect.as_azure_rect()),
                               pattern.azure_color_pattern,
                               addr_of(stroke_options.as_azure_stroke_options()),
                               addr_of(draw_options.as_azure_draw_options()));
    }

    fn draw_surface(surface: SourceSurface, dest: Rect<AzFloat>, source: Rect<AzFloat>,
                    surf_options: DrawSurfaceOptions, options: DrawOptions) {

        AzDrawTargetDrawSurface(self.azure_draw_target,
                                surface.azure_source_surface,
                                addr_of(dest.as_azure_rect()),
                                addr_of(source.as_azure_rect()),
                                addr_of(surf_options.as_azure_draw_surface_options()),
                                addr_of(options.as_azure_draw_options()));
    }

    fn create_source_surface_from_data(data: &[u8], size: Size2D<i32>, stride: i32,
                                       format: SurfaceFormat) -> SourceSurface {

        assert data.len() as i32 == stride * size.height;
        let azure_surface =
            AzDrawTargetCreateSourceSurfaceFromData(self.azure_draw_target,
                                                    addr_of(data[0]),
                                                    addr_of(size.as_azure_int_size()),
                                                    stride,
                                                    format.as_azure_surface_format());
        SourceSurface(azure_surface)
    }
}

struct SourceSurface {
    azure_source_surface: AzSourceSurfaceRef;

    new(azure_source_surface: AzSourceSurfaceRef) {
        self.azure_source_surface = azure_source_surface;
    }

    drop {
        AzReleaseSourceSurface(self.azure_source_surface);
    }
}

<|endoftext|>