<commit_before>use std::fmt::Debug;
use std::hash::{hash,Hash,Hasher,SipHasher};
use std::collections::HashMap;
use std::mem::replace;
use std::mem::transmute;
use std::rc::Rc;
use std::fmt;
use std::marker::PhantomData;
use std::fmt::{Formatter,Result};

use adapton_syntax::{ProgPt};

// use adapton_syntax::*;
use adapton_sigs::*;

#[derive(Debug)]
pub struct Frame {
    loc   : Rc<Loc>,    // The currently-executing node
    path  : Rc<Path>,   // The current path for creating new nodes; invariant: (prefix-of frame.loc.path frame.path)
    succs : Vec<Succ>,  // The currently-executing node's effects (viz., the nodes it demands)
}

// Each location identifies a node in the DCG.
#[derive(Hash,Debug,PartialEq,Eq,Clone)]
pub struct Loc {
    path : Rc<Path>,
    id   : Rc<ArtId<Name>>,
    hash : u64, // hash of (path,id)
}

// Paths are built using the ns command.
#[derive(Hash,Debug,PartialEq,Eq,Clone)]
pub enum Path {
    Empty,
    Child(Rc<Path>,Name),
}

// Names provide a symbolic way to identify nodes.
#[derive(Hash,Debug,PartialEq,Eq,Clone)]
pub struct Name {
    hash : u64, // hash of symbol
    symbol : Rc<Symbol>,
}

// Symbols
//
// For a general semantics of symbols, see Chapter 31 of PFPL 2nd Edition. Harper 2015:
// http://www.cs.cmu.edu/~rwh/plbook/2nded.pdf
//
#[derive(Hash,Debug,PartialEq,Eq,Clone)]
pub enum Symbol {
    Root, // Root identifies the outside environment of Rust code.
    Nil,  // Nil for non-symbolic, hash-based names.
    String(String), U64(u64),   // Strings and U64s are unique symbols.
    Pair(Rc<Symbol>,Rc<Symbol>),
    ForkL(Rc<Symbol>),
    ForkR(Rc<Symbol>),
    //Rc(Rc<Symbol>),
}

#[derive(PartialEq,Eq,Debug,Clone)]
pub enum Effect {
    Observe,
    Allocate,
}

#[derive(Debug,Clone)]
pub struct Succ {
    effect : Effect,
    dep    : Rc<Box<AdaptonDep>>, // Abstracted dependency information (e.g., for Observe Effect, the prior observed value)
    loc    : Rc<Loc>, // Target of the effect, aka, the successor, by this edge
    dirty  : bool,    // mutated to dirty when loc changes, or any of its successors change
}

// AdaptonDep abstracts over the value produced by a dependency, as
// well as mechanisms to update and/or re-produce it.
pub trait AdaptonDep : Debug {
    fn change_prop (self:&Self, st:&mut AdaptonState, loc:&Rc<Loc>) -> AdaptonRes ;
}

#[derive(Debug)]
pub struct NoDependency;
impl AdaptonDep for NoDependency {
    fn change_prop (self:&Self, _st:&mut AdaptonState, _loc:&Rc<Loc>) -> AdaptonRes { AdaptonRes{changed:false} }
}

#[derive(Debug)]
pub struct AllocDependency<T> { val:T }
impl<T:Debug> AdaptonDep for AllocDependency<T> {
    fn change_prop (self:&Self, _st:&mut AdaptonState, _loc:&Rc<Loc>) -> AdaptonRes { AdaptonRes{changed:true} } // TODO-Later: Make this a little better.
}

pub struct AdaptonRes {
    changed : bool,
}

pub trait AdaptonNode {
    // DCG structure:
    fn preds_alloc<'r> (self:&'r mut Self) -> &'r mut Vec<Rc<Loc>> ;
    fn preds_obs<'r>   (self:&'r mut Self) -> &'r mut Vec<Rc<Loc>> ;
    fn succs_def<'r>   (self:&'r mut Self) -> bool ;
    fn succs<'r>       (self:&'r mut Self) -> &'r mut Vec<Succ> ;
}

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

#[derive(Debug)]
pub struct AdaptonState {
    table : HashMap<Rc<Loc>, Box<AdaptonNode>>,
    stack : Vec<Frame>
}

// Structureful (Non-opaque) nodes:
#[derive(Debug)]
pub enum Node<Res> {
    Pure(PureNode<Res>),
    Mut(MutNode<Res>),
    Comp(CompNode<Res>),
}

// PureNode<T> for pure hash-consing of T's.
// Location in table never changes value.
#[derive(Debug)]
pub struct PureNode<T> {
    val : T,
}

// MutNode<T> for mutable content of type T.
// The set operation mutates a MutNode; set may only be called by *outer* Rust environment.
// Its notable that the CompNodes' producers do not directly change the value of MutNodes with set.
// They may indirectly mutate these nodes by performing nominal allocation; mutation is limited to "one-shot" changes.
#[derive(Debug)]
pub struct MutNode<T> {
    preds_alloc : Vec<Rc<Loc>>,
    preds_obs   : Vec<Rc<Loc>>,
    val         : T,
}

// CompNode<Res> for a suspended computation whose resulting value of
// type T.  The result of the CompNode is affected in two ways: the
// (1) producer may change, which may affect the result and (2) the
// values produced by the successors may change, indirectly
// influencing how the producer produces its resulting value.
pub struct CompNode<Res> {
    preds_alloc : Vec<Rc<Loc>>,
    preds_obs   : Vec<Rc<Loc>>,
    succs       : Vec<Succ>,
    producer    : Box<Producer<Res>>, // Producer can be App<Arg,Res>, where type Arg is hidden.
    res         : Option<Res>,
}
// Produce a value of type Res.
pub trait Producer<Res> {
    fn produce(self:&Self, st:&mut AdaptonState) -> Rc<Res>;
    fn copy(self:&Self) -> Box<Producer<Res>>;
}
// Consume a value of type Arg.
pub trait Consumer<Arg> {
    fn consume(self:&mut Self, Rc<Arg>);
    fn get_arg(self:&mut Self) -> Rc<Arg>;
}
// struct App is hidden by traits Comp<Res> and CompWithArg<Res>, below.
#[derive(Clone)]
pub struct App<Arg,Res> {
    prog_pt: ProgPt,
    fn_box:  Rc<Box<Fn(&mut AdaptonState, Rc<Arg>) -> Rc<Res>>>,
    arg:     Rc<Arg>,
}

// ---------- App implementation of Debug and Hash

impl<Arg,Res> Debug for App<Arg,Res> {
    fn fmt(&self, f: &mut Formatter) -> Result { self.prog_pt.fmt(f) }
}

impl<Arg:Hash,Res> Hash for App<Arg,Res> {
    fn hash<H>(&self, state: &mut H) where H: Hasher { (&self.prog_pt,&self.arg).hash(state) }
}

// ---------- App implementation of Producer and Consumer traits:

impl<Arg:'static+Clone+PartialEq+Eq,Res:'static+Clone+PartialEq+Eq> Producer<Res> for App<Arg,Res> {
    fn produce(self:&Self, st:&mut AdaptonState) -> Rc<Res> {
        let f = self.fn_box.clone() ;
        f (st,self.arg.clone())
    }
    fn copy(self:&Self) -> Box<Producer<Res>> {
        Box::new(self.clone())
    }
}
impl<Arg:Clone+PartialEq+Eq,Res> Consumer<Arg> for App<Arg,Res> {
    fn consume(self:&mut Self, arg:Rc<Arg>) { replace(&mut self.arg, arg); }
    fn get_arg(self:&mut Self) -> Rc<Arg>   { self.arg.clone() }
}

// // ---------- Ret implementation of Producer:

// #[derive(Debug,PartialEq,Eq)]
// pub enum Ret<Res> { Ret(Res) }

// impl<Res:Clone> Producer<Res> for Ret<Res> {
//     fn produce(self:&Self, _st:&mut AdaptonState) -> Res {
//         let &Ret::Ret(ref val) = self;
//         val.clone()
//     }
// }

// ----------- Location resolution:

pub fn abs_node_of_loc<'r> (st:&'r mut AdaptonState, loc:&'r Rc<Loc>) -> Option<&'r mut Box<AdaptonNode>> {
    panic!("st.table.get_mut(loc)")
}

// This only is safe in contexts where the type of loc is known.
// Double uses of names and hashes will generally cause uncaught type errors.
pub fn res_node_of_loc<'r,Res> (st:&'r mut AdaptonState, loc:&Rc<Loc>) -> &'r mut Node<Res> {
    match st.table.get(loc) {
        None => panic!("dangling pointer"),
        Some(ref mut node) => {
            unsafe { transmute::<_,_>(node) }
        }
    }
}

pub fn res_node_of_abs_node<'r,Res> (nd:&'r mut Box<AdaptonNode>) -> &'r mut Node<Res> {
    panic!("TODO-Now")
}

// ---------- Node implementation:

impl <Res> AdaptonNode for Node<Res> {
    fn preds_alloc<'r>(self:&'r mut Self) -> &'r mut Vec<Rc<Loc>> {
        match *self { Node::Mut(ref mut nd) => &mut nd.preds_alloc,
                      Node::Comp(ref mut nd) => &mut nd.preds_alloc,
                      Node::Pure(_) => unreachable!(),
        }}

    fn preds_obs<'r>(self:&'r mut Self) -> &'r mut Vec<Rc<Loc>> {
        match *self { Node::Mut(ref mut nd) => &mut nd.preds_obs,
                      Node::Comp(ref mut nd) => &mut nd.preds_obs,
                      Node::Pure(_) => unreachable!(),
        }}
    fn succs_def<'r>(self:&'r mut Self) -> bool {
        match *self { Node::Comp(_) => true, _ => false
        }}
    fn succs<'r>(self:&'r mut Self) -> &'r mut Vec<Succ> {
        match *self { Node::Comp(ref mut n) => &mut n.succs,
                     _ => panic!("undefined"),
        }
    }
}

impl<Res> fmt::Debug for CompNode<Res> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "(CompNode)")
    }
}

pub fn main () { }
<commit_msg>slight of hand; not sure why it worked<commit_after>use std::fmt::Debug;
use std::hash::{hash,Hash,Hasher,SipHasher};
use std::collections::HashMap;
use std::mem::replace;
use std::mem::transmute;
use std::rc::Rc;
use std::fmt;
use std::marker::PhantomData;
use std::fmt::{Formatter,Result};

use adapton_syntax::{ProgPt};

// use adapton_syntax::*;
use adapton_sigs::*;

#[derive(Debug)]
pub struct Frame {
    loc   : Rc<Loc>,    // The currently-executing node
    path  : Rc<Path>,   // The current path for creating new nodes; invariant: (prefix-of frame.loc.path frame.path)
    succs : Vec<Succ>,  // The currently-executing node's effects (viz., the nodes it demands)
}

// Each location identifies a node in the DCG.
#[derive(Hash,Debug,PartialEq,Eq,Clone)]
pub struct Loc {
    path : Rc<Path>,
    id   : Rc<ArtId<Name>>,
    hash : u64, // hash of (path,id)
}

