<commit_before>use env::{Environment, Point};
use liveness::Liveness;
use infer::{InferenceContext, RegionVariable};
use nll_repr::repr::{self, RegionName, Variance};
use std::collections::HashMap;
use std::error::Error;
use region::Region;

pub fn region_check(env: &Environment) -> Result<(), Box<Error>> {
    let ck = &mut RegionCheck {
        env,
        infer: InferenceContext::new(),
        region_map: HashMap::new()
    };
    ck.check()
}

pub struct RegionCheck<'env> {
    env: &'env Environment<'env>,
    infer: InferenceContext,
    region_map: HashMap<repr::RegionName, RegionVariable>,
}

impl<'env> RegionCheck<'env> {
    pub fn env(&self) -> &'env Environment<'env> {
        self.env
    }

    pub fn region(&self, name: RegionName) -> &Region {
        let var = match self.region_map.get(&name) {
            Some(&var) => var,
            None => panic!("no region variable ever created with name `{:?}`", name),
        };
        self.infer.region(var)
    }

    fn check(&mut self) -> Result<(), Box<Error>> {
        let liveness = &Liveness::new(self.env);
        self.populate_inference(liveness);
        self.check_assertions(liveness)
    }

    fn check_assertions(&mut self, liveness: &Liveness) -> Result<(), Box<Error>> {
        let mut errors = 0;

        for assertion in self.env.graph.assertions() {
            match *assertion {
                repr::Assertion::Eq(region_name, ref region_literal) => {
                    let region_var = self.region_variable(region_name);
                    let region_value = self.to_region(region_literal);
                    if *self.infer.region(region_var) != region_value {
                        errors += 1;
                        println!("error: region variable `{:?}` has wrong value", region_name);
                        println!("  expected: {:?}", region_value);
                        println!("  found   : {:?}", self.infer.region(region_var));
                    }
                }

                repr::Assertion::In(region_name, ref point) => {
                    let region_var = self.region_variable(region_name);
                    let point = self.to_point(point);
                    if !self.infer.region(region_var).contains(point) {
                        errors += 1;
                        println!("error: region variable `{:?}` does not contain `{:?}`",
                                 region_name, point);
                        println!("  found   : {:?}", self.infer.region(region_var));
                    }
                }

                repr::Assertion::NotIn(region_name, ref point) => {
                    let region_var = self.region_variable(region_name);
                    let point = self.to_point(point);
                    if self.infer.region(region_var).contains(point) {
                        errors += 1;
                        println!("error: region variable `{:?}` contains `{:?}`",
                                 region_name, point);
                        println!("  found   : {:?}", self.infer.region(region_var));
                    }
                }

                repr::Assertion::Live(var, block_name) => {
                    let block = self.env.graph.block(block_name);
                    if !liveness.var_live_on_entry(var, block) {
                        errors += 1;
                        println!("error: variable `{:?}` not live on entry to `{:?}`",
                                 var, block_name);
                    }
                }

                repr::Assertion::NotLive(var, block_name) => {
                    let block = self.env.graph.block(block_name);
                    if liveness.var_live_on_entry(var, block) {
                        errors += 1;
                        println!("error: variable `{:?}` live on entry to `{:?}`",
                                 var, block_name);
                    }
                }
            }
        }

        if errors > 0 {
            try!(Err(format!("{} errors found", errors)));
        }

        Ok(())
    }

    fn populate_inference(&mut self, liveness: &Liveness) {
        liveness.walk(self.env, |point, action, live_on_entry| {
            // To start, find every variable `x` that is live. All regions
            // in the type of `x` must include `point`.
            for region_name in liveness.live_regions(live_on_entry) {
                let rv = self.region_variable(region_name);
                self.infer.add_live_point(rv, point);
            }

            let action = if let Some(action) = action {
                action
            } else {
                return;
            };

            // Next, walk the actions and establish any additional constraints
            // that may arise from subtyping.
            let successor_point = Point { block: point.block, action: point.action + 1 };
            match *action {
                // `p = &'x` -- first, `'x` must include this point @ P,
                // and second `&'x <: typeof(p) @ succ(P)`
                repr::Action::Borrow(ref dest_path, region_name, borrow_kind, ref source_path) => {
                    let dest_ty = self.env.path_ty(dest_path);
                    let source_ty = self.env.path_ty(source_path);
                    let ref_ty = Box::new(repr::Ty::Ref(repr::Region::Free(region_name),
                                                        borrow_kind,
                                                        source_ty));
                    self.relate_tys(successor_point, repr::Variance::Contra, &dest_ty, &ref_ty);
                }

                // a = b
                repr::Action::Assign(ref a, ref b) => {
                    let a_ty = self.env.path_ty(a);
                    let b_ty = self.env.path_ty(b);

                    // `b` must be a subtype of `a` to be assignable:
                    self.relate_tys(successor_point, repr::Variance::Co, &b_ty, &a_ty);
                }

                // 'X: 'Y
                repr::Action::Constraint(ref c) => {
                    match **c {
                        repr::Constraint::Outlives(c) => {
                            let sup_v = self.region_variable(c.sup);
                            let sub_v = self.region_variable(c.sub);
                            self.infer.add_outlives(sup_v, sub_v, point);
                        }
                        _ => {
                            panic!("unimplemented rich constraint: {:?}", c);
                        }
                    }
                }

                repr::Action::Init(..) | // a = use(...)
                repr::Action::Use(..) | // use(a)
                repr::Action::Drop(..) => { // drop(a)
                    // the basic liveness rules suffice here
                }

                repr::Action::Noop => {
                }
            }
        });

        self.infer.solve(self.env);
    }

    fn region_variable(&mut self, n: repr::RegionName) -> RegionVariable {
        let infer = &mut self.infer;
        let r = *self.region_map.entry(n).or_insert_with(|| infer.add_var());
        log!("{:?} => {:?}", n, r);
        r
    }

    fn to_point(&self, point: &repr::Point) -> Point {
        let block = self.env.graph.block(point.block);
        Point { block: block, action: point.action }
    }

    fn to_region(&self, user_region: &repr::RegionLiteral) -> Region {
        let mut region = Region::new();
        for p in &user_region.points {
            region.add_point(self.to_point(p));
        }
        region
    }

    fn relate_tys(&mut self,
                  successor_point: Point,
                  variance: repr::Variance,
                  a: &repr::Ty,
                  b: &repr::Ty) {
        log!("relate_tys({:?} {:?} {:?} @ {:?})", a, variance, b, successor_point);
        match (a, b) {
            (&repr::Ty::Ref(r_a, bk_a, ref t_a), &repr::Ty::Ref(r_b, bk_b, ref t_b)) => {
                assert_eq!(bk_a, bk_b, "cannot relate {:?} and {:?}", a, b);
                self.relate_regions(successor_point,
                                    variance.invert(),
                                    r_a.assert_free(),
                                    r_b.assert_free());
                let referent_variance = variance.xform(bk_a.variance());
                self.relate_tys(successor_point, referent_variance, t_a, t_b);
            }
            (&repr::Ty::Unit, &repr::Ty::Unit) => {
            }
            (&repr::Ty::Struct(s_a, ref ps_a), &repr::Ty::Struct(s_b, ref ps_b)) => {
                if s_a != s_b {
                    panic!("cannot compare `{:?}` and `{:?}`", s_a, s_b);
                }
                let s_decl = self.env.struct_map[&s_a];
                if ps_a.len() != s_decl.parameters.len() {
                    panic!("wrong number of parameters for `{:?}`", a);
                }
                if ps_b.len() != s_decl.parameters.len() {
                    panic!("wrong number of parameters for `{:?}`", b);
                }
                for (sp, (p_a, p_b)) in s_decl.parameters.iter().zip(ps_a.iter().zip(ps_b)) {
                    let v = variance.xform(sp.variance);
                    self.relate_parameters(successor_point, v, p_a, p_b);
                }
            }
            _ => panic!("cannot relate types `{:?}` and `{:?}`", a, b)
        }
    }

    fn relate_regions(&mut self,
                      successor_point: Point,
                      variance: repr::Variance,
                      a: repr::RegionName,
                      b: repr::RegionName) {
        log!("relate_regions({:?} {:?} {:?} @ {:?})", a, variance, b, successor_point);
        let r_a = self.region_variable(a);
        let r_b = self.region_variable(b);
        match variance {
            Variance::Co =>
                // "a Co b" == "a <= b"
                self.infer.add_outlives(r_b, r_a, successor_point),
            Variance::Contra =>
                // "a Contra b" == "a >= b"
                self.infer.add_outlives(r_a, r_b, successor_point),
            Variance::In => {
                self.infer.add_outlives(r_a, r_b, successor_point);
                self.infer.add_outlives(r_b, r_a, successor_point);
            }
        }
    }

    fn relate_parameters(&mut self,
                         successor_point: Point,
                         variance: repr::Variance,
                         a: &repr::TyParameter,
                         b: &repr::TyParameter) {
        match (a, b) {
            (&repr::TyParameter::Ty(ref t_a), &repr::TyParameter::Ty(ref t_b)) =>
                self.relate_tys(successor_point, variance, t_a, t_b),
            (&repr::TyParameter::Region(r_a), &repr::TyParameter::Region(r_b)) =>
                self.relate_regions(successor_point, variance, r_a.assert_free(), r_b.assert_free()),
            _ => panic!("cannot relate parameters `{:?}` and `{:?}`", a, b)
        }
    }
}
<commit_msg>use `&self` when checking assertions<commit_after>use env::{Environment, Point};
use liveness::Liveness;
use infer::{InferenceContext, RegionVariable};
use nll_repr::repr::{self, RegionName, Variance};
use std::collections::HashMap;
use std::error::Error;
use region::Region;

pub fn region_check(env: &Environment) -> Result<(), Box<Error>> {
    let ck = &mut RegionCheck {
        env,
        infer: InferenceContext::new(),
        region_map: HashMap::new()
    };
    ck.check()
}

pub struct RegionCheck<'env> {
    env: &'env Environment<'env>,
    infer: InferenceContext,
    region_map: HashMap<repr::RegionName, RegionVariable>,
}

impl<'env> RegionCheck<'env> {
    pub fn env(&self) -> &'env Environment<'env> {
        self.env
    }

    pub fn region(&self, name: RegionName) -> &Region {
        let var = match self.region_map.get(&name) {
            Some(&var) => var,
            None => panic!("no region variable ever created with name `{:?}`", name),
        };
        self.infer.region(var)
    }

    fn check(&mut self) -> Result<(), Box<Error>> {
        let liveness = &Liveness::new(self.env);
        self.populate_inference(liveness);
        self.check_assertions(liveness)
    }

    fn check_assertions(&self, liveness: &Liveness) -> Result<(), Box<Error>> {
        let mut errors = 0;

        for assertion in self.env.graph.assertions() {
            match *assertion {
                repr::Assertion::Eq(region_name, ref region_literal) => {
                    let region_var = self.region_map[&region_name];
                    let region_value = self.to_region(region_literal);
                    if *self.infer.region(region_var) != region_value {
                        errors += 1;
                        println!("error: region variable `{:?}` has wrong value", region_name);
                        println!("  expected: {:?}", region_value);
                        println!("  found   : {:?}", self.infer.region(region_var));
                    }
                }

                repr::Assertion::In(region_name, ref point) => {
                    let region_var = self.region_map[&region_name];
                    let point = self.to_point(point);
                    if !self.infer.region(region_var).contains(point) {
                        errors += 1;
                        println!("error: region variable `{:?}` does not contain `{:?}`",
                                 region_name, point);
                        println!("  found   : {:?}", self.infer.region(region_var));
                    }
                }

                repr::Assertion::NotIn(region_name, ref point) => {
                    let region_var = self.region_map[&region_name];
                    let point = self.to_point(point);
                    if self.infer.region(region_var).contains(point) {
                        errors += 1;
                        println!("error: region variable `{:?}` contains `{:?}`",
                                 region_name, point);
                        println!("  found   : {:?}", self.infer.region(region_var));
                    }
                }

                repr::Assertion::Live(var, block_name) => {
                    let block = self.env.graph.block(block_name);
                    if !liveness.var_live_on_entry(var, block) {
                        errors += 1;
                        println!("error: variable `{:?}` not live on entry to `{:?}`",
                                 var, block_name);
                    }
                }

                repr::Assertion::NotLive(var, block_name) => {
                    let block = self.env.graph.block(block_name);
                    if liveness.var_live_on_entry(var, block) {
                        errors += 1;
                        println!("error: variable `{:?}` live on entry to `{:?}`",
                                 var, block_name);
                    }
                }
            }
        }

        if errors > 0 {
            try!(Err(format!("{} errors found", errors)));
        }

        Ok(())
    }

