<commit_before>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use capnp::Error;
use capnp::primitive_list;

use capnp_rpc::{rpc, twoparty, rpc_twoparty_capnp};
use capnp_rpc::rpc::LocalClient;

use calculator_capnp::calculator;
use gj::{EventLoop, Promise, TaskReaper, TaskSet};
use gj::io::tcp;

struct ValueImpl {
    value: f64
}

impl ValueImpl {
    fn new(value: f64) -> ValueImpl {
        ValueImpl { value: value }
    }
}

impl calculator::value::Server for ValueImpl {
    fn read(&mut self,
            _params: calculator::value::ReadParams,
            mut results: calculator::value::ReadResults)
            -> Promise<calculator::value::ReadResults, Error>
    {
        results.get().set_value(self.value);
        Promise::ok(results)
    }
}

fn evaluate_impl(expression: calculator::expression::Reader,
                 params: Option<primitive_list::Reader<f64>>)
                 -> Promise<f64, Error>
{
    match pry!(expression.which()) {
        calculator::expression::Literal(v) => {
            Promise::ok(v)
        },
        calculator::expression::PreviousResult(p) => {
            pry!(p).read_request().send().promise.map(|v| {
                Ok(try!(v.get()).get_value())
            })
        }
        calculator::expression::Parameter(p) => {
            match params {
                Some(params) if p < params.len() => {
                    Promise::ok(params.get(p))
                }
                _ => {
                    Promise::err(Error::failed(format!("bad parameter: {}", p)))
                }
            }
        }
        calculator::expression::Call(call) => {
            let func = pry!(call.get_function());
            let param_promises = pry!(call.get_params()).iter().map(|p| evaluate_impl(p, params));

            Promise::all(param_promises).then(move |param_values| {
                let mut request = func.call_request();
                {
                    let mut params = request.get().init_params(param_values.len() as u32);
                    for ii in 0..param_values.len() {
                        params.set(ii as u32, param_values[ii]);
                    }
                }
                request.send().promise.map(|result| {
                    Ok(try!(result.get()).get_value())
                })
            })
        }
    }
}

struct FunctionImpl {
    param_count: u32,
    body: ::capnp::message::Builder<::capnp::message::HeapAllocator>,
    cap_table: Vec<Option<Box<::capnp::private::capability::ClientHook>>>
}

impl FunctionImpl {
    fn new(param_count: u32, body: calculator::expression::Reader) -> FunctionImpl {
        use ::capnp::traits::ImbueMut;
        let mut result = FunctionImpl {
            param_count: param_count,
            body: ::capnp::message::Builder::new_default(),
            cap_table: Vec::new(),
        };
        {
            let mut root: ::capnp::any_pointer::Builder = result.body.init_root();
            root.imbue_mut(&mut result.cap_table);
            root.set_as(body).unwrap();
        }
        result
    }
}

impl calculator::function::Server for FunctionImpl {
    fn call(&mut self,
            params: calculator::function::CallParams,
            mut results: calculator::function::CallResults)
        -> Promise<calculator::function::CallResults, Error>
    {
        use ::capnp::traits::Imbue;
        let params = pry!(params.get().get_params());
        if params.len() != self.param_count {
            Promise::err(Error::failed(
                format!("Expect {} parameters but got {}.", self.param_count, params.len())))
        } else {
            let mut exp = pry!(self.body.get_root::<calculator::expression::Builder>()).as_reader();
            exp.imbue(&self.cap_table);
            evaluate_impl(
                exp,
                Some(params)).map(move |v| {
                    results.get().set_value(v);
                    Ok(results)
                })
        }
    }
}

#[derive(Clone, Copy)]
pub struct OperatorImpl {
    op: calculator::Operator,
}

impl calculator::function::Server for OperatorImpl {
    fn call(&mut self,
            params: calculator::function::CallParams,
            mut results: calculator::function::CallResults)
            -> Promise<calculator::function::CallResults, Error>
    {
        let params = pry!(params.get().get_params());
        if params.len() != 2 {
            Promise::err(Error::failed("Wrong number of paramters.".to_string()))
        } else {
            let v = match self.op {
                calculator::Operator::Add =>       params.get(0) + params.get(1),
                calculator::Operator::Subtract =>  params.get(0) - params.get(1),
                calculator::Operator::Multiply =>  params.get(0) * params.get(1),
                calculator::Operator::Divide =>    params.get(0) / params.get(1),
            };
            results.get().set_value(v);
            Promise::ok(results)
        }
    }
}

struct CalculatorImpl;

impl calculator::Server for CalculatorImpl {
    fn evaluate(&mut self,
                params: calculator::EvaluateParams,
                mut results: calculator::EvaluateResults)
                -> Promise<calculator::EvaluateResults, Error>
    {
        evaluate_impl(pry!(params.get().get_expression()), None).map(move |v| {
            results.get().set_value(
                calculator::value::ToClient::new(ValueImpl::new(v)).from_server::<LocalClient>());
            Ok(results)
        })
    }
    fn def_function(&mut self,
                    params: calculator::DefFunctionParams,
                    mut results: calculator::DefFunctionResults)
                    -> Promise<calculator::DefFunctionResults, Error>
    {
        results.get().set_func(
            calculator::function::ToClient::new(
                FunctionImpl::new(params.get().get_param_count() as u32, pry!(params.get().get_body())))
                .from_server::<LocalClient>());
        Promise::ok(results)
    }
    fn get_operator(&mut self,
                    params: calculator::GetOperatorParams,
                    mut results: calculator::GetOperatorResults)
                    -> Promise<calculator::GetOperatorResults, Error>
    {
        let op = pry!(params.get().get_op());
        results.get().set_func(
            calculator::function::ToClient::new(OperatorImpl {op : op}).from_server::<LocalClient>());
        Promise::ok(results)
    }
}

pub fn accept_loop(listener: tcp::Listener,
                   mut task_set: TaskSet<(), Box<::std::error::Error>>,
                   calc: calculator::Client,
                   )
                   -> Promise<(), ::std::io::Error>
{
    listener.accept().lift().then(move |(listener, stream)| {
        let stream2 = pry!(stream.try_clone());
        let mut network =
            twoparty::VatNetwork::new(stream, stream2,
                                      rpc_twoparty_capnp::Side::Server, Default::default());
        let disconnect_promise = network.on_disconnect();

        // Should put in the calculator for the bootstrap.
        let rpc_system = rpc::System::new(Box::new(network), Some(calc.clone().client));

        task_set.add(disconnect_promise.attach(rpc_system).lift());
        accept_loop(listener, task_set, calc)
    })
}

struct Reaper;

impl TaskReaper<(), Box<::std::error::Error>> for Reaper {
    fn task_failed(&mut self, error: Box<::std::error::Error>) {
        println!("Task failed: {}", error);
    }
}

pub fn main() {
    let args : Vec<String> = ::std::env::args().collect();
    if args.len() != 3 {
        println!("usage: {} server ADDRESS[:PORT]", args[0]);
        return;
    }

    EventLoop::top_level(move |wait_scope| {
        use std::net::ToSocketAddrs;
        let addr = try!(args[2].to_socket_addrs()).next().expect("could not parse address");
        let listener = try!(tcp::Listener::bind(addr));

        let calc =
            calculator::ToClient::new(CalculatorImpl).from_server::<LocalClient>();

        let task_set = TaskSet::new(Box::new(Reaper));
        try!(accept_loop(listener, task_set, calc).wait(wait_scope));

        Ok(())
    }).expect("top level error");
}
<commit_msg>Now message builders come with their own cap table.<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use capnp::Error;
use capnp::primitive_list;

use capnp_rpc::{rpc, twoparty, rpc_twoparty_capnp};
use capnp_rpc::rpc::LocalClient;

use calculator_capnp::calculator;
use gj::{EventLoop, Promise, TaskReaper, TaskSet};
use gj::io::tcp;

struct ValueImpl {
    value: f64
}

impl ValueImpl {
    fn new(value: f64) -> ValueImpl {
        ValueImpl { value: value }
    }
}

impl calculator::value::Server for ValueImpl {
    fn read(&mut self,
            _params: calculator::value::ReadParams,
            mut results: calculator::value::ReadResults)
            -> Promise<calculator::value::ReadResults, Error>
    {
        results.get().set_value(self.value);
        Promise::ok(results)
    }
}

fn evaluate_impl(expression: calculator::expression::Reader,
                 params: Option<primitive_list::Reader<f64>>)
                 -> Promise<f64, Error>
{
    match pry!(expression.which()) {
        calculator::expression::Literal(v) => {
            Promise::ok(v)
        },
        calculator::expression::PreviousResult(p) => {
            pry!(p).read_request().send().promise.map(|v| {
                Ok(try!(v.get()).get_value())
            })
        }
        calculator::expression::Parameter(p) => {
            match params {
                Some(params) if p < params.len() => {
                    Promise::ok(params.get(p))
                }
                _ => {
                    Promise::err(Error::failed(format!("bad parameter: {}", p)))
                }
            }
        }
        calculator::expression::Call(call) => {
            let func = pry!(call.get_function());
            let param_promises = pry!(call.get_params()).iter().map(|p| evaluate_impl(p, params));

            Promise::all(param_promises).then(move |param_values| {
                let mut request = func.call_request();
                {
                    let mut params = request.get().init_params(param_values.len() as u32);
                    for ii in 0..param_values.len() {
                        params.set(ii as u32, param_values[ii]);
                    }
                }
                request.send().promise.map(|result| {
                    Ok(try!(result.get()).get_value())
                })
            })
        }
    }
}

struct FunctionImpl {
    param_count: u32,
    body: ::capnp::message::Builder<::capnp::message::HeapAllocator>,
}

impl FunctionImpl {
    fn new(param_count: u32, body: calculator::expression::Reader) -> ::capnp::Result<FunctionImpl> {
        let mut result = FunctionImpl {
            param_count: param_count,
            body: ::capnp::message::Builder::new_default(),
        };
        try!(result.body.set_root(body));
        Ok(result)
    }
}

