<commit_before>
use wtest_basic::*;

#[cfg( feature = "in_wtools" )]
use wtools::string as TheModule;
#[cfg( not( feature = "in_wtools" ) )]
use wstring_tools as TheModule;

use TheModule::string::parse as parse;
use std::collections::HashMap;

//

fn _op_type_from_into()
{
  let got = parse::OpType::from( 1 );
  let exp = parse::OpType::Primitive( 1 );
  assert_eq!( got, exp );

  let got = parse::OpType::from( vec![ 1, 2 ] );
  let exp = parse::OpType::Vector( vec![ 1, 2 ] );
  assert_eq!( got, exp );

  /* */

  // let op = parse::OpType::from( 1 ); /* qqq : does not work properly, find better way to convert types */
  // let got : i32 = op.into();
  // assert_eq!( got, 1 );

  let op = parse::OpType::from( vec![ 1, 2 ] );
  let got : Vec<isize> = op.into();
  assert_eq!( got, vec![ 1, 2 ] );
}

//

fn _basic()
{
  let src = "";
  let req = TheModule::string::request_parse()
  .src( src )
  .perform();
  let mut exp = parse::Request::default();
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  let src = " ";
  let req = TheModule::string::request_parse()
  .src( src )
  .perform();
  let mut exp = parse::Request::default();
  exp.original = " ";
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  let src = "  \t ";
  let req = TheModule::string::request_parse()
  .src( src )
  .perform();
  let mut exp = parse::Request::default();
  exp.original = "  \t ";
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );
}

//