    fn populate_inference(&mut self, liveness: &Liveness) {
        liveness.walk(self.env, |point, action, live_on_entry| {
            // To start, find every variable `x` that is live. All regions
            // in the type of `x` must include `point`.
            for region_name in liveness.live_regions(live_on_entry) {
                let rv = self.region_variable(region_name);
                self.infer.add_live_point(rv, point);
            }

            let action = if let Some(action) = action {
                action
            } else {
                return;
            };

            // Next, walk the actions and establish any additional constraints
            // that may arise from subtyping.
            let successor_point = Point { block: point.block, action: point.action + 1 };
            match *action {
                // `p = &'x` -- first, `'x` must include this point @ P,
                // and second `&'x <: typeof(p) @ succ(P)`
                repr::Action::Borrow(ref dest_path, region_name, borrow_kind, ref source_path) => {
                    let dest_ty = self.env.path_ty(dest_path);
                    let source_ty = self.env.path_ty(source_path);
                    let ref_ty = Box::new(repr::Ty::Ref(repr::Region::Free(region_name),
                                                        borrow_kind,
                                                        source_ty));
                    self.relate_tys(successor_point, repr::Variance::Contra, &dest_ty, &ref_ty);
                }

                // a = b
                repr::Action::Assign(ref a, ref b) => {
                    let a_ty = self.env.path_ty(a);
                    let b_ty = self.env.path_ty(b);

                    // `b` must be a subtype of `a` to be assignable:
                    self.relate_tys(successor_point, repr::Variance::Co, &b_ty, &a_ty);
                }

                // 'X: 'Y
                repr::Action::Constraint(ref c) => {
                    match **c {
                        repr::Constraint::Outlives(c) => {
                            let sup_v = self.region_variable(c.sup);
                            let sub_v = self.region_variable(c.sub);
                            self.infer.add_outlives(sup_v, sub_v, point);
                        }
                        _ => {
                            panic!("unimplemented rich constraint: {:?}", c);
                        }
                    }
                }

                repr::Action::Init(..) | // a = use(...)
                repr::Action::Use(..) | // use(a)
                repr::Action::Drop(..) => { // drop(a)
                    // the basic liveness rules suffice here
                }

                repr::Action::Noop => {
                }
            }
        });

        self.infer.solve(self.env);
    }

    fn region_variable(&mut self, n: repr::RegionName) -> RegionVariable {
        let infer = &mut self.infer;
        let r = *self.region_map.entry(n).or_insert_with(|| infer.add_var());
        log!("{:?} => {:?}", n, r);
        r
    }

    fn to_point(&self, point: &repr::Point) -> Point {
        let block = self.env.graph.block(point.block);
        Point { block: block, action: point.action }
    }

    fn to_region(&self, user_region: &repr::RegionLiteral) -> Region {
        let mut region = Region::new();
        for p in &user_region.points {
            region.add_point(self.to_point(p));
        }
        region
    }

    fn relate_tys(&mut self,
                  successor_point: Point,
                  variance: repr::Variance,
                  a: &repr::Ty,
                  b: &repr::Ty) {
        log!("relate_tys({:?} {:?} {:?} @ {:?})", a, variance, b, successor_point);
        match (a, b) {
            (&repr::Ty::Ref(r_a, bk_a, ref t_a), &repr::Ty::Ref(r_b, bk_b, ref t_b)) => {
                assert_eq!(bk_a, bk_b, "cannot relate {:?} and {:?}", a, b);
                self.relate_regions(successor_point,
                                    variance.invert(),
                                    r_a.assert_free(),
                                    r_b.assert_free());
                let referent_variance = variance.xform(bk_a.variance());
                self.relate_tys(successor_point, referent_variance, t_a, t_b);
            }
            (&repr::Ty::Unit, &repr::Ty::Unit) => {
            }
            (&repr::Ty::Struct(s_a, ref ps_a), &repr::Ty::Struct(s_b, ref ps_b)) => {
                if s_a != s_b {
                    panic!("cannot compare `{:?}` and `{:?}`", s_a, s_b);
                }
                let s_decl = self.env.struct_map[&s_a];
                if ps_a.len() != s_decl.parameters.len() {
                    panic!("wrong number of parameters for `{:?}`", a);
                }
                if ps_b.len() != s_decl.parameters.len() {
                    panic!("wrong number of parameters for `{:?}`", b);
                }
                for (sp, (p_a, p_b)) in s_decl.parameters.iter().zip(ps_a.iter().zip(ps_b)) {
                    let v = variance.xform(sp.variance);
                    self.relate_parameters(successor_point, v, p_a, p_b);
                }
            }
            _ => panic!("cannot relate types `{:?}` and `{:?}`", a, b)
        }
    }

    fn relate_regions(&mut self,
                      successor_point: Point,
                      variance: repr::Variance,
                      a: repr::RegionName,
                      b: repr::RegionName) {
        log!("relate_regions({:?} {:?} {:?} @ {:?})", a, variance, b, successor_point);
        let r_a = self.region_variable(a);
        let r_b = self.region_variable(b);
        match variance {
            Variance::Co =>
                // "a Co b" == "a <= b"
                self.infer.add_outlives(r_b, r_a, successor_point),
            Variance::Contra =>
                // "a Contra b" == "a >= b"
                self.infer.add_outlives(r_a, r_b, successor_point),
            Variance::In => {
                self.infer.add_outlives(r_a, r_b, successor_point);
                self.infer.add_outlives(r_b, r_a, successor_point);
            }
        }
    }

    fn relate_parameters(&mut self,
                         successor_point: Point,
                         variance: repr::Variance,
                         a: &repr::TyParameter,
                         b: &repr::TyParameter) {
        match (a, b) {
            (&repr::TyParameter::Ty(ref t_a), &repr::TyParameter::Ty(ref t_b)) =>
                self.relate_tys(successor_point, variance, t_a, t_b),
            (&repr::TyParameter::Region(r_a), &repr::TyParameter::Region(r_b)) =>
                self.relate_regions(successor_point, variance, r_a.assert_free(), r_b.assert_free()),
            _ => panic!("cannot relate parameters `{:?}` and `{:?}`", a, b)
        }
    }
}
<|endoftext|>


<commit_before>#![cfg(feature = "extra-traits")]

extern crate syn;
extern crate proc_macro2;

use syn::TokenTree;
use proc_macro2::{TokenKind, OpKind, Delimiter, TokenStream};
use proc_macro2::Delimiter::*;

fn op(c: char) -> TokenTree {
    TokenTree(proc_macro2::TokenTree {
        span: Default::default(),
        kind: TokenKind::Op(c, OpKind::Alone),
    })
}

fn delimited(delim: Delimiter, tokens: Vec<TokenTree>) -> TokenTree {
    TokenTree(proc_macro2::TokenTree {
        span: Default::default(),
        kind: TokenKind::Sequence(delim, tokens.into_iter().map(|t| t.0).collect()),
    })
}

fn word(sym: &str) -> TokenTree {
    TokenTree(proc_macro2::TokenTree {
        span: Default::default(),
        kind: TokenKind::Word(sym.into()),
    })
}

#[test]
fn test_struct() {
    let raw = "
        #[derive(Debug, Clone)]
        pub struct Item {
            pub ident: Ident,
            pub attrs: Vec<Attribute>,
        }
    ";

    let expected = vec![
        op('#'),
        delimited(Bracket, vec![
           word("derive"),
           delimited(Parenthesis, vec![
               word("Debug"),
               op(','),
               word("Clone"),
           ]),
        ]),
        word("pub"),
        word("struct"),
        word("Item"),
        delimited(Brace, vec![
           word("pub"),
           word("ident"),
           op(':'),
           word("Ident"),
           op(','),

           word("pub"),
           word("attrs"),
           op(':'),
           word("Vec"),
           op('<'),
           word("Attribute"),
           op('>'),
           op(','),
        ],
    )];

    let result = raw.parse::<TokenStream>().unwrap()
                    .into_iter()
                    .map(TokenTree)
                    .collect::<Vec<_>>();
    if result != expected {
        panic!("{:#?}\n!=\n{:#?}", result, expected);
    }
}
<commit_msg>Joint token in test<commit_after>#![cfg(feature = "extra-traits")]

extern crate syn;
extern crate proc_macro2;

use syn::TokenTree;
use proc_macro2::{TokenKind, OpKind, Delimiter, TokenStream};
use proc_macro2::Delimiter::*;

fn alone(c: char) -> TokenTree {
    TokenTree(proc_macro2::TokenTree {
        span: Default::default(),
        kind: TokenKind::Op(c, OpKind::Alone),
    })
}

fn joint(c: char) -> TokenTree {
    TokenTree(proc_macro2::TokenTree {
        span: Default::default(),
        kind: TokenKind::Op(c, OpKind::Joint),
    })
}

fn delimited(delim: Delimiter, tokens: Vec<TokenTree>) -> TokenTree {
    TokenTree(proc_macro2::TokenTree {
        span: Default::default(),
        kind: TokenKind::Sequence(delim, tokens.into_iter().map(|t| t.0).collect()),
    })
}

fn word(sym: &str) -> TokenTree {
    TokenTree(proc_macro2::TokenTree {
        span: Default::default(),
        kind: TokenKind::Word(sym.into()),
    })
}

#[test]
fn test_struct() {
    let raw = "
        #[derive(Debug, Clone)]
        pub struct Item {
            pub ident: Ident,
            pub attrs: Vec<Attribute>,
        }
    ";

    let expected = vec![
        alone('#'),
        delimited(Bracket, vec![
           word("derive"),
           delimited(Parenthesis, vec![
               word("Debug"),
               alone(','),
               word("Clone"),
           ]),
        ]),
        word("pub"),
        word("struct"),
        word("Item"),
        delimited(Brace, vec![
           word("pub"),
           word("ident"),
           alone(':'),
           word("Ident"),
           alone(','),

           word("pub"),
           word("attrs"),
           alone(':'),
           word("Vec"),
           alone('<'),
           word("Attribute"),
           joint('>'),
           alone(','),
        ],
    )];

    let result = raw.parse::<TokenStream>().unwrap()
                    .into_iter()
                    .map(TokenTree)
                    .collect::<Vec<_>>();
    if result != expected {
        panic!("{:#?}\n!=\n{:#?}", result, expected);
    }
}
<|endoftext|>


<commit_before>#![allow(unused_variables,unused_must_use)]
#[macro_use] extern crate sozu_lib as sozu;
extern crate sozu_command_lib as sozu_command;
extern crate openssl;
extern crate time;
extern crate libc;
extern crate mio;
extern crate mio_uds;
extern crate hex;

use std::net::{UdpSocket,ToSocketAddrs};
use std::thread;
use std::env;
use std::io::stdout;
use sozu::network;
use sozu::logging::{Logger,LoggerBackend};
use sozu_command::messages;
use sozu_command::channel::Channel;
use sozu::network::metrics::{METRICS,ProxyMetrics};
use openssl::ssl;