impl calculator::function::Server for FunctionImpl {
    fn call(&mut self,
            params: calculator::function::CallParams,
            mut results: calculator::function::CallResults)
        -> Promise<calculator::function::CallResults, Error>
    {
        let params = pry!(params.get().get_params());
        if params.len() != self.param_count {
            Promise::err(Error::failed(
                format!("Expect {} parameters but got {}.", self.param_count, params.len())))
        } else {
            evaluate_impl(
                pry!(self.body.get_root::<calculator::expression::Builder>()).as_reader(),
                Some(params)).map(move |v| {
                    results.get().set_value(v);
                    Ok(results)
                })
        }
    }
}

#[derive(Clone, Copy)]
pub struct OperatorImpl {
    op: calculator::Operator,
}

impl calculator::function::Server for OperatorImpl {
    fn call(&mut self,
            params: calculator::function::CallParams,
            mut results: calculator::function::CallResults)
            -> Promise<calculator::function::CallResults, Error>
    {
        let params = pry!(params.get().get_params());
        if params.len() != 2 {
            Promise::err(Error::failed("Wrong number of paramters.".to_string()))
        } else {
            let v = match self.op {
                calculator::Operator::Add =>       params.get(0) + params.get(1),
                calculator::Operator::Subtract =>  params.get(0) - params.get(1),
                calculator::Operator::Multiply =>  params.get(0) * params.get(1),
                calculator::Operator::Divide =>    params.get(0) / params.get(1),
            };
            results.get().set_value(v);
            Promise::ok(results)
        }
    }
}

struct CalculatorImpl;

impl calculator::Server for CalculatorImpl {
    fn evaluate(&mut self,
                params: calculator::EvaluateParams,
                mut results: calculator::EvaluateResults)
                -> Promise<calculator::EvaluateResults, Error>
    {
        evaluate_impl(pry!(params.get().get_expression()), None).map(move |v| {
            results.get().set_value(
                calculator::value::ToClient::new(ValueImpl::new(v)).from_server::<LocalClient>());
            Ok(results)
        })
    }
    fn def_function(&mut self,
                    params: calculator::DefFunctionParams,
                    mut results: calculator::DefFunctionResults)
                    -> Promise<calculator::DefFunctionResults, Error>
    {
        results.get().set_func(
            calculator::function::ToClient::new(
                pry!(FunctionImpl::new(params.get().get_param_count() as u32,pry!(params.get().get_body()))))
                .from_server::<LocalClient>());
        Promise::ok(results)
    }
    fn get_operator(&mut self,
                    params: calculator::GetOperatorParams,
                    mut results: calculator::GetOperatorResults)
                    -> Promise<calculator::GetOperatorResults, Error>
    {
        let op = pry!(params.get().get_op());
        results.get().set_func(
            calculator::function::ToClient::new(OperatorImpl {op : op}).from_server::<LocalClient>());
        Promise::ok(results)
    }
}

pub fn accept_loop(listener: tcp::Listener,
                   mut task_set: TaskSet<(), Box<::std::error::Error>>,
                   calc: calculator::Client,
                   )
                   -> Promise<(), ::std::io::Error>
{
    listener.accept().lift().then(move |(listener, stream)| {
        let stream2 = pry!(stream.try_clone());
        let mut network =
            twoparty::VatNetwork::new(stream, stream2,
                                      rpc_twoparty_capnp::Side::Server, Default::default());
        let disconnect_promise = network.on_disconnect();

        // Should put in the calculator for the bootstrap.
        let rpc_system = rpc::System::new(Box::new(network), Some(calc.clone().client));

        task_set.add(disconnect_promise.attach(rpc_system).lift());
        accept_loop(listener, task_set, calc)
    })
}

struct Reaper;

impl TaskReaper<(), Box<::std::error::Error>> for Reaper {
    fn task_failed(&mut self, error: Box<::std::error::Error>) {
        println!("Task failed: {}", error);
    }
}

pub fn main() {
    let args : Vec<String> = ::std::env::args().collect();
    if args.len() != 3 {
        println!("usage: {} server ADDRESS[:PORT]", args[0]);
        return;
    }

    EventLoop::top_level(move |wait_scope| {
        use std::net::ToSocketAddrs;
        let addr = try!(args[2].to_socket_addrs()).next().expect("could not parse address");
        let listener = try!(tcp::Listener::bind(addr));

        let calc =
            calculator::ToClient::new(CalculatorImpl).from_server::<LocalClient>();

        let task_set = TaskSet::new(Box::new(Reaper));
        try!(accept_loop(listener, task_set, calc).wait(wait_scope));

        Ok(())
    }).expect("top level error");
}
<|endoftext|>


<commit_before>import astconv::{type_rscope, instantiate_iface_ref, ty_of_item,
                 empty_rscope, ty_of_native_item, ast_conv};

// Item collection - a pair of bootstrap passes:
//
// (1) Collect the IDs of all type items (typedefs) and store them in a table.
//
// (2) Translate the AST fragments that describe types to determine a type for
//     each item. When we encounter a named type, we consult the table built
//     in pass 1 to find its item, and recursively translate it.
//
// We then annotate the AST with the resulting types and return the annotated
// AST, along with a table mapping item IDs to their types.
fn get_enum_variant_types(ccx: @crate_ctxt,
                          enum_ty: ty::t,
                          variants: [ast::variant],
                          ty_params: [ast::ty_param],
                          rp: ast::region_param) {
    let tcx = ccx.tcx;

    // Create a set of parameter types shared among all the variants.
    for variants.each {|variant|
        // Nullary enum constructors get turned into constants; n-ary enum
        // constructors get turned into functions.
        let result_ty = if vec::len(variant.node.args) == 0u {
            enum_ty
        } else {
            let rs = type_rscope(rp);
            let args = variant.node.args.map { |va|
                let arg_ty = ccx.to_ty(rs, va.ty);
                {mode: ast::expl(ast::by_copy), ty: arg_ty}
            };
            ty::mk_fn(tcx, {proto: ast::proto_box,
                            inputs: args,
                            output: enum_ty,
                            ret_style: ast::return_val,
                            constraints: []})
        };
        let tpt = {bounds: astconv::ty_param_bounds(ccx, ty_params),
                   rp: rp,
                   ty: result_ty};
        tcx.tcache.insert(local_def(variant.node.id), tpt);
        write_ty_to_tcx(tcx, variant.node.id, result_ty);
    }
}

fn ensure_iface_methods(ccx: @crate_ctxt, id: ast::node_id) {
    fn store_methods<T>(ccx: @crate_ctxt, id: ast::node_id,
                        stuff: [T], f: fn@(T) -> ty::method) {
        ty::store_iface_methods(ccx.tcx, id, @vec::map(stuff, f));
    }

    let tcx = ccx.tcx;
    alt check tcx.items.get(id) {
      ast_map::node_item(@{node: ast::item_iface(_, rp, ms), _}, _) {
        store_methods::<ast::ty_method>(ccx, id, ms) {|m|
            ty_of_ty_method(ccx, m, rp)
        };
      }
      ast_map::node_item(@{node: ast::item_class(_,_,its,_,_,rp), _}, _) {
        let (_,ms) = split_class_items(its);
        // All methods need to be stored, since lookup_method
        // relies on the same method cache for self-calls
        store_methods::<@ast::method>(ccx, id, ms) {|m|
            ty_of_method(ccx, m, rp)
        };
      }
    }
}