fn _with_subject_and_map()
{
  let src = "subj";
  let req = TheModule::string::request_parse()
  .src( src )
  .perform();
  let mut exp = parse::Request::default();
  exp.original = "subj";
  exp.subject = "subj".to_string();
  exp.subjects = vec![ "subj".to_string() ];
  exp.maps = vec![ HashMap::new() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  let src = "subj with space";
  let req = TheModule::string::request_parse()
  .src( src )
  .perform();
  let mut exp = parse::Request::default();
  exp.original = "subj with space";
  exp.subject = "subj with space".to_string();
  exp.subjects = vec![ "subj with space".to_string() ];
  exp.maps = vec![ HashMap::new() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  let src = "subj v:1";
  let req = TheModule::string::request_parse()
  .src( src )
  .perform();
  let mut options = HashMap::new();
  options.insert( String::from( "v" ), parse::OpType::Primitive( String::from( "1" ) ) );
  let mut exp = parse::Request::default();
  exp.original = "subj v:1";
  exp.subject = "subj".to_string();
  exp.subjects = vec![ "subj".to_string() ];
  exp.map = options.clone();
  exp.maps = vec![ options.clone() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  let src = "subj v:1 r:some";
  let req = TheModule::string::request_parse()
  .src( src )
  .perform();
  let mut options = HashMap::new();
  options.insert( String::from( "v" ), parse::OpType::Primitive( String::from( "1" ) ) );
  options.insert( String::from( "r" ), parse::OpType::Primitive( String::from( "some" ) ) );
  let mut exp = parse::Request::default();
  exp.original = "subj v:1 r:some";
  exp.subject = "subj".to_string();
  exp.subjects = vec![ "subj".to_string() ];
  exp.map = options.clone();
  exp.maps = vec![ options.clone() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  /* */

  let src = "subj1 ; subj2";
  let req = TheModule::string::request_parse()
  .src( src )
  .perform();
  let mut exp = parse::Request::default();
  exp.original = "subj1 ; subj2";
  exp.subject = "subj1".to_string();
  exp.subjects = vec![ "subj1".to_string(), "subj2".to_string() ];
  exp.maps = vec![ HashMap::new(), HashMap::new() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  let src = "subj1 v:1 ; subj2";
  let req = TheModule::string::request_parse()
  .src( src )
  .perform();
  let mut options = HashMap::new();
  options.insert( String::from( "v" ), parse::OpType::Primitive( String::from( "1" ) ) );
  let mut exp = parse::Request::default();
  exp.original = "subj1 v:1 ; subj2";
  exp.subject = "subj1".to_string();
  exp.subjects = vec![ "subj1".to_string(), "subj2".to_string() ];
  exp.map = options.clone();
  exp.maps = vec![ options.clone(), HashMap::new() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  let src = "subj1 v:1 ; subj2 v:2";
  let req = TheModule::string::request_parse()
  .src( src )
  .perform();
  let mut options1 = HashMap::new();
  options1.insert( String::from( "v" ), parse::OpType::Primitive( String::from( "1" ) ) );
  let mut options2 = HashMap::new();
  options2.insert( String::from( "v" ), parse::OpType::Primitive( String::from( "2" ) ) );
  let mut exp = parse::Request::default();
  exp.original = "subj1 v:1 ; subj2 v:2";
  exp.subject = "subj1".to_string();
  exp.subjects = vec![ "subj1".to_string(), "subj2".to_string() ];
  exp.map = options1.clone();
  exp.maps = vec![ options1.clone(), options2.clone() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  let src = "subj1 v:1 ne:-2 ; subj2 v:2 r:some";
  let req = TheModule::string::request_parse()
  .src( src )
  .perform();
  let mut options1 = HashMap::new();
  options1.insert( String::from( "v" ), parse::OpType::Primitive( String::from( "1" ) ) );
  options1.insert( String::from( "ne" ), parse::OpType::Primitive( String::from( "-2" ) ) );
  let mut options2 = HashMap::new();
  options2.insert( String::from( "v" ), parse::OpType::Primitive( String::from( "2" ) ) );
  options2.insert( String::from( "r" ), parse::OpType::Primitive( String::from( "some" ) ) );
  let mut exp = parse::Request::default();
  exp.original = "subj1 v:1 ne:-2 ; subj2 v:2 r:some";
  exp.subject = "subj1".to_string();
  exp.subjects = vec![ "subj1".to_string(), "subj2".to_string() ];
  exp.map = options1.clone();
  exp.maps = vec![ options1.clone(), options2.clone() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );
}

//

fn _with_several_values()
{
  let src = "subj v:1 v:2";
  let req = TheModule::string::request_parse()
  .src( src )
  .several_values( false )
  .perform();
  let mut options = HashMap::new();
  options.insert( String::from( "v" ), parse::OpType::Primitive( "2".to_string() ) );
  let mut exp = parse::Request::default();
  exp.original = "subj v:1 v:2";
  exp.subject = "subj".to_string();
  exp.subjects = vec![ "subj".to_string() ];
  exp.map = options.clone();
  exp.maps = vec![ options.clone() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  let src = "subj v:1 v:2";
  let req = TheModule::string::request_parse()
  .src( src )
  .several_values( true )
  .perform();
  let mut options = HashMap::new();
  options.insert( String::from( "v" ), parse::OpType::Vector( vec![ "1".to_string(), "2".to_string() ] ) );
  let mut exp = parse::Request::default();
  exp.original = "subj v:1 v:2";
  exp.subject = "subj".to_string();
  exp.subjects = vec![ "subj".to_string() ];
  exp.map = options.clone();
  exp.maps = vec![ options.clone() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );
}

//

fn _with_parsing_arrays()
{
  let src = "subj v:[1,2]";
  let req = TheModule::string::request_parse()
  .src( src )
  .parsing_arrays( false )
  .perform();
  let mut options = HashMap::new();
  options.insert( String::from( "v" ), parse::OpType::Primitive( "[1,2]".to_string() ) );
  let mut exp = parse::Request::default();
  exp.original = "subj v:[1,2]";
  exp.subject = "subj".to_string();
  exp.subjects = vec![ "subj".to_string() ];
  exp.map = options.clone();
  exp.maps = vec![ options.clone() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  let src = "subj v:[1,2]";
  let req = TheModule::string::request_parse()
  .src( src )
  .parsing_arrays( true )
  .perform();
  let mut options = HashMap::new();
  options.insert( String::from( "v" ), parse::OpType::Vector( vec![ "1".to_string(), "2".to_string() ] ) );
  let mut exp = parse::Request::default();
  exp.original = "subj v:[1,2]";
  exp.subject = "subj".to_string();
  exp.subjects = vec![ "subj".to_string() ];
  exp.map = options.clone();
  exp.maps = vec![ options.clone() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  /* */

  let src = "subj v:[1,2] v:3";
  let req = TheModule::string::request_parse()
  .src( src )
  .parsing_arrays( true )
  .several_values( true )
  .perform();
  let mut options = HashMap::new();
  options.insert( String::from( "v" ), parse::OpType::Vector( vec![ "1".to_string(), "2".to_string(), "3".to_string() ] ) );
  let mut exp = parse::Request::default();
  exp.original = "subj v:[1,2] v:3";
  exp.subject = "subj".to_string();
  exp.subjects = vec![ "subj".to_string() ];
  exp.map = options.clone();
  exp.maps = vec![ options.clone() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  let src = "subj v:3 v:[1,2]";
  let req = TheModule::string::request_parse()
  .src( src )
  .parsing_arrays( true )
  .several_values( true )
  .perform();
  let mut options = HashMap::new();
  options.insert( String::from( "v" ), parse::OpType::Vector( vec![ "3".to_string(), "1".to_string(), "2".to_string() ] ) );
  let mut exp = parse::Request::default();
  exp.original = "subj v:3 v:[1,2]";
  exp.subject = "subj".to_string();
  exp.subjects = vec![ "subj".to_string() ];
  exp.map = options.clone();
  exp.maps = vec![ options.clone() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  let src = "subj v:[1,2] v:[3,4]";
  let req = TheModule::string::request_parse()
  .src( src )
  .parsing_arrays( true )
  .several_values( true )
  .perform();
  let mut options = HashMap::new();
  options.insert( String::from( "v" ), parse::OpType::Vector( vec![ "1".to_string(), "2".to_string(), "3".to_string(), "4".to_string() ] ) );
  let mut exp = parse::Request::default();
  exp.original = "subj v:[1,2] v:[3,4]";
  exp.subject = "subj".to_string();
  exp.subjects = vec![ "subj".to_string() ];
  exp.map = options.clone();
  exp.maps = vec![ options.clone() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );
}

//

test_suite!
{
  op_type_from_into,
  basic,
  with_subject_and_map,
  with_several_values,
  with_parsing_arrays,
}
<commit_msg>Extend test routine `op_type_from_into`, add cases with conversion of primitives and vectors<commit_after>
use wtest_basic::*;

#[cfg( feature = "in_wtools" )]
use wtools::string as TheModule;
#[cfg( not( feature = "in_wtools" ) )]
use wstring_tools as TheModule;

use TheModule::string::parse as parse;
use std::collections::HashMap;

//

fn _op_type_from_into()
{
  let got = parse::OpType::from( 1 );
  let exp = parse::OpType::Primitive( 1 );
  assert_eq!( got, exp );

  let got = parse::OpType::from( vec![ 1, 2 ] );
  let exp = parse::OpType::Vector( vec![ 1, 2 ] );
  assert_eq!( got, exp );

  /* */

  let op = parse::OpType::from( vec![ 1, 2 ] );
  let got : Vec<isize> = op.into();
  assert_eq!( got, vec![ 1, 2 ] );

  /* */

  let op = parse::OpType::from( 1 );
  let got = op.primitive(); /* qqq : does not work properly, find better way to convert types */
  assert_eq!( got.unwrap(), 1 );

  let op = parse::OpType::from( vec![ 1, 2 ] );
  let got : Vec<isize> = op.vector().unwrap();
  assert_eq!( got, vec![ 1, 2 ] );

  let op = parse::OpType::from( 1 );
  let got = op.vector();
  assert_eq!( got, None );

  let op : parse::OpType<usize> = parse::OpType::from( vec![ 1, 2 ] );
  let got = op.primitive();
  assert_eq!( got, None );
}

//

fn _basic()
{
  let src = "";
  let req = TheModule::string::request_parse()
  .src( src )
  .perform();
  let mut exp = parse::Request::default();
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  let src = " ";
  let req = TheModule::string::request_parse()
  .src( src )
  .perform();
  let mut exp = parse::Request::default();
  exp.original = " ";
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  let src = "  \t ";
  let req = TheModule::string::request_parse()
  .src( src )
  .perform();
  let mut exp = parse::Request::default();
  exp.original = "  \t ";
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );
}

//

fn _with_subject_and_map()
{
  let src = "subj";
  let req = TheModule::string::request_parse()
  .src( src )
  .perform();
  let mut exp = parse::Request::default();
  exp.original = "subj";
  exp.subject = "subj".to_string();
  exp.subjects = vec![ "subj".to_string() ];
  exp.maps = vec![ HashMap::new() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  let src = "subj with space";
  let req = TheModule::string::request_parse()
  .src( src )
  .perform();
  let mut exp = parse::Request::default();
  exp.original = "subj with space";
  exp.subject = "subj with space".to_string();
  exp.subjects = vec![ "subj with space".to_string() ];
  exp.maps = vec![ HashMap::new() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  let src = "subj v:1";
  let req = TheModule::string::request_parse()
  .src( src )
  .perform();
  let mut options = HashMap::new();
  options.insert( String::from( "v" ), parse::OpType::Primitive( String::from( "1" ) ) );
  let mut exp = parse::Request::default();
  exp.original = "subj v:1";
  exp.subject = "subj".to_string();
  exp.subjects = vec![ "subj".to_string() ];
  exp.map = options.clone();
  exp.maps = vec![ options.clone() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  let src = "subj v:1 r:some";
  let req = TheModule::string::request_parse()
  .src( src )
  .perform();
  let mut options = HashMap::new();
  options.insert( String::from( "v" ), parse::OpType::Primitive( String::from( "1" ) ) );
  options.insert( String::from( "r" ), parse::OpType::Primitive( String::from( "some" ) ) );
  let mut exp = parse::Request::default();
  exp.original = "subj v:1 r:some";
  exp.subject = "subj".to_string();
  exp.subjects = vec![ "subj".to_string() ];
  exp.map = options.clone();
  exp.maps = vec![ options.clone() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  /* */

  let src = "subj1 ; subj2";
  let req = TheModule::string::request_parse()
  .src( src )
  .perform();
  let mut exp = parse::Request::default();
  exp.original = "subj1 ; subj2";
  exp.subject = "subj1".to_string();
  exp.subjects = vec![ "subj1".to_string(), "subj2".to_string() ];
  exp.maps = vec![ HashMap::new(), HashMap::new() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  let src = "subj1 v:1 ; subj2";
  let req = TheModule::string::request_parse()
  .src( src )
  .perform();
  let mut options = HashMap::new();
  options.insert( String::from( "v" ), parse::OpType::Primitive( String::from( "1" ) ) );
  let mut exp = parse::Request::default();
  exp.original = "subj1 v:1 ; subj2";
  exp.subject = "subj1".to_string();
  exp.subjects = vec![ "subj1".to_string(), "subj2".to_string() ];
  exp.map = options.clone();
  exp.maps = vec![ options.clone(), HashMap::new() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  let src = "subj1 v:1 ; subj2 v:2";
  let req = TheModule::string::request_parse()
  .src( src )
  .perform();
  let mut options1 = HashMap::new();
  options1.insert( String::from( "v" ), parse::OpType::Primitive( String::from( "1" ) ) );
  let mut options2 = HashMap::new();
  options2.insert( String::from( "v" ), parse::OpType::Primitive( String::from( "2" ) ) );
  let mut exp = parse::Request::default();
  exp.original = "subj1 v:1 ; subj2 v:2";
  exp.subject = "subj1".to_string();
  exp.subjects = vec![ "subj1".to_string(), "subj2".to_string() ];
  exp.map = options1.clone();
  exp.maps = vec![ options1.clone(), options2.clone() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  let src = "subj1 v:1 ne:-2 ; subj2 v:2 r:some";
  let req = TheModule::string::request_parse()
  .src( src )
  .perform();
  let mut options1 = HashMap::new();
  options1.insert( String::from( "v" ), parse::OpType::Primitive( String::from( "1" ) ) );
  options1.insert( String::from( "ne" ), parse::OpType::Primitive( String::from( "-2" ) ) );
  let mut options2 = HashMap::new();
  options2.insert( String::from( "v" ), parse::OpType::Primitive( String::from( "2" ) ) );
  options2.insert( String::from( "r" ), parse::OpType::Primitive( String::from( "some" ) ) );
  let mut exp = parse::Request::default();
  exp.original = "subj1 v:1 ne:-2 ; subj2 v:2 r:some";
  exp.subject = "subj1".to_string();
  exp.subjects = vec![ "subj1".to_string(), "subj2".to_string() ];
  exp.map = options1.clone();
  exp.maps = vec![ options1.clone(), options2.clone() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );
}

//

fn _with_several_values()
{
  let src = "subj v:1 v:2";
  let req = TheModule::string::request_parse()
  .src( src )
  .several_values( false )
  .perform();
  let mut options = HashMap::new();
  options.insert( String::from( "v" ), parse::OpType::Primitive( "2".to_string() ) );
  let mut exp = parse::Request::default();
  exp.original = "subj v:1 v:2";
  exp.subject = "subj".to_string();
  exp.subjects = vec![ "subj".to_string() ];
  exp.map = options.clone();
  exp.maps = vec![ options.clone() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  let src = "subj v:1 v:2";
  let req = TheModule::string::request_parse()
  .src( src )
  .several_values( true )
  .perform();
  let mut options = HashMap::new();
  options.insert( String::from( "v" ), parse::OpType::Vector( vec![ "1".to_string(), "2".to_string() ] ) );
  let mut exp = parse::Request::default();
  exp.original = "subj v:1 v:2";
  exp.subject = "subj".to_string();
  exp.subjects = vec![ "subj".to_string() ];
  exp.map = options.clone();
  exp.maps = vec![ options.clone() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );
}

//

fn _with_parsing_arrays()
{
  let src = "subj v:[1,2]";
  let req = TheModule::string::request_parse()
  .src( src )
  .parsing_arrays( false )
  .perform();
  let mut options = HashMap::new();
  options.insert( String::from( "v" ), parse::OpType::Primitive( "[1,2]".to_string() ) );
  let mut exp = parse::Request::default();
  exp.original = "subj v:[1,2]";
  exp.subject = "subj".to_string();
  exp.subjects = vec![ "subj".to_string() ];
  exp.map = options.clone();
  exp.maps = vec![ options.clone() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  let src = "subj v:[1,2]";
  let req = TheModule::string::request_parse()
  .src( src )
  .parsing_arrays( true )
  .perform();
  let mut options = HashMap::new();
  options.insert( String::from( "v" ), parse::OpType::Vector( vec![ "1".to_string(), "2".to_string() ] ) );
  let mut exp = parse::Request::default();
  exp.original = "subj v:[1,2]";
  exp.subject = "subj".to_string();
  exp.subjects = vec![ "subj".to_string() ];
  exp.map = options.clone();
  exp.maps = vec![ options.clone() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  /* */

  let src = "subj v:[1,2] v:3";
  let req = TheModule::string::request_parse()
  .src( src )
  .parsing_arrays( true )
  .several_values( true )
  .perform();
  let mut options = HashMap::new();
  options.insert( String::from( "v" ), parse::OpType::Vector( vec![ "1".to_string(), "2".to_string(), "3".to_string() ] ) );
  let mut exp = parse::Request::default();
  exp.original = "subj v:[1,2] v:3";
  exp.subject = "subj".to_string();
  exp.subjects = vec![ "subj".to_string() ];
  exp.map = options.clone();
  exp.maps = vec![ options.clone() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  let src = "subj v:3 v:[1,2]";
  let req = TheModule::string::request_parse()
  .src( src )
  .parsing_arrays( true )
  .several_values( true )
  .perform();
  let mut options = HashMap::new();
  options.insert( String::from( "v" ), parse::OpType::Vector( vec![ "3".to_string(), "1".to_string(), "2".to_string() ] ) );
  let mut exp = parse::Request::default();
  exp.original = "subj v:3 v:[1,2]";
  exp.subject = "subj".to_string();
  exp.subjects = vec![ "subj".to_string() ];
  exp.map = options.clone();
  exp.maps = vec![ options.clone() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );

  let src = "subj v:[1,2] v:[3,4]";
  let req = TheModule::string::request_parse()
  .src( src )
  .parsing_arrays( true )
  .several_values( true )
  .perform();
  let mut options = HashMap::new();
  options.insert( String::from( "v" ), parse::OpType::Vector( vec![ "1".to_string(), "2".to_string(), "3".to_string(), "4".to_string() ] ) );
  let mut exp = parse::Request::default();
  exp.original = "subj v:[1,2] v:[3,4]";
  exp.subject = "subj".to_string();
  exp.subjects = vec![ "subj".to_string() ];
  exp.map = options.clone();
  exp.maps = vec![ options.clone() ];
  exp.key_val_delimeter = ":";
  exp.commands_delimeter = ";";
  assert_eq!( req, exp );
}

//

test_suite!
{
  op_type_from_into,
  basic,
  with_subject_and_map,
  with_several_values,
  with_parsing_arrays,
}
<|endoftext|>


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

extern crate serde_json;
extern crate collections;

use self::collections::vec::IntoIter;
use service::Service;
use std::collections::HashMap;
use std::io::Error;
use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::sync::{ Arc, Mutex };

// The `global` context available to all.
pub struct Context {
    pub verbose: bool,

    hostname: String,
    http_port: u16,
    ws_port: u16,
    services: HashMap<String, Box<Service>>
}

const DEFAULT_HTTP_PORT: u16 = 3000;
const DEFAULT_WS_PORT: u16 = 4000;
const DEFAULT_HOSTNAME: &'static str = "localhost";

pub type SharedContext = Arc<Mutex<Context>>;

impl Context {
    pub fn new(verbose: bool, hostname: Option<String>) -> Context {
        Context { services: HashMap::new(),
                  verbose: verbose,
                  hostname:  hostname.unwrap_or(DEFAULT_HOSTNAME.to_string()),
                  http_port: DEFAULT_HTTP_PORT,
                  ws_port: DEFAULT_WS_PORT }
    }

    pub fn shared(verbose: bool, hostname: Option<String>) -> SharedContext {
        Arc::new(Mutex::new(Context::new(verbose, hostname)))
    }

    pub fn add_service(&mut self, service: Box<Service>) {
        let service_id = service.get_properties().id;
        self.services.insert(service_id, service);
    }

    pub fn remove_service(&mut self, id: String) {
        self.services.remove(&id);
    }

    pub fn services_count(&self) -> usize {
        self.services.len()
    }

    pub fn get_service(&self, id: &str) -> Option<&Box<Service>> {
        self.services.get(id)
    }

    pub fn services_as_json(&self) -> Result<String, serde_json::error::Error> {
        serde_json::to_string(&self.services)
    }

    pub fn get_http_root_for_service(&self, service_id: String) -> String {
        format!("http://{}:{}/services/{}/", self.hostname, self.http_port, service_id)
    }

    pub fn get_ws_root_for_service(&self, service_id: String) -> String {
        format!("ws://{}:{}/services/{}/", self.hostname, self.ws_port, service_id)
    }

    pub fn http_as_addrs(&self) -> Result<IntoIter<SocketAddr>, Error> {
        (self.hostname.as_str(), self.http_port).to_socket_addrs()
    }
}
<commit_msg>Add first (ugly) unit test<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate serde_json;
extern crate collections;

use self::collections::vec::IntoIter;
use service::Service;
use std::collections::HashMap;
use std::io::Error;
use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::sync::{ Arc, Mutex };

// The `global` context available to all.
pub struct Context {
    pub verbose: bool,

    hostname: String,
    http_port: u16,
    ws_port: u16,
    services: HashMap<String, Box<Service>>
}

const DEFAULT_HTTP_PORT: u16 = 3000;
const DEFAULT_WS_PORT: u16 = 4000;
const DEFAULT_HOSTNAME: &'static str = "localhost";

pub type SharedContext = Arc<Mutex<Context>>;

impl Context {
    pub fn new(verbose: bool, hostname: Option<String>) -> Context {
        Context { services: HashMap::new(),
                  verbose: verbose,
                  hostname:  hostname.unwrap_or(DEFAULT_HOSTNAME.to_string()),
                  http_port: DEFAULT_HTTP_PORT,
                  ws_port: DEFAULT_WS_PORT }
    }

    pub fn shared(verbose: bool, hostname: Option<String>) -> SharedContext {
        Arc::new(Mutex::new(Context::new(verbose, hostname)))
    }

    pub fn add_service(&mut self, service: Box<Service>) {
        let service_id = service.get_properties().id;
        self.services.insert(service_id, service);
    }

    pub fn remove_service(&mut self, id: String) {
        self.services.remove(&id);
    }

    pub fn services_count(&self) -> usize {
        self.services.len()
    }

    pub fn get_service(&self, id: &str) -> Option<&Box<Service>> {
        self.services.get(id)
    }

    pub fn services_as_json(&self) -> Result<String, serde_json::error::Error> {
        serde_json::to_string(&self.services)
    }

    pub fn get_http_root_for_service(&self, service_id: String) -> String {
        format!("http://{}:{}/services/{}/", self.hostname, self.http_port, service_id)
    }

    pub fn get_ws_root_for_service(&self, service_id: String) -> String {
        format!("ws://{}:{}/services/{}/", self.hostname, self.ws_port, service_id)
    }

    pub fn http_as_addrs(&self) -> Result<IntoIter<SocketAddr>, Error> {
        (self.hostname.as_str(), self.http_port).to_socket_addrs()
    }
}

#[test]
#[allow(unused_variables)]
fn test_should_add_a_service() {
    use service::{ Service, ServiceProperties };
    use iron::{Request, Response, IronResult};

    struct ServiceStub;

    impl Service for ServiceStub {
        fn get_properties(&self) -> ServiceProperties {
            ServiceProperties {
                id: '1'.to_string(),
                name: "dummy service".to_string(),
                description: "really nothing to see".to_string(),
                http_url: '2'.to_string(),
                ws_url: '3'.to_string()
            }
        }
        fn start(&self)  {}
        fn stop(&self) {}
        fn process_request(&self, req: &Request) -> IronResult<Response> {
            return Ok(Response::new());
        }
    }

    let service = ServiceStub;
    let mut foo = Context::new(false, Some("localhost".to_owned()));

    assert_eq!(foo.services.is_empty(), true);
    foo.add_service(Box::new(service));
    assert_eq!(foo.services.is_empty(), false);
}
<|endoftext|>


<commit_before>// Copyright 2015 The tiny-http Contributors
// Copyright 2015 The rust-chunked-transfer Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::error::Error;
use std::fmt;
use std::io::Error as IoError;
use std::io::ErrorKind;
use std::io::Read;
use std::io::Result as IoResult;

/// Reads HTTP chunks and sends back real data.
///
/// # Example
///
/// ```
/// use chunked_transfer::Decoder;
/// use std::io::Read;
///
/// let encoded = b"3\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n\r\n";
/// let mut decoded = String::new();
///
/// let mut decoder = Decoder::new(encoded as &[u8]);
/// decoder.read_to_string(&mut decoded);
///
/// assert_eq!(decoded, "hello world!!!");
/// ```
pub struct Decoder<R> {
    // where the chunks come from
    source: R,

    // remaining size of the chunk being read
    // none if we are not in a chunk
    remaining_chunks_size: Option<usize>,
}

impl<R> Decoder<R>
where
    R: Read,
{
    pub fn new(source: R) -> Decoder<R> {
        Decoder {
            source,
            remaining_chunks_size: None,
        }
    }

    /// Unwraps the Decoder into its inner `Read` source.
    pub fn into_inner(self) -> R {
        self.source
    }

    fn read_chunk_size(&mut self) -> IoResult<usize> {
        let mut chunk_size_bytes = Vec::new();
        let mut has_ext = false;

        loop {
            let byte = match self.source.by_ref().bytes().next() {
                Some(b) => b?,
                None => return Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
            };

            if byte == b'\r' {
                break;
            }

            if byte == b';' {
                has_ext = true;
                break;
            }

            chunk_size_bytes.push(byte);
        }

        // Ignore extensions for now
        if has_ext {
            loop {
                let byte = match self.source.by_ref().bytes().next() {
                    Some(b) => b?,
                    None => return Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
                };
                if byte == b'\r' {
                    break;
                }
            }
        }

        self.read_line_feed()?;

        let chunk_size = String::from_utf8(chunk_size_bytes)
            .ok()
            .and_then(|c| usize::from_str_radix(c.trim(), 16).ok())
            .ok_or(IoError::new(ErrorKind::InvalidInput, DecoderError))?;

        Ok(chunk_size)
    }

    fn read_carriage_return(&mut self) -> IoResult<()> {
        match self.source.by_ref().bytes().next() {
            Some(Ok(b'\r')) => Ok(()),
            _ => Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
        }
    }

    fn read_line_feed(&mut self) -> IoResult<()> {
        match self.source.by_ref().bytes().next() {
            Some(Ok(b'\n')) => Ok(()),
            _ => Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
        }
    }
}

impl<R> Read for Decoder<R>
where
    R: Read,
{
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        let remaining_chunks_size = match self.remaining_chunks_size {
            Some(c) => c,
            None => {
                // first possibility: we are not in a chunk, so we'll attempt to determine
                // the chunks size
                let chunk_size = self.read_chunk_size()?;

                // if the chunk size is 0, we are at EOF
                if chunk_size == 0 {
                    self.read_carriage_return()?;
                    self.read_line_feed()?;
                    return Ok(0);
                }

                chunk_size
            }
        };

        // second possibility: we continue reading from a chunk
        if buf.len() < remaining_chunks_size {
            let read = self.source.read(buf)?;
            self.remaining_chunks_size = Some(remaining_chunks_size - read);
            return Ok(read);
        }

        // third possibility: the read request goes further than the current chunk
        // we simply read until the end of the chunk and return
        assert!(buf.len() >= remaining_chunks_size);

        let buf = &mut buf[..remaining_chunks_size];
        let read = self.source.read(buf)?;

        self.remaining_chunks_size = if read == remaining_chunks_size {
            self.read_carriage_return()?;
            self.read_line_feed()?;
            None
        } else {
            Some(remaining_chunks_size - read)
        };

        Ok(read)
    }
}

#[derive(Debug, Copy, Clone)]
struct DecoderError;

impl fmt::Display for DecoderError {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        write!(fmt, "Error while decoding chunks")
    }
}

impl Error for DecoderError {
    fn description(&self) -> &str {
        "Error while decoding chunks"
    }
}

#[cfg(test)]
mod test {
    use super::Decoder;
    use std::io;
    use std::io::Read;

    /// This unit test is taken from from Hyper
    /// https://github.com/hyperium/hyper
    /// Copyright (c) 2014 Sean McArthur
    #[test]
    fn test_read_chunk_size() {
        fn read(s: &str, expected: usize) {
            let mut decoded = Decoder::new(s.as_bytes());
            let actual = decoded.read_chunk_size().unwrap();
            assert_eq!(expected, actual);
        }

        fn read_err(s: &str) {
            let mut decoded = Decoder::new(s.as_bytes());
            let err_kind = decoded.read_chunk_size().unwrap_err().kind();
            assert_eq!(err_kind, io::ErrorKind::InvalidInput);
        }

        read("1\r\n", 1);
        read("01\r\n", 1);
        read("0\r\n", 0);
        read("00\r\n", 0);
        read("A\r\n", 10);
        read("a\r\n", 10);
        read("Ff\r\n", 255);
        read("Ff   \r\n", 255);
        // Missing LF or CRLF
        read_err("F\rF");
        read_err("F");
        // Invalid hex digit
        read_err("X\r\n");
        read_err("1X\r\n");
        read_err("-\r\n");
        read_err("-1\r\n");
        // Acceptable (if not fully valid) extensions do not influence the size
        read("1;extension\r\n", 1);
        read("a;ext name=value\r\n", 10);
        read("1;extension;extension2\r\n", 1);
        read("1;;;  ;\r\n", 1);
        read("2; extension...\r\n", 2);
        read("3   ; extension=123\r\n", 3);
        read("3   ;\r\n", 3);
        read("3   ;   \r\n", 3);
        // Invalid extensions cause an error
        read_err("1 invalid extension\r\n");
        read_err("1 A\r\n");
        read_err("1;no CRLF");
    }

    #[test]
    fn test_valid_chunk_decode() {
        let source = io::Cursor::new(
            "3\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n\r\n"
                .to_string()
                .into_bytes(),
        );
        let mut decoded = Decoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).unwrap();

        assert_eq!(string, "hello world!!!");
    }

    #[test]
    fn test_decode_zero_length() {
        let mut decoder = Decoder::new(b"0\r\n\r\n" as &[u8]);

        let mut decoded = String::new();
        decoder.read_to_string(&mut decoded).unwrap();

        assert_eq!(decoded, "");
    }

    #[test]
    fn test_decode_invalid_chunk_length() {
        let mut decoder = Decoder::new(b"m\r\n\r\n" as &[u8]);

        let mut decoded = String::new();
        assert!(decoder.read_to_string(&mut decoded).is_err());
    }

    #[test]
    fn invalid_input1() {
        let source = io::Cursor::new(
            "2\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n"
                .to_string()
                .into_bytes(),
        );
        let mut decoded = Decoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).is_err();
    }

    #[test]
    fn invalid_input2() {
        let source = io::Cursor::new(
            "3\rhel\r\nb\r\nlo world!!!\r\n0\r\n"
                .to_string()
                .into_bytes(),
        );
        let mut decoded = Decoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).is_err();
    }
}
<commit_msg>add missing asserts<commit_after>// Copyright 2015 The tiny-http Contributors
// Copyright 2015 The rust-chunked-transfer Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::error::Error;
use std::fmt;
use std::io::Error as IoError;
use std::io::ErrorKind;
use std::io::Read;
use std::io::Result as IoResult;

/// Reads HTTP chunks and sends back real data.
///
/// # Example
///
/// ```
/// use chunked_transfer::Decoder;
/// use std::io::Read;
///
/// let encoded = b"3\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n\r\n";
/// let mut decoded = String::new();
///
/// let mut decoder = Decoder::new(encoded as &[u8]);
/// decoder.read_to_string(&mut decoded);
///
/// assert_eq!(decoded, "hello world!!!");
/// ```
pub struct Decoder<R> {
    // where the chunks come from
    source: R,

    // remaining size of the chunk being read
    // none if we are not in a chunk
    remaining_chunks_size: Option<usize>,
}

impl<R> Decoder<R>
where
    R: Read,
{
    pub fn new(source: R) -> Decoder<R> {
        Decoder {
            source,
            remaining_chunks_size: None,
        }
    }

    /// Unwraps the Decoder into its inner `Read` source.
    pub fn into_inner(self) -> R {
        self.source
    }

    fn read_chunk_size(&mut self) -> IoResult<usize> {
        let mut chunk_size_bytes = Vec::new();
        let mut has_ext = false;

        loop {
            let byte = match self.source.by_ref().bytes().next() {
                Some(b) => b?,
                None => return Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
            };

            if byte == b'\r' {
                break;
            }

            if byte == b';' {
                has_ext = true;
                break;
            }

            chunk_size_bytes.push(byte);
        }

        // Ignore extensions for now
        if has_ext {
            loop {
                let byte = match self.source.by_ref().bytes().next() {
                    Some(b) => b?,
                    None => return Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
                };
                if byte == b'\r' {
                    break;
                }
            }
        }

        self.read_line_feed()?;

        let chunk_size = String::from_utf8(chunk_size_bytes)
            .ok()
            .and_then(|c| usize::from_str_radix(c.trim(), 16).ok())
            .ok_or(IoError::new(ErrorKind::InvalidInput, DecoderError))?;

        Ok(chunk_size)
    }

    fn read_carriage_return(&mut self) -> IoResult<()> {
        match self.source.by_ref().bytes().next() {
            Some(Ok(b'\r')) => Ok(()),
            _ => Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
        }
    }

    fn read_line_feed(&mut self) -> IoResult<()> {
        match self.source.by_ref().bytes().next() {
            Some(Ok(b'\n')) => Ok(()),
            _ => Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
        }
    }
}

impl<R> Read for Decoder<R>
where
    R: Read,
{
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        let remaining_chunks_size = match self.remaining_chunks_size {
            Some(c) => c,
            None => {
                // first possibility: we are not in a chunk, so we'll attempt to determine
                // the chunks size
                let chunk_size = self.read_chunk_size()?;

                // if the chunk size is 0, we are at EOF
                if chunk_size == 0 {
                    self.read_carriage_return()?;
                    self.read_line_feed()?;
                    return Ok(0);
                }

                chunk_size
            }
        };

        // second possibility: we continue reading from a chunk
        if buf.len() < remaining_chunks_size {
            let read = self.source.read(buf)?;
            self.remaining_chunks_size = Some(remaining_chunks_size - read);
            return Ok(read);
        }

        // third possibility: the read request goes further than the current chunk
        // we simply read until the end of the chunk and return
        assert!(buf.len() >= remaining_chunks_size);

        let buf = &mut buf[..remaining_chunks_size];
        let read = self.source.read(buf)?;

        self.remaining_chunks_size = if read == remaining_chunks_size {
            self.read_carriage_return()?;
            self.read_line_feed()?;
            None
        } else {
            Some(remaining_chunks_size - read)
        };

        Ok(read)
    }
}

#[derive(Debug, Copy, Clone)]
struct DecoderError;

impl fmt::Display for DecoderError {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        write!(fmt, "Error while decoding chunks")
    }
}

impl Error for DecoderError {
    fn description(&self) -> &str {
        "Error while decoding chunks"
    }
}

#[cfg(test)]
mod test {
    use super::Decoder;
    use std::io;
    use std::io::Read;

    /// This unit test is taken from from Hyper
    /// https://github.com/hyperium/hyper
    /// Copyright (c) 2014 Sean McArthur
    #[test]
    fn test_read_chunk_size() {
        fn read(s: &str, expected: usize) {
            let mut decoded = Decoder::new(s.as_bytes());
            let actual = decoded.read_chunk_size().unwrap();
            assert_eq!(expected, actual);
        }

        fn read_err(s: &str) {
            let mut decoded = Decoder::new(s.as_bytes());
            let err_kind = decoded.read_chunk_size().unwrap_err().kind();
            assert_eq!(err_kind, io::ErrorKind::InvalidInput);
        }

        read("1\r\n", 1);
        read("01\r\n", 1);
        read("0\r\n", 0);
        read("00\r\n", 0);
        read("A\r\n", 10);
        read("a\r\n", 10);
        read("Ff\r\n", 255);
        read("Ff   \r\n", 255);
        // Missing LF or CRLF
        read_err("F\rF");
        read_err("F");
        // Invalid hex digit
        read_err("X\r\n");
        read_err("1X\r\n");
        read_err("-\r\n");
        read_err("-1\r\n");
        // Acceptable (if not fully valid) extensions do not influence the size
        read("1;extension\r\n", 1);
        read("a;ext name=value\r\n", 10);
        read("1;extension;extension2\r\n", 1);
        read("1;;;  ;\r\n", 1);
        read("2; extension...\r\n", 2);
        read("3   ; extension=123\r\n", 3);
        read("3   ;\r\n", 3);
        read("3   ;   \r\n", 3);
        // Invalid extensions cause an error
        read_err("1 invalid extension\r\n");
        read_err("1 A\r\n");
        read_err("1;no CRLF");
    }

    #[test]
    fn test_valid_chunk_decode() {
        let source = io::Cursor::new(
            "3\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n\r\n"
                .to_string()
                .into_bytes(),
        );
        let mut decoded = Decoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).unwrap();

        assert_eq!(string, "hello world!!!");
    }

    #[test]
    fn test_decode_zero_length() {
        let mut decoder = Decoder::new(b"0\r\n\r\n" as &[u8]);

        let mut decoded = String::new();
        decoder.read_to_string(&mut decoded).unwrap();

        assert_eq!(decoded, "");
    }

    #[test]
    fn test_decode_invalid_chunk_length() {
        let mut decoder = Decoder::new(b"m\r\n\r\n" as &[u8]);

        let mut decoded = String::new();
        assert!(decoder.read_to_string(&mut decoded).is_err());
    }

    #[test]
    fn invalid_input1() {
        let source = io::Cursor::new(
            "2\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n"
                .to_string()
                .into_bytes(),
        );
        let mut decoded = Decoder::new(source);

        let mut string = String::new();
        assert!(decoded.read_to_string(&mut string).is_err());
    }

    #[test]
    fn invalid_input2() {
        let source = io::Cursor::new(
            "3\rhel\r\nb\r\nlo world!!!\r\n0\r\n"
                .to_string()
                .into_bytes(),
        );
        let mut decoded = Decoder::new(source);

        let mut string = String::new();
        assert!(decoded.read_to_string(&mut string).is_err());
    }
}
<|endoftext|>


<commit_before>use std::iter;

use itertools::Itertools;
use ordered_float::OrderedFloat;
use rayon::prelude::*;

use super::CharIndex;
use super::enigma::Enigma;

use constants::MAX_PLUGS;
use fitness::{IoC, Bigram, Quadgram, FitnessFn};

lazy_static! {
    // The vector of key/ring settings ["AAA", "AAB", ..., "ZZY", "ZZZ"].
    static ref ALPHAS: Vec<String> = {
        iproduct!('A'..='Z', 'A'..='Z', 'A'..='Z')
            .map(|(a, b, c)| [a, b, c].iter().collect())
            .collect()
    };

    // The vector of permutations ["123", "124", "125", ..., "542", "543"].
    static ref ROTORS: Vec<String> = {
        ('1'..='5').permutations(3)
            .map(|p| p.iter().collect())
            .collect()
    };
}

/// Decrypts the given string by iterating through multiple possible Enigma
/// configurations, returning `(plaintext, Enigma)` corresponding to the most
/// probable decryption.
///
/// The decryption algorithm works in three steps:
///
/// 1. Guesses the rotors and first key setting.
/// 2. Guesses the remaining key settings and ring settings.
/// 3. Incrementally adds the best plug until no improvement is made.
///
/// Assumes `msg` contains only uppercase ASCII characters.
pub fn decrypt(msg: &str) -> (String, Enigma) {
    let mut enigma;

    enigma = guess_rotor_and_first_key(msg, IoC::score);
    enigma = guess_key_and_ring(msg, Bigram::score, enigma);
    enigma = guess_plugboard(msg, Quadgram::score, enigma);

    (enigma.encrypt(msg), enigma)
}

type ScoreFn = fn(&str) -> f64;

/// Given a piece of ciphertext and a fitness function, tries all valid rotor
/// and key combinations, and returns an `Enigma` with rotor settings and
/// first key setting that best decrypt the ciphertext. Note that the other
/// key settings and ring settings will be meaningless at this point.
///
/// This method checks 60 * 26^3 == 1,054,560 settings in parallel.
fn guess_rotor_and_first_key(msg: &str, score_fn: ScoreFn) -> Enigma {
    let (rotor, key) = iproduct!(ROTORS.iter(), ALPHAS.iter())
        .collect::<Vec<_>>()
        .into_par_iter()
        .max_by_key(|&(rotor, key)| {
            let mut enigma = Enigma::new(rotor, key, "AAA", 'B', "");
            OrderedFloat(score_fn(&enigma.encrypt(msg)))
        }).unwrap();

    Enigma::new(rotor, key, "AAA", 'B', "")
}

/// Given a piece of ciphertext, fitness function, and an `Enigma` instance
/// with the correct rotors and first key setting, tries all key and ring
/// settings for the mid and fast rotors, and returns an `Enigma` with the
/// best rotors, key, and ring settings assigned.
///
/// This method checks 26^4 == 456,976 settings in parallel.
fn guess_key_and_ring(msg: &str, score_fn: ScoreFn, enigma: Enigma) -> Enigma {
    let rotor = enigma.rotor_list();
    let first_key = enigma.key_settings().chars().nth(0).unwrap();

    // Compute the key offset based on the first key setting, so that we only
    // iterate over the next 676 key settings (this implicitly fixes the slow
    // rotor's key setting at 'A', which is intentional because this setting
    // does not affect the overall decryption).
    let key_offset = first_key.index() * 676;

    let keys = &ALPHAS[key_offset..(key_offset + 676)];
    let rings = &ALPHAS[0..676];

    let (key, ring) = iproduct!(keys, rings)
        .collect::<Vec<_>>()
        .into_par_iter()
        .max_by_key(|&(key, ring)| {
            let mut enigma = Enigma::new(&rotor, key, ring, 'B', "");
            OrderedFloat(score_fn(&enigma.encrypt(msg)))
        }).unwrap();

    Enigma::new(&rotor, key, ring, 'B', "")
}

/// Given a piece of ciphertext, fitness function, and an `Enigma` instance
/// with the correct rotors, key, and ring settings, attempts to add plugs
/// to the plugboard until adding one does not increase the overall fitness
/// of the decryption (or the number of plugs equals `MAX_PLUGS`). Returns the
/// resulting `Enigma`.
///
/// At most, this is MAX_PLUGS * 26^2 == 6,760 tests.
fn guess_plugboard(msg: &str, score_fn: ScoreFn, enigma: Enigma) -> Enigma {
    let rotor = enigma.rotor_list();
    let key = enigma.key_settings();
    let ring = enigma.ring_settings();

    let mut curr_plugboard = Vec::new();
    let mut plug_pool: Vec<char> = ('A'..='Z').collect();
    let mut best_score = score_fn(&msg);

    for _ in 0..MAX_PLUGS {
        let plugs: Vec<String> = plug_pool
            .iter()
            .combinations(2)
            .map(|p| p.into_iter().collect())
            .collect();

        let (score, plug) = plugs.par_iter()
            .map(|plug| {
                let plugboard = curr_plugboard
                    .iter()
                    .chain(iter::once(plug))
                    .join(" ");

                let mut enigma = Enigma::new(&rotor, &key, &ring, 'B', &plugboard);
                (OrderedFloat(score_fn(&enigma.encrypt(&msg))), plug)
            }).max().unwrap();

        if *score > best_score {
            best_score = *score;
            curr_plugboard.push(plug.to_string());
            plug_pool.retain(|&c| !plug.chars().any(|p| p == c));
        } else {
            break;
        }
    }

    Enigma::new(&rotor, &key, &ring, 'B', &curr_plugboard.iter().join(" "))
}

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

    #[test]
    fn static_vars() {
        assert_eq!(ALPHAS.len(), 26 * 26 * 26);
        assert_eq!(ROTORS.len(), 120 / 2);  // n! / (n - k)!
    }
}

<commit_msg>Use static dispatch for decrypt methods<commit_after>use std::iter;

use itertools::Itertools;
use ordered_float::OrderedFloat;
use rayon::prelude::*;

use super::CharIndex;
use super::enigma::Enigma;

use constants::MAX_PLUGS;
use fitness::{IoC, Bigram, Quadgram, FitnessFn};

lazy_static! {
    // The vector of key/ring settings ["AAA", "AAB", ..., "ZZY", "ZZZ"].
    static ref ALPHAS: Vec<String> = {
        iproduct!('A'..='Z', 'A'..='Z', 'A'..='Z')
            .map(|(a, b, c)| [a, b, c].iter().collect())
            .collect()
    };

    // The vector of permutations ["123", "124", "125", ..., "542", "543"].
    static ref ROTORS: Vec<String> = {
        ('1'..='5').permutations(3)
            .map(|p| p.iter().collect())
            .collect()
    };
}

/// Decrypts the given string by iterating through multiple possible Enigma
/// configurations, returning `(plaintext, Enigma)` corresponding to the most
/// probable decryption.
///
/// The decryption algorithm works in three steps:
///
/// 1. Guesses the rotors and first key setting.
/// 2. Guesses the remaining key settings and ring settings.
/// 3. Incrementally adds the best plug until no improvement is made.
///
/// Assumes `msg` contains only uppercase ASCII characters.
pub fn decrypt(msg: &str) -> (String, Enigma) {
    let mut enigma;

    enigma = guess_rotor_and_first_key::<IoC>(msg);
    enigma = guess_key_and_ring::<Bigram>(msg, enigma);
    enigma = guess_plugboard::<Quadgram>(msg, enigma);

    (enigma.encrypt(msg), enigma)
}

/// Given a piece of ciphertext and a fitness function, tries all valid rotor
/// and key combinations, and returns an `Enigma` with rotor settings and
/// first key setting that best decrypt the ciphertext. Note that the other
/// key settings and ring settings will be meaningless at this point.
///
/// This method checks 60 * 26^3 == 1,054,560 settings in parallel.
fn guess_rotor_and_first_key<F: FitnessFn>(msg: &str) -> Enigma {
    let (rotor, key) = iproduct!(ROTORS.iter(), ALPHAS.iter())
        .collect::<Vec<_>>()
        .into_par_iter()
        .max_by_key(|&(rotor, key)| {
            let mut enigma = Enigma::new(rotor, key, "AAA", 'B', "");
            OrderedFloat(F::score(&enigma.encrypt(msg)))
        }).unwrap();

    Enigma::new(rotor, key, "AAA", 'B', "")
}

/// Given a piece of ciphertext, fitness function, and an `Enigma` instance
/// with the correct rotors and first key setting, tries all key and ring
/// settings for the mid and fast rotors, and returns an `Enigma` with the
/// best rotors, key, and ring settings assigned.
///
/// This method checks 26^4 == 456,976 settings in parallel.
fn guess_key_and_ring<F: FitnessFn>(msg: &str, enigma: Enigma) -> Enigma {
    let rotor = enigma.rotor_list();
    let first_key = enigma.key_settings().chars().nth(0).unwrap();

    // Compute the key offset based on the first key setting, so that we only
    // iterate over the next 676 key settings (this implicitly fixes the slow
    // rotor's key setting at 'A', which is intentional because this setting
    // does not affect the overall decryption).
    let key_offset = first_key.index() * 676;

    let keys = &ALPHAS[key_offset..(key_offset + 676)];
    let rings = &ALPHAS[0..676];

    let (key, ring) = iproduct!(keys, rings)
        .collect::<Vec<_>>()
        .into_par_iter()
        .max_by_key(|&(key, ring)| {
            let mut enigma = Enigma::new(&rotor, key, ring, 'B', "");
            OrderedFloat(F::score(&enigma.encrypt(msg)))
        }).unwrap();

    Enigma::new(&rotor, key, ring, 'B', "")
}

/// Given a piece of ciphertext, fitness function, and an `Enigma` instance
/// with the correct rotors, key, and ring settings, attempts to add plugs
/// to the plugboard until adding one does not increase the overall fitness
/// of the decryption (or the number of plugs equals `MAX_PLUGS`). Returns the
/// resulting `Enigma`.
///
/// At most, this is MAX_PLUGS * 26^2 == 6,760 tests.
fn guess_plugboard<F: FitnessFn>(msg: &str, enigma: Enigma) -> Enigma {
    let rotor = enigma.rotor_list();
    let key = enigma.key_settings();
    let ring = enigma.ring_settings();

    let mut curr_plugboard = Vec::new();
    let mut plug_pool: Vec<char> = ('A'..='Z').collect();
    let mut best_score = F::score(&msg);

    for _ in 0..MAX_PLUGS {
        let plugs: Vec<String> = plug_pool
            .iter()
            .combinations(2)
            .map(|p| p.into_iter().collect())
            .collect();

        let (score, plug) = plugs.par_iter()
            .map(|plug| {
                let plugboard = curr_plugboard
                    .iter()
                    .chain(iter::once(plug))
                    .join(" ");

                let mut enigma = Enigma::new(&rotor, &key, &ring, 'B', &plugboard);
                (OrderedFloat(F::score(&enigma.encrypt(&msg))), plug)
            }).max().unwrap();

        if *score > best_score {
            best_score = *score;
            curr_plugboard.push(plug.to_string());
            plug_pool.retain(|&c| !plug.chars().any(|p| p == c));
        } else {
            break;
        }
    }

    Enigma::new(&rotor, &key, &ring, 'B', &curr_plugboard.iter().join(" "))
}

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

    #[test]
    fn static_vars() {
        assert_eq!(ALPHAS.len(), 26 * 26 * 26);
        assert_eq!(ROTORS.len(), 120 / 2);  // n! / (n - k)!
    }
}

<|endoftext|>


<commit_before>use id::{Id, Pool, IdIter};
use point::Point;
use nalgebra::{Cross, Dot};

pub struct VertexData {
    point: Point,
    edges: Vec<Edge>,
    faces: Vec<Face>,
}
pub type Vertex = Id<VertexData>;

pub struct EdgeData {
    vertices: (Vertex, Vertex),
    faces: (Face, Face),
}
pub type Edge = Id<EdgeData>;

pub struct FaceData {
    point: Point,
    edges: Vec<Edge>,
    vertices: Vec<Vertex>,
}
pub type Face = Id<FaceData>;

pub struct Diagram {
    faces: Pool<FaceData>,
    edges: Pool<EdgeData>,
    vertices: Pool<VertexData>,
}

fn is_bad_vertex(vertex_data: &VertexData) -> bool {
    vertex_data.faces.len() <= 2
}

fn is_bad_edge(edge_data: &EdgeData, vertices: &Pool<VertexData>) -> bool {
    let (vertex0, vertex1) = edge_data.vertices;
    is_bad_vertex(&vertices[vertex0]) || is_bad_vertex(&vertices[vertex1])
}

fn remap_id<T>(id: Id<T>, missing_ids: &[Id<T>]) -> Id<T> {
    let position = match missing_ids.binary_search(&id) {
        Ok(position) => position,
        Err(position) => position,
    };
    Id::new(id.index() - position)
}

impl Diagram {
    pub fn new() -> Self {
        Diagram {
            faces: Pool::new(),
            edges: Pool::new(),
            vertices: Pool::new(),
        }
    }

    pub fn new_edge(&mut self, vertex0: Vertex, vertex1: Vertex) -> Edge {
        let edge = self.edges.add(EdgeData {
            vertices: (vertex0, vertex1),
            faces: (Face::none(), Face::none()),
        });
        self.vertices[vertex0].edges.push(edge);
        self.vertices[vertex1].edges.push(edge);
        //println!("Edge: {:?} - {:?}", self.vertex_point(vertex0), self.vertex_point(vertex1));
        edge
    }

    pub fn new_vertex(&mut self, point: Point, faces: Vec<Face>) -> Vertex {
        self.vertices.add(VertexData {
            point: point,
            edges: Vec::new(),
            faces: faces
        })
    }

    pub fn new_face(&mut self, point: Point) -> Face {
        self.faces.add(FaceData {
            point: point,
            edges: Vec::new(),
            vertices: Vec::new(),
        })
    }

    pub fn vertices(&self) -> IdIter<VertexData> {
        self.vertices.ids()
    }

    pub fn vertex_point(&self, vertex: Vertex) -> Point {
        self.vertices[vertex].point
    }

    pub fn vertex_faces(&self, vertex: Vertex) -> &[Face] {
        &self.vertices[vertex].faces
    }

    pub fn vertex_edges(&self, vertex: Vertex) -> &[Edge] {
        &self.vertices[vertex].edges
    }

    pub fn edges(&self) -> IdIter<EdgeData> {
        self.edges.ids()
    }

    pub fn edge_vertices(&self, edge: Edge) -> (Vertex, Vertex) {
        self.edges[edge].vertices
    }

    pub fn faces(&self) -> IdIter<FaceData> {
        self.faces.ids()
    }

    pub fn face_point(&self, face: Face) -> Point {
        self.faces[face].point
    }

    pub fn face_vertices(&self, face: Face) -> &[Vertex] {
        &self.faces[face].vertices
    }

    pub fn face_edges(&self, face: Face) -> &[Edge] {
        &self.faces[face].edges
    }

    pub fn other_edge_vertex(&self, edge: Edge, vertex: Vertex) -> Option<Vertex> {
        let (vertex0, vertex1) = self.edge_vertices(edge);
        if vertex  == vertex0 {
            Some(vertex1)
        } else if vertex == vertex1 {
            Some(vertex0)
        } else {
            None
        }
    }

    pub fn cleanup_vertices(&mut self) {
        for vertex in self.vertices() {
            if self.vertex_faces(vertex).len() == 2 {
                let (vertex0, vertex1) = {
                    let edges = &self.vertices[vertex].edges;
                    //println!("{:?} {:?} {:?}", vertex, edges, &self.vertices[vertex].faces);
                    assert_eq!(edges.len(), 2);
                    (self.other_edge_vertex(edges[0], vertex), self.other_edge_vertex(edges[1], vertex))
                };
                self.new_edge(vertex0.unwrap(), vertex1.unwrap());
            }
        }
        let bad_vertices: Vec<_> = self.vertices().
            filter(|vertex| is_bad_vertex(&self.vertices[*vertex])).
            collect();
        let bad_edges: Vec<_> = self.edges().
            filter(|edge| is_bad_edge(&self.edges[*edge], &self.vertices)).
            collect();
        {
            let vertices = &self.vertices;
            self.edges.retain(|edge| !is_bad_edge(edge, vertices));
        }
        self.vertices.retain(|vertex| !is_bad_vertex(vertex));
        for vertex in self.vertices() {
            for edge in self.vertices[vertex].edges.iter_mut() {
                *edge = remap_id(*edge, &bad_edges);
            }
        }
        for edge in self.edges() {
            let (vertex0, vertex1) = self.edge_vertices(edge);
            self.edges[edge].vertices = (remap_id(vertex0, &bad_vertices), remap_id(vertex1, &bad_vertices));
        }
        for face in self.faces() {
            for vertex in self.faces[face].vertices.iter_mut() {
                *vertex = remap_id(*vertex, &bad_vertices);
            }
            for edge in self.faces[face].edges.iter_mut() {
                *edge = remap_id(*edge, &bad_edges);
            }
        }
    }

    pub fn finish_faces(&mut self) {
        for edge in self.edges() {
            let mut common = Vec::new();
            let (vertex0, vertex1) = self.edge_vertices(edge);
            for face0 in self.vertex_faces(vertex0) {
                for face1 in self.vertex_faces(vertex1) {
                    if face0 == face1 {
                        common.push(*face0);
                    }
                }
            }
            assert_eq!(common.len(), 2);
            self.faces[common[0]].edges.push(edge);
            self.faces[common[1]].edges.push(edge);
            self.edges[edge].faces = (common[0], common[1]);
        }
        for vertex in self.vertices() {
            for face in self.vertices[vertex].faces.iter() {
                self.faces[*face].vertices.push(vertex);
            }
        }
        for face in self.faces() {
            let n = self.face_point(face).position;
            let vertices = &self.vertices;
            self.faces[face].vertices.sort_by(|v1, v2| (vertices[*v1].point.position - n).cross(&(vertices[*v2].point.position - n)).dot(&n).partial_cmp(&0.0).unwrap());
        }
    }
}

<commit_msg>vertex_position & face_position<commit_after>use id::{Id, Pool, IdIter};
use point::Point;
use nalgebra::{Vector3, Cross, Dot};

pub struct VertexData {
    point: Point,
    edges: Vec<Edge>,
    faces: Vec<Face>,
}
pub type Vertex = Id<VertexData>;

pub struct EdgeData {
    vertices: (Vertex, Vertex),
    faces: (Face, Face),
}
pub type Edge = Id<EdgeData>;

pub struct FaceData {
    point: Point,
    edges: Vec<Edge>,
    vertices: Vec<Vertex>,
}
pub type Face = Id<FaceData>;

pub struct Diagram {
    faces: Pool<FaceData>,
    edges: Pool<EdgeData>,
    vertices: Pool<VertexData>,
}

fn is_bad_vertex(vertex_data: &VertexData) -> bool {
    vertex_data.faces.len() <= 2
}

fn is_bad_edge(edge_data: &EdgeData, vertices: &Pool<VertexData>) -> bool {
    let (vertex0, vertex1) = edge_data.vertices;
    is_bad_vertex(&vertices[vertex0]) || is_bad_vertex(&vertices[vertex1])
}

fn remap_id<T>(id: Id<T>, missing_ids: &[Id<T>]) -> Id<T> {
    let position = match missing_ids.binary_search(&id) {
        Ok(position) => position,
        Err(position) => position,
    };
    Id::new(id.index() - position)
}

impl Diagram {
    pub fn new() -> Self {
        Diagram {
            faces: Pool::new(),
            edges: Pool::new(),
            vertices: Pool::new(),
        }
    }

    pub fn new_edge(&mut self, vertex0: Vertex, vertex1: Vertex) -> Edge {
        let edge = self.edges.add(EdgeData {
            vertices: (vertex0, vertex1),
            faces: (Face::none(), Face::none()),
        });
        self.vertices[vertex0].edges.push(edge);
        self.vertices[vertex1].edges.push(edge);
        //println!("Edge: {:?} - {:?}", self.vertex_point(vertex0), self.vertex_point(vertex1));
        edge
    }

    pub fn new_vertex(&mut self, point: Point, faces: Vec<Face>) -> Vertex {
        self.vertices.add(VertexData {
            point: point,
            edges: Vec::new(),
            faces: faces
        })
    }

    pub fn new_face(&mut self, point: Point) -> Face {
        self.faces.add(FaceData {
            point: point,
            edges: Vec::new(),
            vertices: Vec::new(),
        })
    }

    pub fn vertices(&self) -> IdIter<VertexData> {
        self.vertices.ids()
    }

    pub fn vertex_point(&self, vertex: Vertex) -> Point {
        self.vertices[vertex].point
    }

    pub fn vertex_position(&self, vertex: Vertex) -> Vector3<f64> {
        self.vertex_point(vertex).position
    }

    pub fn vertex_faces(&self, vertex: Vertex) -> &[Face] {
        &self.vertices[vertex].faces
    }

    pub fn vertex_edges(&self, vertex: Vertex) -> &[Edge] {
        &self.vertices[vertex].edges
    }

    pub fn edges(&self) -> IdIter<EdgeData> {
        self.edges.ids()
    }

    pub fn edge_vertices(&self, edge: Edge) -> (Vertex, Vertex) {
        self.edges[edge].vertices
    }

    pub fn faces(&self) -> IdIter<FaceData> {
        self.faces.ids()
    }

    pub fn face_point(&self, face: Face) -> Point {
        self.faces[face].point
    }

    pub fn face_position(&self, face: Face) -> Vector3<f64> {
        self.face_point(face).position
    }

    pub fn face_vertices(&self, face: Face) -> &[Vertex] {
        &self.faces[face].vertices
    }

    pub fn face_edges(&self, face: Face) -> &[Edge] {
        &self.faces[face].edges
    }

    pub fn other_edge_vertex(&self, edge: Edge, vertex: Vertex) -> Option<Vertex> {
        let (vertex0, vertex1) = self.edge_vertices(edge);
        if vertex  == vertex0 {
            Some(vertex1)
        } else if vertex == vertex1 {
            Some(vertex0)
        } else {
            None
        }
    }

    pub fn cleanup_vertices(&mut self) {
        for vertex in self.vertices() {
            if self.vertex_faces(vertex).len() == 2 {
                let (vertex0, vertex1) = {
                    let edges = &self.vertices[vertex].edges;
                    //println!("{:?} {:?} {:?}", vertex, edges, &self.vertices[vertex].faces);
                    assert_eq!(edges.len(), 2);
                    (self.other_edge_vertex(edges[0], vertex), self.other_edge_vertex(edges[1], vertex))
                };
                self.new_edge(vertex0.unwrap(), vertex1.unwrap());
            }
        }
        let bad_vertices: Vec<_> = self.vertices().
            filter(|vertex| is_bad_vertex(&self.vertices[*vertex])).
            collect();
        let bad_edges: Vec<_> = self.edges().
            filter(|edge| is_bad_edge(&self.edges[*edge], &self.vertices)).
            collect();
        {
            let vertices = &self.vertices;
            self.edges.retain(|edge| !is_bad_edge(edge, vertices));
        }
        self.vertices.retain(|vertex| !is_bad_vertex(vertex));
        for vertex in self.vertices() {
            for edge in self.vertices[vertex].edges.iter_mut() {
                *edge = remap_id(*edge, &bad_edges);
            }
        }
        for edge in self.edges() {
            let (vertex0, vertex1) = self.edge_vertices(edge);
            self.edges[edge].vertices = (remap_id(vertex0, &bad_vertices), remap_id(vertex1, &bad_vertices));
        }
        for face in self.faces() {
            for vertex in self.faces[face].vertices.iter_mut() {
                *vertex = remap_id(*vertex, &bad_vertices);
            }
            for edge in self.faces[face].edges.iter_mut() {
                *edge = remap_id(*edge, &bad_edges);
            }
        }
    }

    pub fn finish_faces(&mut self) {
        for edge in self.edges() {
            let mut common = Vec::new();
            let (vertex0, vertex1) = self.edge_vertices(edge);
            for face0 in self.vertex_faces(vertex0) {
                for face1 in self.vertex_faces(vertex1) {
                    if face0 == face1 {
                        common.push(*face0);
                    }
                }
            }
            assert_eq!(common.len(), 2);
            self.faces[common[0]].edges.push(edge);
            self.faces[common[1]].edges.push(edge);
            self.edges[edge].faces = (common[0], common[1]);
        }
        for vertex in self.vertices() {
            for face in self.vertices[vertex].faces.iter() {
                self.faces[*face].vertices.push(vertex);
            }
        }
        for face in self.faces() {
            let n = self.face_point(face).position;
            let vertices = &self.vertices;
            self.faces[face].vertices.sort_by(|v1, v2| (vertices[*v1].point.position - n).cross(&(vertices[*v2].point.position - n)).dot(&n).partial_cmp(&0.0).unwrap());
        }
    }
}

<|endoftext|>


<commit_before>use errors::Error;
use guards::{ReadGuard, WriteGuard};
use factory::FactoryBase;
use methods::Method;
use reflect;

use downcast::Downcast;

use std::any::Any;
use std::collections::BTreeMap;
use std::ops::{Deref, DerefMut};

fn type_name<T: ::std::marker::Reflect>() -> &'static str {
    unsafe { ::std::intrinsics::type_name::<T>() }
}

pub trait Container<'a>: Any + Sized {
    type Key: reflect::Key;
    type ServiceBase: ?Sized + Any;

    type ReadGuardBase: Deref<Target = Box<Self::ServiceBase>> + 'a;
    type WriteGuardBase: DerefMut<Target = Box<Self::ServiceBase>> + 'a;

    fn read_service_base(
        &'a self,
        key: &'a Self::Key
    ) -> Result<Self::ReadGuardBase, Error<'a, Self::Key>>;

    fn write_service_base(
        &'a self,
        key: &'a Self::Key
    ) -> Result<Self::WriteGuardBase, Error<'a, Self::Key>>;

    fn read_service<Svc>(
        &'a self,
        key: &'a Self::Key
    ) -> Result<ReadGuard<Svc, Self::ServiceBase, Self::ReadGuardBase>, Error<'a, Self::Key>>
        where Svc: Any, Self::ServiceBase: Downcast<Svc>
    {
        let base = try!{self.read_service_base(key)};
        if !base.is_type() {
            return Err(Error::MismatchedType{
                key: key,
                expected: type_name::<Svc>(),
                found: type_name::<Svc>(),
            })
        };
        Ok(ReadGuard::new(base))
    }

    fn write_service<Svc>(
        &'a self,
        key: &'a Self::Key
    ) -> Result<WriteGuard<Svc, Self::ServiceBase, Self::WriteGuardBase>, Error<'a, Self::Key>>
        where Svc: Any, Self::ServiceBase: Downcast<Svc>
    {
        let base = try!{self.write_service_base(key)};
        if !base.is_type() {
            return Err(Error::MismatchedType{
                key: key,
                expected: type_name::<Svc>(),
                found: type_name::<Svc>(),
            })
        };
        Ok(WriteGuard::new(base))
    }

    fn read<Svc>(
        &'a self
    ) -> Result<ReadGuard<Svc, Self::ServiceBase, Self::ReadGuardBase>, Error<'a, Self::Key>>
        where Svc: reflect::Service<Key = Self::Key>, Self::ServiceBase: Downcast<Svc>
    {
        self.read_service(Svc::key())
    }

    fn write<Svc>(
        &'a self
    ) -> Result<WriteGuard<Svc, Self::ServiceBase, Self::WriteGuardBase>, Error<'a, Self::Key>>
        where Svc: reflect::Service<Key = Self::Key>, Self::ServiceBase: Downcast<Svc>
    {
        self.write_service(Svc::key())
    }

    fn read_all(
        &'a self,
    ) -> Result<BTreeMap<&'a Self::Key, Self::ReadGuardBase>, Error<'a, Self::Key>>;

    fn write_all(
        &'a self,
    ) -> Result<BTreeMap<&'a Self::Key, Self::WriteGuardBase>, Error<'a, Self::Key>>;

    fn create_factory_object<Obj, Svc>(
        &'a self,
        svc: &'a Self::Key
    ) -> Result<Obj, Error<'a, Self::Key>>
        where Svc: FactoryBase<'a, Self, Obj>, Self::ServiceBase: Downcast<Svc>
    {
        let factory = try!{self.read_service::<Svc>(svc)};
        factory.create(svc, self)
    }

    fn create<Obj>(&'a self) -> Result<Obj, Error<'a, Self::Key>>
    where
        Obj: reflect::FactoryObject<Key = Self::Key>,
        Obj::Factory: FactoryBase<'a, Self, Obj>,
        Self::ServiceBase: Downcast<Obj::Factory>
    {
        let key = <Obj::Factory as reflect::Service>::key();
        self.create_factory_object::<Obj, Obj::Factory>(key)
    }

    fn invoke<M>(&'a self) -> Result<M::Ret, Error<'a, Self::Key>>
        where M: Method<'a, Self>
    {
        M::invoke(self)
    }
}

pub trait StagedContainer<'a>: Container<'a> {
    type Stage: Container<'a>;

    /* TODO
    fn get_stage<St>(&self) -> Option<&Self::Stage>
        where St: reflect::Service<Key = Self::Key>;

    fn read_stage<St>(
        &'a self,
    ) -> Result<BTreeMap<&'a Self::Key, Self::ReadGuardBase>, Error<'a, Self::Key>>
        where St: reflect::Service<Key = Self::Key>;

    fn write_stage<St>(
        &'a self,
    ) -> Result<BTreeMap<&'a Self::Key, Self::WriteGuardBase>, Error<'a, Self::Key>>
        where St: reflect::Service<Key = Self::Key>;*/

    type StageIter: Iterator<Item = (&'a Self::Key, &'a Self::Stage)> + 'a;

    fn stages(&'a self) -> Self::StageIter;
}

// ++++++++++++++++++++ methods ++++++++++++++++++++
// TODO move this somewhere else?
/*
// ++++++++++++++++++++ Container ++++++++++++++++++++

pub struct Container<Key, Base: ?Sized> {
    services: BTreeMap<Key, RwLock<Box<Base>>>,
    abba_prevention: Mutex<()>,
}

pub type Services<'a, Key, Base: ?Sized> = btree_map::Iter<'a, Key, RwLock<Box<Base>>>;

impl<Key, Base: ?Sized> Container<Key, Base>
    where Key: reflect::Key, Base: Any
{
    #[doc(hidden)]
    pub fn new() -> Self {
        Container{
            services: BTreeMap::new(),
            abba_prevention: Mutex::new(()),
        }
    }

    #[doc(hidden)]
    pub fn register_service(&mut self, key: Key, svc: Box<Base>){
        self.services.insert(key, RwLock::new(svc));
    }

    #[doc(hidden)]
    pub fn unregister_service(&mut self, key: &Key) -> bool {
        self.services.remove(key).is_some()
    }

    pub fn services(&self) -> Services<Key, Base> {
        self.services.iter()
    }

    pub fn get_service(&self, key: &Key) -> Option<&RwLock<Box<Base>>> {
        self.services.get(key)
    }

    pub fn invoke<'a, M>(&'a self) -> Result<M::Ret, M::Error>
        where M: Method<'a, Self>,
    {
        // prevent AB-BA deadlocks
        let _ = self.abba_prevention.lock();

        M::invoke(self)
    }
}

impl<'a, Key, Base: ?Sized> Method<'a, Container<Key, Base>> for ()
    where Key: reflect::Key, Base: Any
{
    type Ret = ();
    type Error = DummyError;

    fn invoke(_: &'a Container<Key, Base>) -> Result<Self::Ret, Self::Error> {
        Ok(())
    }
}

impl<'a, Key, Base: ?Sized, Svc> Method<'a, Container<Key, Base>> for Read<Svc>
    where Key: reflect::Key, Base: Any + Downcast<Svc>, Svc: reflect::Object<Key = Key>
{
    type Ret = ReadGuard<'a, Svc, Base>;
    type Error = LockError<'a, Key>;

    fn invoke(ioc: &'a Container<Key, Base>) -> Result<Self::Ret, Self::Error> {
        let key = Svc::key();
        let service = match ioc.get_service(key) {
            Some(r) => r,
            None => return Err(LockError::NotFound{ key: key })
        };
        let guard = match service.read() {
            Ok(r) => r,
            Err(_) => return Err(LockError::Poisoned{ key: key })
        };
        if !guard.is_type() {
            return Err(LockError::MismatchedType{
                key: key,
                expected: type_name::<Svc>(),
                found: type_name::<Svc>(),
            })
        };
        Ok(ReadGuard::new(guard))
    }
}

impl<'a, Key, Base: ?Sized, Svc> Method<'a, Container<Key, Base>> for Write<Svc>
    where Key: reflect::Key, Base: Any + Downcast<Svc>, Svc: reflect::Object<Key = Key>
{
    type Ret = WriteGuard<'a, Svc, Base>;
    type Error = LockError<'a, Key>;

    fn invoke(ioc: &'a Container<Key, Base>) -> Result<Self::Ret, Self::Error> {
        let key = Svc::key();
        let service = match ioc.get_service(key) {
            Some(r) => r,
            None => return Err(LockError::NotFound{ key: key })
        };
        let guard = match service.write() {
            Ok(r) => r,
            Err(_) => return Err(LockError::Poisoned{ key: key })
        };
        if !guard.is_type() {
            return Err(LockError::MismatchedType{
                key: key,
                expected: type_name::<Svc>(),
                found: type_name::<Svc>(),
            })
        };
        Ok(WriteGuard::new(guard))
    }
}

impl<'a, Key, Base: ?Sized> Method<'a, Container<Key, Base>> for ReadAll
    where Key: reflect::Key, Base: Any
{
    type Ret = ReadGuardMap<'a, Key, Base>;
    type Error = LockError<'a, Key>;

    fn invoke(ioc: &'a Container<Key, Base>) -> Result<Self::Ret, Self::Error> {
        let mut map = ReadGuardMap::new();
        for (key, service) in ioc.services() {
            let guard = match service.read() {
                Ok(r) => r, Err(_) => return Err(LockError::Poisoned{ key: key })
            };
            map.insert(key, guard);
        }
        Ok(map)
    }
}

impl<'a, Key, Base: ?Sized> Method<'a, Container<Key, Base>> for WriteAll
    where Key: reflect::Key, Base: Any
{
    type Ret = WriteGuardMap<'a, Key, Base>;
    type Error = LockError<'a, Key>;

    fn invoke(ioc: &'a Container<Key, Base>) -> Result<Self::Ret, Self::Error> {
        let mut map = WriteGuardMap::new();
        for (key, service) in ioc.services() {
            let guard = match service.write() {
                Ok(r) => r, Err(_) => return Err(LockError::Poisoned{ key: key })
            };
            map.insert(key, guard);
        }
        Ok(map)
    }
}

impl<'a, Key, Base: ?Sized, Obj> Method<'a, Container<Key, Base>> for Create<Obj>
where
    Key: reflect::Key,
    Base: Any + Downcast<Obj::Factory>,
    Obj: FactoryObject<Key = Key> + 'a,
    Obj::Factory: FactoryBase<'a, Container<Key, Base>, Obj>
{
    type Ret = Obj;
    type Error = CreationError<'a,
        <Obj::Factory as reflect::Object>::Key,
        <Obj::Factory as FactoryBase<'a, Container<Key, Base>, Obj>>::Error
    >;

    fn invoke(ioc: &'a Container<Key, Base>) -> Result<Self::Ret, Self::Error> {
        let factory = try!{Read::<Obj::Factory>::invoke(ioc)};

        factory.create(ioc)
    }
}

impl<Key, Base: ?Sized> Container<Key, Base>
    where Key: reflect::Key, Base: Any
{
    /// Shortcut for `.invoke::<ioc::Read<{Svc}>>(())`.
    pub fn read<Svc>(&self) -> Result<ReadGuard<Svc, Base>, LockError<Svc::Key>>
        where Svc: reflect::Object<Key = Key>, Base: Downcast<Svc>
    {
        self.invoke::<Read<Svc>>()
    }

    /// Shortcut for `.invoke::<ioc::Write<{Svc}>>(())`.
    pub fn write<Svc>(&self) -> Result<WriteGuard<Svc, Base>, LockError<Svc::Key>>
        where Svc: reflect::Object<Key = Key>, Base: Downcast<Svc>
    {
        self.invoke::<Write<Svc>>()
    }

    /// Shortcut for `.invoke::<ioc::ReadAll>(())`.
    pub fn read_all(&self) -> Result<ReadGuardMap<Key, Base>, LockError<Key>> {
        self.invoke::<ReadAll>()
    }

    /// Shortcut for `.invoke::<ioc::WriteAll>(())`.
    pub fn write_all(&self) -> Result<WriteGuardMap<Key, Base>, LockError<Key>> {
        self.invoke::<WriteAll>()
    }

    /// Shortcut for `.invoke::<ioc::Create<{Obj}>>(args)`.
    pub fn create<'a, Obj>(&'a self) -> Result<Obj, CreationError<<Obj::Factory as reflect::Object>::Key, <Obj::Factory as FactoryBase<'a, Self, Obj>>::Error>>
    where
        Obj: FactoryObject<Key = Key> + 'a,
        Obj::Factory: FactoryBase<'a, Self, Obj>,
        Base: Downcast<Obj::Factory>,
    {
        self.invoke::<Create<Obj>>()
    }
}

// ++++++++++++++++++++ ContainerBuilder ++++++++++++++++++++

pub struct ContainerBuilder<Key, Base: ?Sized> {
    ioc: Container<Key, Base>,
}

impl<Key, Base: ?Sized> ContainerBuilder<Key, Base>
    where Key: reflect::Key, Base: Any
{
    pub fn new() -> Self {
        ContainerBuilder{ ioc: Container::new() }
    }

    pub fn register_service(&mut self, key: Key, svc: Box<Base>) -> &mut Self {
        self.ioc.register_service(key, svc);
        self
    }

    /// NOTE: The `Box<Svc>: Into<Box<Base>>`-clause is needed due to rusts lack of
    /// HKT or a `Coercible`-trait (to name two solutions).
    pub fn register<Svc>(&mut self, svc: Svc) -> &mut Self
        where Svc: reflect::Object<Key = Key>, Box<Svc>: Into<Box<Base>>,
    {
        self.register_service(Svc::key().clone(), Box::new(svc).into())
    }

    pub fn build(self) -> Container<Key, Base> {
        self.ioc
    }
}

impl<Key, Base: ?Sized> Default for ContainerBuilder<Key, Base>
    where Key: reflect::Key, Base: Any
{
    fn default() -> Self { Self::new() }
}
*/
<commit_msg>fix Container::Stage<commit_after>use errors::Error;
use guards::{ReadGuard, WriteGuard};
use factory::FactoryBase;
use methods::Method;
use reflect;

use downcast::Downcast;

use std::any::Any;
use std::collections::BTreeMap;
use std::ops::{Deref, DerefMut};

fn type_name<T: ::std::marker::Reflect>() -> &'static str {
    unsafe { ::std::intrinsics::type_name::<T>() }
}

pub trait Container<'a>: Any + Sized {
    type Key: reflect::Key;
    type ServiceBase: ?Sized + Any;

    type ReadGuardBase: Deref<Target = Box<Self::ServiceBase>> + 'a;
    type WriteGuardBase: DerefMut<Target = Box<Self::ServiceBase>> + 'a;

    fn read_service_base(
        &'a self,
        key: &'a Self::Key
    ) -> Result<Self::ReadGuardBase, Error<'a, Self::Key>>;

    fn write_service_base(
        &'a self,
        key: &'a Self::Key
    ) -> Result<Self::WriteGuardBase, Error<'a, Self::Key>>;

    fn read_service<Svc>(
        &'a self,
        key: &'a Self::Key
    ) -> Result<ReadGuard<Svc, Self::ServiceBase, Self::ReadGuardBase>, Error<'a, Self::Key>>
        where Svc: Any, Self::ServiceBase: Downcast<Svc>
    {
        let base = try!{self.read_service_base(key)};
        if !base.is_type() {
            return Err(Error::MismatchedType{
                key: key,
                expected: type_name::<Svc>(),
                found: type_name::<Svc>(),
            })
        };
        Ok(ReadGuard::new(base))
    }

    fn write_service<Svc>(
        &'a self,
        key: &'a Self::Key
    ) -> Result<WriteGuard<Svc, Self::ServiceBase, Self::WriteGuardBase>, Error<'a, Self::Key>>
        where Svc: Any, Self::ServiceBase: Downcast<Svc>
    {
        let base = try!{self.write_service_base(key)};
        if !base.is_type() {
            return Err(Error::MismatchedType{
                key: key,
                expected: type_name::<Svc>(),
                found: type_name::<Svc>(),
            })
        };
        Ok(WriteGuard::new(base))
    }

    fn read<Svc>(
        &'a self
    ) -> Result<ReadGuard<Svc, Self::ServiceBase, Self::ReadGuardBase>, Error<'a, Self::Key>>
        where Svc: reflect::Service<Key = Self::Key>, Self::ServiceBase: Downcast<Svc>
    {
        self.read_service(Svc::key())
    }

    fn write<Svc>(
        &'a self
    ) -> Result<WriteGuard<Svc, Self::ServiceBase, Self::WriteGuardBase>, Error<'a, Self::Key>>
        where Svc: reflect::Service<Key = Self::Key>, Self::ServiceBase: Downcast<Svc>
    {
        self.write_service(Svc::key())
    }

    fn read_all(
        &'a self,
    ) -> Result<BTreeMap<&'a Self::Key, Self::ReadGuardBase>, Error<'a, Self::Key>>;

    fn write_all(
        &'a self,
    ) -> Result<BTreeMap<&'a Self::Key, Self::WriteGuardBase>, Error<'a, Self::Key>>;

    fn create_factory_object<Obj, Svc>(
        &'a self,
        svc: &'a Self::Key
    ) -> Result<Obj, Error<'a, Self::Key>>
        where Svc: FactoryBase<'a, Self, Obj>, Self::ServiceBase: Downcast<Svc>
    {
        let factory = try!{self.read_service::<Svc>(svc)};
        factory.create(svc, self)
    }

    fn create<Obj>(&'a self) -> Result<Obj, Error<'a, Self::Key>>
    where
        Obj: reflect::FactoryObject<Key = Self::Key>,
        Obj::Factory: FactoryBase<'a, Self, Obj>,
        Self::ServiceBase: Downcast<Obj::Factory>
    {
        let key = <Obj::Factory as reflect::Service>::key();
        self.create_factory_object::<Obj, Obj::Factory>(key)
    }

    fn invoke<M>(&'a self) -> Result<M::Ret, Error<'a, Self::Key>>
        where M: Method<'a, Self>
    {
        M::invoke(self)
    }
}

pub trait StagedContainer<'a>: Container<'a> {
    type Stage: Container<'a, Key = Self::Key, ServiceBase = Self::ServiceBase>;

    /* TODO
    fn get_stage<St>(&self) -> Option<&Self::Stage>
        where St: reflect::Service<Key = Self::Key>;

    fn read_stage<St>(
        &'a self,
    ) -> Result<BTreeMap<&'a Self::Key, Self::ReadGuardBase>, Error<'a, Self::Key>>
        where St: reflect::Service<Key = Self::Key>;

    fn write_stage<St>(
        &'a self,
    ) -> Result<BTreeMap<&'a Self::Key, Self::WriteGuardBase>, Error<'a, Self::Key>>
        where St: reflect::Service<Key = Self::Key>;*/

    type StageIter: Iterator<Item = (&'a Self::Key, &'a Self::Stage)> + 'a;

    fn stages(&'a self) -> Self::StageIter;
}

// ++++++++++++++++++++ methods ++++++++++++++++++++
// TODO move this somewhere else?
/*
// ++++++++++++++++++++ Container ++++++++++++++++++++

pub struct Container<Key, Base: ?Sized> {
    services: BTreeMap<Key, RwLock<Box<Base>>>,
    abba_prevention: Mutex<()>,
}

pub type Services<'a, Key, Base: ?Sized> = btree_map::Iter<'a, Key, RwLock<Box<Base>>>;

impl<Key, Base: ?Sized> Container<Key, Base>
    where Key: reflect::Key, Base: Any
{
    #[doc(hidden)]
    pub fn new() -> Self {
        Container{
            services: BTreeMap::new(),
            abba_prevention: Mutex::new(()),
        }
    }

    #[doc(hidden)]
    pub fn register_service(&mut self, key: Key, svc: Box<Base>){
        self.services.insert(key, RwLock::new(svc));
    }

    #[doc(hidden)]
    pub fn unregister_service(&mut self, key: &Key) -> bool {
        self.services.remove(key).is_some()
    }

    pub fn services(&self) -> Services<Key, Base> {
        self.services.iter()
    }

    pub fn get_service(&self, key: &Key) -> Option<&RwLock<Box<Base>>> {
        self.services.get(key)
    }

    pub fn invoke<'a, M>(&'a self) -> Result<M::Ret, M::Error>
        where M: Method<'a, Self>,
    {
        // prevent AB-BA deadlocks
        let _ = self.abba_prevention.lock();

        M::invoke(self)
    }
}

impl<'a, Key, Base: ?Sized> Method<'a, Container<Key, Base>> for ()
    where Key: reflect::Key, Base: Any
{
    type Ret = ();
    type Error = DummyError;

    fn invoke(_: &'a Container<Key, Base>) -> Result<Self::Ret, Self::Error> {
        Ok(())
    }
}

impl<'a, Key, Base: ?Sized, Svc> Method<'a, Container<Key, Base>> for Read<Svc>
    where Key: reflect::Key, Base: Any + Downcast<Svc>, Svc: reflect::Object<Key = Key>
{
    type Ret = ReadGuard<'a, Svc, Base>;
    type Error = LockError<'a, Key>;

    fn invoke(ioc: &'a Container<Key, Base>) -> Result<Self::Ret, Self::Error> {
        let key = Svc::key();
        let service = match ioc.get_service(key) {
            Some(r) => r,
            None => return Err(LockError::NotFound{ key: key })
        };
        let guard = match service.read() {
            Ok(r) => r,
            Err(_) => return Err(LockError::Poisoned{ key: key })
        };
        if !guard.is_type() {
            return Err(LockError::MismatchedType{
                key: key,
                expected: type_name::<Svc>(),
                found: type_name::<Svc>(),
            })
        };
        Ok(ReadGuard::new(guard))
    }
}

impl<'a, Key, Base: ?Sized, Svc> Method<'a, Container<Key, Base>> for Write<Svc>
    where Key: reflect::Key, Base: Any + Downcast<Svc>, Svc: reflect::Object<Key = Key>
{
    type Ret = WriteGuard<'a, Svc, Base>;
    type Error = LockError<'a, Key>;

    fn invoke(ioc: &'a Container<Key, Base>) -> Result<Self::Ret, Self::Error> {
        let key = Svc::key();
        let service = match ioc.get_service(key) {
            Some(r) => r,
            None => return Err(LockError::NotFound{ key: key })
        };
        let guard = match service.write() {
            Ok(r) => r,
            Err(_) => return Err(LockError::Poisoned{ key: key })
        };
        if !guard.is_type() {
            return Err(LockError::MismatchedType{
                key: key,
                expected: type_name::<Svc>(),
                found: type_name::<Svc>(),
            })
        };
        Ok(WriteGuard::new(guard))
    }
}

impl<'a, Key, Base: ?Sized> Method<'a, Container<Key, Base>> for ReadAll
    where Key: reflect::Key, Base: Any
{
    type Ret = ReadGuardMap<'a, Key, Base>;
    type Error = LockError<'a, Key>;

    fn invoke(ioc: &'a Container<Key, Base>) -> Result<Self::Ret, Self::Error> {
        let mut map = ReadGuardMap::new();
        for (key, service) in ioc.services() {
            let guard = match service.read() {
                Ok(r) => r, Err(_) => return Err(LockError::Poisoned{ key: key })
            };
            map.insert(key, guard);
        }
        Ok(map)
    }
}

impl<'a, Key, Base: ?Sized> Method<'a, Container<Key, Base>> for WriteAll
    where Key: reflect::Key, Base: Any
{
    type Ret = WriteGuardMap<'a, Key, Base>;
    type Error = LockError<'a, Key>;

    fn invoke(ioc: &'a Container<Key, Base>) -> Result<Self::Ret, Self::Error> {
        let mut map = WriteGuardMap::new();
        for (key, service) in ioc.services() {
            let guard = match service.write() {
                Ok(r) => r, Err(_) => return Err(LockError::Poisoned{ key: key })
            };
            map.insert(key, guard);
        }
        Ok(map)
    }
}

impl<'a, Key, Base: ?Sized, Obj> Method<'a, Container<Key, Base>> for Create<Obj>
where
    Key: reflect::Key,
    Base: Any + Downcast<Obj::Factory>,
    Obj: FactoryObject<Key = Key> + 'a,
    Obj::Factory: FactoryBase<'a, Container<Key, Base>, Obj>
{
    type Ret = Obj;
    type Error = CreationError<'a,
        <Obj::Factory as reflect::Object>::Key,
        <Obj::Factory as FactoryBase<'a, Container<Key, Base>, Obj>>::Error
    >;

    fn invoke(ioc: &'a Container<Key, Base>) -> Result<Self::Ret, Self::Error> {
        let factory = try!{Read::<Obj::Factory>::invoke(ioc)};

        factory.create(ioc)
    }
}

impl<Key, Base: ?Sized> Container<Key, Base>
    where Key: reflect::Key, Base: Any
{
    /// Shortcut for `.invoke::<ioc::Read<{Svc}>>(())`.
    pub fn read<Svc>(&self) -> Result<ReadGuard<Svc, Base>, LockError<Svc::Key>>
        where Svc: reflect::Object<Key = Key>, Base: Downcast<Svc>
    {
        self.invoke::<Read<Svc>>()
    }

    /// Shortcut for `.invoke::<ioc::Write<{Svc}>>(())`.
    pub fn write<Svc>(&self) -> Result<WriteGuard<Svc, Base>, LockError<Svc::Key>>
        where Svc: reflect::Object<Key = Key>, Base: Downcast<Svc>
    {
        self.invoke::<Write<Svc>>()
    }

    /// Shortcut for `.invoke::<ioc::ReadAll>(())`.
    pub fn read_all(&self) -> Result<ReadGuardMap<Key, Base>, LockError<Key>> {
        self.invoke::<ReadAll>()
    }

    /// Shortcut for `.invoke::<ioc::WriteAll>(())`.
    pub fn write_all(&self) -> Result<WriteGuardMap<Key, Base>, LockError<Key>> {
        self.invoke::<WriteAll>()
    }

    /// Shortcut for `.invoke::<ioc::Create<{Obj}>>(args)`.
    pub fn create<'a, Obj>(&'a self) -> Result<Obj, CreationError<<Obj::Factory as reflect::Object>::Key, <Obj::Factory as FactoryBase<'a, Self, Obj>>::Error>>
    where
        Obj: FactoryObject<Key = Key> + 'a,
        Obj::Factory: FactoryBase<'a, Self, Obj>,
        Base: Downcast<Obj::Factory>,
    {
        self.invoke::<Create<Obj>>()
    }
}

// ++++++++++++++++++++ ContainerBuilder ++++++++++++++++++++

pub struct ContainerBuilder<Key, Base: ?Sized> {
    ioc: Container<Key, Base>,
}

impl<Key, Base: ?Sized> ContainerBuilder<Key, Base>
    where Key: reflect::Key, Base: Any
{
    pub fn new() -> Self {
        ContainerBuilder{ ioc: Container::new() }
    }

    pub fn register_service(&mut self, key: Key, svc: Box<Base>) -> &mut Self {
        self.ioc.register_service(key, svc);
        self
    }

    /// NOTE: The `Box<Svc>: Into<Box<Base>>`-clause is needed due to rusts lack of
    /// HKT or a `Coercible`-trait (to name two solutions).
    pub fn register<Svc>(&mut self, svc: Svc) -> &mut Self
        where Svc: reflect::Object<Key = Key>, Box<Svc>: Into<Box<Base>>,
    {
        self.register_service(Svc::key().clone(), Box::new(svc).into())
    }

    pub fn build(self) -> Container<Key, Base> {
        self.ioc
    }
}

impl<Key, Base: ?Sized> Default for ContainerBuilder<Key, Base>
    where Key: reflect::Key, Base: Any
{
    fn default() -> Self { Self::new() }
}
*/
<|endoftext|>