fn main() {
  if env::var("RUST_LOG").is_ok() {
   Logger::init("EXAMPLE".to_string(), &env::var("RUST_LOG").expect("could not get the RUST_LOG env var"), LoggerBackend::Stdout(stdout()));
  } else {
   Logger::init("EXAMPLE".to_string(), "info", LoggerBackend::Stdout(stdout()));
  }

  info!("MAIN\tstarting up");

  metrics_set_up!("127.0.0.1", 8125);
  gauge!("sozu.TEST", 42);

  let config = messages::HttpProxyConfiguration {
    front: "127.0.0.1:8080".parse().expect("could not parse address"),
    max_connections: 500,
    buffer_size: 16384,
    ..Default::default()
  };

  let (mut command, channel) = Channel::generate(1000, 10000).expect("should create a channel");
  let jg = thread::spawn(move || {
    network::http::start(config, channel);
  });

  let http_front = messages::HttpFront { app_id: String::from("app_1"), hostname: String::from("lolcatho.st"), path_begin: String::from("/") };
  let http_instance = messages::Instance { app_id: String::from("app_1"),  instance_id: String::from("app_1-0"), ip_address: String::from("127.0.0.1"), port: 1026 };
  command.write_message(&messages::OrderMessage { id: String::from("ID_ABCD"), order: messages::Order::AddHttpFront(http_front) });
  command.write_message(&messages::OrderMessage { id: String::from("ID_EFGH"), order: messages::Order::AddInstance(http_instance) });
  info!("MAIN\tHTTP -> {:?}", command.read_message());
  info!("MAIN\tHTTP -> {:?}", command.read_message());

  let config = messages::HttpsProxyConfiguration {
    front: "127.0.0.1:8443".parse().expect("could not parse address"),
    max_connections: 500,
    buffer_size: 16384,
    options: (ssl::SSL_OP_CIPHER_SERVER_PREFERENCE | ssl::SSL_OP_NO_COMPRESSION |
               ssl::SSL_OP_NO_TICKET | ssl::SSL_OP_NO_SSLV2 |
               ssl::SSL_OP_NO_SSLV3 | ssl::SSL_OP_NO_TLSV1).bits(),
    cipher_list: String::from("ECDHE-ECDSA-CHACHA20-POLY1305:\
    ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:\
    ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:\
    ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:\
    DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:\
    ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:\
    ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:\
    ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:\
    ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:\
    DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:\
    ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:\
    AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:\
    AES256-SHA:DES-CBC3-SHA:!DSS"),

    ..Default::default()
  };

  let (mut command2, channel2) = Channel::generate(1000, 10000).expect("should create a channel");
  let jg2 = thread::spawn(move || {
    network::tls::start(config, channel2);
  });

  let cert1 = include_str!("../assets/certificate.pem");
  let key1  = include_str!("../assets/key.pem");

  let certificate_and_key = messages::CertificateAndKey {
    certificate:       String::from(cert1),
    key:               String::from(key1),
    certificate_chain: vec!()
  };
  command2.write_message(&messages::OrderMessage {
    id:    String::from("ID_IJKL1"),
    order: messages::Order::AddCertificate(certificate_and_key)
  });

  let tls_front = messages::HttpsFront {
    app_id:      String::from("app_1"),
    hostname:    String::from("lolcatho.st"),
    path_begin:  String::from("/"),
    fingerprint: messages::CertFingerprint(hex::FromHex::from_hex("AB2618B674E15243FD02A5618C66509E4840BA60E7D64CEBEC84CDBFECEEE0C5").unwrap()),
  };
  command2.write_message(&messages::OrderMessage { id: String::from("ID_IJKL2"), order: messages::Order::AddHttpsFront(tls_front) });
  let tls_instance = messages::Instance { app_id: String::from("app_1"),  instance_id: String::from("app_1-0"), ip_address: String::from("127.0.0.1"), port: 1026 };
  command2.write_message(&messages::OrderMessage { id: String::from("ID_MNOP"), order: messages::Order::AddInstance(tls_instance) });

  let cert2 = include_str!("../assets/cert_test.pem");
  let key2  = include_str!("../assets/key_test.pem");

  let certificate_and_key2 = messages::CertificateAndKey {
    certificate: String::from(cert2),
    key: String::from(key2),
    certificate_chain: vec!()
  };
  command2.write_message(&messages::OrderMessage {
    id:    String::from("ID_QRST1"),
    order: messages::Order::AddCertificate(certificate_and_key2)
  });
  let tls_front2 = messages::HttpsFront {
    app_id:      String::from("app_2"),
    hostname:    String::from("test.local"),
    path_begin:  String::from("/"),
    fingerprint: messages::CertFingerprint(hex::FromHex::from_hex("7E8EBF9AD0645AB755A2E51EB3734B91D4ACACEF1F28AD9D96D9385487FAE6E6").unwrap()),
  };
  command2.write_message(&messages::OrderMessage { id: String::from("ID_QRST2"), order: messages::Order::AddHttpsFront(tls_front2) });
  let tls_instance2 = messages::Instance { app_id: String::from("app_2"), instance_id: String::from("app_2-0"), ip_address: String::from("127.0.0.1"), port: 1026 };
  command2.write_message(&messages::OrderMessage { id: String::from("ID_UVWX"), order: messages::Order::AddInstance(tls_instance2) });

  info!("MAIN\tTLS -> {:?}", command2.read_message());
  info!("MAIN\tTLS -> {:?}", command2.read_message());
  info!("MAIN\tTLS -> {:?}", command2.read_message());
  info!("MAIN\tTLS -> {:?}", command2.read_message());

  let _ = jg.join();
  info!("MAIN\tgood bye");
}

<commit_msg>make the examples slightly more readable<commit_after>#![allow(unused_variables,unused_must_use)]
#[macro_use] extern crate sozu_lib as sozu;
extern crate sozu_command_lib as sozu_command;
extern crate openssl;
extern crate time;
extern crate libc;
extern crate mio;
extern crate mio_uds;
extern crate hex;

use std::net::{UdpSocket,ToSocketAddrs};
use std::thread;
use std::env;
use std::io::stdout;
use sozu::network;
use sozu::logging::{Logger,LoggerBackend};
use sozu_command::messages;
use sozu_command::channel::Channel;
use sozu::network::metrics::{METRICS,ProxyMetrics};
use openssl::ssl;

fn main() {
  if env::var("RUST_LOG").is_ok() {
   Logger::init("EXAMPLE".to_string(), &env::var("RUST_LOG").expect("could not get the RUST_LOG env var"), LoggerBackend::Stdout(stdout()));
  } else {
   Logger::init("EXAMPLE".to_string(), "info", LoggerBackend::Stdout(stdout()));
  }

  info!("MAIN\tstarting up");

  metrics_set_up!("127.0.0.1", 8125);
  gauge!("sozu.TEST", 42);

  let config = messages::HttpProxyConfiguration {
    front: "127.0.0.1:8080".parse().expect("could not parse address"),
    max_connections: 500,
    buffer_size: 16384,
    ..Default::default()
  };

  let (mut command, channel) = Channel::generate(1000, 10000).expect("should create a channel");
  let jg = thread::spawn(move || {
    network::http::start(config, channel);
  });

  let http_front = messages::HttpFront {
    app_id:     String::from("app_1"),
    hostname:   String::from("lolcatho.st"),
    path_begin: String::from("/")
  };

  let http_instance = messages::Instance {
    app_id:      String::from("app_1"),
    instance_id: String::from("app_1-0"),
    ip_address:  String::from("127.0.0.1"),
    port:        1026
  };

  command.write_message(&messages::OrderMessage {
    id:    String::from("ID_ABCD"),
    order: messages::Order::AddHttpFront(http_front)
  });

  command.write_message(&messages::OrderMessage {
    id:    String::from("ID_EFGH"),
    order: messages::Order::AddInstance(http_instance)
  });

  info!("MAIN\tHTTP -> {:?}", command.read_message());
  info!("MAIN\tHTTP -> {:?}", command.read_message());

  let config = messages::HttpsProxyConfiguration {
    front: "127.0.0.1:8443".parse().expect("could not parse address"),
    max_connections: 500,
    buffer_size: 16384,
    options: (ssl::SSL_OP_CIPHER_SERVER_PREFERENCE | ssl::SSL_OP_NO_COMPRESSION |
               ssl::SSL_OP_NO_TICKET | ssl::SSL_OP_NO_SSLV2 |
               ssl::SSL_OP_NO_SSLV3 | ssl::SSL_OP_NO_TLSV1).bits(),
    cipher_list: String::from("ECDHE-ECDSA-CHACHA20-POLY1305:\
    ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:\
    ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:\
    ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:\
    DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:\
    ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:\
    ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:\
    ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:\
    ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:\
    DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:\
    ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:\
    AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:\
    AES256-SHA:DES-CBC3-SHA:!DSS"),

    ..Default::default()
  };

  let (mut command2, channel2) = Channel::generate(1000, 10000).expect("should create a channel");
  let jg2 = thread::spawn(move || {
    network::tls::start(config, channel2);
  });

  let cert1 = include_str!("../assets/certificate.pem");
  let key1  = include_str!("../assets/key.pem");

  let certificate_and_key = messages::CertificateAndKey {
    certificate:       String::from(cert1),
    key:               String::from(key1),
    certificate_chain: vec!()
  };
  command2.write_message(&messages::OrderMessage {
    id:    String::from("ID_IJKL1"),
    order: messages::Order::AddCertificate(certificate_and_key)
  });

  let tls_front = messages::HttpsFront {
    app_id:      String::from("app_1"),
    hostname:    String::from("lolcatho.st"),
    path_begin:  String::from("/"),
    fingerprint: messages::CertFingerprint(hex::FromHex::from_hex("AB2618B674E15243FD02A5618C66509E4840BA60E7D64CEBEC84CDBFECEEE0C5").unwrap()),
  };

  command2.write_message(&messages::OrderMessage {
    id:    String::from("ID_IJKL2"),
    order: messages::Order::AddHttpsFront(tls_front)
  });
  let tls_instance = messages::Instance {
    app_id:      String::from("app_1"),
    instance_id: String::from("app_1-0"),
    ip_address:  String::from("127.0.0.1"),
    port:        1026
  };

  command2.write_message(&messages::OrderMessage {
    id:    String::from("ID_MNOP"),
    order: messages::Order::AddInstance(tls_instance)
  });

  let cert2 = include_str!("../assets/cert_test.pem");
  let key2  = include_str!("../assets/key_test.pem");

  let certificate_and_key2 = messages::CertificateAndKey {
    certificate: String::from(cert2),
    key: String::from(key2),
    certificate_chain: vec!()
  };

  command2.write_message(&messages::OrderMessage {
    id:    String::from("ID_QRST1"),
    order: messages::Order::AddCertificate(certificate_and_key2)
  });

  let tls_front2 = messages::HttpsFront {
    app_id:      String::from("app_2"),
    hostname:    String::from("test.local"),
    path_begin:  String::from("/"),
    fingerprint: messages::CertFingerprint(hex::FromHex::from_hex("7E8EBF9AD0645AB755A2E51EB3734B91D4ACACEF1F28AD9D96D9385487FAE6E6").unwrap()),
  };

  command2.write_message(&messages::OrderMessage {
    id:    String::from("ID_QRST2"),
    order: messages::Order::AddHttpsFront(tls_front2)
  });

  let tls_instance2 = messages::Instance {
    app_id:      String::from("app_2"),
    instance_id: String::from("app_2-0"),
    ip_address:  String::from("127.0.0.1"),
    port:        1026
  };

  command2.write_message(&messages::OrderMessage {
    id:    String::from("ID_UVWX"),
    order: messages::Order::AddInstance(tls_instance2)
  });

  info!("MAIN\tTLS -> {:?}", command2.read_message());
  info!("MAIN\tTLS -> {:?}", command2.read_message());
  info!("MAIN\tTLS -> {:?}", command2.read_message());
  info!("MAIN\tTLS -> {:?}", command2.read_message());

  let _ = jg.join();
  info!("MAIN\tgood bye");
}

<|endoftext|>


<commit_before>extern crate pkg_config;

use std::env;
use std::fs::{self, File};
use std::io::ErrorKind;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::process::Command;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(n) => n,
        Err(e) => fail(&format!("\n{} failed with {}\n", stringify!($e), e)),
    })
}