fn check_methods_against_iface(ccx: @crate_ctxt,
                               tps: [ast::ty_param],
                               rp: ast::region_param,
                               selfty: ty::t,
                               a_ifacety: @ast::iface_ref,
                               ms: [@ast::method]) {

    let tcx = ccx.tcx;
    let i_bounds = astconv::ty_param_bounds(ccx, tps);
    let my_methods = convert_methods(ccx, ms, rp, i_bounds, selfty);
    let (did, tpt) = instantiate_iface_ref(ccx, a_ifacety, rp);
    if did.crate == ast::local_crate {
        ensure_iface_methods(ccx, did.node);
    }
    for vec::each(*ty::iface_methods(tcx, did)) {|if_m|
        alt vec::find(my_methods, {|m| if_m.ident == m.mty.ident}) {
          some({mty: m, id, span}) {
            if m.purity != if_m.purity {
                ccx.tcx.sess.span_err(
                    span, #fmt["method `%s`'s purity \
                                not match the iface method's \
                                purity", m.ident]);
            }
            let mt = compare_impl_method(
                ccx.tcx, span, m, vec::len(tps),
                if_m, tpt.substs, selfty);
            let old = tcx.tcache.get(local_def(id));
            if old.ty != mt {
                tcx.tcache.insert(
                    local_def(id),
                    {bounds: old.bounds,
                     rp: old.rp,
                     ty: mt});
                write_ty_to_tcx(tcx, id, mt);
            }
          }
          none {
            tcx.sess.span_err(
                a_ifacety.path.span,
                #fmt["missing method `%s`", if_m.ident]);
          }
        } // alt
    } // |if_m|
} // fn

fn convert_class_item(ccx: @crate_ctxt,
                      rp: ast::region_param,
                      v: ast_util::ivar) {
    /* we want to do something here, b/c within the
    scope of the class, it's ok to refer to fields &
    methods unqualified */
    /* they have these types *within the scope* of the
    class. outside the class, it's done with expr_field */
    let tt = ccx.to_ty(type_rscope(rp), v.ty);
    write_ty_to_tcx(ccx.tcx, v.id, tt);
}

fn convert_methods(ccx: @crate_ctxt,
                   ms: [@ast::method],
                   rp: ast::region_param,
                   i_bounds: @[ty::param_bounds],
                   self_ty: ty::t)
    -> [{mty: ty::method, id: ast::node_id, span: span}] {

    let tcx = ccx.tcx;
    vec::map(ms) { |m|
        write_ty_to_tcx(tcx, m.self_id, self_ty);
        let bounds = astconv::ty_param_bounds(ccx, m.tps);
        let mty = ty_of_method(ccx, m, rp);
        let fty = ty::mk_fn(tcx, mty.fty);
        tcx.tcache.insert(
            local_def(m.id),
            // n.b. This code is kind of sketchy (concat'ing i_bounds
            // with bounds), but removing *i_bounds breaks other stuff
            {bounds: @(*i_bounds + *bounds), rp: rp, ty: fty});
        write_ty_to_tcx(tcx, m.id, fty);
        {mty: mty, id: m.id, span: m.span}
    }
}

fn convert(ccx: @crate_ctxt, it: @ast::item) {
    let tcx = ccx.tcx;
    alt it.node {
      // These don't define types.
      ast::item_mod(_) {}
      ast::item_native_mod(m) {
        if syntax::attr::native_abi(it.attrs) ==
            either::right(ast::native_abi_rust_intrinsic) {
            for m.items.each { |item| check_intrinsic_type(ccx, item); }
        }
      }
      ast::item_enum(variants, ty_params, rp) {
        let tpt = ty_of_item(ccx, it);
        write_ty_to_tcx(tcx, it.id, tpt.ty);
        get_enum_variant_types(ccx, tpt.ty, variants,
                               ty_params, rp);
      }
      ast::item_impl(tps, rp, ifce, selfty, ms) {
        let i_bounds = astconv::ty_param_bounds(ccx, tps);
        let selfty = ccx.to_ty(type_rscope(rp), selfty);
        write_ty_to_tcx(tcx, it.id, selfty);
        tcx.tcache.insert(local_def(it.id),
                          {bounds: i_bounds,
                           rp: rp,
                           ty: selfty});
        alt ifce {
          some(t) {
            check_methods_against_iface(
                ccx, tps, rp,
                selfty, t, ms);
          }
          _ {
            // Still have to do this to write method types
            // into the table
            convert_methods(
                ccx, ms, rp,
                i_bounds, selfty);
          }
        }
      }
      ast::item_res(decl, tps, _, dtor_id, ctor_id, rp) {
        let {bounds, substs} = mk_substs(ccx, tps, rp);
        let def_id = local_def(it.id);
        let t_arg = astconv::ty_of_arg(ccx, type_rscope(rp),
                                       decl.inputs[0], none);
        let t_res = ty::mk_res(tcx, def_id, t_arg.ty, substs);

        let t_ctor = ty::mk_fn(tcx, {
            proto: ast::proto_box,
            inputs: [{mode: ast::expl(ast::by_copy), ty: t_arg.ty}],
            output: t_res,
            ret_style: ast::return_val, constraints: []
        });
        let t_dtor = ty::mk_fn(tcx, {
            proto: ast::proto_box,
            inputs: [t_arg], output: ty::mk_nil(tcx),
            ret_style: ast::return_val, constraints: []
        });
        write_ty_to_tcx(tcx, it.id, t_res);
        write_ty_to_tcx(tcx, ctor_id, t_ctor);
        tcx.tcache.insert(local_def(ctor_id),
                          {bounds: bounds,
                           rp: rp,
                           ty: t_ctor});
        tcx.tcache.insert(def_id, {bounds: bounds,
                                   rp: rp,
                                   ty: t_res});
        write_ty_to_tcx(tcx, dtor_id, t_dtor);
      }
      ast::item_iface(*) {
        let tpt = ty_of_item(ccx, it);
        #debug["item_iface(it.id=%d, tpt.ty=%s)",
               it.id, ty_to_str(tcx, tpt.ty)];
        write_ty_to_tcx(tcx, it.id, tpt.ty);
        ensure_iface_methods(ccx, it.id);
      }
      ast::item_class(tps, ifaces, members, ctor, m_dtor, rp) {
        // Write the class type
        let tpt = ty_of_item(ccx, it);
        write_ty_to_tcx(tcx, it.id, tpt.ty);
        // Write the ctor type
        let t_ctor =
            ty::mk_fn(
                tcx,
                astconv::ty_of_fn_decl(ccx,
                                       empty_rscope,
                                       ast::proto_any,
                                       ctor.node.dec,
                                       none));
        write_ty_to_tcx(tcx, ctor.node.id, t_ctor);
        tcx.tcache.insert(local_def(ctor.node.id),
                          {bounds: tpt.bounds,
                           rp: ast::rp_none,
                           ty: t_ctor});
        option::iter(m_dtor) {|dtor|
            // Write the dtor type
            let t_dtor = ty::mk_fn(
                tcx,
                // not sure about empty_rscope
                // FIXME
                astconv::ty_of_fn_decl(ccx,
                                       empty_rscope,
                                       ast::proto_any,
                                       ast_util::dtor_dec(),
                                       none));
            write_ty_to_tcx(tcx, dtor.node.id, t_dtor);
            tcx.tcache.insert(local_def(dtor.node.id),
                              {bounds: tpt.bounds,
                               rp: ast::rp_none,
                               ty: t_dtor});
        };
        ensure_iface_methods(ccx, it.id);
        /* FIXME: check for proper public/privateness */
        // Write the type of each of the members
        let (fields, methods) = split_class_items(members);
        for fields.each {|f|
            convert_class_item(ccx, rp, f);
        }
        // The selfty is just the class type
        let {bounds:_, substs} = mk_substs(ccx, tps, rp);
        let selfty = ty::mk_class(tcx, local_def(it.id), substs);
        // Need to convert all methods so we can check internal
        // references to private methods

        // NDM to TJC---I think we ought to be using bounds here, not @[].
        // But doing so causes errors later on.
        convert_methods(ccx, methods, rp, @[], selfty);

        /*
        Finally, check that the class really implements the ifaces
        that it claims to implement.
        */
        for ifaces.each { |ifce|
            check_methods_against_iface(ccx, tps, rp, selfty,
                                        ifce, methods);
            let t = ty::node_id_to_type(tcx, ifce.id);

            // FIXME: This assumes classes only implement
            // non-parameterized ifaces. add a test case for
            // a class implementing a parameterized iface.
            // -- tjc (#1726)
            tcx.tcache.insert(local_def(ifce.id), no_params(t));
        }
      }
      _ {
        // This call populates the type cache with the converted type
        // of the item in passing. All we have to do here is to write
        // it into the node type table.
        let tpt = ty_of_item(ccx, it);
        write_ty_to_tcx(tcx, it.id, tpt.ty);
      }
    }
}
fn convert_native(ccx: @crate_ctxt, i: @ast::native_item) {
    // As above, this call populates the type table with the converted
    // type of the native item. We simply write it into the node type
    // table.
    let tpt = ty_of_native_item(ccx, i);
    alt i.node {
      ast::native_item_fn(_, _) {
        write_ty_to_tcx(ccx.tcx, i.id, tpt.ty);
      }
    }
}
fn collect_item_types(ccx: @crate_ctxt, crate: @ast::crate) {
    visit::visit_crate(*crate, (), visit::mk_simple_visitor(@{
        visit_item: bind convert(ccx, _),
        visit_native_item: bind convert_native(ccx, _)
        with *visit::default_simple_visitor()
    }));
}

fn ty_of_method(ccx: @crate_ctxt,
                m: @ast::method,
                rp: ast::region_param) -> ty::method {
    {ident: m.ident,
     tps: astconv::ty_param_bounds(ccx, m.tps),
     fty: astconv::ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare,
                                 m.decl, none),
     purity: m.decl.purity,
     vis: m.vis}
}

fn ty_of_ty_method(self: @crate_ctxt,
                   m: ast::ty_method,
                   rp: ast::region_param) -> ty::method {
    {ident: m.ident,
     tps: astconv::ty_param_bounds(self, m.tps),
     fty: astconv::ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare,
                                 m.decl, none),
     // assume public, because this is only invoked on iface methods
     purity: m.decl.purity, vis: ast::public}
}
<commit_msg>Add classes and class fields to the tcache<commit_after>import astconv::{type_rscope, instantiate_iface_ref, ty_of_item,
                 empty_rscope, ty_of_native_item, ast_conv};

// Item collection - a pair of bootstrap passes:
//
// (1) Collect the IDs of all type items (typedefs) and store them in a table.
//
// (2) Translate the AST fragments that describe types to determine a type for
//     each item. When we encounter a named type, we consult the table built
//     in pass 1 to find its item, and recursively translate it.
//
// We then annotate the AST with the resulting types and return the annotated
// AST, along with a table mapping item IDs to their types.
fn get_enum_variant_types(ccx: @crate_ctxt,
                          enum_ty: ty::t,
                          variants: [ast::variant],
                          ty_params: [ast::ty_param],
                          rp: ast::region_param) {
    let tcx = ccx.tcx;

    // Create a set of parameter types shared among all the variants.
    for variants.each {|variant|
        // Nullary enum constructors get turned into constants; n-ary enum
        // constructors get turned into functions.
        let result_ty = if vec::len(variant.node.args) == 0u {
            enum_ty
        } else {
            let rs = type_rscope(rp);
            let args = variant.node.args.map { |va|
                let arg_ty = ccx.to_ty(rs, va.ty);
                {mode: ast::expl(ast::by_copy), ty: arg_ty}
            };
            ty::mk_fn(tcx, {proto: ast::proto_box,
                            inputs: args,
                            output: enum_ty,
                            ret_style: ast::return_val,
                            constraints: []})
        };
        let tpt = {bounds: astconv::ty_param_bounds(ccx, ty_params),
                   rp: rp,
                   ty: result_ty};
        tcx.tcache.insert(local_def(variant.node.id), tpt);
        write_ty_to_tcx(tcx, variant.node.id, result_ty);
    }
}