// Paths are built using the ns command.
#[derive(Hash,Debug,PartialEq,Eq,Clone)]
pub enum Path {
    Empty,
    Child(Rc<Path>,Name),
}

// Names provide a symbolic way to identify nodes.
#[derive(Hash,Debug,PartialEq,Eq,Clone)]
pub struct Name {
    hash : u64, // hash of symbol
    symbol : Rc<Symbol>,
}

// Symbols
//
// For a general semantics of symbols, see Chapter 31 of PFPL 2nd Edition. Harper 2015:
// http://www.cs.cmu.edu/~rwh/plbook/2nded.pdf
//
#[derive(Hash,Debug,PartialEq,Eq,Clone)]
pub enum Symbol {
    Root, // Root identifies the outside environment of Rust code.
    Nil,  // Nil for non-symbolic, hash-based names.
    String(String), U64(u64),   // Strings and U64s are unique symbols.
    Pair(Rc<Symbol>,Rc<Symbol>),
    ForkL(Rc<Symbol>),
    ForkR(Rc<Symbol>),
    //Rc(Rc<Symbol>),
}

#[derive(PartialEq,Eq,Debug,Clone)]
pub enum Effect {
    Observe,
    Allocate,
}

#[derive(Debug,Clone)]
pub struct Succ {
    effect : Effect,
    dep    : Rc<Box<AdaptonDep>>, // Abstracted dependency information (e.g., for Observe Effect, the prior observed value)
    loc    : Rc<Loc>, // Target of the effect, aka, the successor, by this edge
    dirty  : bool,    // mutated to dirty when loc changes, or any of its successors change
}

// AdaptonDep abstracts over the value produced by a dependency, as
// well as mechanisms to update and/or re-produce it.
pub trait AdaptonDep : Debug {
    fn change_prop (self:&Self, st:&mut AdaptonState, loc:&Rc<Loc>) -> AdaptonRes ;
}

#[derive(Debug)]
pub struct NoDependency;
impl AdaptonDep for NoDependency {
    fn change_prop (self:&Self, _st:&mut AdaptonState, _loc:&Rc<Loc>) -> AdaptonRes { AdaptonRes{changed:false} }
}

#[derive(Debug)]
pub struct AllocDependency<T> { val:T }
impl<T:Debug> AdaptonDep for AllocDependency<T> {
    fn change_prop (self:&Self, _st:&mut AdaptonState, _loc:&Rc<Loc>) -> AdaptonRes { AdaptonRes{changed:true} } // TODO-Later: Make this a little better.
}

pub struct AdaptonRes {
    changed : bool,
}

pub trait AdaptonNode {
    // DCG structure:
    fn preds_alloc<'r> (self:&'r mut Self) -> &'r mut Vec<Rc<Loc>> ;
    fn preds_obs<'r>   (self:&'r mut Self) -> &'r mut Vec<Rc<Loc>> ;
    fn succs_def<'r>   (self:&'r mut Self) -> bool ;
    fn succs<'r>       (self:&'r mut Self) -> &'r mut Vec<Succ> ;
    fn be<'r>          (self:&'r mut Self) -> &'r mut AdaptonNode ;
}

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

#[derive(Debug)]
pub struct AdaptonState {
    table : HashMap<Rc<Loc>, Box<AdaptonNode>>,
    stack : Vec<Frame>
}

// Structureful (Non-opaque) nodes:
#[derive(Debug)]
pub enum Node<Res> {
    Pure(PureNode<Res>),
    Mut(MutNode<Res>),
    Comp(CompNode<Res>),
}

// PureNode<T> for pure hash-consing of T's.
// Location in table never changes value.
#[derive(Debug)]
pub struct PureNode<T> {
    val : T,
}

// MutNode<T> for mutable content of type T.
// The set operation mutates a MutNode; set may only be called by *outer* Rust environment.
// Its notable that the CompNodes' producers do not directly change the value of MutNodes with set.
// They may indirectly mutate these nodes by performing nominal allocation; mutation is limited to "one-shot" changes.
#[derive(Debug)]
pub struct MutNode<T> {
    preds_alloc : Vec<Rc<Loc>>,
    preds_obs   : Vec<Rc<Loc>>,
    val         : T,
}

// CompNode<Res> for a suspended computation whose resulting value of
// type T.  The result of the CompNode is affected in two ways: the
// (1) producer may change, which may affect the result and (2) the
// values produced by the successors may change, indirectly
// influencing how the producer produces its resulting value.
pub struct CompNode<Res> {
    preds_alloc : Vec<Rc<Loc>>,
    preds_obs   : Vec<Rc<Loc>>,
    succs       : Vec<Succ>,
    producer    : Box<Producer<Res>>, // Producer can be App<Arg,Res>, where type Arg is hidden.
    res         : Option<Res>,
}
// Produce a value of type Res.
pub trait Producer<Res> {
    fn produce(self:&Self, st:&mut AdaptonState) -> Rc<Res>;
    fn copy(self:&Self) -> Box<Producer<Res>>;
}
// Consume a value of type Arg.
pub trait Consumer<Arg> {
    fn consume(self:&mut Self, Rc<Arg>);
    fn get_arg(self:&mut Self) -> Rc<Arg>;
}
// struct App is hidden by traits Comp<Res> and CompWithArg<Res>, below.
#[derive(Clone)]
pub struct App<Arg,Res> {
    prog_pt: ProgPt,
    fn_box:  Rc<Box<Fn(&mut AdaptonState, Rc<Arg>) -> Rc<Res>>>,
    arg:     Rc<Arg>,
}

// ---------- App implementation of Debug and Hash

impl<Arg,Res> Debug for App<Arg,Res> {
    fn fmt(&self, f: &mut Formatter) -> Result { self.prog_pt.fmt(f) }
}

impl<Arg:Hash,Res> Hash for App<Arg,Res> {
    fn hash<H>(&self, state: &mut H) where H: Hasher { (&self.prog_pt,&self.arg).hash(state) }
}

// ---------- App implementation of Producer and Consumer traits:

impl<Arg:'static+Clone+PartialEq+Eq,Res:'static+Clone+PartialEq+Eq> Producer<Res> for App<Arg,Res> {
    fn produce(self:&Self, st:&mut AdaptonState) -> Rc<Res> {
        let f = self.fn_box.clone() ;
        f (st,self.arg.clone())
    }
    fn copy(self:&Self) -> Box<Producer<Res>> {
        Box::new(self.clone())
    }
}
impl<Arg:Clone+PartialEq+Eq,Res> Consumer<Arg> for App<Arg,Res> {
    fn consume(self:&mut Self, arg:Rc<Arg>) { replace(&mut self.arg, arg); }
    fn get_arg(self:&mut Self) -> Rc<Arg>   { self.arg.clone() }
}

// // ---------- Ret implementation of Producer:

// #[derive(Debug,PartialEq,Eq)]
// pub enum Ret<Res> { Ret(Res) }

// impl<Res:Clone> Producer<Res> for Ret<Res> {
//     fn produce(self:&Self, _st:&mut AdaptonState) -> Res {
//         let &Ret::Ret(ref val) = self;
//         val.clone()
//     }
// }

// ----------- Location resolution:

pub fn abs_node_of_loc<'r> (st:&'r mut AdaptonState, loc:&'r Rc<Loc>) -> Option<&'r mut Box<AdaptonNode>> {
    panic!("st.table.get_mut(loc)")
}

fn lookup<'r>(st:&'r mut AdaptonState, loc:&Rc<Loc>) -> &'r mut AdaptonNode {
    match st.table.get_mut( loc ) {
        None => panic!("dangling pointer"),
        Some(node) => node.be()
    }
}

// This only is safe in contexts where the type of loc is known.
// Double uses of names and hashes will generally cause uncaught type errors.
pub fn res_node_of_loc<'r,'s,Res> (st:&'r mut AdaptonState, loc:&'s Rc<Loc>) -> &'r mut Node<Res> {
    match st.table.get(loc) {
        None => panic!("dangling pointer"),
        Some(ref mut node) => {
            unsafe { transmute::<_,_>(node) }
        }
    }
}

pub fn res_node_of_abs_node<'r,Res> (nd:&'r mut Box<AdaptonNode>) -> &'r mut Node<Res> {
    panic!("TODO-Now")
}

// ---------- Node implementation:

impl <Res> AdaptonNode for Node<Res> {
    fn preds_alloc<'r>(self:&'r mut Self) -> &'r mut Vec<Rc<Loc>> {
        match *self { Node::Mut(ref mut nd) => &mut nd.preds_alloc,
                      Node::Comp(ref mut nd) => &mut nd.preds_alloc,
                      Node::Pure(_) => unreachable!(),
        }}

    fn preds_obs<'r>(self:&'r mut Self) -> &'r mut Vec<Rc<Loc>> {
        match *self { Node::Mut(ref mut nd) => &mut nd.preds_obs,
                      Node::Comp(ref mut nd) => &mut nd.preds_obs,
                      Node::Pure(_) => unreachable!(),
        }}
    fn succs_def<'r>(self:&'r mut Self) -> bool {
        match *self { Node::Comp(_) => true, _ => false
        }}
    fn succs<'r>(self:&'r mut Self) -> &'r mut Vec<Succ> {
        match *self { Node::Comp(ref mut n) => &mut n.succs,
                     _ => panic!("undefined"),
        }
    }
    fn be<'r>(self:&'r mut Self) -> &'r mut AdaptonNode {
        self
    }
}

impl<Res> fmt::Debug for CompNode<Res> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "(CompNode)")
    }
}

pub fn main () { }
<|endoftext|>


<commit_before>//! Contains an implementation of an asynchronous client.
//!
//! It allows users to make requests to the same underlying connection from
//! different threads concurrently, as well as to receive the response
//! asynchronously.
use std::net::TcpStream;
use std::collections::HashMap;

use std::sync::Future;
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc;
use std::thread;

use super::super::http::{StreamId, HttpError, Response, Request, Header};
use super::super::http::connection::ClientConnection;
use super::super::http::session::{DefaultSession, DefaultStream};

/// A struct representing an asynchronously dispatched request. It is used
/// internally be the `ClientService` and `Client` structs.
struct AsyncRequest {
    /// The method of the request
    pub method: Vec<u8>,
    /// The path being requested
    pub path: Vec<u8>,
    /// Extra headers that should be included in the request. Does *not*
    /// include meta-headers.
    pub headers: Vec<Header>,
    /// The sender side of a channel where the response to this request should
    /// be delivered.
    tx: Sender<Response>,
}

/// An enum that represents errors that can be raised by the operation of a
/// `ClientService`.
enum ClientServiceErr {
    /// Corresponds to the case where the service has finished its operation.
    Done,
    /// Corresponds to the case where the service is unable to continue due to
    /// an error that occurred on the underlying HTTP/2 connection.
    Http(HttpError),
}