fn main() {
    register_dep("SSH2");
    register_dep("OPENSSL");

    if env::var("LIBSSH2_SYS_USE_PKG_CONFIG").is_ok() {
        if pkg_config::find_library("libgit2").is_ok() {
            return
        }
    }

    let mut cflags = env::var("CFLAGS").unwrap_or(String::new());
    let target = env::var("TARGET").unwrap();
    let mingw = target.contains("windows-gnu");
    cflags.push_str(" -ffunction-sections -fdata-sections");

    if target.contains("i686") {
        cflags.push_str(" -m32");
    } else if target.contains("x86_64") {
        cflags.push_str(" -m64");
    }
    if !target.contains("i686") {
        cflags.push_str(" -fPIC");
    }

    // libgit2 uses pkg-config to discover libssh2, but this doesn't work on
    // windows as libssh2 doesn't come with a libssh2.pc file in that install.
    // As a result we just manually turn on SSH support in libgit2 (a little
    // jankily) here...
    if mingw {
        cflags.push_str(" -DGIT_SSH");
        let libssh2_root = env::var("DEP_SSH2_ROOT").unwrap();
        cflags.push_str(&format!(" -I{}/include", libssh2_root));
    }

    let src = PathBuf::from(&env::var("CARGO_MANIFEST_DIR").unwrap());
    let dst = PathBuf::from(&env::var("OUT_DIR").unwrap());
    let _ = fs::create_dir(&dst.join("build"));

    let mut cmd = Command::new("cmake");
    cmd.arg(&src.join("libgit2"))
       .current_dir(&dst.join("build"));
    if mingw {
        cmd.arg("-G").arg("Unix Makefiles");
    }
    let profile = match &env::var("PROFILE").unwrap()[..] {
        "bench" | "release" => "Release",
        _ => "Debug",
    };
    run(cmd.arg("-DBUILD_SHARED_LIBS=OFF")
           .arg("-DBUILD_CLAR=OFF")
           .arg(&format!("-DCMAKE_BUILD_TYPE={}", profile))
           .arg(&format!("-DCMAKE_INSTALL_PREFIX={}", dst.display()))
           .arg(&format!("-DCMAKE_C_FLAGS={}", cflags)), "cmake");

    let flags = dst.join("build/CMakeFiles/git2.dir/flags.make");
    let mut contents = String::new();
    t!(t!(File::open(flags)).read_to_string(&mut contents));
    if !contents.contains("-DGIT_SSH") {
        fail("libgit2 failed to find libssh2, and SSH support is required");
    }

    run(Command::new("cmake")
                .arg("--build").arg(".")
                .arg("--target").arg("install")
                .current_dir(&dst.join("build")), "cmake");

    println!("cargo:root={}", dst.display());
    if mingw || target.contains("windows") {
        println!("cargo:rustc-flags=-l winhttp -l rpcrt4 -l ole32 \
                                    -l static=git2");
        println!("cargo:rustc-link-search=native={}/lib", dst.display());
        return
    }

    if env::var("HOST") == env::var("TARGET") {
        prepend("PKG_CONFIG_PATH", dst.join("lib/pkgconfig"));
        if pkg_config::Config::new().statik(true).find("libgit2").is_ok() {
            return
        }
    }

    println!("cargo:rustc-flags=-l static=git2");
    println!("cargo:rustc-flags=-L {}", dst.join("lib").display());
    if target.contains("apple") {
        println!("cargo:rustc-flags=-l iconv");
    }
}

fn run(cmd: &mut Command, program: &str) {
    println!("running: {:?}", cmd);
    let status = match cmd.status() {
        Ok(status) => status,
        Err(ref e) if e.kind() == ErrorKind::NotFound => {
            fail(&format!("failed to execute command: {}\nis `{}` not installed?",
                          e, program));
        }
        Err(e) => fail(&format!("failed to execute command: {}", e)),
    };
    if !status.success() {
        fail(&format!("command did not execute successfully, got: {}", status));
    }
}

fn register_dep(dep: &str) {
    match env::var(&format!("DEP_{}_ROOT", dep)) {
        Ok(s) => {
            prepend("CMAKE_PREFIX_PATH", PathBuf::from(&s));
            prepend("PKG_CONFIG_PATH", Path::new(&s).join("lib/pkgconfig"));
        }
        Err(..) => {}
    }
}

fn prepend(var: &str, val: PathBuf) {
    let prefix = env::var(var).unwrap_or(String::new());
    let mut v = vec![val];
    v.extend(env::split_paths(&prefix));
    env::set_var(var, &env::join_paths(v).unwrap());
}

fn fail(s: &str) -> ! {
    panic!("\n{}\n\nbuild script failed, must exit now", s)
}
<commit_msg>Add support for MSVC builds<commit_after>extern crate pkg_config;

use std::env;
use std::fs::{self, File};
use std::io::ErrorKind;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::process::Command;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(n) => n,
        Err(e) => fail(&format!("\n{} failed with {}\n", stringify!($e), e)),
    })
}

fn main() {
    register_dep("SSH2");
    register_dep("OPENSSL");

    if env::var("LIBSSH2_SYS_USE_PKG_CONFIG").is_ok() {
        if pkg_config::find_library("libgit2").is_ok() {
            return
        }
    }

    let mut cflags = env::var("CFLAGS").unwrap_or(String::new());
    let target = env::var("TARGET").unwrap();
    let mingw = target.contains("windows-gnu");
    let msvc = target.contains("msvc");

    if msvc {
        // libgit2 passes the /GL flag to enable whole program optimization, but
        // this requires that the /LTCG flag is passed to the linker later on,
        // and currently the compiler does not do that, so we disable whole
        // program optimization entirely.
        cflags.push_str(" /GL-");
    } else {
        cflags.push_str(" -ffunction-sections -fdata-sections");

        if target.contains("i686") {
            cflags.push_str(" -m32");
        } else if target.contains("x86_64") {
            cflags.push_str(" -m64");
        }
        if !target.contains("i686") {
            cflags.push_str(" -fPIC");
        }
    }

    // libgit2 uses pkg-config to discover libssh2, but this doesn't work on
    // windows as libssh2 doesn't come with a libssh2.pc file in that install.
    // As a result we just manually turn on SSH support in libgit2 (a little
    // jankily) here...
    if mingw {
        cflags.push_str(" -DGIT_SSH");
        let libssh2_root = env::var("DEP_SSH2_ROOT").unwrap();
        cflags.push_str(&format!(" -I{}/include", libssh2_root));
    } else if msvc {
        cflags.push_str(" /DGIT_SSH");
        let libssh2_root = env::var("DEP_SSH2_ROOT").unwrap();
        cflags.push_str(&format!(" /I{}\\include", libssh2_root));
    }

    let src = PathBuf::from(&env::var("CARGO_MANIFEST_DIR").unwrap());
    let dst = PathBuf::from(&env::var("OUT_DIR").unwrap());
    let _ = fs::create_dir(&dst.join("build"));

    let mut cmd = Command::new("cmake");
    cmd.arg(&src.join("libgit2"))
       .current_dir(&dst.join("build"));
    if mingw {
        cmd.arg("-G").arg("Unix Makefiles");
    } else if msvc {
        // If we don't pass this unfortunately cmake produces 32-bit builds
        cmd.arg("-G").arg("Visual Studio 12 2013 Win64");

        // Currently liblibc links to msvcrt which apparently is a dynamic CRT,
        // so we need to turn this off to get it to link right.
        cmd.arg("-DSTATIC_CRT=OFF");
    }
    let profile = match &env::var("PROFILE").unwrap()[..] {
        "bench" | "release" => "Release",
        _ => "Debug",
    };
    run(cmd.arg("-DBUILD_SHARED_LIBS=OFF")
           .arg("-DBUILD_CLAR=OFF")
           .arg(&format!("-DCMAKE_BUILD_TYPE={}", profile))
           .arg(&format!("-DCMAKE_INSTALL_PREFIX={}", dst.display()))
           .arg(&format!("-DCMAKE_C_FLAGS={}", cflags)), "cmake");

    let flags = dst.join("build/CMakeFiles/git2.dir/flags.make");
    let mut contents = String::new();

    // Make sure libssh2 was detected on unix systems, because it definitely
    // should have been!
    if !msvc {
        t!(t!(File::open(flags)).read_to_string(&mut contents));
        if !contents.contains("-DGIT_SSH") {
            fail("libgit2 failed to find libssh2, and SSH support is required");
        }
    }

    run(Command::new("cmake")
                .arg("--build").arg(".")
                .arg("--target").arg("install")
                .current_dir(&dst.join("build")), "cmake");

    println!("cargo:root={}", dst.display());
    if mingw || target.contains("windows") {
        println!("cargo:rustc-flags=-l winhttp -l rpcrt4 -l ole32 \
                                    -l static=git2");
        println!("cargo:rustc-link-search=native={}/lib", dst.display());
        return
    }

    if env::var("HOST") == env::var("TARGET") {
        prepend("PKG_CONFIG_PATH", dst.join("lib/pkgconfig"));
        if pkg_config::Config::new().statik(true).find("libgit2").is_ok() {
            return
        }
    }

    println!("cargo:rustc-flags=-l static=git2");
    println!("cargo:rustc-flags=-L {}", dst.join("lib").display());
    if target.contains("apple") {
        println!("cargo:rustc-flags=-l iconv");
    }
}

fn run(cmd: &mut Command, program: &str) {
    println!("running: {:?}", cmd);
    let status = match cmd.status() {
        Ok(status) => status,
        Err(ref e) if e.kind() == ErrorKind::NotFound => {
            fail(&format!("failed to execute command: {}\nis `{}` not installed?",
                          e, program));
        }
        Err(e) => fail(&format!("failed to execute command: {}", e)),
    };
    if !status.success() {
        fail(&format!("command did not execute successfully, got: {}", status));
    }
}

fn register_dep(dep: &str) {
    match env::var(&format!("DEP_{}_ROOT", dep)) {
        Ok(s) => {
            prepend("CMAKE_PREFIX_PATH", PathBuf::from(&s));
            prepend("PKG_CONFIG_PATH", Path::new(&s).join("lib/pkgconfig"));
        }
        Err(..) => {}
    }
}

fn prepend(var: &str, val: PathBuf) {
    let prefix = env::var(var).unwrap_or(String::new());
    let mut v = vec![val];
    v.extend(env::split_paths(&prefix));
    env::set_var(var, &env::join_paths(v).unwrap());
}

fn fail(s: &str) -> ! {
    panic!("\n{}\n\nbuild script failed, must exit now", s)
}
<|endoftext|>


<commit_before>extern crate elf;
extern crate getopts;

use getopts::Options;
use std::cmp;
use std::env;
use std::fmt;
use std::fs::File;
use std::io;
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
use std::mem;
use std::path::Path;
use std::slice;

/// Takes a value and rounds it up to be aligned % 8
macro_rules! align8 {
    ( $e:expr ) => ( ($e) + ((8 - (($e) % 8)) % 8 ) );
}

/// Takes a value and rounds it up to be aligned % 4
macro_rules! align4 {
    ( $e:expr ) => ( ($e) + ((4 - (($e) % 4)) % 4 ) );
}

#[repr(u16)]
#[derive(Clone, Copy, Debug)]
#[allow(dead_code)]
enum TbfHeaderTypes {
    TbfHeaderMain = 1,
    TbfHeaderWriteableFlashRegions = 2,
    TbfHeaderPackageName = 3,
    TbfHeaderPicOption1 = 4,
}

#[repr(C)]
#[derive(Clone, Copy, Debug)]
struct TbfHeaderTlv {
    tipe: TbfHeaderTypes,
    length: u16,
}

#[repr(C)]
#[derive(Clone, Copy, Debug)]
struct TbfHeaderBase {
    version: u16,
    header_size: u16,
    total_size: u32,
    flags: u32,
    checksum: u32,
}

#[repr(C)]
#[derive(Clone, Copy, Debug)]
struct TbfHeaderMain {
    base: TbfHeaderTlv,
    init_fn_offset: u32,
    protected_size: u32,
    minimum_ram_size: u32,
}

#[repr(C)]
#[derive(Clone, Copy, Debug)]
struct TbfHeaderWriteableFlashRegion {
    offset: u32,
    size: u32,
}