fn ensure_iface_methods(ccx: @crate_ctxt, id: ast::node_id) {
    fn store_methods<T>(ccx: @crate_ctxt, id: ast::node_id,
                        stuff: [T], f: fn@(T) -> ty::method) {
        ty::store_iface_methods(ccx.tcx, id, @vec::map(stuff, f));
    }

    let tcx = ccx.tcx;
    alt check tcx.items.get(id) {
      ast_map::node_item(@{node: ast::item_iface(_, rp, ms), _}, _) {
        store_methods::<ast::ty_method>(ccx, id, ms) {|m|
            ty_of_ty_method(ccx, m, rp)
        };
      }
      ast_map::node_item(@{node: ast::item_class(_,_,its,_,_,rp), _}, _) {
        let (_,ms) = split_class_items(its);
        // All methods need to be stored, since lookup_method
        // relies on the same method cache for self-calls
        store_methods::<@ast::method>(ccx, id, ms) {|m|
            ty_of_method(ccx, m, rp)
        };
      }
    }
}

fn check_methods_against_iface(ccx: @crate_ctxt,
                               tps: [ast::ty_param],
                               rp: ast::region_param,
                               selfty: ty::t,
                               a_ifacety: @ast::iface_ref,
                               ms: [@ast::method]) {

    let tcx = ccx.tcx;
    let i_bounds = astconv::ty_param_bounds(ccx, tps);
    let my_methods = convert_methods(ccx, ms, rp, i_bounds, selfty);
    let (did, tpt) = instantiate_iface_ref(ccx, a_ifacety, rp);
    if did.crate == ast::local_crate {
        ensure_iface_methods(ccx, did.node);
    }
    for vec::each(*ty::iface_methods(tcx, did)) {|if_m|
        alt vec::find(my_methods, {|m| if_m.ident == m.mty.ident}) {
          some({mty: m, id, span}) {
            if m.purity != if_m.purity {
                ccx.tcx.sess.span_err(
                    span, #fmt["method `%s`'s purity \
                                not match the iface method's \
                                purity", m.ident]);
            }
            let mt = compare_impl_method(
                ccx.tcx, span, m, vec::len(tps),
                if_m, tpt.substs, selfty);
            let old = tcx.tcache.get(local_def(id));
            if old.ty != mt {
                tcx.tcache.insert(
                    local_def(id),
                    {bounds: old.bounds,
                     rp: old.rp,
                     ty: mt});
                write_ty_to_tcx(tcx, id, mt);
            }
          }
          none {
            tcx.sess.span_err(
                a_ifacety.path.span,
                #fmt["missing method `%s`", if_m.ident]);
          }
        } // alt
    } // |if_m|
} // fn

fn convert_class_item(ccx: @crate_ctxt,
                      rp: ast::region_param,
                      bounds: @[ty::param_bounds],
                      v: ast_util::ivar) {
    /* we want to do something here, b/c within the
    scope of the class, it's ok to refer to fields &
    methods unqualified */
    /* they have these types *within the scope* of the
    class. outside the class, it's done with expr_field */
    let tt = ccx.to_ty(type_rscope(rp), v.ty);
    write_ty_to_tcx(ccx.tcx, v.id, tt);
    /* add the field to the tcache */
    ccx.tcx.tcache.insert(local_def(v.id), {bounds: bounds, rp: rp, ty: tt});
}

fn convert_methods(ccx: @crate_ctxt,
                   ms: [@ast::method],
                   rp: ast::region_param,
                   i_bounds: @[ty::param_bounds],
                   self_ty: ty::t)
    -> [{mty: ty::method, id: ast::node_id, span: span}] {

    let tcx = ccx.tcx;
    vec::map(ms) { |m|
        write_ty_to_tcx(tcx, m.self_id, self_ty);
        let bounds = astconv::ty_param_bounds(ccx, m.tps);
        let mty = ty_of_method(ccx, m, rp);
        let fty = ty::mk_fn(tcx, mty.fty);
        tcx.tcache.insert(
            local_def(m.id),
            // n.b. This code is kind of sketchy (concat'ing i_bounds
            // with bounds), but removing *i_bounds breaks other stuff
            {bounds: @(*i_bounds + *bounds), rp: rp, ty: fty});
        write_ty_to_tcx(tcx, m.id, fty);
        {mty: mty, id: m.id, span: m.span}
    }
}

fn convert(ccx: @crate_ctxt, it: @ast::item) {
    let tcx = ccx.tcx;
    alt it.node {
      // These don't define types.
      ast::item_mod(_) {}
      ast::item_native_mod(m) {
        if syntax::attr::native_abi(it.attrs) ==
            either::right(ast::native_abi_rust_intrinsic) {
            for m.items.each { |item| check_intrinsic_type(ccx, item); }
        }
      }
      ast::item_enum(variants, ty_params, rp) {
        let tpt = ty_of_item(ccx, it);
        write_ty_to_tcx(tcx, it.id, tpt.ty);
        get_enum_variant_types(ccx, tpt.ty, variants,
                               ty_params, rp);
      }
      ast::item_impl(tps, rp, ifce, selfty, ms) {
        let i_bounds = astconv::ty_param_bounds(ccx, tps);
        let selfty = ccx.to_ty(type_rscope(rp), selfty);
        write_ty_to_tcx(tcx, it.id, selfty);
        tcx.tcache.insert(local_def(it.id),
                          {bounds: i_bounds,
                           rp: rp,
                           ty: selfty});
        alt ifce {
          some(t) {
            check_methods_against_iface(
                ccx, tps, rp,
                selfty, t, ms);
          }
          _ {
            // Still have to do this to write method types
            // into the table
            convert_methods(
                ccx, ms, rp,
                i_bounds, selfty);
          }
        }
      }
      ast::item_res(decl, tps, _, dtor_id, ctor_id, rp) {
        let {bounds, substs} = mk_substs(ccx, tps, rp);
        let def_id = local_def(it.id);
        let t_arg = astconv::ty_of_arg(ccx, type_rscope(rp),
                                       decl.inputs[0], none);
        let t_res = ty::mk_res(tcx, def_id, t_arg.ty, substs);

        let t_ctor = ty::mk_fn(tcx, {
            proto: ast::proto_box,
            inputs: [{mode: ast::expl(ast::by_copy), ty: t_arg.ty}],
            output: t_res,
            ret_style: ast::return_val, constraints: []
        });
        let t_dtor = ty::mk_fn(tcx, {
            proto: ast::proto_box,
            inputs: [t_arg], output: ty::mk_nil(tcx),
            ret_style: ast::return_val, constraints: []
        });
        write_ty_to_tcx(tcx, it.id, t_res);
        write_ty_to_tcx(tcx, ctor_id, t_ctor);
        tcx.tcache.insert(local_def(ctor_id),
                          {bounds: bounds,
                           rp: rp,
                           ty: t_ctor});
        tcx.tcache.insert(def_id, {bounds: bounds,
                                   rp: rp,
                                   ty: t_res});
        write_ty_to_tcx(tcx, dtor_id, t_dtor);
      }
      ast::item_iface(*) {
        let tpt = ty_of_item(ccx, it);
        #debug["item_iface(it.id=%d, tpt.ty=%s)",
               it.id, ty_to_str(tcx, tpt.ty)];
        write_ty_to_tcx(tcx, it.id, tpt.ty);
        ensure_iface_methods(ccx, it.id);
      }
      ast::item_class(tps, ifaces, members, ctor, m_dtor, rp) {
        // Write the class type
        let tpt = ty_of_item(ccx, it);
        write_ty_to_tcx(tcx, it.id, tpt.ty);
        tcx.tcache.insert(local_def(it.id), {bounds: tpt.bounds,
              rp: rp, ty: tpt.ty});
        // Write the ctor type
        let t_ctor =
            ty::mk_fn(
                tcx,
                astconv::ty_of_fn_decl(ccx,
                                       empty_rscope,
                                       ast::proto_any,
                                       ctor.node.dec,
                                       none));
        write_ty_to_tcx(tcx, ctor.node.id, t_ctor);
        tcx.tcache.insert(local_def(ctor.node.id),
                          {bounds: tpt.bounds,
                           rp: ast::rp_none,
                           ty: t_ctor});
        option::iter(m_dtor) {|dtor|
            // Write the dtor type
            let t_dtor = ty::mk_fn(
                tcx,
                // not sure about empty_rscope
                // FIXME
                astconv::ty_of_fn_decl(ccx,
                                       empty_rscope,
                                       ast::proto_any,
                                       ast_util::dtor_dec(),
                                       none));
            write_ty_to_tcx(tcx, dtor.node.id, t_dtor);
            tcx.tcache.insert(local_def(dtor.node.id),
                              {bounds: tpt.bounds,
                               rp: ast::rp_none,
                               ty: t_dtor});
        };
        ensure_iface_methods(ccx, it.id);
        /* FIXME: check for proper public/privateness */
        // Write the type of each of the members
        let (fields, methods) = split_class_items(members);
        for fields.each {|f|
           convert_class_item(ccx, rp, tpt.bounds, f);
        }
        // The selfty is just the class type
        let {bounds:_, substs} = mk_substs(ccx, tps, rp);
        let selfty = ty::mk_class(tcx, local_def(it.id), substs);
        // Need to convert all methods so we can check internal
        // references to private methods

        // NDM to TJC---I think we ought to be using bounds here, not @[].
        // But doing so causes errors later on.
        convert_methods(ccx, methods, rp, @[], selfty);

        /*
        Finally, check that the class really implements the ifaces
        that it claims to implement.
        */
        for ifaces.each { |ifce|
            check_methods_against_iface(ccx, tps, rp, selfty,
                                        ifce, methods);
            let t = ty::node_id_to_type(tcx, ifce.id);

            // FIXME: This assumes classes only implement
            // non-parameterized ifaces. add a test case for
            // a class implementing a parameterized iface.
            // -- tjc (#1726)
            tcx.tcache.insert(local_def(ifce.id), no_params(t));
        }
      }
      _ {
        // This call populates the type cache with the converted type
        // of the item in passing. All we have to do here is to write
        // it into the node type table.
        let tpt = ty_of_item(ccx, it);
        write_ty_to_tcx(tcx, it.id, tpt.ty);
      }
    }
}
fn convert_native(ccx: @crate_ctxt, i: @ast::native_item) {
    // As above, this call populates the type table with the converted
    // type of the native item. We simply write it into the node type
    // table.
    let tpt = ty_of_native_item(ccx, i);
    alt i.node {
      ast::native_item_fn(_, _) {
        write_ty_to_tcx(ccx.tcx, i.id, tpt.ty);
      }
    }
}
fn collect_item_types(ccx: @crate_ctxt, crate: @ast::crate) {
    visit::visit_crate(*crate, (), visit::mk_simple_visitor(@{
        visit_item: bind convert(ccx, _),
        visit_native_item: bind convert_native(ccx, _)
        with *visit::default_simple_visitor()
    }));
}

fn ty_of_method(ccx: @crate_ctxt,
                m: @ast::method,
                rp: ast::region_param) -> ty::method {
    {ident: m.ident,
     tps: astconv::ty_param_bounds(ccx, m.tps),
     fty: astconv::ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare,
                                 m.decl, none),
     purity: m.decl.purity,
     vis: m.vis}
}