/// An internal struct encapsulating a service that lets multiple clients
/// issue concurrent requests to the same HTTP/2 connection.
///
/// The service handles issuing requests that it receives on a channel (the
/// receiving end of it is `rx`) to the server and relaying the requests to
/// the corresponding channel (the one given in the `AsyncRequest` instance
/// that was read off the requests channel).
///
/// The service does not automatically start running in a background thread.
/// The user needs to start that explicitly and decide how they want to handle
/// running the `run_once` method.
struct ClientService {
    /// The ID that will be assigned to the next client-initiated stream.
    next_stream_id: StreamId,
    /// The number of requests that have been sent, but are yet unanswered.
    outstanding_reqs: u32,
    /// The limit to the number of requests that can be pending (unanswered,
    /// but sent).
    limit: u32,
    /// The host name of the host to which the client is connected to.
    host: Vec<u8>,
    /// The connection that is used for underlying HTTP/2 communication.
    conn: ClientConnection<TcpStream, DefaultSession>,
    /// A mapping of stream IDs to the sender side of a channel that is
    /// expecting a response to the request that is to arrive on that stream.
    chans: HashMap<StreamId, Sender<Response>>,
    /// The receiver end of a channel to which requests that clients wish to
    /// issue are queued.
    rx: Receiver<AsyncRequest>,
}

impl ClientService {
    /// Creates a new `ClientService` that will communicate over a new HTTP/2
    /// connection to the server found at the given host and port combination.
    ///
    /// # Returns
    ///
    /// Returns the newly created `ClientService` and the sender side of the
    /// channel on which the new service instance expects requests to arrive.
    ///
    /// If no HTTP/2 connection can be established to the given host on the
    /// given port, returns `None`.
    pub fn new(host: &str, port: u16) -> Option<(ClientService, Sender<AsyncRequest>)> {
        let (tx, rx): (Sender<AsyncRequest>, Receiver<AsyncRequest>) =
                mpsc::channel();
        let mut conn = ClientConnection::new(
                TcpStream::connect(&(host, port)).unwrap(),
                DefaultSession::<DefaultStream>::new());
        match conn.init() {
            Ok(_) => {},
            Err(_) => return None,
        };

        let service = ClientService {
            next_stream_id: 1,
            outstanding_reqs: 0,
            limit: 3,
            host: host.as_bytes().to_vec(),
            conn: conn,
            chans: HashMap::new(),
            rx: rx,
        };

        Some((service, tx))
    }

    /// Performs one iteration of the service.
    ///
    /// If there are no currently oustanding requests (sent, but yet no full
    /// response received), the function blocks until a new request is received.
    /// Once there is a new request, it will be sent to the server in its
    /// entirety.
    ///
    /// If there is an outstanding request, the function tries to handle the
    /// response-related payload incoming on the HTTP/2 connection. This could
    /// be more than one HTTP/2 frame since `SETTINGS` or other frames might be
    /// interleaved with `DATA` and `HEADERS` frames representing the responses.
    ///
    /// Any received responses after handling the first payload are sent to the
    /// corresponding channel that is expecting the particular response.
    ///
    /// Finally, an additional request is sent (in its entirety) if the limit
    /// to the number of concurrent requests was not reached and there are
    /// queued requests from clients.
    ///
    /// # Returns
    ///
    /// On a successful pass, the function returns an `Ok(())`.
    ///
    /// The `Err` response is returned when there are no more responses to be
    /// received and there are no more clients connected to the service (and
    /// thus no more requests could ever be issued by the instance). This
    /// corresponds to the `ClientServiceErr::Done` variant.
    ///
    /// Any HTTP/2 error is propagated (wrapped into a ClientServiceErr::Http
    /// variant).
    pub fn run_once(&mut self) -> Result<(), ClientServiceErr> {
        // If there are no responses that we should read, block until there's
        // a new request. This precludes handling server pushes, pings, or
        // settings changes that may happen in the mean time until there's a
        // new request, since nothing is reading from the connection until then.
        if self.outstanding_reqs == 0 {
            debug!("Service thread blocking until there's a new request...");
            let async_req = match self.rx.recv() {
                Ok(req) => req,
                // The receive operation can only fail if the sender has
                // disconnected implying no further receives are possible.
                // At that point, we make sure to gracefully stop the service.
                Err(_) => return Err(ClientServiceErr::Done),
            };
            self.send_request(async_req);
        }

        // Handles the next frame...
        debug!("Handling next frame");
        match self.conn.handle_next_frame() {
            Ok(_) => {},
            Err(e) => return Err(ClientServiceErr::Http(e)),
        };
        // ...and then any connections that may have been closed in the meantime
        // are converted to responses and notifications sent to appropriate
        // channels.
        self.handle_closed();
        // At this point we try to queue another outstanding request (if the
        // limit has not been reached).
        self.queue_next_request();

        Ok(())
    }

    /// Internal helper method. Sends a request to the server based on the
    /// parameters given in the `AsyncRequest`. It blocks until the request is
    /// fully transmitted to the server.
    fn send_request(&mut self, async_req: AsyncRequest) {
        let req = self.create_request(
                                 async_req.method,
                                 async_req.path,
                                 async_req.headers);

        debug!("Sending new request... id = {}", req.stream_id);

        self.conn.session.new_stream(req.stream_id);
        self.chans.insert(req.stream_id, async_req.tx);
        self.conn.send_request(req).ok().unwrap();
        self.outstanding_reqs += 1;
    }

    /// Internal helper method. Creates a new `Request` instance based on the
    /// given parameters. Such a `Request` instance is ready to be passed to
    /// the connection for transmission to the server.
    fn create_request(&mut self,
                      method: Vec<u8>,
                      path: Vec<u8>,
                      extra_headers: Vec<Header>) -> Request {
        let mut headers: Vec<Header> = Vec::new();
        headers.extend(vec![
            (b":method".to_vec(), method),
            (b":path".to_vec(), path),
            (b":authority".to_vec(), self.host.clone()),
            (b":scheme".to_vec(), b"http".to_vec()),
        ].into_iter());
        headers.extend(extra_headers.into_iter());

        let req = Request {
            stream_id: self.next_stream_id,
            headers: headers,
            body: Vec::new(),
        };
        self.next_stream_id += 2;

        req
    }

    /// Internal helper method. Sends a response assembled from the given
    /// stream to the corresponding channel that is waiting for the response.
    ///
    /// The given `stream` instance is consumed by this method.
    fn send_response(&mut self, stream: DefaultStream) {
        match self.chans.remove(&stream.stream_id) {
            None => {
                // This should never happen, it means the session gave us
                // a response that we didn't request.
                panic!("Received a response for an unknown request!");
            },
            Some(tx) => {
                let _ = tx.send(Response {
                    stream_id: stream.stream_id,
                    headers: stream.headers.unwrap(),
                    body: stream.body,
                });
            }
        };
    }

    /// Internal helper method. Handles all closed streams by sending appropriate
    /// notifications to waiting channels.
    ///
    /// For now, the channels are all given a `Response`, even though the
    /// stream might end up being closed by the server with an error.
    fn handle_closed(&mut self) {
        let done = self.conn.session.get_closed();
        for stream in done {
            self.send_response(stream);
            self.outstanding_reqs -= 1;
        }
    }

    /// Internal helper method. If there are yet unsent requests queued by a
    /// client to the service and the service has not exceeded the limit of
    /// concurrent requests that it is allowed to issue, it sends a single
    /// new request to the server. Blocks until this request is sent.
    fn queue_next_request(&mut self) {
        if self.outstanding_reqs < self.limit {
            // Try to queue another request since we haven't gone over
            // the (arbitrary) limit.
            debug!("Not over the limit yet. Checking for more requests...");
            if let Ok(async_req) = self.rx.try_recv() {
                self.send_request(async_req);
            }
        }
    }
}

/// A struct representing an HTTP/2 client that receives responses to its
/// requests asynchronously. Additionally, this client can be cloned and all
/// clones can issue (concurrently) requests to the server, using the same
/// underlying HTTP/2 connection.
///
/// # Example
///
/// ```no_run
/// #![feature(std_misc)]
/// use solicit::client::Client;
/// use std::thread;
/// use std::str;
///
/// // Connect to a server that supports HTTP/2
/// let client = Client::new("nghttp2.org", 80).unwrap();
///
/// // Issue 5 requests from 5 different threads concurrently and wait for all
/// // threads to receive their response.
/// let _: Vec<_> = (0..5).map(|i| {
///     let this = client.clone();
///     thread::scoped(move || {
///         let resp = this.get(b"/", &[]).unwrap();
///         let response = resp.into_inner();
///         println!("Thread {} got response ... {}", i, response.status_code().ok().unwrap());
///         println!("The response contains the following headers:");
///         for header in response.headers.iter() {
///             println!("  {}: {}",
///                   str::from_utf8(&header.0[]).unwrap(),
///                   str::from_utf8(&header.1[]).unwrap());
///         }
///     })
/// }).collect();
/// ```
#[derive(Clone)]
pub struct Client {
    /// The sender side of a channel on which a running `ClientService` expects
    /// to receive new requests, which are to be sent to the server.
    sender: Sender<AsyncRequest>,
}

impl Client {
    /// Creates a brand new HTTP/2 client. This means that a new HTTP/2
    /// connection will be established behind the scenes. A thread is spawned
    /// to handle the connection in the background, so that the thread that
    /// creates the client can use it asynchronously.
    ///
    /// # Returns
    ///
    /// A `Client` instance that allows access to the underlying HTTP/2
    /// connection on the application level. Only full requests and responses
    /// are exposed to users.
    ///
    /// The returned `Client` can be cloned and all clones will use the same
    /// underlying HTTP/2 connection. Once all cloned instances (as well as the
    /// original one) are dropped, the thread that was spawned will also exit
    /// gracefully. Any error on the underlying HTTP/2 connection also causes
    /// the thread to exit.
    ///
    /// If the HTTP/2 connection cannot be initialized returns `None`.
    pub fn new(host: &str, port: u16) -> Option<Client> {
        let (mut service, rx) = match ClientService::new(host, port) {
            Some((service, rx)) => (service, rx),
            None => return None,
        };

        thread::spawn(move || {
            while let Ok(_) = service.run_once() {}
            debug!("Service thread halting");
        });

        Some(Client {
            sender: rx,
        })
    }

    /// Issues a new request to the server.
    ///
    /// The request's method, path, and extra headers are provided as parameters.
    /// The headers should *never* include any meta-headers (such as `:method`).
    ///
    /// # Returns
    ///
    /// The method itself returns immediately upon queuing the request. It does
    /// not wait for the request to be transmitted nor for the response to
    /// arrive. Once the caller is interested in the final response, they can
    /// block on the returned `Future`.
    ///
    /// The `Response` instance wrapped by the future contains the full
    /// response body and is available only once the full response body has
    /// been received.
    ///
    /// If the method is unable to queue the request, it must mean that the
    /// underlying HTTP/2 connection to which this client is associated has
    /// failed and it returns `None`.
    pub fn request(&self, method: &[u8], path: &[u8], headers: &[Header])
            -> Option<Future<Response>> {
        let (resp_tx, resp_rx): (Sender<Response>, Receiver<Response>) =
                mpsc::channel();
        // A send can only fail if the receiver is disconnected. If the send
        // fails here, it means that the service hit an error on the underlying
        // HTTP/2 connection and will never come alive again.
        let res = self.sender.send(AsyncRequest {
            method: method.to_vec(),
            path: path.to_vec(),
            headers: headers.to_vec(),
            tx: resp_tx,
        });

        match res {
            Ok(_) => Some(Future::from_receiver(resp_rx)),
            Err(_) => None,
        }
    }