impl fmt::Display for TbfHeaderBase {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "
               version: {:>8} {:>#10X}
           header_size: {:>8} {:>#10X}
            total_size: {:>8} {:>#10X}
                 flags: {:>8} {:>#10X}
",
        self.version, self.version,
        self.header_size, self.header_size,
        self.total_size, self.total_size,
        self.flags, self.flags,
        )
    }
}

impl fmt::Display for TbfHeaderMain {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "
        init_fn_offset: {:>8} {:>#10X}
        protected_size: {:>8} {:>#10X}
      minimum_ram_size: {:>8} {:>#10X}
",
        self.init_fn_offset, self.init_fn_offset,
        self.protected_size, self.protected_size,
        self.minimum_ram_size, self.minimum_ram_size,
        )
    }
}

impl fmt::Display for TbfHeaderWriteableFlashRegion {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "
    flash region:
                offset: {:>8} {:>#10X}
                  size: {:>8} {:>#10X}
",
        self.offset, self.offset,
        self.size, self.size,
        )
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();
    let mut opts = Options::new();
    opts.optopt("o", "", "set output file name", "OUTFILE");
    opts.optopt("n", "", "set package name", "PACKAGE_NAME");
    opts.optflag("v", "verbose", "be verbose");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string()),
    };
    let output = matches.opt_str("o");
    let package_name = matches.opt_str("n");
    let verbose = matches.opt_present("v");
    let input = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(&program, opts);
        return;
    };

    let path = Path::new(&input);
    let file = match elf::File::open_path(&path) {
        Ok(f) => f,
        Err(e) => panic!("Error: {:?}", e),
    };

    match output {
            None => {
                let mut out = io::stdout();
                do_work(&file, &mut out, package_name, verbose)
            }
            Some(name) => {
                match File::create(Path::new(&name)) {
                    Ok(mut f) => do_work(&file, &mut f, package_name, verbose),
                    Err(e) => panic!("Error: {:?}", e),
                }
            }
        }
        .expect("Failed to write output");
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [-o OUTFILE] FILE", program);
    print!("{}", opts.usage(&brief));
}

fn get_section<'a>(input: &'a elf::File, name: &str) -> elf::Section {
    match input.get_section(name) {
        Some(section) => {
            elf::Section {
                data: section.data.clone(),
                shdr: section.shdr.clone(),
            }
        }
        None => {
            elf::Section {
                data: Vec::new(),
                shdr: elf::types::SectionHeader {
                    name: String::from(name),
                    shtype: elf::types::SHT_NULL,
                    flags: elf::types::SHF_NONE,
                    addr: 0,
                    offset: 0,
                    size: 0,
                    link: 0,
                    info: 0,
                    addralign: 0,
                    entsize: 0,
                },
            }
        }
    }
}

unsafe fn as_byte_slice<'a, T: Copy>(input: &'a T) -> &'a [u8] {
    slice::from_raw_parts(input as *const T as *const u8, mem::size_of::<T>())
}

fn do_work(input: &elf::File,
           output: &mut Write,
           package_name: Option<String>,
           verbose: bool)
           -> io::Result<()> {
    let package_name = package_name.unwrap_or(String::new());
    let (relocation_data_size, rel_data) = match input.sections
        .iter()
        .find(|section| section.shdr.name == ".rel.data".as_ref()) {
        Some(section) => (section.shdr.size, section.data.as_ref()),
        None => (0 as u64, &[] as &[u8]),

    };
    let text = get_section(input, ".text");
    let got = get_section(input, ".got");
    let data = get_section(input, ".data");
    let bss = get_section(input, ".bss");
    let appstate = get_section(input, ".app_state");

    // For these, we only care about the length
    let stack_len = get_section(input, ".stack").data.len() as u32;
    let app_heap_len = get_section(input, ".app_heap").data.len() as u32;
    let kernel_heap_len = get_section(input, ".kernel_heap").data.len() as u32;

    // Need to calculate lengths ahead of time.
    // Need the base and the main section.
    let mut header_length = mem::size_of::<TbfHeaderBase>() + mem::size_of::<TbfHeaderMain>();

    // If we have a package name, add that section.
    let mut post_name_pad = 0;
    if package_name.len() > 0 {
        let name_total_size = align4!(mem::size_of::<TbfHeaderTlv>() + package_name.len());
        header_length += name_total_size;

        // Calculate the padding required after the package name TLV. All blocks
        // must be four byte aligned, so we may need to add some padding.
        post_name_pad = name_total_size - (mem::size_of::<TbfHeaderTlv>() + package_name.len());
    }

    // We have one app flash region, add that.
    if appstate.data.len() > 0 {
        header_length += mem::size_of::<TbfHeaderTlv>() +
                         mem::size_of::<TbfHeaderWriteableFlashRegion>();
    }

    // Calculate the offset between the start of the flash region and the actual
    // app code. Also need to get the padding size.
    let app_start_offset = align8!(header_length);
    let post_header_pad = app_start_offset as usize - header_length;
    println!("{}", post_header_pad);

    // Now we can calculate the entire size of the app in flash.
    let mut total_size = (header_length + post_header_pad + rel_data.len() + text.data.len() +
                          got.data.len() +
                          data.data.len() + appstate.data.len()) as u32;

    let ending_pad = if total_size.count_ones() > 1 {
        let power2len = cmp::max(1 << (32 - total_size.leading_zeros()), 512);
        power2len - total_size
    } else {
        0
    };
    total_size += ending_pad;

    // To start we just restrict the app from writing all of the space before
    // its actual code and whatnot.
    let protected_size = 0;

    // First up is the app writeable app_state section. If this is not used or
    // non-existent, it will just be zero and won't matter. But we put it first
    // so that changes to the app won't move it.
    let appstate_offset = app_start_offset as u32;
    let appstate_size = appstate.shdr.size as u32;
    // Make sure we pad back to a multiple of 8.
    let post_appstate_pad = align8!(appstate_offset + appstate_size) -
                            (appstate_offset + appstate_size);
    let init_fn_offset = (input.ehdr.entry - text.shdr.addr) as u32;
    let got_size = got.shdr.size as u32;
    let data_size = data.shdr.size as u32;
    let bss_size = bss.shdr.size as u32;
    let minimum_ram_size = stack_len + app_heap_len + kernel_heap_len + got_size + data_size +
                           bss_size;

    // Flags default to app is enabled.
    let flags = 0x00000001;

    let tbf_header_version = 2;

    let tbf_header = TbfHeaderBase {
        version: tbf_header_version,
        header_size: header_length as u16,
        total_size: total_size,
        flags: flags,
        checksum: 0,
    };

    let tbf_main = TbfHeaderMain {
        base: TbfHeaderTlv {
            tipe: TbfHeaderTypes::TbfHeaderMain,
            length: (mem::size_of::<TbfHeaderMain>() - mem::size_of::<TbfHeaderTlv>()) as u16,
        },
        init_fn_offset: init_fn_offset,
        protected_size: protected_size as u32,
        minimum_ram_size: minimum_ram_size,
    };

    let tbf_package_name_tlv = TbfHeaderTlv {
        tipe: TbfHeaderTypes::TbfHeaderPackageName,
        length: package_name.len() as u16,
    };

    let tbf_flash_regions_tlv = TbfHeaderTlv {
        tipe: TbfHeaderTypes::TbfHeaderWriteableFlashRegions,
        length: 8,
    };

    let tbf_flash_region = TbfHeaderWriteableFlashRegion {
        offset: appstate_offset,
        size: appstate_size,
    };

    if verbose {
        print!("{}", tbf_header);
        print!("{}", tbf_main);
        print!("{}", tbf_flash_region);
    }

    // Calculate the header checksum.
    let mut header_buf = Cursor::new(Vec::new());

    // Write all bytes to an in-memory file for the header.
    try!(header_buf.write_all(unsafe { as_byte_slice(&tbf_header) }));
    try!(header_buf.write_all(unsafe { as_byte_slice(&tbf_main) }));
    try!(header_buf.write_all(unsafe { as_byte_slice(&tbf_package_name_tlv) }));
    try!(header_buf.write_all(package_name.as_ref()));
    try!(do_pad(&mut header_buf, post_name_pad));

    // Only put these in the header if the app_state section is nonzero.
    if appstate.data.len() > 0 {
        try!(header_buf.write_all(unsafe { as_byte_slice(&tbf_flash_regions_tlv) }));
        try!(header_buf.write_all(unsafe { as_byte_slice(&tbf_flash_region) }));
    }

    // Start from the beginning and iterate through the buffer as words.
    try!(header_buf.seek(SeekFrom::Start(0)));
    let mut wordbuf = [0u8; 4];
    let mut checksum: u32 = 0;
    loop {
        let ret = header_buf.read(&mut wordbuf);
        match ret {
            Ok(count) => {
                // Combine the bytes back into a word, handling if we don't
                // get a full word.
                let mut word = 0;
                for i in 0..count {
                    word |= (wordbuf[i] as u32) << (8 * i);
                }
                checksum ^= word;
                if count != 4 {
                    break;
                }
            }
            Err(_) => println!("Error calculating checksum."),
        }
    }

    // Now we need to insert the checksum into the correct position in the
    // header.
    try!(header_buf.seek(SeekFrom::Start(12)));
    wordbuf[0] = ((checksum >> 0) & 0xFF) as u8;
    wordbuf[1] = ((checksum >> 8) & 0xFF) as u8;
    wordbuf[2] = ((checksum >> 16) & 0xFF) as u8;
    wordbuf[3] = ((checksum >> 24) & 0xFF) as u8;
    try!(header_buf.write(&wordbuf));
    try!(header_buf.seek(SeekFrom::Start(0)));

    fn do_pad(output: &mut Write, length: usize) -> io::Result<()> {
        let mut pad = length;
        let zero_buf = [0u8; 512];
        while pad > 0 {
            let amount_to_write = cmp::min(zero_buf.len(), pad);
            pad -= try!(output.write(&zero_buf[..amount_to_write]));
        }
        Ok(())
    }

    // Write the header and actual app to a binary file.
    try!(output.write_all(header_buf.get_ref()));
    try!(do_pad(output, post_header_pad as usize));
    try!(output.write_all(appstate.data.as_ref()));
    try!(do_pad(output, post_appstate_pad as usize));
    try!(output.write_all(text.data.as_ref()));
    try!(output.write_all(got.data.as_ref()));
    try!(output.write_all(data.data.as_ref()));
    let rel_data_len: [u8; 4] = [(rel_data.len() & 0xff) as u8,
                                 (rel_data.len() >> 8 & 0xff) as u8,
                                 (rel_data.len() >> 16 & 0xff) as u8,
                                 (rel_data.len() >> 24 & 0xff) as u8];
    try!(output.write_all(&rel_data_len));
    try!(output.write_all(rel_data.as_ref()));

    // Pad to get a power of 2 sized flash app.
    try!(do_pad(output, ending_pad as usize));

    Ok(())
}
<commit_msg>Don't needlessly align to 8 bytes<commit_after>extern crate elf;
extern crate getopts;

use getopts::Options;
use std::cmp;
use std::env;
use std::fmt;
use std::fs::File;
use std::io;
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
use std::mem;
use std::path::Path;
use std::slice;

/// Takes a value and rounds it up to be aligned % 8
macro_rules! align8 {
    ( $e:expr ) => ( ($e) + ((8 - (($e) % 8)) % 8 ) );
}

/// Takes a value and rounds it up to be aligned % 4
macro_rules! align4 {
    ( $e:expr ) => ( ($e) + ((4 - (($e) % 4)) % 4 ) );
}

#[repr(u16)]
#[derive(Clone, Copy, Debug)]
#[allow(dead_code)]
enum TbfHeaderTypes {
    TbfHeaderMain = 1,
    TbfHeaderWriteableFlashRegions = 2,
    TbfHeaderPackageName = 3,
    TbfHeaderPicOption1 = 4,
}

#[repr(C)]
#[derive(Clone, Copy, Debug)]
struct TbfHeaderTlv {
    tipe: TbfHeaderTypes,
    length: u16,
}

#[repr(C)]
#[derive(Clone, Copy, Debug)]
struct TbfHeaderBase {
    version: u16,
    header_size: u16,
    total_size: u32,
    flags: u32,
    checksum: u32,
}

#[repr(C)]
#[derive(Clone, Copy, Debug)]
struct TbfHeaderMain {
    base: TbfHeaderTlv,
    init_fn_offset: u32,
    protected_size: u32,
    minimum_ram_size: u32,
}