fn ty_of_ty_method(self: @crate_ctxt,
                   m: ast::ty_method,
                   rp: ast::region_param) -> ty::method {
    {ident: m.ident,
     tps: astconv::ty_param_bounds(self, m.tps),
     fty: astconv::ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare,
                                 m.decl, none),
     // assume public, because this is only invoked on iface methods
     purity: m.decl.purity, vis: ast::public}
}
<|endoftext|>


<commit_before>extern crate dirs;
extern crate libc;
extern crate yaml_rust;

extern crate common;

pub mod command;
pub mod project;
pub mod tmux;

use args::Args;
use command::Commands;
use common::project_paths::project_paths;
use common::{args, first_run};
use project::parser;
use tmux::config::Config;

pub fn exec(args: Args) -> Result<(), String> {
    let project_paths = project_paths(&args);

    // FIXME: Should have an error message
    let yaml = project::read(&args.arg_project, &project_paths).unwrap();
    let project_name = &yaml[0]["name"]
        .as_str()
        .unwrap_or(&args.arg_project)
        .to_string();

    let commands: Vec<Commands>;
    match project::session_exists(project_name) {
        Some(c) => {
            commands = vec![c];
        }
        None => {
            let config = Config::from_string(tmux::get_config());
            commands = parser::call(&yaml, project_name, args.flag_d, &config)
                .expect("Couldn't parse commands");
        }
    };

    if args.flag_debug {
        println!("{:?}", &commands);
    };

    for command in &commands {
        command
            .as_trait()
            .call(args.flag_debug)
            .map_err(|e| format!("Had a problem running commands for tmux {}", e))
            .unwrap();
    }

    Ok(())
}
<commit_msg>Use the ? operator<commit_after>extern crate dirs;
extern crate libc;
extern crate yaml_rust;

extern crate common;

pub mod command;
pub mod project;
pub mod tmux;

use args::Args;
use command::Commands;
use common::project_paths::project_paths;
use common::{args, first_run};
use project::parser;
use tmux::config::Config;

pub fn exec(args: Args) -> Result<(), String> {
    let project_paths = project_paths(&args);

    // FIXME: Should have an error message
    let yaml = project::read(&args.arg_project, &project_paths).unwrap();
    let project_name = &yaml[0]["name"]
        .as_str()
        .unwrap_or(&args.arg_project)
        .to_string();

    let commands: Vec<Commands>;
    match project::session_exists(project_name) {
        Some(c) => {
            commands = vec![c];
        }
        None => {
            let config = Config::from_string(tmux::get_config());
            commands = parser::call(&yaml, project_name, args.flag_d, &config)
                .expect("Couldn't parse commands");
        }
    };

    if args.flag_debug {
        println!("{:?}", &commands);
    };

    for command in &commands {
        command
            .as_trait()
            .call(args.flag_debug)
            .map_err(|e| format!("Had a problem running commands for tmux {}", e))?;
    }

    Ok(())
}
<|endoftext|>


<commit_before>extern crate rmp_serde;
extern crate time;

use std::cmp;
use std::collections::{HashMap, HashSet};
use std::ops::Add;

use commands::{Command, CommandExecutor};
use commands::pool::PoolCommand;
use errors::common::CommonError;
use errors::pool::PoolError;
use self::time::Duration;
use super::{
    MerkleTree,
    RemoteNode,
};
use super::rust_base58::{FromBase58, ToBase58};
use super::types::*;
use services::pool::PoolWorker;

pub const CATCHUP_ROUND_TIMEOUT: i64 = 50;

enum CatchupStepResult {
    Finished,
    Continue,
    FailedAtNode(usize),
}

enum CatchupProgress {
    ShouldBeStarted,
    NotNeeded,
    Finished(MerkleTree),
    InProgress,
}

pub struct CatchupHandler {
    pub f: usize,
    pub ledger_status_same: usize,
    pub merkle_tree: MerkleTree,
    pub target_mt_size: usize,
    pub target_mt_root: Vec<u8>,
    pub new_mt_vote: usize,
    pub nodes: Vec<RemoteNode>,
    pub initiate_cmd_id: i32,
    pub is_refresh: bool,
    pub pending_catchup: Option<CatchUpProcess>,
    pub timeout: time::Tm,
    pub pool_id: i32,
    pub nodes_votes: Vec<Option<(String, usize, Option<Vec<String>>)>>,
    pub pool_name: String,
}

impl Default for CatchupHandler {
    fn default() -> Self {
        CatchupHandler {
            f: 0,
            ledger_status_same: 0,
            merkle_tree: MerkleTree::from_vec(Vec::new()).unwrap(),
            nodes: Vec::new(),
            target_mt_size: 0,
            new_mt_vote: 0,
            target_mt_root: Vec::new(),
            pending_catchup: None,
            initiate_cmd_id: 0,
            is_refresh: false,
            pool_id: 0,
            nodes_votes: Vec::new(),
            timeout: time::now_utc(),
            pool_name: "".to_string(),
        }
    }
}

impl CatchupHandler {
    pub fn process_msg(&mut self, msg: Message, _raw_msg: &String, src_ind: usize) -> Result<Option<MerkleTree>, PoolError> {
        let catchup_status: CatchupProgress = match msg {
            Message::Pong => {
                //sending ledger status
                //TODO not send ledger status directly as response on ping, wait pongs from all nodes?
                let ls: LedgerStatus = LedgerStatus {
                    txnSeqNo: self.nodes.len(),
                    merkleRoot: self.merkle_tree.root_hash().as_slice().to_base58(),
                    ledgerId: 0,
                    ppSeqNo: None,
                    viewNo: None,
                };
                let resp_msg: Message = Message::LedgerStatus(ls);
                self.nodes[src_ind].send_msg(&resp_msg)?;
                CatchupProgress::InProgress
            }
            Message::LedgerStatus(ledger_status) => {
                self.nodes_votes[src_ind] = Some((ledger_status.merkleRoot, ledger_status.txnSeqNo, None));
                self.check_nodes_responses_on_status()?
            }
            Message::ConsistencyProof(cons_proof) => {
                self.nodes_votes[src_ind] = Some((cons_proof.newMerkleRoot, cons_proof.seqNoEnd, Some(cons_proof.hashes)));
                self.check_nodes_responses_on_status()?
            }
            Message::CatchupRep(catchup) => {
                self.process_catchup_rep(catchup, src_ind)?
            }
            _ => {
                warn!("unhandled msg {:?}", msg);
                CatchupProgress::InProgress
            }
        };

        match catchup_status {
            CatchupProgress::Finished(mt) => return Ok(Some(mt)),
            CatchupProgress::NotNeeded => return Ok(Some(self.merkle_tree.clone())),
            CatchupProgress::ShouldBeStarted => self.start_catchup()?,
            CatchupProgress::InProgress => { /* nothing to do */ }
        }
        Ok(None)
    }

    fn check_nodes_responses_on_status(&mut self) -> Result<CatchupProgress, PoolError> {
        if self.pending_catchup.is_some() {
            return Ok(CatchupProgress::InProgress);
        }

        let votes: HashMap<(String, usize, Option<Vec<String>>), usize> = self.nodes_votes.iter().cloned()
            .filter_map(|e| e)
            .fold(HashMap::new(), |mut acc, vote| {
                //WARN: It can be processed without excessive cloning two steps before, but then we will face double write borrowing.
                //WARN: This is the most readable variant. However, not the most effective.
                let cnt = acc.get(&vote).unwrap_or(&0) + 1;
                acc.insert(vote, cnt);
                acc
            });

        if let Some((most_popular_vote, votes_cnt)) = votes.iter().max_by_key(|entry| entry.1) {
            if *votes_cnt == self.nodes.len() - self.f {
                return self._try_to_catch_up(most_popular_vote).or_else(|err| {
                    if PoolWorker::drop_saved_txns(&self.pool_name).is_ok() {
                        self.merkle_tree = PoolWorker::restore_merkle_tree_from_pool_name(&self.pool_name)?;
                        self._try_to_catch_up(most_popular_vote)
                    } else {
                        Err(err)
                    }
                })
            }
        }
        Ok(CatchupProgress::InProgress)
    }