    /// Issues a GET request to the server.
    ///
    /// A convenience wrapper around the `request` method that sets the correct
    /// method.
    pub fn get(&self, path: &[u8], headers: &[Header]) -> Option<Future<Response>> {
        self.request(b"GET", path, headers)
    }
}
<commit_msg>Fix obsolete syntax in the examples<commit_after>//! Contains an implementation of an asynchronous client.
//!
//! It allows users to make requests to the same underlying connection from
//! different threads concurrently, as well as to receive the response
//! asynchronously.
use std::net::TcpStream;
use std::collections::HashMap;

use std::sync::Future;
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc;
use std::thread;

use super::super::http::{StreamId, HttpError, Response, Request, Header};
use super::super::http::connection::ClientConnection;
use super::super::http::session::{DefaultSession, DefaultStream};

/// A struct representing an asynchronously dispatched request. It is used
/// internally be the `ClientService` and `Client` structs.
struct AsyncRequest {
    /// The method of the request
    pub method: Vec<u8>,
    /// The path being requested
    pub path: Vec<u8>,
    /// Extra headers that should be included in the request. Does *not*
    /// include meta-headers.
    pub headers: Vec<Header>,
    /// The sender side of a channel where the response to this request should
    /// be delivered.
    tx: Sender<Response>,
}

/// An enum that represents errors that can be raised by the operation of a
/// `ClientService`.
enum ClientServiceErr {
    /// Corresponds to the case where the service has finished its operation.
    Done,
    /// Corresponds to the case where the service is unable to continue due to
    /// an error that occurred on the underlying HTTP/2 connection.
    Http(HttpError),
}

/// An internal struct encapsulating a service that lets multiple clients
/// issue concurrent requests to the same HTTP/2 connection.
///
/// The service handles issuing requests that it receives on a channel (the
/// receiving end of it is `rx`) to the server and relaying the requests to
/// the corresponding channel (the one given in the `AsyncRequest` instance
/// that was read off the requests channel).
///
/// The service does not automatically start running in a background thread.
/// The user needs to start that explicitly and decide how they want to handle
/// running the `run_once` method.
struct ClientService {
    /// The ID that will be assigned to the next client-initiated stream.
    next_stream_id: StreamId,
    /// The number of requests that have been sent, but are yet unanswered.
    outstanding_reqs: u32,
    /// The limit to the number of requests that can be pending (unanswered,
    /// but sent).
    limit: u32,
    /// The host name of the host to which the client is connected to.
    host: Vec<u8>,
    /// The connection that is used for underlying HTTP/2 communication.
    conn: ClientConnection<TcpStream, DefaultSession>,
    /// A mapping of stream IDs to the sender side of a channel that is
    /// expecting a response to the request that is to arrive on that stream.
    chans: HashMap<StreamId, Sender<Response>>,
    /// The receiver end of a channel to which requests that clients wish to
    /// issue are queued.
    rx: Receiver<AsyncRequest>,
}

impl ClientService {
    /// Creates a new `ClientService` that will communicate over a new HTTP/2
    /// connection to the server found at the given host and port combination.
    ///
    /// # Returns
    ///
    /// Returns the newly created `ClientService` and the sender side of the
    /// channel on which the new service instance expects requests to arrive.
    ///
    /// If no HTTP/2 connection can be established to the given host on the
    /// given port, returns `None`.
    pub fn new(host: &str, port: u16) -> Option<(ClientService, Sender<AsyncRequest>)> {
        let (tx, rx): (Sender<AsyncRequest>, Receiver<AsyncRequest>) =
                mpsc::channel();
        let mut conn = ClientConnection::new(
                TcpStream::connect(&(host, port)).unwrap(),
                DefaultSession::<DefaultStream>::new());
        match conn.init() {
            Ok(_) => {},
            Err(_) => return None,
        };

        let service = ClientService {
            next_stream_id: 1,
            outstanding_reqs: 0,
            limit: 3,
            host: host.as_bytes().to_vec(),
            conn: conn,
            chans: HashMap::new(),
            rx: rx,
        };

        Some((service, tx))
    }

    /// Performs one iteration of the service.
    ///
    /// If there are no currently oustanding requests (sent, but yet no full
    /// response received), the function blocks until a new request is received.
    /// Once there is a new request, it will be sent to the server in its
    /// entirety.
    ///
    /// If there is an outstanding request, the function tries to handle the
    /// response-related payload incoming on the HTTP/2 connection. This could
    /// be more than one HTTP/2 frame since `SETTINGS` or other frames might be
    /// interleaved with `DATA` and `HEADERS` frames representing the responses.
    ///
    /// Any received responses after handling the first payload are sent to the
    /// corresponding channel that is expecting the particular response.
    ///
    /// Finally, an additional request is sent (in its entirety) if the limit
    /// to the number of concurrent requests was not reached and there are
    /// queued requests from clients.
    ///
    /// # Returns
    ///
    /// On a successful pass, the function returns an `Ok(())`.
    ///
    /// The `Err` response is returned when there are no more responses to be
    /// received and there are no more clients connected to the service (and
    /// thus no more requests could ever be issued by the instance). This
    /// corresponds to the `ClientServiceErr::Done` variant.
    ///
    /// Any HTTP/2 error is propagated (wrapped into a ClientServiceErr::Http
    /// variant).
    pub fn run_once(&mut self) -> Result<(), ClientServiceErr> {
        // If there are no responses that we should read, block until there's
        // a new request. This precludes handling server pushes, pings, or
        // settings changes that may happen in the mean time until there's a
        // new request, since nothing is reading from the connection until then.
        if self.outstanding_reqs == 0 {
            debug!("Service thread blocking until there's a new request...");
            let async_req = match self.rx.recv() {
                Ok(req) => req,
                // The receive operation can only fail if the sender has
                // disconnected implying no further receives are possible.
                // At that point, we make sure to gracefully stop the service.
                Err(_) => return Err(ClientServiceErr::Done),
            };
            self.send_request(async_req);
        }

        // Handles the next frame...
        debug!("Handling next frame");
        match self.conn.handle_next_frame() {
            Ok(_) => {},
            Err(e) => return Err(ClientServiceErr::Http(e)),
        };
        // ...and then any connections that may have been closed in the meantime
        // are converted to responses and notifications sent to appropriate
        // channels.
        self.handle_closed();
        // At this point we try to queue another outstanding request (if the
        // limit has not been reached).
        self.queue_next_request();

        Ok(())
    }

    /// Internal helper method. Sends a request to the server based on the
    /// parameters given in the `AsyncRequest`. It blocks until the request is
    /// fully transmitted to the server.
    fn send_request(&mut self, async_req: AsyncRequest) {
        let req = self.create_request(
                                 async_req.method,
                                 async_req.path,
                                 async_req.headers);

        debug!("Sending new request... id = {}", req.stream_id);

        self.conn.session.new_stream(req.stream_id);
        self.chans.insert(req.stream_id, async_req.tx);
        self.conn.send_request(req).ok().unwrap();
        self.outstanding_reqs += 1;
    }

    /// Internal helper method. Creates a new `Request` instance based on the
    /// given parameters. Such a `Request` instance is ready to be passed to
    /// the connection for transmission to the server.
    fn create_request(&mut self,
                      method: Vec<u8>,
                      path: Vec<u8>,
                      extra_headers: Vec<Header>) -> Request {
        let mut headers: Vec<Header> = Vec::new();
        headers.extend(vec![
            (b":method".to_vec(), method),
            (b":path".to_vec(), path),
            (b":authority".to_vec(), self.host.clone()),
            (b":scheme".to_vec(), b"http".to_vec()),
        ].into_iter());
        headers.extend(extra_headers.into_iter());

        let req = Request {
            stream_id: self.next_stream_id,
            headers: headers,
            body: Vec::new(),
        };
        self.next_stream_id += 2;

        req
    }

    /// Internal helper method. Sends a response assembled from the given
    /// stream to the corresponding channel that is waiting for the response.
    ///
    /// The given `stream` instance is consumed by this method.
    fn send_response(&mut self, stream: DefaultStream) {
        match self.chans.remove(&stream.stream_id) {
            None => {
                // This should never happen, it means the session gave us
                // a response that we didn't request.
                panic!("Received a response for an unknown request!");
            },
            Some(tx) => {
                let _ = tx.send(Response {
                    stream_id: stream.stream_id,
                    headers: stream.headers.unwrap(),
                    body: stream.body,
                });
            }
        };
    }

    /// Internal helper method. Handles all closed streams by sending appropriate
    /// notifications to waiting channels.
    ///
    /// For now, the channels are all given a `Response`, even though the
    /// stream might end up being closed by the server with an error.
    fn handle_closed(&mut self) {
        let done = self.conn.session.get_closed();
        for stream in done {
            self.send_response(stream);
            self.outstanding_reqs -= 1;
        }
    }

    /// Internal helper method. If there are yet unsent requests queued by a
    /// client to the service and the service has not exceeded the limit of
    /// concurrent requests that it is allowed to issue, it sends a single
    /// new request to the server. Blocks until this request is sent.
    fn queue_next_request(&mut self) {
        if self.outstanding_reqs < self.limit {
            // Try to queue another request since we haven't gone over
            // the (arbitrary) limit.
            debug!("Not over the limit yet. Checking for more requests...");
            if let Ok(async_req) = self.rx.try_recv() {
                self.send_request(async_req);
            }
        }
    }
}

/// A struct representing an HTTP/2 client that receives responses to its
/// requests asynchronously. Additionally, this client can be cloned and all
/// clones can issue (concurrently) requests to the server, using the same
/// underlying HTTP/2 connection.
///
/// # Example
///
/// ```no_run
/// #![feature(std_misc)]
/// use solicit::client::Client;
/// use std::thread;
/// use std::str;
///
/// // Connect to a server that supports HTTP/2
/// let client = Client::new("nghttp2.org", 80).unwrap();
///
/// // Issue 5 requests from 5 different threads concurrently and wait for all
/// // threads to receive their response.
/// let _: Vec<_> = (0..5).map(|i| {
///     let this = client.clone();
///     thread::scoped(move || {
///         let resp = this.get(b"/", &[]).unwrap();
///         let response = resp.into_inner();
///         println!("Thread {} got response ... {}", i, response.status_code().ok().unwrap());
///         println!("The response contains the following headers:");
///         for header in response.headers.iter() {
///             println!("  {}: {}",
///                   str::from_utf8(&header.0).unwrap(),
///                   str::from_utf8(&header.1).unwrap());
///         }
///     })
/// }).collect();
/// ```
#[derive(Clone)]
pub struct Client {
    /// The sender side of a channel on which a running `ClientService` expects
    /// to receive new requests, which are to be sent to the server.
    sender: Sender<AsyncRequest>,
}