#[repr(C)]
#[derive(Clone, Copy, Debug)]
struct TbfHeaderWriteableFlashRegion {
    offset: u32,
    size: u32,
}

impl fmt::Display for TbfHeaderBase {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "
               version: {:>8} {:>#10X}
           header_size: {:>8} {:>#10X}
            total_size: {:>8} {:>#10X}
                 flags: {:>8} {:>#10X}
",
        self.version, self.version,
        self.header_size, self.header_size,
        self.total_size, self.total_size,
        self.flags, self.flags,
        )
    }
}

impl fmt::Display for TbfHeaderMain {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "
        init_fn_offset: {:>8} {:>#10X}
        protected_size: {:>8} {:>#10X}
      minimum_ram_size: {:>8} {:>#10X}
",
        self.init_fn_offset, self.init_fn_offset,
        self.protected_size, self.protected_size,
        self.minimum_ram_size, self.minimum_ram_size,
        )
    }
}

impl fmt::Display for TbfHeaderWriteableFlashRegion {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "
    flash region:
                offset: {:>8} {:>#10X}
                  size: {:>8} {:>#10X}
",
        self.offset, self.offset,
        self.size, self.size,
        )
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();
    let mut opts = Options::new();
    opts.optopt("o", "", "set output file name", "OUTFILE");
    opts.optopt("n", "", "set package name", "PACKAGE_NAME");
    opts.optflag("v", "verbose", "be verbose");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string()),
    };
    let output = matches.opt_str("o");
    let package_name = matches.opt_str("n");
    let verbose = matches.opt_present("v");
    let input = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(&program, opts);
        return;
    };

    let path = Path::new(&input);
    let file = match elf::File::open_path(&path) {
        Ok(f) => f,
        Err(e) => panic!("Error: {:?}", e),
    };

    match output {
            None => {
                let mut out = io::stdout();
                do_work(&file, &mut out, package_name, verbose)
            }
            Some(name) => {
                match File::create(Path::new(&name)) {
                    Ok(mut f) => do_work(&file, &mut f, package_name, verbose),
                    Err(e) => panic!("Error: {:?}", e),
                }
            }
        }
        .expect("Failed to write output");
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [-o OUTFILE] FILE", program);
    print!("{}", opts.usage(&brief));
}

fn get_section<'a>(input: &'a elf::File, name: &str) -> elf::Section {
    match input.get_section(name) {
        Some(section) => {
            elf::Section {
                data: section.data.clone(),
                shdr: section.shdr.clone(),
            }
        }
        None => {
            elf::Section {
                data: Vec::new(),
                shdr: elf::types::SectionHeader {
                    name: String::from(name),
                    shtype: elf::types::SHT_NULL,
                    flags: elf::types::SHF_NONE,
                    addr: 0,
                    offset: 0,
                    size: 0,
                    link: 0,
                    info: 0,
                    addralign: 0,
                    entsize: 0,
                },
            }
        }
    }
}

unsafe fn as_byte_slice<'a, T: Copy>(input: &'a T) -> &'a [u8] {
    slice::from_raw_parts(input as *const T as *const u8, mem::size_of::<T>())
}