    fn _try_to_catch_up(&mut self, ledger_status: &(String, usize, Option<Vec<String>>)) -> Result<CatchupProgress, PoolError> {
        let &(ref target_mt_root, target_mt_size, ref hashes) = ledger_status;
        let cur_mt_size = self.merkle_tree.count();
        let cur_mt_hash = self.merkle_tree.root_hash().to_base58();
        if target_mt_size == cur_mt_size {
            if cur_mt_hash.eq(target_mt_root) {
                return Ok(CatchupProgress::NotNeeded);
            } else {
                return Err(PoolError::CommonError(CommonError::InvalidState(
                    "Ledger merkle tree doesn't acceptable for current tree.".to_string())));
            }
        } else if target_mt_size > cur_mt_size {
            self.target_mt_size = target_mt_size;
            self.target_mt_root = target_mt_root.from_base58().map_err(|_|
                CommonError::InvalidStructure(
                    "Can't parse target MerkleTree hash from nodes responses".to_string()))?;
            match hashes {
                &None => {return Err(PoolError::from(CommonError::InvalidState("Empty consistency proof but catch up needed".to_string())));},
                &Some(ref hashes) => {
                    match CatchupHandler::check_cons_proofs(&self.merkle_tree, hashes, &self.target_mt_root, self.target_mt_size) {
                        Ok(_) => (),
                        Err(err) => {
                            return Err(PoolError::from(err));
                        }
                    }
                }
            };
            return Ok(CatchupProgress::ShouldBeStarted);
        } else {
            return Err(PoolError::CommonError(CommonError::InvalidState(
                "Local merkle tree greater than mt from ledger".to_string())));
        }
    }

    pub fn reset_nodes_votes(&mut self) {
        self.nodes_votes.clear();
        self.nodes_votes.resize(self.nodes.len(), None);
    }

    pub fn start_catchup(&mut self) -> Result<(), PoolError> {
        trace!("start_catchup");
        if self.pending_catchup.is_some() {
            return Err(PoolError::CommonError(
                CommonError::InvalidState(
                    "CatchUp already started for the pool".to_string())));
        }

        let active_node_cnt = self.nodes.iter().filter(|node| !node.is_blacklisted).count();

        if active_node_cnt == 0 {
            // TODO FIXME
            return Err(PoolError::Terminate);
        }

        let txns_cnt_in_cur_mt = self.merkle_tree.count();
        let cnt_to_catchup = self.target_mt_size - txns_cnt_in_cur_mt;
        if cnt_to_catchup <= 0 {
            return Err(PoolError::CommonError(CommonError::InvalidState(
                "Nothing to CatchUp, but started".to_string())));
        }

        self.pending_catchup = Some(CatchUpProcess {
            merkle_tree: self.merkle_tree.clone(),
            pending_reps: Vec::new(),
            resp_not_received_node_idx: HashSet::new(),
        });
        self.timeout = time::now_utc().add(Duration::seconds(CATCHUP_ROUND_TIMEOUT));

        let portion = (cnt_to_catchup + active_node_cnt - 1) / active_node_cnt; //TODO check standard round up div
        let mut catchup_req = CatchupReq {
            ledgerId: 0,
            seqNoStart: txns_cnt_in_cur_mt + 1,
            seqNoEnd: txns_cnt_in_cur_mt + 1 + portion - 1,
            catchupTill: self.target_mt_size,
        };
        for idx in 0..self.nodes.len() {
            let node = &self.nodes[idx];
            //TODO do not perform duplicate requests, update resp_not_received_node_idx
            if node.is_blacklisted {
                continue;
            }
            self.pending_catchup.as_mut().map(|pc| {
                pc.resp_not_received_node_idx.insert(idx);
            });
            node.send_msg(&Message::CatchupReq(catchup_req.clone()))?;
            catchup_req.seqNoStart += portion;
            catchup_req.seqNoEnd = cmp::min(catchup_req.seqNoStart + portion - 1,
                                            catchup_req.catchupTill);

            if catchup_req.seqNoStart > catchup_req.seqNoEnd {
                // We don't have more portions to ask
                break;
            }
        }
        Ok(())
    }

    fn process_catchup_rep(&mut self, catchup: CatchupRep, node_idx: usize) -> Result<CatchupProgress, PoolError> {
        trace!("append {:?}", catchup);
        let catchup_finished = self.catchup_step(catchup, node_idx)?;
        match catchup_finished {
            CatchupStepResult::Finished => return Ok(CatchupProgress::Finished(self.finish_catchup()?)),
            CatchupStepResult::Continue => { /* nothing to do */ }
            CatchupStepResult::FailedAtNode(failed_node_idx) => {
                warn!("Fail to continue catch-up by response from node with idx {}. Node will be blacklisted and catchup will be restarted", failed_node_idx);
                self.nodes[failed_node_idx].is_blacklisted = true;
                self.pending_catchup = None;
                // TODO may be send ledger status again and re-obtain target MerkleTree params
                self.start_catchup()?
            }
        }
        Ok(CatchupProgress::InProgress)
    }

    fn catchup_step(&mut self, catchup: CatchupRep, node_idx: usize) -> Result<CatchupStepResult, PoolError> {
        let process = self.pending_catchup.as_mut()
            .ok_or(CommonError::InvalidState("Process non-existing CatchUp".to_string()))?;
        process.pending_reps.push((catchup, node_idx));
        process.resp_not_received_node_idx.remove(&node_idx);

        while !process.pending_reps.is_empty() {
            let index = process.pending_reps.get_min_index()?;
            {
                let &mut (ref mut first_resp, node_idx) = process.pending_reps.get_mut(index)
                    .ok_or(CommonError::InvalidStructure(format!("Element not Found")))?;
                if first_resp.min_tx()? - 1 != process.merkle_tree.count() { break; }

                let mut temp_mt = process.merkle_tree.clone();
                let mut vec_to_dump: Vec<Vec<u8>> = vec![];
                while !first_resp.txns.is_empty() {
                    let key = first_resp.min_tx()?.to_string();
                    let new_gen_tx = first_resp.txns.remove(&key).unwrap();
                    if let Ok(new_get_txn_bytes) = rmp_serde::to_vec_named(&new_gen_tx) {
                        temp_mt.append(new_get_txn_bytes.clone())?;
                        vec_to_dump.push(new_get_txn_bytes);
                    } else {
                        return Ok(CatchupStepResult::FailedAtNode(node_idx));
                    }
                }

                if CatchupHandler::check_cons_proofs(&temp_mt, &first_resp.consProof, &self.target_mt_root, self.target_mt_size)
                    .map_err(map_err_err!()).is_err() {
                    return Ok(CatchupStepResult::FailedAtNode(node_idx));
                }

                PoolWorker::dump_new_txns(&self.pool_name, &vec_to_dump)?;

                process.merkle_tree = temp_mt;
            }
            process.pending_reps.remove(index);
        }
        trace!("updated mt hash {}, tree {:?}", process.merkle_tree.root_hash().as_slice().to_base58(), process.merkle_tree);
        if &process.merkle_tree.count() == &self.target_mt_size {
            if process.merkle_tree.root_hash().ne(&self.target_mt_root) {
                return Err(PoolError::CommonError(CommonError::InvalidState(
                    "CatchUp failed: all transactions added, proofs checked, but root hash differ with target".to_string())));
            }
            return Ok(CatchupStepResult::Finished);
        } else {
            return Ok(CatchupStepResult::Continue);
        }
    }

    fn check_cons_proofs(mt: &MerkleTree, cons_proofs: &Vec<String>, target_mt_root: &Vec<u8>, target_mt_size: usize) -> Result<(), CommonError> {
        let mut bytes_proofs: Vec<Vec<u8>> = Vec::new();
        for cons_proof in cons_proofs {
            let cons_proof: &String = cons_proof;
            bytes_proofs.push(cons_proof.from_base58().map_err(|err|
                CommonError::InvalidStructure(
                    format!("Can't decode node consistency proof: {}", err)))?)
        }
        if !mt.consistency_proof(target_mt_root, target_mt_size, &bytes_proofs)? {
            return Err(CommonError::InvalidStructure("Consistency proof verification failed".to_string()));
        }
        Ok(())
    }

    fn finish_catchup(&mut self) -> Result<MerkleTree, PoolError> {
        Ok(self.pending_catchup.take().
            ok_or(CommonError::InvalidState("Try to finish non-existing CatchUp".to_string()))?
            .merkle_tree)
    }

    pub fn flush_requests(&mut self, status: Result<(), PoolError>) -> Result<(), PoolError> {
        if self.initiate_cmd_id == -1 {
            return Ok(());
        }
        let cmd = if self.is_refresh {
            PoolCommand::RefreshAck(self.initiate_cmd_id, status)
        } else {
            PoolCommand::OpenAck(self.initiate_cmd_id, self.pool_id, status)
        };
        self.initiate_cmd_id = -1;
        CommandExecutor::instance()
            .send(Command::Pool(cmd))
            .map_err(|err|
                PoolError::CommonError(
                    CommonError::InvalidState(format!("Can't send ACK cmd: {:?}", err))))
    }

    pub fn get_upcoming_timeout(&self) -> Option<time::Tm> {
        Some(self.timeout)
    }

    pub fn process_timeout(&mut self) -> Result<(), PoolError> {
        let pc = if let Some(pc) = self.pending_catchup.take() { pc } else {
            return Err(PoolError::Timeout);
        };
        warn!("Fail to continue catch-up response(s) not received from nodes with idx {:?}. Node will be blacklisted and catchup will be restarted", pc.resp_not_received_node_idx);
        pc.resp_not_received_node_idx.iter()
            .for_each(|idx| self.nodes[*idx].is_blacklisted = true);
        // TODO may be send ledger status again and re-obtain target MerkleTree params
        self.start_catchup()
    }
}
<commit_msg>Fix problem with txn count and failed node<commit_after>extern crate rmp_serde;
extern crate time;

use std::cmp;
use std::collections::{HashMap, HashSet};
use std::ops::Add;

use commands::{Command, CommandExecutor};
use commands::pool::PoolCommand;
use errors::common::CommonError;
use errors::pool::PoolError;
use self::time::Duration;
use super::{
    MerkleTree,
    RemoteNode,
};
use super::rust_base58::{FromBase58, ToBase58};
use super::types::*;
use services::pool::PoolWorker;