impl Client {
    /// Creates a brand new HTTP/2 client. This means that a new HTTP/2
    /// connection will be established behind the scenes. A thread is spawned
    /// to handle the connection in the background, so that the thread that
    /// creates the client can use it asynchronously.
    ///
    /// # Returns
    ///
    /// A `Client` instance that allows access to the underlying HTTP/2
    /// connection on the application level. Only full requests and responses
    /// are exposed to users.
    ///
    /// The returned `Client` can be cloned and all clones will use the same
    /// underlying HTTP/2 connection. Once all cloned instances (as well as the
    /// original one) are dropped, the thread that was spawned will also exit
    /// gracefully. Any error on the underlying HTTP/2 connection also causes
    /// the thread to exit.
    ///
    /// If the HTTP/2 connection cannot be initialized returns `None`.
    pub fn new(host: &str, port: u16) -> Option<Client> {
        let (mut service, rx) = match ClientService::new(host, port) {
            Some((service, rx)) => (service, rx),
            None => return None,
        };

        thread::spawn(move || {
            while let Ok(_) = service.run_once() {}
            debug!("Service thread halting");
        });

        Some(Client {
            sender: rx,
        })
    }

    /// Issues a new request to the server.
    ///
    /// The request's method, path, and extra headers are provided as parameters.
    /// The headers should *never* include any meta-headers (such as `:method`).
    ///
    /// # Returns
    ///
    /// The method itself returns immediately upon queuing the request. It does
    /// not wait for the request to be transmitted nor for the response to
    /// arrive. Once the caller is interested in the final response, they can
    /// block on the returned `Future`.
    ///
    /// The `Response` instance wrapped by the future contains the full
    /// response body and is available only once the full response body has
    /// been received.
    ///
    /// If the method is unable to queue the request, it must mean that the
    /// underlying HTTP/2 connection to which this client is associated has
    /// failed and it returns `None`.
    pub fn request(&self, method: &[u8], path: &[u8], headers: &[Header])
            -> Option<Future<Response>> {
        let (resp_tx, resp_rx): (Sender<Response>, Receiver<Response>) =
                mpsc::channel();
        // A send can only fail if the receiver is disconnected. If the send
        // fails here, it means that the service hit an error on the underlying
        // HTTP/2 connection and will never come alive again.
        let res = self.sender.send(AsyncRequest {
            method: method.to_vec(),
            path: path.to_vec(),
            headers: headers.to_vec(),
            tx: resp_tx,
        });

        match res {
            Ok(_) => Some(Future::from_receiver(resp_rx)),
            Err(_) => None,
        }
    }

    /// Issues a GET request to the server.
    ///
    /// A convenience wrapper around the `request` method that sets the correct
    /// method.
    pub fn get(&self, path: &[u8], headers: &[Header]) -> Option<Future<Response>> {
        self.request(b"GET", path, headers)
    }
}
<|endoftext|>


<commit_before>use crate::config::types::*;
use clap::{value_t, values_t, ArgMatches};
use coveralls_api::CiService;
use log::error;
use regex::Regex;
use std::env;
use std::path::PathBuf;
use std::time::Duration;

pub(super) fn get_list(args: &ArgMatches, key: &str) -> Vec<String> {
    args.values_of_lossy(key).unwrap_or_else(Vec::new)
}

pub(super) fn get_line_cov(args: &ArgMatches) -> bool {
    let cover_lines = args.is_present("line");
    let cover_branches = args.is_present("branch");

    cover_lines || !(cover_lines || cover_branches)
}

pub(super) fn get_branch_cov(args: &ArgMatches) -> bool {
    let cover_lines = args.is_present("line");
    let cover_branches = args.is_present("branch");

    cover_branches || !(cover_lines || cover_branches)
}

pub(super) fn get_manifest(args: &ArgMatches) -> PathBuf {
    if let Some(path) = args.value_of("manifest-path") {
        return PathBuf::from(path);
    }

    let mut manifest = env::current_dir().unwrap();

    if let Some(path) = args.value_of("root") {
        manifest.push(path);
    }

    manifest.push("Cargo.toml");
    manifest.canonicalize().unwrap_or(manifest)
}

pub(super) fn get_root(args: &ArgMatches) -> Option<String> {
    args.value_of("root").map(ToString::to_string)
}

pub(super) fn get_ci(args: &ArgMatches) -> Option<CiService> {
    value_t!(args, "ciserver", Ci).map(|x| x.0).ok()
}

pub(super) fn get_coveralls(args: &ArgMatches) -> Option<String> {
    args.value_of("coveralls").map(ToString::to_string)
}

pub(super) fn get_report_uri(args: &ArgMatches) -> Option<String> {
    args.value_of("report-uri").map(ToString::to_string)
}

pub(super) fn get_outputs(args: &ArgMatches) -> Vec<OutputFile> {
    values_t!(args.values_of("out"), OutputFile).unwrap_or(vec![])
}

pub(super) fn get_output_directory(args: &ArgMatches) -> PathBuf {
    if let Some(path) = args.value_of("output-dir") {
        return PathBuf::from(path);
    }
    env::current_dir().unwrap()
}

pub(super) fn get_run_types(args: &ArgMatches) -> Vec<RunType> {
    values_t!(args.values_of("run-types"), RunType).unwrap_or(vec![RunType::Tests])
}

pub(super) fn get_excluded(args: &ArgMatches) -> Vec<Regex> {
    let mut files = vec![];

    for temp_str in &get_list(args, "exclude-files") {
        let s = &temp_str.replace(".", r"\.").replace("*", ".*");

        if let Ok(re) = Regex::new(s) {
            files.push(re);
        } else {
            error!("Invalid regex: {}", temp_str);
        }
    }

    files
}

pub(super) fn get_timeout(args: &ArgMatches) -> Duration {
    if args.is_present("timeout") {
        let duration = value_t!(args.value_of("timeout"), u64).unwrap_or(60);
        Duration::from_secs(duration)
    } else {
        Duration::from_secs(60)
    }
}
<commit_msg>allow relative paths for manifest-path<commit_after>use crate::config::types::*;
use clap::{value_t, values_t, ArgMatches};
use coveralls_api::CiService;
use log::error;
use regex::Regex;
use std::env;
use std::path::PathBuf;
use std::time::Duration;

pub(super) fn get_list(args: &ArgMatches, key: &str) -> Vec<String> {
    args.values_of_lossy(key).unwrap_or_else(Vec::new)
}

pub(super) fn get_line_cov(args: &ArgMatches) -> bool {
    let cover_lines = args.is_present("line");
    let cover_branches = args.is_present("branch");

    cover_lines || !(cover_lines || cover_branches)
}

pub(super) fn get_branch_cov(args: &ArgMatches) -> bool {
    let cover_lines = args.is_present("line");
    let cover_branches = args.is_present("branch");

    cover_branches || !(cover_lines || cover_branches)
}

pub(super) fn get_manifest(args: &ArgMatches) -> PathBuf {
    if let Some(path) = args.value_of("manifest-path") {
        let path = PathBuf::from(path);
        if path.is_relative() {
            return env::current_dir().unwrap().join(path).canonicalize().unwrap();
        }
        return path;
    }

    let mut manifest = env::current_dir().unwrap();

    if let Some(path) = args.value_of("root") {
        manifest.push(path);
    }

    manifest.push("Cargo.toml");
    manifest.canonicalize().unwrap_or(manifest)
}

pub(super) fn get_root(args: &ArgMatches) -> Option<String> {
    args.value_of("root").map(ToString::to_string)
}

pub(super) fn get_ci(args: &ArgMatches) -> Option<CiService> {
    value_t!(args, "ciserver", Ci).map(|x| x.0).ok()
}

pub(super) fn get_coveralls(args: &ArgMatches) -> Option<String> {
    args.value_of("coveralls").map(ToString::to_string)
}

pub(super) fn get_report_uri(args: &ArgMatches) -> Option<String> {
    args.value_of("report-uri").map(ToString::to_string)
}

pub(super) fn get_outputs(args: &ArgMatches) -> Vec<OutputFile> {
    values_t!(args.values_of("out"), OutputFile).unwrap_or(vec![])
}

pub(super) fn get_output_directory(args: &ArgMatches) -> PathBuf {
    if let Some(path) = args.value_of("output-dir") {
        return PathBuf::from(path);
    }
    env::current_dir().unwrap()
}

pub(super) fn get_run_types(args: &ArgMatches) -> Vec<RunType> {
    values_t!(args.values_of("run-types"), RunType).unwrap_or(vec![RunType::Tests])
}

pub(super) fn get_excluded(args: &ArgMatches) -> Vec<Regex> {
    let mut files = vec![];

    for temp_str in &get_list(args, "exclude-files") {
        let s = &temp_str.replace(".", r"\.").replace("*", ".*");

        if let Ok(re) = Regex::new(s) {
            files.push(re);
        } else {
            error!("Invalid regex: {}", temp_str);
        }
    }

    files
}

pub(super) fn get_timeout(args: &ArgMatches) -> Duration {
    if args.is_present("timeout") {
        let duration = value_t!(args.value_of("timeout"), u64).unwrap_or(60);
        Duration::from_secs(duration)
    } else {
        Duration::from_secs(60)
    }
}
<|endoftext|>


<commit_before>use socket::Socket;

pub struct Acquire {
    socket: Socket,
    started: bool,
}

impl Acquire {
    pub fn new(socket: Socket) -> Self {
        Acquire {
            socket: socket,
            started: false,
        }
    }

    pub fn start(&mut self) {
        self.socket.send("ACQ:START");
        self.started = true;
    }

    pub fn stop(&mut self) {
        self.socket.send("ACQ:STOP");
        self.started = false;
    }

    pub fn is_started(&self) -> bool {
        self.started
    }

    pub fn reset(&mut self) {
        self.socket.send("ACQ:RST");
    }

    pub fn set_decimation(&mut self, decimation: u8) {
        self.socket.send(format!("ACQ:DEC {}", decimation));
    }

    pub fn get_decimation(&mut self) -> u8 {
        self.socket.send("ACQ:DEC?");

        self.socket.receive()
            .parse()
            .unwrap()
    }

    pub fn enable_average(&mut self) {
        self.socket.send("ACQ:AVG ON");
    }

    pub fn disable_average(&mut self) {
        self.socket.send("ACQ:AVG OFF");
    }

    pub fn is_average_enabled(&mut self) -> bool {
        self.socket.send("ACQ:AVG?");

        let message = self.socket.receive();

        match message.as_str() {
            "ON" => true,
            _ => false,
        }
    }

    pub fn set_gain(&mut self, source: u8, gain: &str) {
        self.socket.send(format!("ACQ:SOUR{}:GAIN {}", source, gain));
    }
}

#[cfg(test)]
mod test {
    macro_rules! acquire_assert {
        ($f:ident, $e:expr) => {
            let (rx, mut acquire) = create_acquire();

            acquire.$f();
            assert_eq!($e, rx.recv().unwrap());
        }
    }

    #[test]
    fn test_start() {
        acquire_assert!(start, "ACQ:START\r\n");
    }

    #[test]
    fn test_stop() {
        acquire_assert!(stop, "ACQ:STOP\r\n");
    }

    #[test]
    fn test_is_started() {
        let (_, mut acquire) = create_acquire();

        assert_eq!(acquire.is_started(), false);
        acquire.start();
        assert_eq!(acquire.is_started(), true);
        acquire.stop();
        assert_eq!(acquire.is_started(), false);
    }