fn do_work(input: &elf::File,
           output: &mut Write,
           package_name: Option<String>,
           verbose: bool)
           -> io::Result<()> {
    let package_name = package_name.unwrap_or(String::new());
    let (relocation_data_size, rel_data) = match input.sections
        .iter()
        .find(|section| section.shdr.name == ".rel.data".as_ref()) {
        Some(section) => (section.shdr.size, section.data.as_ref()),
        None => (0 as u64, &[] as &[u8]),

    };
    let text = get_section(input, ".text");
    let got = get_section(input, ".got");
    let data = get_section(input, ".data");
    let bss = get_section(input, ".bss");
    let appstate = get_section(input, ".app_state");

    // For these, we only care about the length
    let stack_len = get_section(input, ".stack").data.len() as u32;
    let app_heap_len = get_section(input, ".app_heap").data.len() as u32;
    let kernel_heap_len = get_section(input, ".kernel_heap").data.len() as u32;

    // Need to calculate lengths ahead of time.
    // Need the base and the main section.
    let mut header_length = mem::size_of::<TbfHeaderBase>() + mem::size_of::<TbfHeaderMain>();

    // If we have a package name, add that section.
    let mut post_name_pad = 0;
    if package_name.len() > 0 {
        let name_total_size = align4!(mem::size_of::<TbfHeaderTlv>() + package_name.len());
        header_length += name_total_size;

        // Calculate the padding required after the package name TLV. All blocks
        // must be four byte aligned, so we may need to add some padding.
        post_name_pad = name_total_size - (mem::size_of::<TbfHeaderTlv>() + package_name.len());
    }

    // We have one app flash region, add that.
    if appstate.data.len() > 0 {
        header_length += mem::size_of::<TbfHeaderTlv>() +
                         mem::size_of::<TbfHeaderWriteableFlashRegion>();
    }

    // Calculate the offset between the start of the flash region and the actual
    // app code. Also need to get the padding size.
    let app_start_offset = align4!(header_length);
    let post_header_pad = app_start_offset as usize - header_length;
    println!("{}", post_header_pad);

    // Now we can calculate the entire size of the app in flash.
    let mut total_size = (header_length + post_header_pad + rel_data.len() + text.data.len() +
                          got.data.len() +
                          data.data.len() + appstate.data.len()) as u32;

    let ending_pad = if total_size.count_ones() > 1 {
        let power2len = cmp::max(1 << (32 - total_size.leading_zeros()), 512);
        power2len - total_size
    } else {
        0
    };
    total_size += ending_pad;

    // To start we just restrict the app from writing all of the space before
    // its actual code and whatnot.
    let protected_size = 0;

    // First up is the app writeable app_state section. If this is not used or
    // non-existent, it will just be zero and won't matter. But we put it first
    // so that changes to the app won't move it.
    let appstate_offset = app_start_offset as u32;
    let appstate_size = appstate.shdr.size as u32;
    // Make sure we pad back to a multiple of 8.
    let post_appstate_pad = align4!(appstate_offset + appstate_size) -
                            (appstate_offset + appstate_size);
    let init_fn_offset = (input.ehdr.entry - text.shdr.addr) as u32;
    let got_size = got.shdr.size as u32;
    let data_size = data.shdr.size as u32;
    let bss_size = bss.shdr.size as u32;
    let minimum_ram_size = stack_len + app_heap_len + kernel_heap_len + got_size + data_size +
                           bss_size;

    // Flags default to app is enabled.
    let flags = 0x00000001;

    let tbf_header_version = 2;

    let tbf_header = TbfHeaderBase {
        version: tbf_header_version,
        header_size: header_length as u16,
        total_size: total_size,
        flags: flags,
        checksum: 0,
    };

    let tbf_main = TbfHeaderMain {
        base: TbfHeaderTlv {
            tipe: TbfHeaderTypes::TbfHeaderMain,
            length: (mem::size_of::<TbfHeaderMain>() - mem::size_of::<TbfHeaderTlv>()) as u16,
        },
        init_fn_offset: init_fn_offset,
        protected_size: protected_size as u32,
        minimum_ram_size: minimum_ram_size,
    };

    let tbf_package_name_tlv = TbfHeaderTlv {
        tipe: TbfHeaderTypes::TbfHeaderPackageName,
        length: package_name.len() as u16,
    };

    let tbf_flash_regions_tlv = TbfHeaderTlv {
        tipe: TbfHeaderTypes::TbfHeaderWriteableFlashRegions,
        length: 8,
    };

    let tbf_flash_region = TbfHeaderWriteableFlashRegion {
        offset: appstate_offset,
        size: appstate_size,
    };

    if verbose {
        print!("{}", tbf_header);
        print!("{}", tbf_main);
        print!("{}", tbf_flash_region);
    }

    // Calculate the header checksum.
    let mut header_buf = Cursor::new(Vec::new());

    // Write all bytes to an in-memory file for the header.
    try!(header_buf.write_all(unsafe { as_byte_slice(&tbf_header) }));
    try!(header_buf.write_all(unsafe { as_byte_slice(&tbf_main) }));
    try!(header_buf.write_all(unsafe { as_byte_slice(&tbf_package_name_tlv) }));
    try!(header_buf.write_all(package_name.as_ref()));
    try!(do_pad(&mut header_buf, post_name_pad));

    // Only put these in the header if the app_state section is nonzero.
    if appstate.data.len() > 0 {
        try!(header_buf.write_all(unsafe { as_byte_slice(&tbf_flash_regions_tlv) }));
        try!(header_buf.write_all(unsafe { as_byte_slice(&tbf_flash_region) }));
    }

    // Start from the beginning and iterate through the buffer as words.
    try!(header_buf.seek(SeekFrom::Start(0)));
    let mut wordbuf = [0u8; 4];
    let mut checksum: u32 = 0;
    loop {
        let ret = header_buf.read(&mut wordbuf);
        match ret {
            Ok(count) => {
                // Combine the bytes back into a word, handling if we don't
                // get a full word.
                let mut word = 0;
                for i in 0..count {
                    word |= (wordbuf[i] as u32) << (8 * i);
                }
                checksum ^= word;
                if count != 4 {
                    break;
                }
            }
            Err(_) => println!("Error calculating checksum."),
        }
    }

    // Now we need to insert the checksum into the correct position in the
    // header.
    try!(header_buf.seek(SeekFrom::Start(12)));
    wordbuf[0] = ((checksum >> 0) & 0xFF) as u8;
    wordbuf[1] = ((checksum >> 8) & 0xFF) as u8;
    wordbuf[2] = ((checksum >> 16) & 0xFF) as u8;
    wordbuf[3] = ((checksum >> 24) & 0xFF) as u8;
    try!(header_buf.write(&wordbuf));
    try!(header_buf.seek(SeekFrom::Start(0)));

    fn do_pad(output: &mut Write, length: usize) -> io::Result<()> {
        let mut pad = length;
        let zero_buf = [0u8; 512];
        while pad > 0 {
            let amount_to_write = cmp::min(zero_buf.len(), pad);
            pad -= try!(output.write(&zero_buf[..amount_to_write]));
        }
        Ok(())
    }

    // Write the header and actual app to a binary file.
    try!(output.write_all(header_buf.get_ref()));
    try!(do_pad(output, post_header_pad as usize));
    try!(output.write_all(appstate.data.as_ref()));
    try!(do_pad(output, post_appstate_pad as usize));
    try!(output.write_all(text.data.as_ref()));
    try!(output.write_all(got.data.as_ref()));
    try!(output.write_all(data.data.as_ref()));
    let rel_data_len: [u8; 4] = [(rel_data.len() & 0xff) as u8,
                                 (rel_data.len() >> 8 & 0xff) as u8,
                                 (rel_data.len() >> 16 & 0xff) as u8,
                                 (rel_data.len() >> 24 & 0xff) as u8];
    try!(output.write_all(&rel_data_len));
    try!(output.write_all(rel_data.as_ref()));

    // Pad to get a power of 2 sized flash app.
    try!(do_pad(output, ending_pad as usize));

    Ok(())
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::ops::Deref;
use std::fmt::Display;
use std::process::exit;

use clap::ArgMatches;
use toml::Value;

use libimagstore::store::FileLockEntry;
use libimagstore::storeid::build_entry_path;
use libimagrt::runtime::Runtime;
use libimagutil::trace::trace_error;

pub fn retrieve(rt: &Runtime) {
    rt.cli()
        .subcommand_matches("retrieve")
        .map(|scmd| {
            scmd.value_of("id")
                .map(|id| {
                    let path = build_entry_path(rt.store(), id);
                    if path.is_err() {
                        trace_error(&path.err().unwrap());
                        exit(1);
                    }
                    let path = path.unwrap();
                    debug!("path = {:?}", path);

                    rt.store()
                        // "id" must be present, enforced via clap spec
                        .retrieve(path)
                        .map(|e| print_entry(rt, scmd, e))
                        .map_err(|e| {
                            debug!("No entry.");
                            debug!("{}:", e);
                            trace_error(&e);
                        })
                })
        });
}

fn print_entry(rt: &Runtime, scmd: &ArgMatches, e: FileLockEntry) {
    if do_print_raw(scmd) {
        debug!("Printing raw content...");
        println!("{}", e.deref().to_str());
    } else if do_filter(scmd) {
        debug!("Filtering...");
        warn!("Filtering via header specs is currently now supported.");
        warn!("Will fail now!");
        unimplemented!()
    } else {
        debug!("Printing structured...");
        let entry = e.deref();
        if do_print_header(scmd) {
            debug!("Printing header...");
            if do_print_header_as_json(rt.cli()) {
                debug!("Printing header as json...");
                warn!("Printing as JSON currently not supported.");
                warn!("Will fail now!");
                unimplemented!()
            } else {
                debug!("Printing header as TOML...");
                // We have to Value::Table() for Display
                println!("{}", Value::Table(entry.get_header().clone().into()))
            }
        }

        if do_print_content(scmd) {
            debug!("Printing content...");
            println!("{}", entry.get_content());
        }

    }
}

fn do_print_header(m: &ArgMatches) -> bool {
    m.is_present("header")
}

fn do_print_header_as_json(m: &ArgMatches) -> bool {
    m.is_present("header-json")
}

fn do_print_content(m: &ArgMatches) -> bool {
    m.is_present("content")
}

fn do_print_raw(m: &ArgMatches) -> bool {
    m.is_present("raw")
}

fn do_filter(m: &ArgMatches) -> bool {
    m.subcommand_matches("filter-header").is_some()
}

<commit_msg>Remove unneeded calls to deref()<commit_after>use std::path::PathBuf;
use std::ops::Deref;
use std::fmt::Display;
use std::process::exit;

use clap::ArgMatches;
use toml::Value;

use libimagstore::store::FileLockEntry;
use libimagstore::storeid::build_entry_path;
use libimagrt::runtime::Runtime;
use libimagutil::trace::trace_error;

pub fn retrieve(rt: &Runtime) {
    rt.cli()
        .subcommand_matches("retrieve")
        .map(|scmd| {
            scmd.value_of("id")
                .map(|id| {
                    let path = build_entry_path(rt.store(), id);
                    if path.is_err() {
                        trace_error(&path.err().unwrap());
                        exit(1);
                    }
                    let path = path.unwrap();
                    debug!("path = {:?}", path);

                    rt.store()
                        // "id" must be present, enforced via clap spec
                        .retrieve(path)
                        .map(|e| print_entry(rt, scmd, e))
                        .map_err(|e| {
                            debug!("No entry.");
                            debug!("{}:", e);
                            trace_error(&e);
                        })
                })
        });
}

fn print_entry(rt: &Runtime, scmd: &ArgMatches, e: FileLockEntry) {
    if do_print_raw(scmd) {
        debug!("Printing raw content...");
        println!("{}", e.to_str());
    } else if do_filter(scmd) {
        debug!("Filtering...");
        warn!("Filtering via header specs is currently now supported.");
        warn!("Will fail now!");
        unimplemented!()
    } else {
        debug!("Printing structured...");
        if do_print_header(scmd) {
            debug!("Printing header...");
            if do_print_header_as_json(rt.cli()) {
                debug!("Printing header as json...");
                warn!("Printing as JSON currently not supported.");
                warn!("Will fail now!");
                unimplemented!()
            } else {
                debug!("Printing header as TOML...");
                // We have to Value::Table() for Display
                println!("{}", Value::Table(e.get_header().clone().into()))
            }
        }

        if do_print_content(scmd) {
            debug!("Printing content...");
            println!("{}", e.get_content());
        }

    }
}

fn do_print_header(m: &ArgMatches) -> bool {
    m.is_present("header")
}

fn do_print_header_as_json(m: &ArgMatches) -> bool {
    m.is_present("header-json")
}

fn do_print_content(m: &ArgMatches) -> bool {
    m.is_present("content")
}

fn do_print_raw(m: &ArgMatches) -> bool {
    m.is_present("raw")
}

fn do_filter(m: &ArgMatches) -> bool {
    m.subcommand_matches("filter-header").is_some()
}

<|endoftext|>


<commit_before>extern crate clap;
extern crate libimagrt;
extern crate libimagentrytag;
extern crate libimagutil;
#[macro_use] extern crate version;

use clap::Shell;
use libimagrt::runtime::Runtime;

macro_rules! gen_types_buildui {
    ($(($p:expr, $n:ident)$(,)*)*) => (
        $(
            mod $n {
                include!($p);
            }
         )*
        )
}

macro_rules! build_subcommand {
    ($name:expr, $module:ident) => (
        $module::build_ui(Runtime::get_default_cli_builder(
                $name,
                &version!()[..],
                $name))
    )
}

gen_types_buildui!(
    ("../imag-bookmark/src/ui.rs",  imagbookmark),
    ("../imag-counter/src/ui.rs",   imagcounter),
    ("../imag-diary/src/ui.rs",     imagdiary),
    ("../imag-link/src/ui.rs",      imaglink),
    ("../imag-notes/src/ui.rs",     imagnotes),
    ("../imag-ref/src/ui.rs",       imagref),
    ("../imag-store/src/ui.rs",     imagstore),
    ("../imag-tag/src/ui.rs",       imagtag),
    ("../imag-todo/src/ui.rs",      imagtodo),
    ("../imag-view/src/ui.rs",      imagview)
);

fn main() {
    let mut app = Runtime::get_default_cli_builder(
        "imag",
        &version!()[..],
        "imag")
        .subcommand(build_subcommand!("bookmark",   imagbookmark))
        .subcommand(build_subcommand!("counter",    imagcounter))
        .subcommand(build_subcommand!("diary",      imagdiary))
        .subcommand(build_subcommand!("link",       imaglink))
        .subcommand(build_subcommand!("notes",      imagnotes))
        .subcommand(build_subcommand!("ref",        imagref))
        .subcommand(build_subcommand!("store",      imagstore))
        .subcommand(build_subcommand!("tag",        imagtag))
        .subcommand(build_subcommand!("todo",       imagtodo))
        .subcommand(build_subcommand!("view",       imagview));

    app.gen_completions("imag", Shell::Bash, env!("OUT_DIR"));
    app.gen_completions("imag", Shell::Fish, env!("OUT_DIR"));
    app.gen_completions("imag", Shell::Zsh, env!("OUT_DIR"));

}

<commit_msg>Add comments about functionality, increase verbosity of some variables<commit_after>extern crate clap;
extern crate libimagrt;
extern crate libimagentrytag;
extern crate libimagutil;
#[macro_use] extern crate version;

use clap::Shell;
use libimagrt::runtime::Runtime;

/// This macro generates mods with the given '$modulename',
/// whose content is the file given with `$path`.
/// In this case, It is used specifically to include the
/// `ui.rs` files of the imag binaries.
/// The imag project (accidentally?) followed the convention
/// to write a `ui.rs` containing the function
/// `fn build_ui(app : App) -> App`.
/// This macro allows us to use the same named functions by
/// putting them each into their own module.
macro_rules! gen_mods_buildui {
    ($(($path:expr, $modulename:ident)$(,)*)*) => (
        $(
            mod $modulename {
                include!($path);
            }
         )*
        )
}

/// This macro reduces boilerplate code.
///
/// For example: `build_subcommand!("counter", imagcounter)`
/// will result in the following code:
/// ```ignore
/// imagcounter::build_ui(Runtime::get_default_cli_builder(
///     "counter",
///     &version!()[..],
///     "counter"))
/// ```
macro_rules! build_subcommand {
    ($name:expr, $module:ident) => (
        $module::build_ui(Runtime::get_default_cli_builder(
                $name,
                &version!()[..],
                $name))
    )
}

// Actually generates the module.
gen_mods_buildui!(
    ("../imag-bookmark/src/ui.rs",  imagbookmark),
    ("../imag-counter/src/ui.rs",   imagcounter),
    ("../imag-diary/src/ui.rs",     imagdiary),
    ("../imag-link/src/ui.rs",      imaglink),
    ("../imag-notes/src/ui.rs",     imagnotes),
    ("../imag-ref/src/ui.rs",       imagref),
    ("../imag-store/src/ui.rs",     imagstore),
    ("../imag-tag/src/ui.rs",       imagtag),
    ("../imag-todo/src/ui.rs",      imagtodo),
    ("../imag-view/src/ui.rs",      imagview)
);

fn main() {
    // Make the `imag`-App...
    let mut app = Runtime::get_default_cli_builder(
        "imag",
        &version!()[..],
        "imag")
        // and add all the subapps as subcommands.
        .subcommand(build_subcommand!("bookmark",   imagbookmark))
        .subcommand(build_subcommand!("counter",    imagcounter))
        .subcommand(build_subcommand!("diary",      imagdiary))
        .subcommand(build_subcommand!("link",       imaglink))
        .subcommand(build_subcommand!("notes",      imagnotes))
        .subcommand(build_subcommand!("ref",        imagref))
        .subcommand(build_subcommand!("store",      imagstore))
        .subcommand(build_subcommand!("tag",        imagtag))
        .subcommand(build_subcommand!("todo",       imagtodo))
        .subcommand(build_subcommand!("view",       imagview));

    // Actually generates the completion files
    app.gen_completions("imag", Shell::Bash, env!("OUT_DIR"));
    app.gen_completions("imag", Shell::Fish, env!("OUT_DIR"));
    app.gen_completions("imag", Shell::Zsh, env!("OUT_DIR"));

}

<|endoftext|>


<commit_before>extern crate eventual;
extern crate robots;

use eventual::Async;

use std::any::Any;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Sender};
use std::time::Duration;

use robots::actors::{Actor, ActorSystem, ActorCell, ActorContext, ActorRef, Props};

#[derive(Debug, PartialEq)]
enum Res {
    Ok,
    Err,
}

#[derive(Copy, Clone)]
enum InternalStateMessage {
    Set(u32),
    Get,
    Panic,
}

struct InternalState {
    last: Mutex<u32>,
    sender: Arc<Mutex<Sender<Res>>>,
}

impl Actor for InternalState {
    fn receive(&self, message: Box<Any>, context: ActorCell) {
        if let Ok(message) = Box::<Any>::downcast::<InternalStateMessage>(message) {
            match *message {
                InternalStateMessage::Get => {
                    context.tell(context.sender(), *self.last.lock().unwrap())
                }
                InternalStateMessage::Set(message) => {
                    // Here mixing the test actor for the two tests might seem a bit weird,
                    // but we would get two very similar actors otherwise.
                    let mut last = self.last.lock().unwrap();
                    if message <= *last {
                        let _ = self.sender.lock().unwrap().send(Res::Err);
                    } else {
                        *last = message;
                    }
                    if *last == 1000 {
                        let _ = self.sender.lock().unwrap().send(Res::Ok);
                    }
                }
                InternalStateMessage::Panic => panic!(""),
            }
        }
    }
}

impl InternalState {
    fn new(sender: Arc<Mutex<Sender<Res>>>) -> InternalState {
        InternalState {
            last: Mutex::new(0),
            sender: sender,
        }
    }
}

#[test]
fn read_messages_in_order() {
    let actor_system = ActorSystem::new("test".to_owned());
    actor_system.spawn_threads(9);

    let (tx, rx) = channel();
    let tx = Arc::new(Mutex::new(tx));

    let props = Props::new(Arc::new(InternalState::new), tx);
    let actor_ref_1 = actor_system.actor_of(props.clone(), "sender".to_owned());
    let actor_ref_2 = actor_system.actor_of(props.clone(), "receiver".to_owned());

    for i in 1..1001 {
        actor_ref_1.tell_to(actor_ref_2.clone(), InternalStateMessage::Set(i as u32));
    }

    let res = rx.recv();
    assert_eq!(Ok(Res::Ok), res);

    actor_system.shutdown();
}