pub const CATCHUP_ROUND_TIMEOUT: i64 = 50;

enum CatchupStepResult {
    Finished,
    Continue,
    FailedAtNode(usize),
}

enum CatchupProgress {
    ShouldBeStarted,
    NotNeeded,
    Finished(MerkleTree),
    InProgress,
}

pub struct CatchupHandler {
    pub f: usize,
    pub ledger_status_same: usize,
    pub merkle_tree: MerkleTree,
    pub target_mt_size: usize,
    pub target_mt_root: Vec<u8>,
    pub new_mt_vote: usize,
    pub nodes: Vec<RemoteNode>,
    pub initiate_cmd_id: i32,
    pub is_refresh: bool,
    pub pending_catchup: Option<CatchUpProcess>,
    pub timeout: time::Tm,
    pub pool_id: i32,
    pub nodes_votes: Vec<Option<(String, usize, Option<Vec<String>>)>>,
    pub pool_name: String,
}

impl Default for CatchupHandler {
    fn default() -> Self {
        CatchupHandler {
            f: 0,
            ledger_status_same: 0,
            merkle_tree: MerkleTree::from_vec(Vec::new()).unwrap(),
            nodes: Vec::new(),
            target_mt_size: 0,
            new_mt_vote: 0,
            target_mt_root: Vec::new(),
            pending_catchup: None,
            initiate_cmd_id: 0,
            is_refresh: false,
            pool_id: 0,
            nodes_votes: Vec::new(),
            timeout: time::now_utc(),
            pool_name: "".to_string(),
        }
    }
}

impl CatchupHandler {
    pub fn process_msg(&mut self, msg: Message, _raw_msg: &String, src_ind: usize) -> Result<Option<MerkleTree>, PoolError> {
        let catchup_status: CatchupProgress = match msg {
            Message::Pong => {
                //sending ledger status
                //TODO not send ledger status directly as response on ping, wait pongs from all nodes?
                let ls: LedgerStatus = LedgerStatus {
                    txnSeqNo: self.merkle_tree.count,
                    merkleRoot: self.merkle_tree.root_hash().as_slice().to_base58(),
                    ledgerId: 0,
                    ppSeqNo: None,
                    viewNo: None,
                };
                let resp_msg: Message = Message::LedgerStatus(ls);
                self.nodes[src_ind].send_msg(&resp_msg)?;
                CatchupProgress::InProgress
            }
            Message::LedgerStatus(ledger_status) => {
                self.nodes_votes[src_ind] = Some((ledger_status.merkleRoot, ledger_status.txnSeqNo, None));
                self.check_nodes_responses_on_status()?
            }
            Message::ConsistencyProof(cons_proof) => {
                self.nodes_votes[src_ind] = Some((cons_proof.newMerkleRoot, cons_proof.seqNoEnd, Some(cons_proof.hashes)));
                self.check_nodes_responses_on_status()?
            }
            Message::CatchupRep(catchup) => {
                self.process_catchup_rep(catchup, src_ind)?
            }
            _ => {
                warn!("unhandled msg {:?}", msg);
                CatchupProgress::InProgress
            }
        };

        match catchup_status {
            CatchupProgress::Finished(mt) => return Ok(Some(mt)),
            CatchupProgress::NotNeeded => return Ok(Some(self.merkle_tree.clone())),
            CatchupProgress::ShouldBeStarted => self.start_catchup()?,
            CatchupProgress::InProgress => { /* nothing to do */ }
        }
        Ok(None)
    }

    fn check_nodes_responses_on_status(&mut self) -> Result<CatchupProgress, PoolError> {
        if self.pending_catchup.is_some() {
            return Ok(CatchupProgress::InProgress);
        }

        let votes: HashMap<(String, usize, Option<Vec<String>>), usize> = self.nodes_votes.iter().cloned()
            .filter_map(|e| e)
            .fold(HashMap::new(), |mut acc, vote| {
                //WARN: It can be processed without excessive cloning two steps before, but then we will face double write borrowing.
                //WARN: This is the most readable variant. However, not the most effective.
                let cnt = acc.get(&vote).unwrap_or(&0) + 1;
                acc.insert(vote, cnt);
                acc
            });

        if let Some((most_popular_vote, votes_cnt)) = votes.iter().max_by_key(|entry| entry.1) {
            if *votes_cnt == self.nodes.len() - self.f {
                return self._try_to_catch_up(most_popular_vote).or_else(|err| {
                    if PoolWorker::drop_saved_txns(&self.pool_name).is_ok() {
                        self.merkle_tree = PoolWorker::restore_merkle_tree_from_pool_name(&self.pool_name)?;
                        self._try_to_catch_up(most_popular_vote)
                    } else {
                        Err(err)
                    }
                })
            }
        }
        Ok(CatchupProgress::InProgress)
    }

    fn _try_to_catch_up(&mut self, ledger_status: &(String, usize, Option<Vec<String>>)) -> Result<CatchupProgress, PoolError> {
        let &(ref target_mt_root, target_mt_size, ref hashes) = ledger_status;
        let cur_mt_size = self.merkle_tree.count();
        let cur_mt_hash = self.merkle_tree.root_hash().to_base58();
        if target_mt_size == cur_mt_size {
            if cur_mt_hash.eq(target_mt_root) {
                return Ok(CatchupProgress::NotNeeded);
            } else {
                return Err(PoolError::CommonError(CommonError::InvalidState(
                    "Ledger merkle tree doesn't acceptable for current tree.".to_string())));
            }
        } else if target_mt_size > cur_mt_size {
            self.target_mt_size = target_mt_size;
            self.target_mt_root = target_mt_root.from_base58().map_err(|_|
                CommonError::InvalidStructure(
                    "Can't parse target MerkleTree hash from nodes responses".to_string()))?;
            match hashes {
                &None => {return Err(PoolError::from(CommonError::InvalidState("Empty consistency proof but catch up needed".to_string())));},
                &Some(ref hashes) => {
                    match CatchupHandler::check_cons_proofs(&self.merkle_tree, hashes, &self.target_mt_root, self.target_mt_size) {
                        Ok(_) => (),
                        Err(err) => {
                            return Err(PoolError::from(err));
                        }
                    }
                }
            };
            return Ok(CatchupProgress::ShouldBeStarted);
        } else {
            return Err(PoolError::CommonError(CommonError::InvalidState(
                "Local merkle tree greater than mt from ledger".to_string())));
        }
    }

    pub fn reset_nodes_votes(&mut self) {
        self.nodes_votes.clear();
        self.nodes_votes.resize(self.nodes.len(), None);
    }

    pub fn start_catchup(&mut self) -> Result<(), PoolError> {
        trace!("start_catchup");
        if self.pending_catchup.is_some() {
            return Err(PoolError::CommonError(
                CommonError::InvalidState(
                    "CatchUp already started for the pool".to_string())));
        }

        let active_node_cnt = self.nodes.iter().filter(|node| !node.is_blacklisted).count();

        if active_node_cnt == 0 {
            // TODO FIXME
            return Err(PoolError::Terminate);
        }

        let txns_cnt_in_cur_mt = self.merkle_tree.count();
        let cnt_to_catchup = self.target_mt_size - txns_cnt_in_cur_mt;
        if cnt_to_catchup <= 0 {
            return Err(PoolError::CommonError(CommonError::InvalidState(
                "Nothing to CatchUp, but started".to_string())));
        }

        self.pending_catchup = Some(CatchUpProcess {
            merkle_tree: self.merkle_tree.clone(),
            pending_reps: Vec::new(),
            resp_not_received_node_idx: HashSet::new(),
        });
        self.timeout = time::now_utc().add(Duration::seconds(CATCHUP_ROUND_TIMEOUT));

        let portion = (cnt_to_catchup + active_node_cnt - 1) / active_node_cnt; //TODO check standard round up div
        let mut catchup_req = CatchupReq {
            ledgerId: 0,
            seqNoStart: txns_cnt_in_cur_mt + 1,
            seqNoEnd: txns_cnt_in_cur_mt + 1 + portion - 1,
            catchupTill: self.target_mt_size,
        };
        for idx in 0..self.nodes.len() {
            let node = &self.nodes[idx];
            //TODO do not perform duplicate requests, update resp_not_received_node_idx
            if node.is_blacklisted {
                continue;
            }
            self.pending_catchup.as_mut().map(|pc| {
                pc.resp_not_received_node_idx.insert(idx);
            });
            node.send_msg(&Message::CatchupReq(catchup_req.clone()))?;
            catchup_req.seqNoStart += portion;
            catchup_req.seqNoEnd = cmp::min(catchup_req.seqNoStart + portion - 1,
                                            catchup_req.catchupTill);

            if catchup_req.seqNoStart > catchup_req.seqNoEnd {
                // We don't have more portions to ask
                break;
            }
        }
        Ok(())
    }

    fn process_catchup_rep(&mut self, catchup: CatchupRep, node_idx: usize) -> Result<CatchupProgress, PoolError> {
        trace!("append {:?}", catchup);
        let catchup_finished = self.catchup_step(catchup, node_idx)?;
        match catchup_finished {
            CatchupStepResult::Finished => return Ok(CatchupProgress::Finished(self.finish_catchup()?)),
            CatchupStepResult::Continue => { /* nothing to do */ }
            CatchupStepResult::FailedAtNode(failed_node_idx) => {
                warn!("Fail to continue catch-up by response from node with idx {}. Node will be blacklisted and catchup will be restarted", failed_node_idx);
                self.nodes[failed_node_idx].is_blacklisted = true;
                self.pending_catchup = None;
                // TODO may be send ledger status again and re-obtain target MerkleTree params
                self.start_catchup()?
            }
        }
        Ok(CatchupProgress::InProgress)
    }