    #[test]
    fn test_reset() {
        acquire_assert!(reset, "ACQ:RST\r\n");
    }

    #[test]
    fn test_set_decimation() {
        let (rx, mut acquire) = create_acquire();

        acquire.set_decimation(1);
        assert_eq!("ACQ:DEC 1\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_get_decimation() {
        let (_, mut acquire) = create_acquire();

        assert_eq!(acquire.get_decimation(), 1);
    }

    #[test]
    fn test_enable_average() {
        acquire_assert!(enable_average, "ACQ:AVG ON\r\n");
    }

    #[test]
    fn test_disable_average() {
        acquire_assert!(disable_average, "ACQ:AVG OFF\r\n");
    }

    #[test]
    fn test_is_average_enabled() {
        let (_, mut acquire) = create_acquire();

        assert_eq!(acquire.is_average_enabled(), true);
    }

    #[test]
    fn test_set_gain() {
        let (rx, mut trigger) = create_acquire();

        trigger.set_gain(1, "LV");
        assert_eq!("ACQ:SOUR1:GAIN LV\r\n", rx.recv().unwrap());
    }

    fn create_acquire() -> (::std::sync::mpsc::Receiver<String>, ::acquire::Acquire) {
        let (addr, rx) = ::test::launch_server();
        let socket = ::socket::Socket::new(
            format!("{}", addr.ip()).as_str(),
            addr.port()
        );

        (rx, ::acquire::Acquire::new(socket))
    }
}
<commit_msg>[acquire] Add acquire::Decimation enum<commit_after>use socket::Socket;

#[derive(Debug, PartialEq)]
pub enum Decimation {
    DEC_1,
    DEC_8,
    DEC_64,
    DEC_1024,
    DEC_8192,
    DEC_65536,
}

impl ::std::fmt::Display for Decimation {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let display = match self {
            &Decimation::DEC_1 => "1",
            &Decimation::DEC_8 => "8",
            &Decimation::DEC_64 => "64",
            &Decimation::DEC_1024 => "1024",
            &Decimation::DEC_8192 => "8192",
            &Decimation::DEC_65536 => "65536",
        };

        write!(f, "{}", display)
    }
}

impl ::std::convert::From<String> for Decimation {
    fn from(s: String) -> Self {
        match s.as_str() {
            "1" => Decimation::DEC_1,
            "8" => Decimation::DEC_8,
            "64" => Decimation::DEC_64,
            "1024" => Decimation::DEC_1024,
            "8192" => Decimation::DEC_8192,
            "65536" => Decimation::DEC_65536,
            _ => Decimation::DEC_1,
        }
    }
}

pub struct Acquire {
    socket: Socket,
    started: bool,
}

impl Acquire {
    pub fn new(socket: Socket) -> Self {
        Acquire {
            socket: socket,
            started: false,
        }
    }

    pub fn start(&mut self) {
        self.socket.send("ACQ:START");
        self.started = true;
    }

    pub fn stop(&mut self) {
        self.socket.send("ACQ:STOP");
        self.started = false;
    }

    pub fn is_started(&self) -> bool {
        self.started
    }

    pub fn reset(&mut self) {
        self.socket.send("ACQ:RST");
    }

    pub fn set_decimation(&mut self, decimation: Decimation) {
        self.socket.send(format!("ACQ:DEC {}", decimation));
    }

    pub fn get_decimation(&mut self) -> Decimation {
        self.socket.send("ACQ:DEC?");

        self.socket.receive()
            .into()
    }

    pub fn enable_average(&mut self) {
        self.socket.send("ACQ:AVG ON");
    }

    pub fn disable_average(&mut self) {
        self.socket.send("ACQ:AVG OFF");
    }

    pub fn is_average_enabled(&mut self) -> bool {
        self.socket.send("ACQ:AVG?");

        let message = self.socket.receive();

        match message.as_str() {
            "ON" => true,
            _ => false,
        }
    }

    pub fn set_gain(&mut self, source: u8, gain: &str) {
        self.socket.send(format!("ACQ:SOUR{}:GAIN {}", source, gain));
    }
}

#[cfg(test)]
mod test {
    macro_rules! acquire_assert {
        ($f:ident, $e:expr) => {
            let (rx, mut acquire) = create_acquire();

            acquire.$f();
            assert_eq!($e, rx.recv().unwrap());
        }
    }

    #[test]
    fn test_start() {
        acquire_assert!(start, "ACQ:START\r\n");
    }

    #[test]
    fn test_stop() {
        acquire_assert!(stop, "ACQ:STOP\r\n");
    }

    #[test]
    fn test_is_started() {
        let (_, mut acquire) = create_acquire();

        assert_eq!(acquire.is_started(), false);
        acquire.start();
        assert_eq!(acquire.is_started(), true);
        acquire.stop();
        assert_eq!(acquire.is_started(), false);
    }

    #[test]
    fn test_reset() {
        acquire_assert!(reset, "ACQ:RST\r\n");
    }

    #[test]
    fn test_set_decimation() {
        let (rx, mut acquire) = create_acquire();

        acquire.set_decimation(::acquire::Decimation::DEC_8);
        assert_eq!("ACQ:DEC 8\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_get_decimation() {
        let (_, mut acquire) = create_acquire();

        assert_eq!(acquire.get_decimation(), ::acquire::Decimation::DEC_1);
    }

    #[test]
    fn test_enable_average() {
        acquire_assert!(enable_average, "ACQ:AVG ON\r\n");
    }

    #[test]
    fn test_disable_average() {
        acquire_assert!(disable_average, "ACQ:AVG OFF\r\n");
    }

    #[test]
    fn test_is_average_enabled() {
        let (_, mut acquire) = create_acquire();

        assert_eq!(acquire.is_average_enabled(), true);
    }

    #[test]
    fn test_set_gain() {
        let (rx, mut trigger) = create_acquire();

        trigger.set_gain(1, "LV");
        assert_eq!("ACQ:SOUR1:GAIN LV\r\n", rx.recv().unwrap());
    }

    fn create_acquire() -> (::std::sync::mpsc::Receiver<String>, ::acquire::Acquire) {
        let (addr, rx) = ::test::launch_server();
        let socket = ::socket::Socket::new(
            format!("{}", addr.ip()).as_str(),
            addr.port()
        );

        (rx, ::acquire::Acquire::new(socket))
    }
}
<|endoftext|>


<commit_before><commit_msg>stale file<commit_after><|endoftext|>


<commit_before>#![deny(warning)]
use rustorm::FromDao;
use rustorm_dao::ToDao;
use rustorm_dao::ToTableName;

#[derive(Debug, FromDao, rustorm::ToDao, rustorm::ToTableName)]
struct User {
    id: i32,
    username: String,
}

fn main() {
    let user = User {
        id: 1,
        username: "ivanceras".to_string(),
    };
    println!("user: {:#?}", user);
    let dao = user.to_dao();
    println!("dao: {:#?}", dao);
    let table = User::to_table_name();
    println!("table name: {}", table.name);
    println!("table: {:#?}", table);
}
<commit_msg>Fix examples<commit_after>#![deny(warnings)]

use rustorm::FromDao;
use rustorm::ToDao;
use rustorm::ToTableName;

#[derive(Debug, FromDao, ToDao, ToTableName)]
struct User {
    id: i32,
    username: String,
}

fn main() {
    // imported here since we are using the trait methods
    // `to_dao` and `to_table_name` without
    // conflicting with the derive ToDao and ToTableName macro
    use rustorm::dao::ToDao;
    use rustorm::dao::ToTableName;

    let user = User {
        id: 1,
        username: "ivanceras".to_string(),
    };
    println!("user: {:#?}", user);
    let dao = user.to_dao();
    println!("dao: {:#?}", dao);
    let table = User::to_table_name();
    println!("table name: {}", table.name);
    println!("table: {:#?}", table);
}
<|endoftext|>


<commit_before>use request::{Request, ToRequest};
use service::Service;
use application::Application;
use user::User;

#[derive(Debug)]
pub enum Type {
    Authorize,
    AuthRep,
    Report
}

impl Type {
    pub fn method(&self) -> &str {
        use self::Type::*;
        match *self {
            Report => "POST",
            AuthRep | Authorize => "GET",
        }
    }
}

#[derive(Debug)]
pub struct Info<'service, 'app, 'user> {
    kind: Type,
    service: &'service Service,
    application: &'app Application,
    user: Option<&'user User>,
}

const AUTHORIZE_ENDPOINT: &str = "/transactions/authorize.xml";
const AUTHREP_ENDPOINT: &str = "/transactions/authrep.xml";
const REPORT_ENDPOINT: &str = "/transactions.xml";
const OAUTH_AUTHORIZE_ENDPOINT: &str = "/transactions/oauth_authorize.xml";
const OAUTH_AUTHREP_ENDPOINT: &str = "/transactions/oauth_authrep.xml";

impl<'service, 'app, 'user> Info<'service, 'app, 'user> {
    pub fn new(kind: Type, service: &'service Service, application: &'app Application, user: Option<&'user User>) -> Self {
        Self { kind, service, application, user }
    }

    fn endpoint(&self) -> &str {
        use self::Type::*;

        match (&self.kind, self.application, self.user) {
            (&Authorize, &Application::OAuthToken(_), _) => OAUTH_AUTHORIZE_ENDPOINT,
            (&Authorize, _, Some(&User::OAuthToken(_))) => OAUTH_AUTHORIZE_ENDPOINT,
            (&Authorize, _, _) => AUTHORIZE_ENDPOINT,
            (&AuthRep, &Application::OAuthToken(_), _) => OAUTH_AUTHREP_ENDPOINT,
            (&AuthRep, _, Some(&User::OAuthToken(_))) => OAUTH_AUTHREP_ENDPOINT,
            (&AuthRep, _, _) => AUTHREP_ENDPOINT,
            (&Report, _, _) => REPORT_ENDPOINT,
        }
    }

    fn path(&self) -> String {
        use request::ToParams;

        let mut params: Vec<(&str, &str)> = Vec::new();
        params.extend(self.service.to_params());
        params.extend(self.application.to_params());

        if let Some(user_params) = self.user.as_ref() {
            params.extend(user_params.to_params());
        }

        let params = params.into_iter()
            .map(|(param, value)| param.to_owned() + "=" + value)
            .collect::<Vec<String>>()
            .join("&");

        self.endpoint().to_owned() + "?" + params.as_str()
    }
}

impl<'service, 'app, 'user> ToRequest for Info<'service, 'app, 'user> {
    fn to_request(&self) -> Request {
        Request::new(self.kind.method(), self.path(), None)
    }
}
<commit_msg>apicall: implement #params and invoke Request::new correctly<commit_after>use request::{Request, ToRequest};
use service::Service;
use application::Application;
use user::User;

#[derive(Debug)]
pub enum Type {
    Authorize,
    AuthRep,
    Report
}

impl Type {
    pub fn method(&self) -> &str {
        use self::Type::*;
        match *self {
            Report => "POST",
            AuthRep | Authorize => "GET",
        }
    }
}

#[derive(Debug)]
pub struct Info<'service, 'app, 'user> {
    kind: Type,
    service: &'service Service,
    application: &'app Application,
    user: Option<&'user User>,
}