#[test]
fn recover_from_panic() {
    let actor_system = ActorSystem::new("test".to_owned());
    actor_system.spawn_threads(1);

    let (tx, _rx) = channel();
    let tx = Arc::new(Mutex::new(tx));

    let props = Props::new(Arc::new(InternalState::new), tx);
    let requester = actor_system.actor_of(props.clone(), "sender".to_owned());
    let answerer = actor_system.actor_of(props.clone(), "receiver".to_owned());

    requester.tell_to(answerer.clone(), InternalStateMessage::Set(10));
    let res = answerer.ask(InternalStateMessage::Get).await().unwrap();
    let res = Box::<Any>::downcast::<u32>(res).unwrap();
    assert_eq!(10u32, *res);

    requester.tell_to(answerer.clone(), InternalStateMessage::Panic);
    let res = answerer.ask(InternalStateMessage::Get).await().unwrap();
    let res = Box::<Any>::downcast::<u32>(res).unwrap();
    assert_eq!(0u32, *res);

    actor_system.shutdown();
}

struct Resolver;

impl Actor for Resolver {
    fn receive(&self, message: Box<Any>, context: ActorCell) {
        if let Ok(message) = Box::<Any>::downcast::<String>(message) {
            let res = context.identify_actor(*message)
                             .await()
                             .unwrap();
            context.tell(context.sender(), res);
        }
    }
}

impl Resolver {
    fn new(_dummy: ()) -> Resolver {
        Resolver
    }
}

#[test]
fn resolve_name_real_path() {
    let actor_system = ActorSystem::new("test".to_owned());
    actor_system.spawn_threads(2);

    let props = Props::new(Arc::new(Resolver::new), ());
    let answerer = actor_system.actor_of(props.clone(), "answerer".to_owned());
    let requester = actor_system.actor_of(props.clone(), "sender".to_owned());

    // We wait to be sure that the actors will be registered to the name resolver.
    std::thread::sleep(Duration::from_millis(100));

    let res = answerer.ask("/user/sender".to_owned()).await().unwrap();
    let res = Box::<Any>::downcast::<Option<ActorRef>>(res).unwrap();
    assert_eq!(requester.path(), (*res).unwrap().path());

    actor_system.shutdown();
}

#[test]
fn resolve_name_fake_path() {
    let actor_system = ActorSystem::new("test".to_owned());
    actor_system.spawn_threads(2);

    let props = Props::new(Arc::new(Resolver::new), ());
    let answerer = actor_system.actor_of(props.clone(), "answerer".to_owned());

    // We wait to be sure that the actors will be registered to the name resolver.
    std::thread::sleep(Duration::from_millis(100));

    let res = answerer.ask("/foo/bar".to_owned()).await().unwrap();
    let res = *Box::<Any>::downcast::<Option<ActorRef>>(res).unwrap();

    match res {
        None => {}
        Some(_) => panic!("The name resolver gave an ActorRef when he should not."),
    };

    actor_system.shutdown();
}

// This actor simply answers twice with () when send a message.
// He also sends () through a channel when restarted.
struct DoubleAnswer {
    sender: Arc<Mutex<Sender<()>>>,
}

impl Actor for DoubleAnswer {
    fn post_restart(&self, _context: ActorCell) {
        let mut sender = self.sender.lock().unwrap();
        sender.send(());
    }

    fn receive(&self, _message: Box<Any>, context: ActorCell) {
        context.tell(context.sender(), ());
        context.tell(context.sender(), ());
    }
}

impl DoubleAnswer {
    fn new(sender: Arc<Mutex<Sender<()>>>) -> DoubleAnswer {
        DoubleAnswer {
            sender: sender
        }
    }
}

#[test]
fn ask_answer_twice() {
    let actor_system = ActorSystem::new("test".to_owned());

    let (tx, rx) = channel();
    let tx = Arc::new(Mutex::new(tx));

    let props = Props::new(Arc::new(DoubleAnswer::new), tx);
    let answerer = actor_system.actor_of(props.clone(), "answerer".to_owned());

    let res = answerer.ask(()).await().unwrap();
    let res = *Box::<Any>::downcast::<()>(res).unwrap();
    // We chack that the value contained in the future is the correct one.
    assert_eq!(res, ());

    // We check that the actor has been restarted because of a panic (reason is not caught yet).
    let res = rx.recv();
    assert_eq!(res, Ok(()));

    std::thread::sleep(Duration::from_millis(10));

    actor_system.shutdown();
}
<commit_msg>Panic when trying to complete a future twice.<commit_after>extern crate eventual;
extern crate robots;

use eventual::Async;

use std::any::Any;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Sender};
use std::time::Duration;

use robots::actors::{Actor, ActorSystem, ActorCell, ActorContext, ActorRef, Props};

#[derive(Debug, PartialEq)]
enum Res {
    Ok,
    Err,
}

#[derive(Copy, Clone)]
enum InternalStateMessage {
    Set(u32),
    Get,
    Panic,
}

struct InternalState {
    last: Mutex<u32>,
    sender: Arc<Mutex<Sender<Res>>>,
}

impl Actor for InternalState {
    fn receive(&self, message: Box<Any>, context: ActorCell) {
        if let Ok(message) = Box::<Any>::downcast::<InternalStateMessage>(message) {
            match *message {
                InternalStateMessage::Get => {
                    context.tell(context.sender(), *self.last.lock().unwrap())
                }
                InternalStateMessage::Set(message) => {
                    // Here mixing the test actor for the two tests might seem a bit weird,
                    // but we would get two very similar actors otherwise.
                    let mut last = self.last.lock().unwrap();
                    if message <= *last {
                        let _ = self.sender.lock().unwrap().send(Res::Err);
                    } else {
                        *last = message;
                    }
                    if *last == 1000 {
                        let _ = self.sender.lock().unwrap().send(Res::Ok);
                    }
                }
                InternalStateMessage::Panic => panic!(""),
            }
        }
    }
}

impl InternalState {
    fn new(sender: Arc<Mutex<Sender<Res>>>) -> InternalState {
        InternalState {
            last: Mutex::new(0),
            sender: sender,
        }
    }
}

#[test]
fn read_messages_in_order() {
    let actor_system = ActorSystem::new("test".to_owned());
    actor_system.spawn_threads(9);

    let (tx, rx) = channel();
    let tx = Arc::new(Mutex::new(tx));

    let props = Props::new(Arc::new(InternalState::new), tx);
    let actor_ref_1 = actor_system.actor_of(props.clone(), "sender".to_owned());
    let actor_ref_2 = actor_system.actor_of(props.clone(), "receiver".to_owned());

    for i in 1..1001 {
        actor_ref_1.tell_to(actor_ref_2.clone(), InternalStateMessage::Set(i as u32));
    }

    let res = rx.recv();
    assert_eq!(Ok(Res::Ok), res);

    actor_system.shutdown();
}

#[test]
fn recover_from_panic() {
    let actor_system = ActorSystem::new("test".to_owned());
    actor_system.spawn_threads(1);

    let (tx, _rx) = channel();
    let tx = Arc::new(Mutex::new(tx));

    let props = Props::new(Arc::new(InternalState::new), tx);
    let requester = actor_system.actor_of(props.clone(), "sender".to_owned());
    let answerer = actor_system.actor_of(props.clone(), "receiver".to_owned());

    requester.tell_to(answerer.clone(), InternalStateMessage::Set(10));
    let res = answerer.ask(InternalStateMessage::Get).await().unwrap();
    let res = Box::<Any>::downcast::<u32>(res).unwrap();
    assert_eq!(10u32, *res);

    requester.tell_to(answerer.clone(), InternalStateMessage::Panic);
    let res = answerer.ask(InternalStateMessage::Get).await().unwrap();
    let res = Box::<Any>::downcast::<u32>(res).unwrap();
    assert_eq!(0u32, *res);

    actor_system.shutdown();
}

struct Resolver;

impl Actor for Resolver {
    fn receive(&self, message: Box<Any>, context: ActorCell) {
        if let Ok(message) = Box::<Any>::downcast::<String>(message) {
            let res = context.identify_actor(*message)
                             .await()
                             .unwrap();
            context.tell(context.sender(), res);
        }
    }
}

impl Resolver {
    fn new(_dummy: ()) -> Resolver {
        Resolver
    }
}

#[test]
fn resolve_name_real_path() {
    let actor_system = ActorSystem::new("test".to_owned());
    actor_system.spawn_threads(2);

    let props = Props::new(Arc::new(Resolver::new), ());
    let answerer = actor_system.actor_of(props.clone(), "answerer".to_owned());
    let requester = actor_system.actor_of(props.clone(), "sender".to_owned());

    // We wait to be sure that the actors will be registered to the name resolver.
    std::thread::sleep(Duration::from_millis(100));

    let res = answerer.ask("/user/sender".to_owned()).await().unwrap();
    let res = Box::<Any>::downcast::<Option<ActorRef>>(res).unwrap();
    assert_eq!(requester.path(), (*res).unwrap().path());

    actor_system.shutdown();
}

#[test]
fn resolve_name_fake_path() {
    let actor_system = ActorSystem::new("test".to_owned());
    actor_system.spawn_threads(2);

    let props = Props::new(Arc::new(Resolver::new), ());
    let answerer = actor_system.actor_of(props.clone(), "answerer".to_owned());

    // We wait to be sure that the actors will be registered to the name resolver.
    std::thread::sleep(Duration::from_millis(100));

    let res = answerer.ask("/foo/bar".to_owned()).await().unwrap();
    let res = *Box::<Any>::downcast::<Option<ActorRef>>(res).unwrap();

    match res {
        None => {}
        Some(_) => panic!("The name resolver gave an ActorRef when he should not."),
    };

    actor_system.shutdown();
}

// This actor simply answers twice with () when send a message.
// He also sends () through a channel when restarted.
struct DoubleAnswer {
    sender: Arc<Mutex<Sender<()>>>,
}

impl Actor for DoubleAnswer {
    fn post_restart(&self, _context: ActorCell) {
        let mut sender = self.sender.lock().unwrap();
        sender.send(());
    }

    fn receive(&self, _message: Box<Any>, context: ActorCell) {
        context.tell(context.sender(), ());
        context.tell(context.sender(), ());
    }
}

impl DoubleAnswer {
    fn new(sender: Arc<Mutex<Sender<()>>>) -> DoubleAnswer {
        DoubleAnswer {
            sender: sender
        }
    }
}

#[test]
fn ask_answer_twice() {
    let actor_system = ActorSystem::new("test".to_owned());

    let (tx, rx) = channel();
    let tx = Arc::new(Mutex::new(tx));

    let props = Props::new(Arc::new(DoubleAnswer::new), tx);
    let answerer = actor_system.actor_of(props.clone(), "answerer".to_owned());

    let res = answerer.ask(()).await().unwrap();
    let res = *Box::<Any>::downcast::<()>(res).unwrap();
    // We chack that the value contained in the future is the correct one.
    assert_eq!(res, ());

    // We check that the actor has been restarted because of a panic (reason is not caught yet).
    let res = rx.recv();
    assert_eq!(res, Ok(()));

    std::thread::sleep(Duration::from_millis(10));

    actor_system.shutdown();
}

// This actor simply answers twice with () when send a message.
// He also sends () through a channel when restarted.
struct DoubleAnswer {
    sender: Arc<Mutex<Sender<()>>>,
}

impl Actor for DoubleAnswer {
    fn post_restart(&self, _context: ActorCell) {
        let mut sender = self.sender.lock().unwrap();
        sender.send(());
    }

    fn receive(&self, _message: Box<Any>, context: ActorCell) {
        context.tell(context.sender(), ());
        context.tell(context.sender(), ());
    }
}

impl DoubleAnswer {
    fn new(sender: Arc<Mutex<Sender<()>>>) -> DoubleAnswer {
        DoubleAnswer {
            sender: sender
        }
    }
}

#[test]
fn ask_answer_twice() {
    let actor_system = ActorSystem::new("test".to_owned());

    let (tx, rx) = channel();
    let tx = Arc::new(Mutex::new(tx));

    let props = Props::new(Arc::new(DoubleAnswer::new), tx);
    let answerer = actor_system.actor_of(props.clone(), "answerer".to_owned());

    let res = answerer.ask(()).await().unwrap();
    let res = *Box::<Any>::downcast::<()>(res).unwrap();
    // We chack that the value contained in the future is the correct one.
    assert_eq!(res, ());

    // We check that the actor has been restarted because of a panic (reason is not caught yet).
    let res = rx.recv();
    assert_eq!(res, Ok(()));

    std::thread::sleep(Duration::from_millis(10));

    actor_system.shutdown();
}
<|endoftext|>