    fn catchup_step(&mut self, catchup: CatchupRep, node_idx: usize) -> Result<CatchupStepResult, PoolError> {
        let process = self.pending_catchup.as_mut()
            .ok_or(CommonError::InvalidState("Process non-existing CatchUp".to_string()))?;
        process.pending_reps.push((catchup, node_idx));
        process.resp_not_received_node_idx.remove(&node_idx);

        while !process.pending_reps.is_empty() {
            let index = process.pending_reps.get_min_index()?;
            {
                let &mut (ref mut first_resp, node_idx) = process.pending_reps.get_mut(index)
                    .ok_or(CommonError::InvalidStructure(format!("Element not Found")))?;
                if first_resp.min_tx()? - 1 != process.merkle_tree.count() { break; }

                let mut temp_mt = process.merkle_tree.clone();
                let mut vec_to_dump: Vec<Vec<u8>> = vec![];
                while !first_resp.txns.is_empty() {
                    let key = first_resp.min_tx()?.to_string();
                    let new_gen_tx = first_resp.txns.remove(&key).unwrap();
                    if let Ok(new_get_txn_bytes) = rmp_serde::to_vec_named(&new_gen_tx) {
                        temp_mt.append(new_get_txn_bytes.clone())?;
                        vec_to_dump.push(new_get_txn_bytes);
                    } else {
                        return Ok(CatchupStepResult::FailedAtNode(node_idx));
                    }
                }

                if CatchupHandler::check_cons_proofs(&temp_mt, &first_resp.consProof, &self.target_mt_root, self.target_mt_size)
                    .map_err(map_err_err!()).is_err() {
                    return Ok(CatchupStepResult::FailedAtNode(node_idx));
                }

                PoolWorker::dump_new_txns(&self.pool_name, &vec_to_dump)?;
                self.merkle_tree = PoolWorker::restore_merkle_tree_from_pool_name(&self.pool_name)?;

                process.merkle_tree = temp_mt;
            }
            process.pending_reps.remove(index);
        }
        trace!("updated mt hash {}, tree {:?}", process.merkle_tree.root_hash().as_slice().to_base58(), process.merkle_tree);
        if &process.merkle_tree.count() == &self.target_mt_size {
            if process.merkle_tree.root_hash().ne(&self.target_mt_root) {
                return Err(PoolError::CommonError(CommonError::InvalidState(
                    "CatchUp failed: all transactions added, proofs checked, but root hash differ with target".to_string())));
            }
            return Ok(CatchupStepResult::Finished);
        } else {
            return Ok(CatchupStepResult::Continue);
        }
    }

    fn check_cons_proofs(mt: &MerkleTree, cons_proofs: &Vec<String>, target_mt_root: &Vec<u8>, target_mt_size: usize) -> Result<(), CommonError> {
        let mut bytes_proofs: Vec<Vec<u8>> = Vec::new();
        for cons_proof in cons_proofs {
            let cons_proof: &String = cons_proof;
            bytes_proofs.push(cons_proof.from_base58().map_err(|err|
                CommonError::InvalidStructure(
                    format!("Can't decode node consistency proof: {}", err)))?)
        }
        if !mt.consistency_proof(target_mt_root, target_mt_size, &bytes_proofs)? {
            return Err(CommonError::InvalidStructure("Consistency proof verification failed".to_string()));
        }
        Ok(())
    }

    fn finish_catchup(&mut self) -> Result<MerkleTree, PoolError> {
        Ok(self.pending_catchup.take().
            ok_or(CommonError::InvalidState("Try to finish non-existing CatchUp".to_string()))?
            .merkle_tree)
    }

    pub fn flush_requests(&mut self, status: Result<(), PoolError>) -> Result<(), PoolError> {
        if self.initiate_cmd_id == -1 {
            return Ok(());
        }
        let cmd = if self.is_refresh {
            PoolCommand::RefreshAck(self.initiate_cmd_id, status)
        } else {
            PoolCommand::OpenAck(self.initiate_cmd_id, self.pool_id, status)
        };
        self.initiate_cmd_id = -1;
        CommandExecutor::instance()
            .send(Command::Pool(cmd))
            .map_err(|err|
                PoolError::CommonError(
                    CommonError::InvalidState(format!("Can't send ACK cmd: {:?}", err))))
    }

    pub fn get_upcoming_timeout(&self) -> Option<time::Tm> {
        Some(self.timeout)
    }

    pub fn process_timeout(&mut self) -> Result<(), PoolError> {
        let pc = if let Some(pc) = self.pending_catchup.take() { pc } else {
            return Err(PoolError::Timeout);
        };
        warn!("Fail to continue catch-up response(s) not received from nodes with idx {:?}. Node will be blacklisted and catchup will be restarted", pc.resp_not_received_node_idx);
        pc.resp_not_received_node_idx.iter()
            .for_each(|idx| self.nodes[*idx].is_blacklisted = true);
        // TODO may be send ledger status again and re-obtain target MerkleTree params
        self.start_catchup()
    }
}
<|endoftext|>


<commit_before>// An integer division that doesn't `panic!`
fn checked_division(dividend: i32, divisor: i32) -> Option<i32> {
    if divisor == 0 {
        // Failure is represented as the `None` variant
        None
    } else {
        // Result is wrapped in a `Some` variant
        Some(dividend / divisor)
    }
}

// This function handles a division that may not succeed
fn try_division(dividend: i32, divisor: i32) {
    // `Option` values can be pattern matched, just like other enums
    match checked_division(dividend, divisor) {
        None => println!("{} / {} failed!", dividend, divisor),
        Some(quotient) => {
            println!("{} / {} = {}", dividend, divisor, quotient)
        },
    }
}

fn main() {
    try_division(4, 2);
    try_division(1, 0);

    // Binding `None` to a variable needs to be type annotated
    let none: Option<i32> = None;
    let _equivalent_none = None::<i32>;

    let optional_float = Some(0f32);

    // The `unwrap` method will extract the value wrapped in a `Some` variant,
    // or will `panic!` if called on a `None` variant
    println!("{:?} unwraps to {:?}", optional_float, optional_float.unwrap());
    println!("{:?} unwraps to {:?}", none, none.unwrap());
}
<commit_msg>Better? wording for unwrap<commit_after>// An integer division that doesn't `panic!`
fn checked_division(dividend: i32, divisor: i32) -> Option<i32> {
    if divisor == 0 {
        // Failure is represented as the `None` variant
        None
    } else {
        // Result is wrapped in a `Some` variant
        Some(dividend / divisor)
    }
}

// This function handles a division that may not succeed
fn try_division(dividend: i32, divisor: i32) {
    // `Option` values can be pattern matched, just like other enums
    match checked_division(dividend, divisor) {
        None => println!("{} / {} failed!", dividend, divisor),
        Some(quotient) => {
            println!("{} / {} = {}", dividend, divisor, quotient)
        },
    }
}

fn main() {
    try_division(4, 2);
    try_division(1, 0);

    // Binding `None` to a variable needs to be type annotated
    let none: Option<i32> = None;
    let _equivalent_none = None::<i32>;

    let optional_float = Some(0f32);

    // Unwrapping a `Some` variant will extract the value wrapped.
    println!("{:?} unwraps to {:?}", optional_float, optional_float.unwrap());

    // Unwrapping a `None` variant will `panic!`
    println!("{:?} unwraps to {:?}", none, none.unwrap());
}
<|endoftext|>


<commit_before>// A unit struct without resources
#[derive(Debug, Clone, Copy)]
struct Nil;

// A tuple struct with resources that implements the `Clone` trait
#[derive(Clone, Debug)]
struct Pair(Box<i32>, Box<i32>);

fn main() {
    // Instantiate `Nil`
    let nil = Nil;
    // Copy `Nil`, there are no resources to move
    let copied_nil = nil;

    // Both `Nil`s can be used independently
    println!("original: {:?}", nil);
    println!("copy: {:?}", copied_nil);

    // Instantiate a `Pair`
    let pair = Pair(Box::new(1), Box::new(2));
    println!("original: {:?}", pair);

    // Copy `pair` into `moved_pair`, moves resources
    let moved_pair = pair;
    println!("copy: {:?}", moved_pair);

    // Error! `pair` has lost it resources
    //println!("original: {:?}", pair);
    // TODO ^ Try uncommenting this line

    // "Clone" `moved_pair` into `cloned_pair` (resources included)
    let cloned_pair = moved_pair.clone();

    // `Drop` the original pair
    drop(moved_pair);

    // Error! `moved_pair` has been `drop`ed
    //println!("copy: {}", moved_pair);
    // TODO ^ Try uncommenting this line

    // Clone can still be used
    println!("clone: {:?}", cloned_pair);
}
<commit_msg>Update clone.rs<commit_after>// A unit struct without resources
#[derive(Debug, Clone, Copy)]
struct Nil;

// A tuple struct with resources that implements the `Clone` trait
#[derive(Clone, Debug)]
struct Pair(Box<i32>, Box<i32>);

fn main() {
    // Instantiate `Nil`
    let nil = Nil;
    // Copy `Nil`, there are no resources to move
    let copied_nil = nil;

    // Both `Nil`s can be used independently
    println!("original: {:?}", nil);
    println!("copy: {:?}", copied_nil);

    // Instantiate a `Pair`
    let pair = Pair(Box::new(1), Box::new(2));
    println!("original: {:?}", pair);

    // Copy `pair` into `moved_pair`, moves resources
    let moved_pair = pair;
    println!("copy: {:?}", moved_pair);

    // Error! `pair` has lost it resources
    //println!("original: {:?}", pair);
    // TODO ^ Try uncommenting this line

    // "Clone" `moved_pair` into `cloned_pair` (resources included)
    let cloned_pair = moved_pair.clone();

    // `Drop` the original pair
    drop(moved_pair);

    // Error! `moved_pair` has been `drop`ed
    //println!("copy: {:?}", moved_pair);
    // TODO ^ Try uncommenting this line

    // Clone can still be used
    println!("clone: {:?}", cloned_pair);
}
<|endoftext|>