const AUTHORIZE_ENDPOINT: &str = "/transactions/authorize.xml";
const AUTHREP_ENDPOINT: &str = "/transactions/authrep.xml";
const REPORT_ENDPOINT: &str = "/transactions.xml";
const OAUTH_AUTHORIZE_ENDPOINT: &str = "/transactions/oauth_authorize.xml";
const OAUTH_AUTHREP_ENDPOINT: &str = "/transactions/oauth_authrep.xml";

impl<'service, 'app, 'user> Info<'service, 'app, 'user> {
    pub fn new(kind: Type, service: &'service Service, application: &'app Application, user: Option<&'user User>) -> Self {
        Self { kind, service, application, user }
    }

    fn endpoint(&self) -> &str {
        use self::Type::*;

        match (&self.kind, self.application, self.user) {
            (&Authorize, &Application::OAuthToken(_), _) => OAUTH_AUTHORIZE_ENDPOINT,
            (&Authorize, _, Some(&User::OAuthToken(_))) => OAUTH_AUTHORIZE_ENDPOINT,
            (&Authorize, _, _) => AUTHORIZE_ENDPOINT,
            (&AuthRep, &Application::OAuthToken(_), _) => OAUTH_AUTHREP_ENDPOINT,
            (&AuthRep, _, Some(&User::OAuthToken(_))) => OAUTH_AUTHREP_ENDPOINT,
            (&AuthRep, _, _) => AUTHREP_ENDPOINT,
            (&Report, _, _) => REPORT_ENDPOINT,
        }
    }

    fn params(&self) -> Vec<(&str, &str)> {
        use request::ToParams;

        let mut params: Vec<(&str, &str)> = Vec::new();
        params.extend(self.service.to_params());
        params.extend(self.application.to_params());

        if let Some(user_params) = self.user.as_ref() {
            params.extend(user_params.to_params());
        }

        params
    }
}

impl<'service, 'app, 'user> ToRequest for Info<'service, 'app, 'user> {
    fn to_request(&self) -> Request {
        Request::new(self.kind.method(), self.endpoint(), self.params(), None)
    }
}
<|endoftext|>


<commit_before>use std::io::{Read, Cursor, Error, ErrorKind};
use tokio_codec::{Encoder, Decoder};
use bytes::{BufMut, BytesMut};
use serializer::*;

use blockchain::Properties;
use tx::TxVariant;
use net::rpc::*;

// 5 MiB limit
const MAX_PAYLOAD_LEN: u32 = 5_242_880;

#[derive(Default)]
pub struct RpcCodec {
    msg_len: u32
}

impl RpcCodec {
    pub fn new() -> RpcCodec {
        RpcCodec::default()
    }
}

impl Encoder for RpcCodec {
    type Item = RpcPayload;
    type Error = Error;

    fn encode(&mut self, pl: Self::Item, buf: &mut BytesMut) -> Result<(), Error> {
        let mut payload = Vec::<u8>::with_capacity(10240);
        payload.push_u32(pl.id);
        if let Some(msg) = pl.msg {
            match msg {
                RpcMsg::Error(err) => {
                    payload.push(RpcMsgType::Error as u8);
                    payload.push_bytes(err.as_bytes());
                },
                RpcMsg::Event(evt) => {
                    payload.push(RpcMsgType::Event as u8);
                    match evt {
                        RpcEvent::Tx(tx) => {
                            payload.push(RpcEventType::TX as u8);
                            tx.encode_with_sigs(&mut payload);
                        },
                        RpcEvent::Block(block) => {
                            payload.push(RpcEventType::BLOCK as u8);
                            block.encode_with_tx(&mut payload);
                        }
                    }
                },
                RpcMsg::Handshake(peer_type) => {
                    payload.push(RpcMsgType::Handshake as u8);
                    payload.push(peer_type as u8);
                },
                RpcMsg::Broadcast(tx) => {
                    payload.push(RpcMsgType::Broadcast as u8);
                    tx.encode_with_sigs(&mut payload);
                },
                RpcMsg::Properties(rpc) => {
                    payload.push(RpcMsgType::Properties as u8);
                    if let Some(props) = rpc.response() {
                        payload.push(RpcVariantType::Res as u8);
                        payload.push_u64(props.height);
                        payload.push_asset(&props.token_supply.gold);
                        payload.push_asset(&props.token_supply.silver);
                    } else {
                        payload.push(RpcVariantType::Req as u8);
                    }
                },
                RpcMsg::Block(rpc) => {
                    payload.push(RpcMsgType::Block as u8);
                    match rpc {
                        RpcVariant::Req(height) => {
                            payload.push(RpcVariantType::Req as u8);
                            payload.push_u64(height);
                        },
                        RpcVariant::Res(block) => {
                            payload.push(RpcVariantType::Res as u8);
                            if let Some(block) = block {
                                block.encode_with_tx(&mut payload);
                            }
                        }
                    }
                },
                RpcMsg::Balance(rpc) => {
                    payload.push(RpcMsgType::Balance as u8);
                    match rpc {
                        RpcVariant::Req(addr) => {
                            payload.push(RpcVariantType::Req as u8);
                            payload.push_pub_key(&addr);
                        },
                        RpcVariant::Res(bal) => {
                            payload.push(RpcVariantType::Res as u8);
                            payload.push_asset(&bal.gold);
                            payload.push_asset(&bal.silver);
                        }
                    }
                },
                RpcMsg::TotalFee(rpc) => {
                    payload.push(RpcMsgType::Balance as u8);
                    match rpc {
                        RpcVariant::Req(addr) => {
                            payload.push(RpcVariantType::Req as u8);
                            payload.push_pub_key(&addr);
                        },
                        RpcVariant::Res(bal) => {
                            payload.push(RpcVariantType::Res as u8);
                            payload.push_asset(&bal.gold);
                            payload.push_asset(&bal.silver);
                        }
                    }
                }
            }
        }

        buf.reserve(4 + payload.len());
        buf.put_u32_be(4 + (payload.len() as u32));
        buf.put_slice(&payload);
        debug_assert!((buf.capacity() as u32) < MAX_PAYLOAD_LEN);
        let mut v = Vec::<u8>::with_capacity(buf.len());
        v.extend_from_slice(buf);
        Ok(())
    }
}

impl Decoder for RpcCodec {
    type Item = RpcPayload;
    type Error = Error;

    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Error> {
        if self.msg_len == 0 && buf.len() >= 4 {
            let buf = buf.split_to(4);
            self.msg_len = u32_from_buf!(buf);
            if self.msg_len <= 4 {
                return Err(Error::new(ErrorKind::Other, "payload must be >4 bytes"))
            } else if self.msg_len > MAX_PAYLOAD_LEN {
                return Err(Error::new(ErrorKind::Other, format!("payload must be <={} bytes", MAX_PAYLOAD_LEN)))
            }
            self.msg_len -= 4;
        }
        if self.msg_len != 0 && buf.len() >= self.msg_len as usize {
            let msg_len = self.msg_len;
            let split = buf.split_to(msg_len as usize);
            let mut cur = Cursor::new(split.as_ref());
            self.msg_len = 0;

            let id = cur.take_u32()?;
            if msg_len == 4 {
                return Ok(Some(RpcPayload {
                    id,
                    msg: None
                }))
            }

            let msg = match cur.take_u8()? {
                t if t == RpcMsgType::Error as u8 => {
                    let len = msg_len as u64 - cur.position();
                    let mut buf = Vec::with_capacity(len as usize);
                    cur.read_exact(&mut buf).map_err(|_| {
                        Error::new(ErrorKind::Other, "failed to read error string")
                    })?;
                    RpcMsg::Error(String::from_utf8_lossy(&buf).into_owned())
                },
                t if t == RpcMsgType::Event as u8 => {
                    let event_type = cur.take_u8()?;
                    match event_type {
                        t if t == RpcEventType::TX as u8 => {
                            let tx = TxVariant::decode_with_sigs(&mut cur).ok_or_else(|| {
                                Error::new(ErrorKind::Other, "failed to decode tx")
                            })?;
                            RpcMsg::Event(RpcEvent::Tx(tx))
                        },
                        t if t == RpcEventType::BLOCK as u8 => {
                            let block = SignedBlock::decode_with_tx(&mut cur).ok_or_else(|| {
                                Error::new(ErrorKind::Other, "failed to decode signed block")
                            })?;
                            RpcMsg::Event(RpcEvent::Block(block))
                        },
                        _ => return Err(Error::new(ErrorKind::Other, "invalid event type"))
                    }
                },
                t if t == RpcMsgType::Handshake as u8 => {
                    let peer_type = match cur.take_u8()? {
                        t if t == PeerType::NODE as u8 => PeerType::NODE,
                        t if t == PeerType::WALLET as u8 => PeerType::WALLET,
                        _ => return Err(Error::new(ErrorKind::Other, "invalid peer type"))
                    };
                    RpcMsg::Handshake(peer_type)
                },
                t if t == RpcMsgType::Broadcast as u8 => {
                    let tx = TxVariant::decode_with_sigs(&mut cur).ok_or_else(|| {
                        Error::new(ErrorKind::Other, "failed to decode broadcast tx")
                    })?;
                    RpcMsg::Broadcast(tx)
                },
                t if t == RpcMsgType::Properties as u8 => {
                    let rpc = cur.take_u8()?;
                    match rpc {
                        t if t == RpcVariantType::Req as u8 => {
                            RpcMsg::Properties(RpcVariant::Req(()))
                        },
                        t if t == RpcVariantType::Res as u8 => {
                            let height = cur.take_u64()?;
                            let gold = cur.take_asset()?;
                            let silver = cur.take_asset()?;
                            RpcMsg::Properties(RpcVariant::Res(Properties {
                                height,
                                token_supply: Balance { gold, silver }
                            }))
                        },
                        _ => return Err(Error::new(ErrorKind::Other, "invalid rpc type"))
                    }
                },
                t if t == RpcMsgType::Block as u8 => {
                    let rpc = cur.take_u8()?;
                    match rpc {
                        t if t == RpcVariantType::Req as u8 => {
                            let height = cur.take_u64()?;
                            RpcMsg::Block(RpcVariant::Req(height))
                        },
                        t if t == RpcVariantType::Res as u8 => {
                            if u64::from(msg_len).saturating_sub(cur.position()) > 0 {
                                let block = SignedBlock::decode_with_tx(&mut cur).ok_or_else(|| {
                                    Error::new(ErrorKind::Other, "failed to decode block")
                                })?;
                                RpcMsg::Block(RpcVariant::Res(Some(block)))
                            } else {
                                RpcMsg::Block(RpcVariant::Res(None))
                            }
                        },
                        _ => return Err(Error::new(ErrorKind::Other, "invalid rpc type"))
                    }
                },
                t if t == RpcMsgType::Balance as u8 => {
                    let rpc = cur.take_u8()?;
                    match rpc {
                        t if t == RpcVariantType::Req as u8 => {
                            let addr = cur.take_pub_key()?;
                            RpcMsg::Balance(RpcVariant::Req(addr))
                        },
                        t if t == RpcVariantType::Res as u8 => {
                            let gold = cur.take_asset()?;
                            let silver = cur.take_asset()?;
                            RpcMsg::Balance(RpcVariant::Res(Balance { gold, silver }))
                        },
                        _ => return Err(Error::new(ErrorKind::Other, "invalid rpc type"))
                    }
                },
                t if t == RpcMsgType::TotalFee as u8 => {
                    let rpc = cur.take_u8()?;
                    match rpc {
                        t if t == RpcVariantType::Req as u8 => {
                            let addr = cur.take_pub_key()?;
                            RpcMsg::TotalFee(RpcVariant::Req(addr))
                        },
                        t if t == RpcVariantType::Res as u8 => {
                            let gold = cur.take_asset()?;
                            let silver = cur.take_asset()?;
                            RpcMsg::TotalFee(RpcVariant::Res(Balance { gold, silver }))
                        },
                        _ => return Err(Error::new(ErrorKind::Other, "invalid rpc type"))
                    }
                },
                _ => return Err(Error::new(ErrorKind::Other, "invalid msg type"))
            };

            Ok(Some(RpcPayload {
                id,
                msg: Some(msg)
            }))
        } else {
            Ok(None)
        }
    }
}
<commit_msg>Correctly take the bytes using BufRead when decoding error RPC messages<commit_after>use std::io::{Cursor, Error, ErrorKind};
use tokio_codec::{Encoder, Decoder};
use bytes::{BufMut, BytesMut};
use serializer::*;

use blockchain::Properties;
use tx::TxVariant;
use net::rpc::*;

// 5 MiB limit
const MAX_PAYLOAD_LEN: u32 = 5_242_880;

#[derive(Default)]
pub struct RpcCodec {
    msg_len: u32
}

impl RpcCodec {
    pub fn new() -> RpcCodec {
        RpcCodec::default()
    }
}

impl Encoder for RpcCodec {
    type Item = RpcPayload;
    type Error = Error;

    fn encode(&mut self, pl: Self::Item, buf: &mut BytesMut) -> Result<(), Error> {
        let mut payload = Vec::<u8>::with_capacity(10240);
        payload.push_u32(pl.id);
        if let Some(msg) = pl.msg {
            match msg {
                RpcMsg::Error(err) => {
                    payload.push(RpcMsgType::Error as u8);
                    payload.push_bytes(err.as_bytes());
                },
                RpcMsg::Event(evt) => {
                    payload.push(RpcMsgType::Event as u8);
                    match evt {
                        RpcEvent::Tx(tx) => {
                            payload.push(RpcEventType::TX as u8);
                            tx.encode_with_sigs(&mut payload);
                        },
                        RpcEvent::Block(block) => {
                            payload.push(RpcEventType::BLOCK as u8);
                            block.encode_with_tx(&mut payload);
                        }
                    }
                },
                RpcMsg::Handshake(peer_type) => {
                    payload.push(RpcMsgType::Handshake as u8);
                    payload.push(peer_type as u8);
                },
                RpcMsg::Broadcast(tx) => {
                    payload.push(RpcMsgType::Broadcast as u8);
                    tx.encode_with_sigs(&mut payload);
                },
                RpcMsg::Properties(rpc) => {
                    payload.push(RpcMsgType::Properties as u8);
                    if let Some(props) = rpc.response() {
                        payload.push(RpcVariantType::Res as u8);
                        payload.push_u64(props.height);
                        payload.push_asset(&props.token_supply.gold);
                        payload.push_asset(&props.token_supply.silver);
                    } else {
                        payload.push(RpcVariantType::Req as u8);
                    }
                },
                RpcMsg::Block(rpc) => {
                    payload.push(RpcMsgType::Block as u8);
                    match rpc {
                        RpcVariant::Req(height) => {
                            payload.push(RpcVariantType::Req as u8);
                            payload.push_u64(height);
                        },
                        RpcVariant::Res(block) => {
                            payload.push(RpcVariantType::Res as u8);
                            if let Some(block) = block {
                                block.encode_with_tx(&mut payload);
                            }
                        }
                    }
                },
                RpcMsg::Balance(rpc) => {
                    payload.push(RpcMsgType::Balance as u8);
                    match rpc {
                        RpcVariant::Req(addr) => {
                            payload.push(RpcVariantType::Req as u8);
                            payload.push_pub_key(&addr);
                        },
                        RpcVariant::Res(bal) => {
                            payload.push(RpcVariantType::Res as u8);
                            payload.push_asset(&bal.gold);
                            payload.push_asset(&bal.silver);
                        }
                    }
                },
                RpcMsg::TotalFee(rpc) => {
                    payload.push(RpcMsgType::Balance as u8);
                    match rpc {
                        RpcVariant::Req(addr) => {
                            payload.push(RpcVariantType::Req as u8);
                            payload.push_pub_key(&addr);
                        },
                        RpcVariant::Res(bal) => {
                            payload.push(RpcVariantType::Res as u8);
                            payload.push_asset(&bal.gold);
                            payload.push_asset(&bal.silver);
                        }
                    }
                }
            }
        }

        buf.reserve(4 + payload.len());
        buf.put_u32_be(4 + (payload.len() as u32));
        buf.put_slice(&payload);
        debug_assert!((buf.capacity() as u32) < MAX_PAYLOAD_LEN);
        let mut v = Vec::<u8>::with_capacity(buf.len());
        v.extend_from_slice(buf);
        Ok(())
    }
}

impl Decoder for RpcCodec {
    type Item = RpcPayload;
    type Error = Error;

    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Error> {
        if self.msg_len == 0 && buf.len() >= 4 {
            let buf = buf.split_to(4);
            self.msg_len = u32_from_buf!(buf);
            if self.msg_len <= 4 {
                return Err(Error::new(ErrorKind::Other, "payload must be >4 bytes"))
            } else if self.msg_len > MAX_PAYLOAD_LEN {
                return Err(Error::new(ErrorKind::Other, format!("payload must be <={} bytes", MAX_PAYLOAD_LEN)))
            }
            self.msg_len -= 4;
        }
        if self.msg_len != 0 && buf.len() >= self.msg_len as usize {
            let msg_len = self.msg_len;
            let split = buf.split_to(msg_len as usize);
            let mut cur = Cursor::new(split.as_ref());
            self.msg_len = 0;

            let id = cur.take_u32()?;
            if msg_len == 4 {
                return Ok(Some(RpcPayload {
                    id,
                    msg: None
                }))
            }

            let msg = match cur.take_u8()? {
                t if t == RpcMsgType::Error as u8 => {
                    let bytes = cur.take_bytes()?;
                    RpcMsg::Error(String::from_utf8_lossy(&bytes).into_owned())
                },
                t if t == RpcMsgType::Event as u8 => {
                    let event_type = cur.take_u8()?;
                    match event_type {
                        t if t == RpcEventType::TX as u8 => {
                            let tx = TxVariant::decode_with_sigs(&mut cur).ok_or_else(|| {
                                Error::new(ErrorKind::Other, "failed to decode tx")
                            })?;
                            RpcMsg::Event(RpcEvent::Tx(tx))
                        },
                        t if t == RpcEventType::BLOCK as u8 => {
                            let block = SignedBlock::decode_with_tx(&mut cur).ok_or_else(|| {
                                Error::new(ErrorKind::Other, "failed to decode signed block")
                            })?;
                            RpcMsg::Event(RpcEvent::Block(block))
                        },
                        _ => return Err(Error::new(ErrorKind::Other, "invalid event type"))
                    }
                },
                t if t == RpcMsgType::Handshake as u8 => {
                    let peer_type = match cur.take_u8()? {
                        t if t == PeerType::NODE as u8 => PeerType::NODE,
                        t if t == PeerType::WALLET as u8 => PeerType::WALLET,
                        _ => return Err(Error::new(ErrorKind::Other, "invalid peer type"))
                    };
                    RpcMsg::Handshake(peer_type)
                },
                t if t == RpcMsgType::Broadcast as u8 => {
                    let tx = TxVariant::decode_with_sigs(&mut cur).ok_or_else(|| {
                        Error::new(ErrorKind::Other, "failed to decode broadcast tx")
                    })?;
                    RpcMsg::Broadcast(tx)
                },
                t if t == RpcMsgType::Properties as u8 => {
                    let rpc = cur.take_u8()?;
                    match rpc {
                        t if t == RpcVariantType::Req as u8 => {
                            RpcMsg::Properties(RpcVariant::Req(()))
                        },
                        t if t == RpcVariantType::Res as u8 => {
                            let height = cur.take_u64()?;
                            let gold = cur.take_asset()?;
                            let silver = cur.take_asset()?;
                            RpcMsg::Properties(RpcVariant::Res(Properties {
                                height,
                                token_supply: Balance { gold, silver }
                            }))
                        },
                        _ => return Err(Error::new(ErrorKind::Other, "invalid rpc type"))
                    }
                },
                t if t == RpcMsgType::Block as u8 => {
                    let rpc = cur.take_u8()?;
                    match rpc {
                        t if t == RpcVariantType::Req as u8 => {
                            let height = cur.take_u64()?;
                            RpcMsg::Block(RpcVariant::Req(height))
                        },
                        t if t == RpcVariantType::Res as u8 => {
                            if u64::from(msg_len).saturating_sub(cur.position()) > 0 {
                                let block = SignedBlock::decode_with_tx(&mut cur).ok_or_else(|| {
                                    Error::new(ErrorKind::Other, "failed to decode block")
                                })?;
                                RpcMsg::Block(RpcVariant::Res(Some(block)))
                            } else {
                                RpcMsg::Block(RpcVariant::Res(None))
                            }
                        },
                        _ => return Err(Error::new(ErrorKind::Other, "invalid rpc type"))
                    }
                },
                t if t == RpcMsgType::Balance as u8 => {
                    let rpc = cur.take_u8()?;
                    match rpc {
                        t if t == RpcVariantType::Req as u8 => {
                            let addr = cur.take_pub_key()?;
                            RpcMsg::Balance(RpcVariant::Req(addr))
                        },
                        t if t == RpcVariantType::Res as u8 => {
                            let gold = cur.take_asset()?;
                            let silver = cur.take_asset()?;
                            RpcMsg::Balance(RpcVariant::Res(Balance { gold, silver }))
                        },
                        _ => return Err(Error::new(ErrorKind::Other, "invalid rpc type"))
                    }
                },
                t if t == RpcMsgType::TotalFee as u8 => {
                    let rpc = cur.take_u8()?;
                    match rpc {
                        t if t == RpcVariantType::Req as u8 => {
                            let addr = cur.take_pub_key()?;
                            RpcMsg::TotalFee(RpcVariant::Req(addr))
                        },
                        t if t == RpcVariantType::Res as u8 => {
                            let gold = cur.take_asset()?;
                            let silver = cur.take_asset()?;
                            RpcMsg::TotalFee(RpcVariant::Res(Balance { gold, silver }))
                        },
                        _ => return Err(Error::new(ErrorKind::Other, "invalid rpc type"))
                    }
                },
                _ => return Err(Error::new(ErrorKind::Other, "invalid msg type"))
            };

            Ok(Some(RpcPayload {
                id,
                msg: Some(msg)
            }))
        } else {
            Ok(None)
        }
    }
}
<|endoftext|>