<commit_before>
use super::*;
// qqq : for Dima : bad /* aaa : Dmytro : fixed */
use wstring_tools::string::parse::OpType::{ Primitive, Vector };

//

tests_impls!
{
  #[ test ]
  fn basic()
  {
    let instruction = wca::instruction::instruction_parse()
    .instruction( "" )
    .perform();
    let exp = wca::instruction::Instruction
    {
      err : Some( wtools::error::Error::new( "Invalid command" ) ),
      command_name : "".to_string(),
      subject : "".to_string(),
      properties_map : HashMap::new(),
    };
    a_id!( instruction, exp );

    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get" )
    .perform();
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "".to_string(),
      properties_map : HashMap::new(),
    };
    a_id!( instruction, exp );

    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get some" )
    .perform();
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "some".to_string(),
      properties_map : HashMap::new(),
    };
    a_id!( instruction, exp );

    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get v:1" )
    .perform();
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "".to_string(),
      properties_map : HashMap::from([ ( "v".to_string(), Primitive( "1".to_string() ) ) ]),
    };
    a_id!( instruction, exp );

    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get some v:1" )
    .perform();
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "some".to_string(),
      properties_map : HashMap::from([ ( "v".to_string(), Primitive( "1".to_string() ) ) ]),
    };
    a_id!( instruction, exp );

    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get some v:1 routine:some" )
    .perform();
    let properties_map = HashMap::from
    ([
      ( "v".to_string(), Primitive( "1".to_string() ) ),
      ( "routine".to_string(), Primitive( "some".to_string() ) ),
    ]);
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "some".to_string(),
      properties_map,
    };
    a_id!( instruction, exp );

    /* */

    let aggregator_map = HashMap::new();
    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get some v:1 routine:some" )
    .properties_map( aggregator_map )
    .perform();
    let properties_map = HashMap::from
    ([
      ( "v".to_string(), Primitive( "1".to_string() ) ),
      ( "routine".to_string(), Primitive( "some".to_string() ) ),
    ]);
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "some".to_string(),
      properties_map,
    };
    a_id!( instruction, exp );

    let mut aggregator_map = HashMap::new();
    aggregator_map.insert( "ne".to_string(), Primitive( "-2".to_string() ) );
    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get some v:1 routine:some" )
    .properties_map( aggregator_map )
    .perform();
    let properties_map = HashMap::from
    ([
      ( "v".to_string(), Primitive( "1".to_string() ) ),
      ( "routine".to_string(), Primitive( "some".to_string() ) ),
      ( "ne".to_string(), Primitive( "-2".to_string() ) ),
    ]);
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "some".to_string(),
      properties_map,
    };
    a_id!( instruction, exp );
  }

  //

  #[ test ]
  fn with_several_values()
  {
    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get some v:1 v:2" )
    .several_values( false )
    .perform();
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "some".to_string(),
      properties_map : HashMap::from([ ( "v".to_string(), Primitive( "2".to_string() ) ) ]),
    };
    a_id!( instruction, exp );

    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get some v:[1,2]" )
    .several_values( false )
    .perform();
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "some".to_string(),
      properties_map : HashMap::from([ ( "v".to_string(), Vector( vec![ "1".to_string(), "2".to_string() ] ) ) ]),
    };
    a_id!( instruction, exp );

    /* */

    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get some v:1 v:2" )
    .several_values( true )
    .perform();
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "some".to_string(),
      properties_map : HashMap::from([ ( "v".to_string(), Vector( vec![ "1".to_string(), "2".to_string() ] ) ) ]),
    };
    a_id!( instruction, exp );

    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get some v:[1,2]" )
    .several_values( true )
    .perform();
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "some".to_string(),
      properties_map : HashMap::from([ ( "v".to_string(), Vector( vec![ "1".to_string(), "2".to_string() ] ) ) ]),
    };
    a_id!( instruction, exp );

    /* */

    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get some v:[1,2] v:3" )
    .several_values( true )
    .perform();
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "some".to_string(),
      properties_map : HashMap::from([ ( "v".to_string(), Vector( vec![ "1".to_string(), "2".to_string(), "3".to_string() ] ) ) ]),
    };
    a_id!( instruction, exp );

    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get some v:3 v:[1,2]" )
    .several_values( true )
    .perform();
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "some".to_string(),
      properties_map : HashMap::from([ ( "v".to_string(), Vector( vec![ "3".to_string(), "1".to_string(), "2".to_string() ] ) ) ]),
    };
    a_id!( instruction, exp );
  }
}

//

tests_index!
{
  basic,
  with_several_values,
}
<commit_msg>Fix test suite `instruction_test`, use no extra directives<commit_after>
use super::*;
// qqq : for Dima : bad /* aaa : Dmytro : fixed */
use wstring_tools::string::parse::OpType::{ Primitive, Vector };

//

tests_impls!
{
  fn basic()
  {
    let instruction = wca::instruction::instruction_parse()
    .instruction( "" )
    .perform();
    let exp = wca::instruction::Instruction
    {
      err : Some( wtools::error::Error::new( "Invalid command" ) ),
      command_name : "".to_string(),
      subject : "".to_string(),
      properties_map : HashMap::new(),
    };
    a_id!( instruction, exp );

    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get" )
    .perform();
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "".to_string(),
      properties_map : HashMap::new(),
    };
    a_id!( instruction, exp );

    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get some" )
    .perform();
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "some".to_string(),
      properties_map : HashMap::new(),
    };
    a_id!( instruction, exp );

    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get v:1" )
    .perform();
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "".to_string(),
      properties_map : HashMap::from([ ( "v".to_string(), Primitive( "1".to_string() ) ) ]),
    };
    a_id!( instruction, exp );

    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get some v:1" )
    .perform();
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "some".to_string(),
      properties_map : HashMap::from([ ( "v".to_string(), Primitive( "1".to_string() ) ) ]),
    };
    a_id!( instruction, exp );

    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get some v:1 routine:some" )
    .perform();
    let properties_map = HashMap::from
    ([
      ( "v".to_string(), Primitive( "1".to_string() ) ),
      ( "routine".to_string(), Primitive( "some".to_string() ) ),
    ]);
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "some".to_string(),
      properties_map,
    };
    a_id!( instruction, exp );

    /* */

    let aggregator_map = HashMap::new();
    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get some v:1 routine:some" )
    .properties_map( aggregator_map )
    .perform();
    let properties_map = HashMap::from
    ([
      ( "v".to_string(), Primitive( "1".to_string() ) ),
      ( "routine".to_string(), Primitive( "some".to_string() ) ),
    ]);
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "some".to_string(),
      properties_map,
    };
    a_id!( instruction, exp );

    let mut aggregator_map = HashMap::new();
    aggregator_map.insert( "ne".to_string(), Primitive( "-2".to_string() ) );
    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get some v:1 routine:some" )
    .properties_map( aggregator_map )
    .perform();
    let properties_map = HashMap::from
    ([
      ( "v".to_string(), Primitive( "1".to_string() ) ),
      ( "routine".to_string(), Primitive( "some".to_string() ) ),
      ( "ne".to_string(), Primitive( "-2".to_string() ) ),
    ]);
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "some".to_string(),
      properties_map,
    };
    a_id!( instruction, exp );
  }

  //

  fn with_several_values()
  {
    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get some v:1 v:2" )
    .several_values( false )
    .perform();
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "some".to_string(),
      properties_map : HashMap::from([ ( "v".to_string(), Primitive( "2".to_string() ) ) ]),
    };
    a_id!( instruction, exp );

    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get some v:[1,2]" )
    .several_values( false )
    .perform();
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "some".to_string(),
      properties_map : HashMap::from([ ( "v".to_string(), Vector( vec![ "1".to_string(), "2".to_string() ] ) ) ]),
    };
    a_id!( instruction, exp );

    /* */

    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get some v:1 v:2" )
    .several_values( true )
    .perform();
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "some".to_string(),
      properties_map : HashMap::from([ ( "v".to_string(), Vector( vec![ "1".to_string(), "2".to_string() ] ) ) ]),
    };
    a_id!( instruction, exp );

    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get some v:[1,2]" )
    .several_values( true )
    .perform();
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "some".to_string(),
      properties_map : HashMap::from([ ( "v".to_string(), Vector( vec![ "1".to_string(), "2".to_string() ] ) ) ]),
    };
    a_id!( instruction, exp );

    /* */

    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get some v:[1,2] v:3" )
    .several_values( true )
    .perform();
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "some".to_string(),
      properties_map : HashMap::from([ ( "v".to_string(), Vector( vec![ "1".to_string(), "2".to_string(), "3".to_string() ] ) ) ]),
    };
    a_id!( instruction, exp );

    let instruction = wca::instruction::instruction_parse()
    .instruction( ".get some v:3 v:[1,2]" )
    .several_values( true )
    .perform();
    let exp = wca::instruction::Instruction
    {
      err : None,
      command_name : ".get".to_string(),
      subject : "some".to_string(),
      properties_map : HashMap::from([ ( "v".to_string(), Vector( vec![ "3".to_string(), "1".to_string(), "2".to_string() ] ) ) ]),
    };
    a_id!( instruction, exp );
  }
}

//

tests_index!
{
  basic,
  with_several_values,
}
<|endoftext|>


<commit_before>// Copyright 2014 The CGMath Developers. For a full listing of the authors,
// refer to the Cargo.toml file at the top-level directory of this distribution.
//
// 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.

#[macro_use]
extern crate cgmath;

use cgmath::*;

#[test]
fn macro_assert_approx_eq_eps() {
    assert_approx_eq_eps!(1.0f64, 1.001, 0.01);
}

#[test]
#[should_fail]
fn macro_assert_approx_eq_eps_fail() {
    assert_approx_eq_eps!(1.0f32, 1.02, 0.01);
}

#[test]
fn macro_assert_approx_eq() {
    assert_approx_eq!(7.0f32 / 5.0, 1.4);
}

#[test]
#[should_fail]
fn macro_assert_approx_eq_fail() {
    assert_approx_eq!(1.0f64 / 3.0, 0.333);
}
<commit_msg>#[should_fail] -> #[should_panic]<commit_after>// Copyright 2014 The CGMath Developers. For a full listing of the authors,
// refer to the Cargo.toml file at the top-level directory of this distribution.
//
// 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.

#[macro_use]
extern crate cgmath;

use cgmath::*;

#[test]
fn macro_assert_approx_eq_eps() {
    assert_approx_eq_eps!(1.0f64, 1.001, 0.01);
}

#[test]
#[should_panic]
fn macro_assert_approx_eq_eps_fail() {
    assert_approx_eq_eps!(1.0f32, 1.02, 0.01);
}

#[test]
fn macro_assert_approx_eq() {
    assert_approx_eq!(7.0f32 / 5.0, 1.4);
}

#[test]
#[should_panic]
fn macro_assert_approx_eq_fail() {
    assert_approx_eq!(1.0f64 / 3.0, 0.333);
}
<|endoftext|>


<commit_before>use std;
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::path::Path;

use rand;
use rand::Rng;

use aes::{pad, padding_valid, Aes128, MODE};
use aes::BLOCK_SIZE;

use serialize::from_base64_file;

use unstable_features::all_bytes;
use unstable_features::MoveFrom;

use xor::XOR;

use helper::ceil_div;

use errors::*;

use prefix_suffix_oracles::{DeterministicOracle, Oracle};
use prefix_suffix_oracles::{Oracle11, Oracle12, Oracle13, Oracle14, Oracle16};

fn matasano2_9() -> Result<()> {
    compare(
        [
            89,
            69,
            76,
            76,
            79,
            87,
            32,
            83,
            85,
            66,
            77,
            65,
            82,
            73,
            78,
            69,
            4,
            4,
            4,
            4,
        ].as_ref(),
        &pad(b"YELLOW SUBMARINE".as_ref(), 20)?,
    )
}

#[test]
fn aes_128_cbc() {
    let iv = [0; BLOCK_SIZE];
    let key = b"YELLOW SUBMARINE";
    let input = b"ABCDEFGHIJKLMNOP";
    assert_eq!(
        input.as_ref(),
        &input
            .encrypt(key, Some(&iv), MODE::CBC)
            .unwrap()
            .decrypt(key, Some(&iv), MODE::CBC)
            .unwrap()[..]
    );
}

fn matasano2_10() -> Result<()> {
    let key = b"YELLOW SUBMARINE";
    let input = from_base64_file(Path::new("data/10.txt"))?;
    let cleartext = input.decrypt(key, Some(&[0; BLOCK_SIZE]), MODE::CBC)?;

    //Read reference cleartext
    let path = Path::new("data/10.ref.txt");
    let mut file = File::open(&path)?;
    let mut cleartext_ref = String::new();
    file.read_to_string(&mut cleartext_ref)?;

    compare(cleartext_ref.as_bytes(), &cleartext)
}

fn uses_ecb(oracle: &mut Oracle11) -> Result<bool> {
    // Assumes that oracle prepends at most one block of jibber
    // TODO: Can we relax this condition?
    let input = vec![0; 3 * BLOCK_SIZE];
    let ciphertext = oracle.encrypt(&input)?;
    let blocks: Vec<&[u8]> = ciphertext.chunks(BLOCK_SIZE).skip(1).take(2).collect();
    Ok(blocks[0] == blocks[1])
}

fn uses_padding<T: Oracle>(oracle: &T) -> Result<bool> {
    Ok((oracle.encrypt(&[0])?.len()-oracle.encrypt(&[])?.len()) % BLOCK_SIZE == 0)
}

fn prefix_plus_suffix_length<T: Oracle>(oracle: &T) -> Result<usize> {
    let initial = oracle.encrypt(&[])?.len();
    if !uses_padding(oracle)? {
        return Ok(initial);
    }

    let input = [0; BLOCK_SIZE];
    //Would profit from range_inclusive
    if let Some(index) = (1..BLOCK_SIZE + 1).find(|&i| {
        if let Ok(ciphertext) = oracle.encrypt(&input[BLOCK_SIZE - i..]) {
            initial != ciphertext.len()
        } else {
            false
        }
    }) {
        Ok(initial - index)
    } else {
        bail!(
            "length of oracle output did not change, something is wrong with the provided oracle"
        );
    }
}

/* For an oracle prepending prefix and appending suffix to its input, this function returns
 * prefix.len()/BLOCK_SIZE, that is the number of blocks fully occupied by the prefix.
 *
 * To determine this number, we pass two different cleartexts to the oracle and count the number
 * of identical blocks at the start of the corresponding ciphertexts. */
fn prefix_blocks_count<T: DeterministicOracle>(oracle: &T) -> Result<usize> {
    if let Some(result) = oracle
        .encrypt(&[0])?
        .chunks(BLOCK_SIZE)
        .zip(oracle.encrypt(&[1])?.chunks(BLOCK_SIZE))
        .position(|(x, y)| x != y)
    {
        Ok(result)
    } else {
        bail!("no differing blocks found, something is wrong with the provided oracle");
    }
}

// We look at the first block C not fully occupied by the prefix and fill it with a
// constant block B, say consisting of 0's.
// This part of the cleartext in oracle looks as follows:
//
//                               <------ B ------->
// prefix[?] prefix[?] prefix[?] 0 0 ... 0 || 0 0 0 suffix[0] suffix[1]
// <---------- C ------------------------>
//
// We then successively reduce the length of B until the ciphertext of C
// changes. This happens as soon as the cleartext in oracle looks as follows:
//
//                               <-- B -->
// prefix[?] prefix[?] prefix[?] 0 0 ... 0 suffix[0] || suffix[1]
// <---------- C ---------------------------------->
//
// This gives us the length of the prefix in C.
//
// We need to do this with two different constants because suffix[0] might accidentally
// coincide with the constant we have chosen.

pub fn prefix_length<T: DeterministicOracle>(oracle: &T) -> Result<usize> {
    let n = prefix_blocks_count(oracle)?;
    let helper = |k: u8| -> Result<usize> {
        let constant_block = vec![k; BLOCK_SIZE];

        let mut prev = oracle.encrypt(&constant_block)?;

        for i in 0..BLOCK_SIZE {
            let cur = oracle.encrypt(&constant_block[i + 1..])?;
            if prev.chunks(BLOCK_SIZE).nth(n) != cur.chunks(BLOCK_SIZE).nth(n) {
                return Ok(i);
            }
            prev = cur;
        }
        Ok(BLOCK_SIZE)
    };

    Ok(n * BLOCK_SIZE + std::cmp::min(helper(0)?, helper(1)?))
}

fn suffix_length<T: DeterministicOracle>(oracle: &T) -> Result<usize> {
    Ok(prefix_plus_suffix_length(oracle)? - prefix_length(oracle)?)
}

#[test]
fn test_length_functions() {
    let key = random_block();
    let mut prefix = Vec::new();
    let mut suffix = Vec::new();
    for _ in 0..64 {
        for _ in 0..64 {
            {
                let oracle = CommonPrefixSuffixOracle {
                    key: key.clone(),
                    prefix: prefix.clone(),
                    suffix: suffix.clone(),
                    mode: MODE::CTR,
                };
                println!("{}", prefix.len());
                println!("{}", prefix_length(&oracle).unwrap());
                assert!(prefix.len() == prefix_length(&oracle).unwrap());
                //assert!(suffix.len() == suffix_length(&oracle).unwrap());
            }
            suffix.push(1);
        }
        suffix.clear();
        prefix.push(0);
    }
}

fn matasano2_11() -> Result<()> {
    let mut oracle = Oracle11::new()?;
    let uses_ecb = uses_ecb(&mut oracle)?;
    oracle.verify_solution(uses_ecb)
}

fn decrypt_suffix<T: DeterministicOracle>(oracle: &T) -> Result<Vec<u8>> {
    // The following input is chosen in such a way that the cleartext in oracle looks as follows:
    //
    //            input start      input end
    //                ↓                ↓
    // <-- prefix --> 0 ... 0 || 0 ... 0 suffix[0] || suffix[1] ...
    //                ↑          ↑
    //            prefix_len  prefix_blocks*BLOCK_SIZE
    //
    // The resulting ciphertext is compared to oracle([input, u]). The u yielding a match is
    // equal to suffix[0].

    let prefix_len = prefix_length(oracle)?;
    let (prefix_blocks, prefix_padding) = ceil_div(prefix_len, BLOCK_SIZE);
    let suffix_len = suffix_length(oracle)?;

    let mut suffix = Vec::with_capacity(suffix_len);

    let mut input = vec![0; prefix_padding + BLOCK_SIZE - 1];
    let reference_ciphertexts = (0..BLOCK_SIZE)
        .map(|left_shift| oracle.encrypt(&input[left_shift..]))
        .collect::<Result<Vec<Vec<u8>>>>()?;

    for i in 0..suffix_len {
        let block = prefix_blocks + i / BLOCK_SIZE;
        //let block_range = block*BLOCK_SIZE .. (block + 1)*BLOCK_SIZE;
        let left_shift = i % BLOCK_SIZE;
        for u in all_bytes() {
            input.push(u);
            if reference_ciphertexts[left_shift][block * BLOCK_SIZE..(block + 1) * BLOCK_SIZE]
                == oracle.encrypt(&input[left_shift..])?
                    [block * BLOCK_SIZE..(block + 1) * BLOCK_SIZE]
            {
                suffix.push(u);
                break;
            }
            input.pop();
        }
    }
    Ok(suffix)
}

fn matasano2_12() -> Result<()> {
    let oracle = Oracle12::new()?;
    oracle.verify_suffix(&decrypt_suffix(&oracle)?)
}

pub fn decode_profile(u: &[u8], sep: u8) -> HashMap<&[u8], &[u8]> {
    let mut p = HashMap::new();
    for pair in u.split(|&x| x == sep) {
        let mut components = pair.split(|&x| x == b'=');
        p.insert(components.next().unwrap(), components.next().unwrap_or(&[]));
    }
    p
}

/* The following function works under the single assumption that the target value "user" (to be
   replaced by "admin") is stored at the very end of the profile. */
fn matasano2_13() -> Result<()> {
    let oracle = Oracle13::new()?;

    let prefix_len = prefix_length(&oracle)?;
    let (prefix_blocks, prefix_padding) = ceil_div(prefix_len, BLOCK_SIZE);
    let target_cleartext = b"admin".pad();
    let mut input = vec![0; prefix_padding];
    input.extend_from_slice(&target_cleartext);
    let target_last_block = oracle
        .encrypt(&input)?
        .split_off(prefix_blocks * BLOCK_SIZE);

    let (blocks, padding) = ceil_div(prefix_plus_suffix_length(&oracle)?, BLOCK_SIZE);
    let mut ciphertext = oracle.encrypt(&vec![0; padding + "user".len()])?;
    compare((blocks + 1) * BLOCK_SIZE, ciphertext.len())?;

    ciphertext[blocks * BLOCK_SIZE..].move_from2(target_last_block, 0, BLOCK_SIZE);

    oracle.verify_solution(&ciphertext)
}

fn matasano2_14() -> Result<()> {
    let oracle = Oracle14::new()?;
    oracle.verify_suffix(&decrypt_suffix(&oracle)?)
}

pub fn random_block() -> Vec<u8> {
    let mut rng = rand::thread_rng();
    rng.gen_iter().take(BLOCK_SIZE).collect()
}

fn matasano2_15() -> Result<()> {
    compare(true, b"ICE ICE BABY\x04\x04\x04\x04".padding_valid())?;
    compare(false, b"ICE ICE BABY\x05\x05\x05\x05".padding_valid())?;
    compare(false, b"ICE ICE BABY\x01\x02\x03\x04".padding_valid())?;
    compare(false, b"ICE ICE BABY\x03\x03\x03".padding_valid())?;
    compare(
        true,
        padding_valid(
            b"ICE ICE BABY\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C",
            12,
        ).unwrap(),
    )?;
    Ok(())
}

fn matasano2_16() -> Result<()> {
    let oracle = Oracle16::new()?;

    let (blocks, padding) = ceil_div(prefix_plus_suffix_length(&oracle)?, BLOCK_SIZE);
    let mut ciphertext = oracle.encrypt(&vec![0; padding])?;
    compare((blocks + 1) * BLOCK_SIZE, ciphertext.len())?;

    let target_last_block = b";admin=true".pad();
    let current_last_block = vec![BLOCK_SIZE as u8; BLOCK_SIZE];
    let attack_bitflip = target_last_block.xor(&current_last_block);

    // Flip the next to last block
    ciphertext[(blocks - 1) * BLOCK_SIZE..blocks * BLOCK_SIZE].xor_inplace(&attack_bitflip);

    oracle.verify_solution(&ciphertext)
}

pub fn run() {
    println!("Set 2");
    run_exercise(matasano2_9, 9);
    run_exercise(matasano2_10, 10);
    run_exercise(matasano2_11, 11);
    run_exercise(matasano2_12, 12);
    run_exercise(matasano2_13, 13);
    run_exercise(matasano2_14, 14);
    run_exercise(matasano2_15, 15);
    run_exercise(matasano2_16, 16);
}
<commit_msg>Simplify<commit_after>use std;
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::path::Path;

use rand;
use rand::Rng;

use aes::{pad, padding_valid, Aes128, MODE};
use aes::BLOCK_SIZE;

use serialize::from_base64_file;

use unstable_features::all_bytes;
use unstable_features::MoveFrom;

use xor::XOR;

use helper::ceil_div;

use errors::*;

use prefix_suffix_oracles::{DeterministicOracle, Oracle};
use prefix_suffix_oracles::{Oracle11, Oracle12, Oracle13, Oracle14, Oracle16};

fn matasano2_9() -> Result<()> {
    compare(
        [
            89,
            69,
            76,
            76,
            79,
            87,
            32,
            83,
            85,
            66,
            77,
            65,
            82,
            73,
            78,
            69,
            4,
            4,
            4,
            4,
        ].as_ref(),
        &pad(b"YELLOW SUBMARINE".as_ref(), 20)?,
    )
}

#[test]
fn aes_128_cbc() {
    let iv = [0; BLOCK_SIZE];
    let key = b"YELLOW SUBMARINE";
    let input = b"ABCDEFGHIJKLMNOP";
    assert_eq!(
        input.as_ref(),
        &input
            .encrypt(key, Some(&iv), MODE::CBC)
            .unwrap()
            .decrypt(key, Some(&iv), MODE::CBC)
            .unwrap()[..]
    );
}

fn matasano2_10() -> Result<()> {
    let key = b"YELLOW SUBMARINE";
    let input = from_base64_file(Path::new("data/10.txt"))?;
    let cleartext = input.decrypt(key, Some(&[0; BLOCK_SIZE]), MODE::CBC)?;

    //Read reference cleartext
    let path = Path::new("data/10.ref.txt");
    let mut file = File::open(&path)?;
    let mut cleartext_ref = String::new();
    file.read_to_string(&mut cleartext_ref)?;

    compare(cleartext_ref.as_bytes(), &cleartext)
}

fn uses_ecb(oracle: &mut Oracle11) -> Result<bool> {
    // Assumes that oracle prepends at most one block of jibber
    // TODO: Can we relax this condition?
    let input = vec![0; 3 * BLOCK_SIZE];
    let ciphertext = oracle.encrypt(&input)?;
    let blocks: Vec<&[u8]> = ciphertext.chunks(BLOCK_SIZE).skip(1).take(2).collect();
    Ok(blocks[0] == blocks[1])
}

fn uses_padding<T: Oracle>(oracle: &T) -> Result<bool> {
    Ok((oracle.encrypt(&[0])?.len()-oracle.encrypt(&[])?.len()) % BLOCK_SIZE == 0)
}

fn prefix_plus_suffix_length<T: Oracle>(oracle: &T) -> Result<usize> {
    let initial = oracle.encrypt(&[])?.len();
    if !uses_padding(oracle)? {
        return Ok(initial);
    }

    let input = [0; BLOCK_SIZE];
    //Would profit from range_inclusive
    if let Some(index) = (1..BLOCK_SIZE + 1).find(|&i| {
        if let Ok(ciphertext) = oracle.encrypt(&input[..i]) {
            initial != ciphertext.len()
        } else {
            false
        }
    }) {
        Ok(initial - index)
    } else {
        bail!(
            "length of oracle output did not change, something is wrong with the provided oracle"
        );
    }
}

/* For an oracle prepending prefix and appending suffix to its input, this function returns
 * prefix.len()/BLOCK_SIZE, that is the number of blocks fully occupied by the prefix.
 *
 * To determine this number, we pass two different cleartexts to the oracle and count the number
 * of identical blocks at the start of the corresponding ciphertexts. */
fn prefix_blocks_count<T: DeterministicOracle>(oracle: &T) -> Result<usize> {
    if let Some(result) = oracle
        .encrypt(&[0])?
        .chunks(BLOCK_SIZE)
        .zip(oracle.encrypt(&[1])?.chunks(BLOCK_SIZE))
        .position(|(x, y)| x != y)
    {
        Ok(result)
    } else {
        bail!("no differing blocks found, something is wrong with the provided oracle");
    }
}

// We look at the first block C not fully occupied by the prefix and fill it with a
// constant block B, say consisting of 0's.
// This part of the cleartext in oracle looks as follows:
//
//                               <------ B ------->
// prefix[?] prefix[?] prefix[?] 0 0 ... 0 || 0 0 0 suffix[0] suffix[1]
// <---------- C ------------------------>
//
// We then successively reduce the length of B until the ciphertext of C
// changes. This happens as soon as the cleartext in oracle looks as follows:
//
//                               <-- B -->
// prefix[?] prefix[?] prefix[?] 0 0 ... 0 suffix[0] || suffix[1]
// <---------- C ---------------------------------->
//
// This gives us the length of the prefix in C.
//
// We need to do this with two different constants because suffix[0] might accidentally
// coincide with the constant we have chosen.

pub fn prefix_length<T: DeterministicOracle>(oracle: &T) -> Result<usize> {
    let n = prefix_blocks_count(oracle)?;
    let helper = |k: u8| -> Result<usize> {
        let constant_block = vec![k; BLOCK_SIZE];

        let mut prev = oracle.encrypt(&constant_block)?;

        for i in 0..BLOCK_SIZE {
            let cur = oracle.encrypt(&constant_block[i + 1..])?;
            if prev.chunks(BLOCK_SIZE).nth(n) != cur.chunks(BLOCK_SIZE).nth(n) {
                return Ok(i);
            }
            prev = cur;
        }
        Ok(BLOCK_SIZE)
    };

    Ok(n * BLOCK_SIZE + std::cmp::min(helper(0)?, helper(1)?))
}

fn suffix_length<T: DeterministicOracle>(oracle: &T) -> Result<usize> {
    Ok(prefix_plus_suffix_length(oracle)? - prefix_length(oracle)?)
}

#[test]
fn test_length_functions() {
    let key = random_block();
    let mut prefix = Vec::new();
    let mut suffix = Vec::new();
    for _ in 0..64 {
        for _ in 0..64 {
            {
                let oracle = CommonPrefixSuffixOracle {
                    key: key.clone(),
                    prefix: prefix.clone(),
                    suffix: suffix.clone(),
                    mode: MODE::CTR,
                };
                println!("{}", prefix.len());
                println!("{}", prefix_length(&oracle).unwrap());
                assert!(prefix.len() == prefix_length(&oracle).unwrap());
                //assert!(suffix.len() == suffix_length(&oracle).unwrap());
            }
            suffix.push(1);
        }
        suffix.clear();
        prefix.push(0);
    }
}

fn matasano2_11() -> Result<()> {
    let mut oracle = Oracle11::new()?;
    let uses_ecb = uses_ecb(&mut oracle)?;
    oracle.verify_solution(uses_ecb)
}

fn decrypt_suffix<T: DeterministicOracle>(oracle: &T) -> Result<Vec<u8>> {
    // The following input is chosen in such a way that the cleartext in oracle looks as follows:
    //
    //            input start      input end
    //                ↓                ↓
    // <-- prefix --> 0 ... 0 || 0 ... 0 suffix[0] || suffix[1] ...
    //                ↑          ↑
    //            prefix_len  prefix_blocks*BLOCK_SIZE
    //
    // The resulting ciphertext is compared to oracle([input, u]). The u yielding a match is
    // equal to suffix[0].

    let prefix_len = prefix_length(oracle)?;
    let (prefix_blocks, prefix_padding) = ceil_div(prefix_len, BLOCK_SIZE);
    let suffix_len = suffix_length(oracle)?;

    let mut suffix = Vec::with_capacity(suffix_len);

    let mut input = vec![0; prefix_padding + BLOCK_SIZE - 1];
    let reference_ciphertexts = (0..BLOCK_SIZE)
        .map(|left_shift| oracle.encrypt(&input[left_shift..]))
        .collect::<Result<Vec<Vec<u8>>>>()?;

    for i in 0..suffix_len {
        let block = prefix_blocks + i / BLOCK_SIZE;
        //let block_range = block*BLOCK_SIZE .. (block + 1)*BLOCK_SIZE;
        let left_shift = i % BLOCK_SIZE;
        for u in all_bytes() {
            input.push(u);
            if reference_ciphertexts[left_shift][block * BLOCK_SIZE..(block + 1) * BLOCK_SIZE]
                == oracle.encrypt(&input[left_shift..])?
                    [block * BLOCK_SIZE..(block + 1) * BLOCK_SIZE]
            {
                suffix.push(u);
                break;
            }
            input.pop();
        }
    }
    Ok(suffix)
}

fn matasano2_12() -> Result<()> {
    let oracle = Oracle12::new()?;
    oracle.verify_suffix(&decrypt_suffix(&oracle)?)
}

pub fn decode_profile(u: &[u8], sep: u8) -> HashMap<&[u8], &[u8]> {
    let mut p = HashMap::new();
    for pair in u.split(|&x| x == sep) {
        let mut components = pair.split(|&x| x == b'=');
        p.insert(components.next().unwrap(), components.next().unwrap_or(&[]));
    }
    p
}

/* The following function works under the single assumption that the target value "user" (to be
   replaced by "admin") is stored at the very end of the profile. */
fn matasano2_13() -> Result<()> {
    let oracle = Oracle13::new()?;

    let prefix_len = prefix_length(&oracle)?;
    let (prefix_blocks, prefix_padding) = ceil_div(prefix_len, BLOCK_SIZE);
    let target_cleartext = b"admin".pad();
    let mut input = vec![0; prefix_padding];
    input.extend_from_slice(&target_cleartext);
    let target_last_block = oracle
        .encrypt(&input)?
        .split_off(prefix_blocks * BLOCK_SIZE);

    let (blocks, padding) = ceil_div(prefix_plus_suffix_length(&oracle)?, BLOCK_SIZE);
    let mut ciphertext = oracle.encrypt(&vec![0; padding + "user".len()])?;
    compare((blocks + 1) * BLOCK_SIZE, ciphertext.len())?;

    ciphertext[blocks * BLOCK_SIZE..].move_from2(target_last_block, 0, BLOCK_SIZE);

    oracle.verify_solution(&ciphertext)
}

fn matasano2_14() -> Result<()> {
    let oracle = Oracle14::new()?;
    oracle.verify_suffix(&decrypt_suffix(&oracle)?)
}

pub fn random_block() -> Vec<u8> {
    let mut rng = rand::thread_rng();
    rng.gen_iter().take(BLOCK_SIZE).collect()
}

fn matasano2_15() -> Result<()> {
    compare(true, b"ICE ICE BABY\x04\x04\x04\x04".padding_valid())?;
    compare(false, b"ICE ICE BABY\x05\x05\x05\x05".padding_valid())?;
    compare(false, b"ICE ICE BABY\x01\x02\x03\x04".padding_valid())?;
    compare(false, b"ICE ICE BABY\x03\x03\x03".padding_valid())?;
    compare(
        true,
        padding_valid(
            b"ICE ICE BABY\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C",
            12,
        ).unwrap(),
    )?;
    Ok(())
}

fn matasano2_16() -> Result<()> {
    let oracle = Oracle16::new()?;

    let (blocks, padding) = ceil_div(prefix_plus_suffix_length(&oracle)?, BLOCK_SIZE);
    let mut ciphertext = oracle.encrypt(&vec![0; padding])?;
    compare((blocks + 1) * BLOCK_SIZE, ciphertext.len())?;

    let target_last_block = b";admin=true".pad();
    let current_last_block = vec![BLOCK_SIZE as u8; BLOCK_SIZE];
    let attack_bitflip = target_last_block.xor(&current_last_block);

    // Flip the next to last block
    ciphertext[(blocks - 1) * BLOCK_SIZE..blocks * BLOCK_SIZE].xor_inplace(&attack_bitflip);

    oracle.verify_solution(&ciphertext)
}

pub fn run() {
    println!("Set 2");
    run_exercise(matasano2_9, 9);
    run_exercise(matasano2_10, 10);
    run_exercise(matasano2_11, 11);
    run_exercise(matasano2_12, 12);
    run_exercise(matasano2_13, 13);
    run_exercise(matasano2_14, 14);
    run_exercise(matasano2_15, 15);
    run_exercise(matasano2_16, 16);
}
<|endoftext|>


<commit_before>#![deny(warnings)]
extern crate hyper;
extern crate futures;
extern crate tokio_core;
extern crate pretty_env_logger;

use std::io::{self, Read, Write};
use std::net::TcpListener;
use std::thread;
use std::time::Duration;

use hyper::client::{Client, Request, HttpConnector};
use hyper::{Method, StatusCode};

use futures::{Future, Stream};
use futures::sync::oneshot;

use tokio_core::reactor::{Core, Handle};

fn client(handle: &Handle) -> Client<HttpConnector> {
    Client::new(handle)
}

fn s(buf: &[u8]) -> &str {
    ::std::str::from_utf8(buf).unwrap()
}

macro_rules! test {
    (
        name: $name:ident,
        server:
            expected: $server_expected:expr,
            reply: $server_reply:expr,
        client:
            request:
                method: $client_method:ident,
                url: $client_url:expr,
                headers: [ $($request_headers:expr,)* ],
                body: $request_body:expr,
                proxy: $request_proxy:expr,

            response:
                status: $client_status:ident,
                headers: [ $($response_headers:expr,)* ],
                body: $response_body:expr,
    ) => (
        #[test]
        fn $name() {
            #![allow(unused)]
            use hyper::header::*;
            let _ = pretty_env_logger::init();
            let server = TcpListener::bind("127.0.0.1:0").unwrap();
            let addr = server.local_addr().unwrap();
            let mut core = Core::new().unwrap();
            let client = client(&core.handle());
            let mut req = Request::new(Method::$client_method, format!($client_url, addr=addr).parse().unwrap());
            $(
                req.headers_mut().set($request_headers);
            )*

            if let Some(body) = $request_body {
                let body: &'static str = body;
                req.set_body(body);
            }
            req.set_proxy($request_proxy);

            let res = client.request(req);

            let (tx, rx) = oneshot::channel();

            thread::spawn(move || {
                let mut inc = server.accept().unwrap().0;
                inc.set_read_timeout(Some(Duration::from_secs(5))).unwrap();
                inc.set_write_timeout(Some(Duration::from_secs(5))).unwrap();
                let expected = format!($server_expected, addr=addr);
                let mut buf = [0; 4096];
                let mut n = 0;
                while n < buf.len() && n < expected.len() {
                    n += inc.read(&mut buf[n..]).unwrap();
                }
                assert_eq!(s(&buf[..n]), expected);

                inc.write_all($server_reply.as_ref()).unwrap();
                let _ = tx.send(());
            });

            let rx = rx.map_err(|_| hyper::Error::Io(io::Error::new(io::ErrorKind::Other, "thread panicked")));

            let work = res.join(rx).map(|r| r.0);

            let res = core.run(work).unwrap();
            assert_eq!(res.status(), StatusCode::$client_status);
            $(
                assert_eq!(res.headers().get(), Some(&$response_headers));
            )*

            let body = core.run(res.body().concat2()).unwrap();

            let expected_res_body = Option::<&[u8]>::from($response_body)
                .unwrap_or_default();
            assert_eq!(body.as_ref(), expected_res_body);
        }
    );
}

static REPLY_OK: &'static str = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n";

test! {
    name: client_get,

    server:
        expected: "GET / HTTP/1.1\r\nHost: {addr}\r\n\r\n",
        reply: REPLY_OK,

    client:
        request:
            method: Get,
            url: "http://{addr}/",
            headers: [],
            body: None,
            proxy: false,
        response:
            status: Ok,
            headers: [
                ContentLength(0),
            ],
            body: None,
}

test! {
    name: client_get_query,

    server:
        expected: "GET /foo?key=val HTTP/1.1\r\nHost: {addr}\r\n\r\n",
        reply: REPLY_OK,

    client:
        request:
            method: Get,
            url: "http://{addr}/foo?key=val#dont_send_me",
            headers: [],
            body: None,
            proxy: false,
        response:
            status: Ok,
            headers: [
                ContentLength(0),
            ],
            body: None,
}

test! {
    name: client_post_sized,

    server:
        expected: "\
            POST /length HTTP/1.1\r\n\
            Host: {addr}\r\n\
            Content-Length: 7\r\n\
            \r\n\
            foo bar\
            ",
        reply: REPLY_OK,

    client:
        request:
            method: Post,
            url: "http://{addr}/length",
            headers: [
                ContentLength(7),
            ],
            body: Some("foo bar"),
            proxy: false,
        response:
            status: Ok,
            headers: [],
            body: None,
}

test! {
    name: client_post_chunked,

    server:
        expected: "\
            POST /chunks HTTP/1.1\r\n\
            Host: {addr}\r\n\
            Transfer-Encoding: chunked\r\n\
            \r\n\
            B\r\n\
            foo bar baz\r\n\
            0\r\n\r\n\
            ",
        reply: REPLY_OK,

    client:
        request:
            method: Post,
            url: "http://{addr}/chunks",
            headers: [
                TransferEncoding::chunked(),
            ],
            body: Some("foo bar baz"),
            proxy: false,
        response:
            status: Ok,
            headers: [],
            body: None,
}

test! {
    name: client_http_proxy,

    server:
        expected: "\
            GET http://{addr}/proxy HTTP/1.1\r\n\
            Host: {addr}\r\n\
            \r\n\
            ",
        reply: REPLY_OK,

    client:
        request:
            method: Get,
            url: "http://{addr}/proxy",
            headers: [],
            body: None,
            proxy: true,
        response:
            status: Ok,
            headers: [],
            body: None,
}

test! {
    name: client_head_ignores_body,

    server:
        expected: "\
            HEAD /head HTTP/1.1\r\n\
            Host: {addr}\r\n\
            \r\n\
            ",
        reply: "\
            HTTP/1.1 200 OK\r\n\
            Content-Length: 11\r\n\
            \r\n\
            Hello World\
            ",

    client:
        request:
            method: Head,
            url: "http://{addr}/head",
            headers: [],
            body: None,
            proxy: false,
        response:
            status: Ok,
            headers: [],
            body: None,
}

#[test]
fn client_keep_alive() {
    let server = TcpListener::bind("127.0.0.1:0").unwrap();
    let addr = server.local_addr().unwrap();
    let mut core = Core::new().unwrap();
    let client = client(&core.handle());

    let (tx1, rx1) = oneshot::channel();
    let (tx2, rx2) = oneshot::channel();
    thread::spawn(move || {
        let mut sock = server.accept().unwrap().0;
        sock.set_read_timeout(Some(Duration::from_secs(5))).unwrap();
        sock.set_write_timeout(Some(Duration::from_secs(5))).unwrap();
        let mut buf = [0; 4096];
        sock.read(&mut buf).expect("read 1");
        sock.write_all(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n").expect("write 1");
        let _ = tx1.send(());

        sock.read(&mut buf).expect("read 2");
        let second_get = b"GET /b HTTP/1.1\r\n";
        assert_eq!(&buf[..second_get.len()], second_get);
        sock.write_all(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n").expect("write 2");
        let _ = tx2.send(());
    });

    let rx = rx1.map_err(|_| hyper::Error::Io(io::Error::new(io::ErrorKind::Other, "thread panicked")));
    let res = client.get(format!("http://{}/a", addr).parse().unwrap());
    core.run(res.join(rx).map(|r| r.0)).unwrap();

    let rx = rx2.map_err(|_| hyper::Error::Io(io::Error::new(io::ErrorKind::Other, "thread panicked")));
    let res = client.get(format!("http://{}/b", addr).parse().unwrap());
    core.run(res.join(rx).map(|r| r.0)).unwrap();
}

/* TODO: re-enable once retry works, its currently a flaky test
#[test]
fn client_pooled_socket_disconnected() {
    let _ = pretty_env_logger::init();
    let server = TcpListener::bind("127.0.0.1:0").unwrap();
    let addr = server.local_addr().unwrap();
    let mut core = Core::new().unwrap();
    let client = client(&core.handle());

    let (tx1, rx1) = oneshot::channel();
    let (tx2, rx2) = oneshot::channel();
    thread::spawn(move || {
        let mut sock = server.accept().unwrap().0;
        sock.set_read_timeout(Some(Duration::from_secs(5))).unwrap();
        sock.set_write_timeout(Some(Duration::from_secs(5))).unwrap();
        let mut buf = [0; 4096];
        sock.read(&mut buf).expect("read 1");
        let remote_addr = sock.peer_addr().unwrap().to_string();
        let out = format!("HTTP/1.1 200 OK\r\nContent-Length: {}\r\n\r\n{}", remote_addr.len(), remote_addr);
        sock.write_all(out.as_bytes()).expect("write 1");
        drop(sock);
        tx1.send(());

        let mut sock = server.accept().unwrap().0;
        sock.read(&mut buf).expect("read 2");
        let second_get = b"GET /b HTTP/1.1\r\n";
        assert_eq!(&buf[..second_get.len()], second_get);
        let remote_addr = sock.peer_addr().unwrap().to_string();
        let out = format!("HTTP/1.1 200 OK\r\nContent-Length: {}\r\n\r\n{}", remote_addr.len(), remote_addr);
        sock.write_all(out.as_bytes()).expect("write 2");
        tx2.send(());
    });

    // spin shortly so we receive the hangup on the client socket
    let sleep = Timeout::new(Duration::from_millis(500), &core.handle()).unwrap();
    core.run(sleep).unwrap();

    let rx = rx1.map_err(|_| hyper::Error::Io(io::Error::new(io::ErrorKind::Other, "thread panicked")));
    let res = client.get(format!("http://{}/a", addr).parse().unwrap())
        .and_then(|res| {
            res.body()
                .map(|chunk| chunk.to_vec())
                .collect()
                .map(|vec| vec.concat())
                .map(|vec| String::from_utf8(vec).unwrap())
        });
    let addr1 = core.run(res.join(rx).map(|r| r.0)).unwrap();

    let rx = rx2.map_err(|_| hyper::Error::Io(io::Error::new(io::ErrorKind::Other, "thread panicked")));
    let res = client.get(format!("http://{}/b", addr).parse().unwrap())
        .and_then(|res| {
            res.body()
                .map(|chunk| chunk.to_vec())
                .collect()
                .map(|vec| vec.concat())
                .map(|vec| String::from_utf8(vec).unwrap())
        });
    let addr2 = core.run(res.join(rx).map(|r| r.0)).unwrap();

    assert_ne!(addr1, addr2);
}
*/
<commit_msg>tests(client): improve panic message when client tests fail<commit_after>#![deny(warnings)]
extern crate hyper;
extern crate futures;
extern crate tokio_core;
extern crate pretty_env_logger;

use std::io::{self, Read, Write};
use std::net::TcpListener;
use std::thread;
use std::time::Duration;

use hyper::client::{Client, Request, HttpConnector};
use hyper::{Method, StatusCode};

use futures::{Future, Stream};
use futures::sync::oneshot;

use tokio_core::reactor::{Core, Handle};

fn client(handle: &Handle) -> Client<HttpConnector> {
    Client::new(handle)
}

fn s(buf: &[u8]) -> &str {
    ::std::str::from_utf8(buf).unwrap()
}

macro_rules! test {
    (
        name: $name:ident,
        server:
            expected: $server_expected:expr,
            reply: $server_reply:expr,
        client:
            request:
                method: $client_method:ident,
                url: $client_url:expr,
                headers: [ $($request_headers:expr,)* ],
                body: $request_body:expr,
                proxy: $request_proxy:expr,

            response:
                status: $client_status:ident,
                headers: [ $($response_headers:expr,)* ],
                body: $response_body:expr,
    ) => (
        #[test]
        fn $name() {
            #![allow(unused)]
            use hyper::header::*;
            let _ = pretty_env_logger::init();
            let server = TcpListener::bind("127.0.0.1:0").unwrap();
            let addr = server.local_addr().unwrap();
            let mut core = Core::new().unwrap();
            let client = client(&core.handle());
            let mut req = Request::new(Method::$client_method, format!($client_url, addr=addr).parse().unwrap());
            $(
                req.headers_mut().set($request_headers);
            )*

            if let Some(body) = $request_body {
                let body: &'static str = body;
                req.set_body(body);
            }
            req.set_proxy($request_proxy);

            let res = client.request(req);

            let (tx, rx) = oneshot::channel();

            let thread = thread::Builder::new()
                .name(format!("tcp-server<{}>", stringify!($name)));
            thread.spawn(move || {
                let mut inc = server.accept().unwrap().0;
                inc.set_read_timeout(Some(Duration::from_secs(5))).unwrap();
                inc.set_write_timeout(Some(Duration::from_secs(5))).unwrap();
                let expected = format!($server_expected, addr=addr);
                let mut buf = [0; 4096];
                let mut n = 0;
                while n < buf.len() && n < expected.len() {
                    n += match inc.read(&mut buf[n..]) {
                        Ok(n) => n,
                        Err(e) => panic!("failed to read request, partialy read = {:?}, error: {}", s(&buf[..n]), e),
                    };
                }
                assert_eq!(s(&buf[..n]), expected);

                inc.write_all($server_reply.as_ref()).unwrap();
                let _ = tx.send(());
            }).unwrap();

            let rx = rx.map_err(|_| hyper::Error::Io(io::Error::new(io::ErrorKind::Other, "thread panicked")));

            let work = res.join(rx).map(|r| r.0);

            let res = core.run(work).unwrap();
            assert_eq!(res.status(), StatusCode::$client_status);
            $(
                assert_eq!(res.headers().get(), Some(&$response_headers));
            )*

            let body = core.run(res.body().concat2()).unwrap();

            let expected_res_body = Option::<&[u8]>::from($response_body)
                .unwrap_or_default();
            assert_eq!(body.as_ref(), expected_res_body);
        }
    );
}

static REPLY_OK: &'static str = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n";

test! {
    name: client_get,

    server:
        expected: "GET / HTTP/1.1\r\nHost: {addr}\r\n\r\n",
        reply: REPLY_OK,

    client:
        request:
            method: Get,
            url: "http://{addr}/",
            headers: [],
            body: None,
            proxy: false,
        response:
            status: Ok,
            headers: [
                ContentLength(0),
            ],
            body: None,
}

test! {
    name: client_get_query,

    server:
        expected: "GET /foo?key=val HTTP/1.1\r\nHost: {addr}\r\n\r\n",
        reply: REPLY_OK,

    client:
        request:
            method: Get,
            url: "http://{addr}/foo?key=val#dont_send_me",
            headers: [],
            body: None,
            proxy: false,
        response:
            status: Ok,
            headers: [
                ContentLength(0),
            ],
            body: None,
}

test! {
    name: client_post_sized,

    server:
        expected: "\
            POST /length HTTP/1.1\r\n\
            Host: {addr}\r\n\
            Content-Length: 7\r\n\
            \r\n\
            foo bar\
            ",
        reply: REPLY_OK,

    client:
        request:
            method: Post,
            url: "http://{addr}/length",
            headers: [
                ContentLength(7),
            ],
            body: Some("foo bar"),
            proxy: false,
        response:
            status: Ok,
            headers: [],
            body: None,
}

test! {
    name: client_post_chunked,

    server:
        expected: "\
            POST /chunks HTTP/1.1\r\n\
            Host: {addr}\r\n\
            Transfer-Encoding: chunked\r\n\
            \r\n\
            B\r\n\
            foo bar baz\r\n\
            0\r\n\r\n\
            ",
        reply: REPLY_OK,

    client:
        request:
            method: Post,
            url: "http://{addr}/chunks",
            headers: [
                TransferEncoding::chunked(),
            ],
            body: Some("foo bar baz"),
            proxy: false,
        response:
            status: Ok,
            headers: [],
            body: None,
}

test! {
    name: client_http_proxy,

    server:
        expected: "\
            GET http://{addr}/proxy HTTP/1.1\r\n\
            Host: {addr}\r\n\
            \r\n\
            ",
        reply: REPLY_OK,

    client:
        request:
            method: Get,
            url: "http://{addr}/proxy",
            headers: [],
            body: None,
            proxy: true,
        response:
            status: Ok,
            headers: [],
            body: None,
}

test! {
    name: client_head_ignores_body,

    server:
        expected: "\
            HEAD /head HTTP/1.1\r\n\
            Host: {addr}\r\n\
            \r\n\
            ",
        reply: "\
            HTTP/1.1 200 OK\r\n\
            Content-Length: 11\r\n\
            \r\n\
            Hello World\
            ",

    client:
        request:
            method: Head,
            url: "http://{addr}/head",
            headers: [],
            body: None,
            proxy: false,
        response:
            status: Ok,
            headers: [],
            body: None,
}

#[test]
fn client_keep_alive() {
    let server = TcpListener::bind("127.0.0.1:0").unwrap();
    let addr = server.local_addr().unwrap();
    let mut core = Core::new().unwrap();
    let client = client(&core.handle());

    let (tx1, rx1) = oneshot::channel();
    let (tx2, rx2) = oneshot::channel();
    thread::spawn(move || {
        let mut sock = server.accept().unwrap().0;
        sock.set_read_timeout(Some(Duration::from_secs(5))).unwrap();
        sock.set_write_timeout(Some(Duration::from_secs(5))).unwrap();
        let mut buf = [0; 4096];
        sock.read(&mut buf).expect("read 1");
        sock.write_all(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n").expect("write 1");
        let _ = tx1.send(());

        sock.read(&mut buf).expect("read 2");
        let second_get = b"GET /b HTTP/1.1\r\n";
        assert_eq!(&buf[..second_get.len()], second_get);
        sock.write_all(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n").expect("write 2");
        let _ = tx2.send(());
    });

    let rx = rx1.map_err(|_| hyper::Error::Io(io::Error::new(io::ErrorKind::Other, "thread panicked")));
    let res = client.get(format!("http://{}/a", addr).parse().unwrap());
    core.run(res.join(rx).map(|r| r.0)).unwrap();

    let rx = rx2.map_err(|_| hyper::Error::Io(io::Error::new(io::ErrorKind::Other, "thread panicked")));
    let res = client.get(format!("http://{}/b", addr).parse().unwrap());
    core.run(res.join(rx).map(|r| r.0)).unwrap();
}

/* TODO: re-enable once retry works, its currently a flaky test
#[test]
fn client_pooled_socket_disconnected() {
    let _ = pretty_env_logger::init();
    let server = TcpListener::bind("127.0.0.1:0").unwrap();
    let addr = server.local_addr().unwrap();
    let mut core = Core::new().unwrap();
    let client = client(&core.handle());

    let (tx1, rx1) = oneshot::channel();
    let (tx2, rx2) = oneshot::channel();
    thread::spawn(move || {
        let mut sock = server.accept().unwrap().0;
        sock.set_read_timeout(Some(Duration::from_secs(5))).unwrap();
        sock.set_write_timeout(Some(Duration::from_secs(5))).unwrap();
        let mut buf = [0; 4096];
        sock.read(&mut buf).expect("read 1");
        let remote_addr = sock.peer_addr().unwrap().to_string();
        let out = format!("HTTP/1.1 200 OK\r\nContent-Length: {}\r\n\r\n{}", remote_addr.len(), remote_addr);
        sock.write_all(out.as_bytes()).expect("write 1");
        drop(sock);
        tx1.send(());

        let mut sock = server.accept().unwrap().0;
        sock.read(&mut buf).expect("read 2");
        let second_get = b"GET /b HTTP/1.1\r\n";
        assert_eq!(&buf[..second_get.len()], second_get);
        let remote_addr = sock.peer_addr().unwrap().to_string();
        let out = format!("HTTP/1.1 200 OK\r\nContent-Length: {}\r\n\r\n{}", remote_addr.len(), remote_addr);
        sock.write_all(out.as_bytes()).expect("write 2");
        tx2.send(());
    });

    // spin shortly so we receive the hangup on the client socket
    let sleep = Timeout::new(Duration::from_millis(500), &core.handle()).unwrap();
    core.run(sleep).unwrap();

    let rx = rx1.map_err(|_| hyper::Error::Io(io::Error::new(io::ErrorKind::Other, "thread panicked")));
    let res = client.get(format!("http://{}/a", addr).parse().unwrap())
        .and_then(|res| {
            res.body()
                .map(|chunk| chunk.to_vec())
                .collect()
                .map(|vec| vec.concat())
                .map(|vec| String::from_utf8(vec).unwrap())
        });
    let addr1 = core.run(res.join(rx).map(|r| r.0)).unwrap();

    let rx = rx2.map_err(|_| hyper::Error::Io(io::Error::new(io::ErrorKind::Other, "thread panicked")));
    let res = client.get(format!("http://{}/b", addr).parse().unwrap())
        .and_then(|res| {
            res.body()
                .map(|chunk| chunk.to_vec())
                .collect()
                .map(|vec| vec.concat())
                .map(|vec| String::from_utf8(vec).unwrap())
        });
    let addr2 = core.run(res.join(rx).map(|r| r.0)).unwrap();

    assert_ne!(addr1, addr2);
}
*/
<|endoftext|>


<commit_before>extern crate desync;
extern crate futures;

use desync::Desync;

mod scheduler;
use self::scheduler::timeout::*;

use std::time::*;
use std::thread::*;

#[derive(Debug)]
struct TestData {
    val: u32
}

#[test]
fn can_retrieve_data_synchronously() {
    let desynced = Desync::new(TestData { val: 0 });

    assert!(desynced.sync(|data| data.val) == 0);
}

#[test]
fn can_update_data_asynchronously() {
    let desynced = Desync::new(TestData { val: 0 });

    desynced.async(|data| {
        sleep(Duration::from_millis(100));
        data.val = 42;
    });

    assert!(desynced.sync(|data| data.val) == 42);
}

#[test]
fn can_update_data_asynchronously_1000_times() {
    for _i in 0..1000 {
        timeout(|| {
            let desynced = Desync::new(TestData { val: 0 });

            desynced.async(|data| {
                data.val = 42;
            });
            desynced.async(|data| {
                data.val = 43;
            });

            assert!(desynced.sync(|data| data.val) == 43);
        }, 500);
    }
}

#[test]
fn can_update_data_with_future() {
    timeout(|| {
        use futures::executor;

        let desynced = Desync::new(TestData { val: 0 });

        desynced.async(|data| {
            sleep(Duration::from_millis(100));
            data.val = 42;
        });

        let mut future = executor::spawn(desynced.future(|data| {
            data.val
        }));

        assert!(future.wait_future().unwrap() == 42);
    }, 500);
}

#[test]
fn can_update_data_with_future_1000_times() {
    // Seems to timeout fairly reliably after signalling the future
    use futures::executor;

    for _i in 0..1000 {
        timeout(|| {
            let desynced = Desync::new(TestData { val: 0 });

            desynced.async(|data| {
                data.val = 42;
            });
            desynced.async(|data| {
                data.val = 43;
            });

            let mut future = executor::spawn(desynced.future(|data| data.val));

            assert!(future.wait_future().unwrap() == 43);
        }, 500);
    }
}

#[test]
fn dropping_while_running_isnt_obviously_bad() {
    let desynced = Desync::new(TestData { val: 0 });

    desynced.async(|data| {
        sleep(Duration::from_millis(100));
        data.val = 42;
    });
    desynced.async(|data| {
        sleep(Duration::from_millis(100));
        data.val = 42;
    });
}

#[test]
fn can_wait_for_future() {
    // TODO: occasional test failure that happens if the future 'arrives' before the queue is empty
    // (Because we need a future that arrives when the queue is actually suspended)
    timeout(|| {
        use futures::executor;
        use futures::sync::oneshot;

        // We use a oneshot as our future, and a mpsc channel to track progress
        let desynced = Desync::new(0);
        let (future_tx, future_rx)  = oneshot::channel();

        // First value 0 -> 1
        desynced.async(|val| {
            // Sleep here so the future should be waiting for us
            sleep(Duration::from_millis(100));
            assert!(*val == 0);
            *val = 1;
        });

        // Future should go 1 -> 2, but takes whatever future_tx sends
        let future = desynced.after(future_rx, |val, future_result| {
            assert!(*val == 1);
            *val = future_result.unwrap();

            // Return '4' to anything listening for this future
            Ok(4)
        });

        // Finally, 3
        desynced.async(move |val| { assert!(*val == 2); *val = 3 });

        // Send '2' to the future
        future_tx.send(2).unwrap();
        let mut future  = executor::spawn(future);

        // Future should resolve to 4
        assert!(future.wait_future().unwrap() == 4);

        // Final value should be 3
        assert!(desynced.sync(|val| *val) == 3);
    }, 500);
}
<commit_msg>Demonstrate using desync to update a local variable<commit_after>extern crate desync;
extern crate futures;

use desync::Desync;

mod scheduler;
use self::scheduler::timeout::*;

use std::time::*;
use std::thread::*;

#[derive(Debug)]
struct TestData {
    val: u32
}

#[test]
fn can_retrieve_data_synchronously() {
    let desynced = Desync::new(TestData { val: 0 });

    assert!(desynced.sync(|data| data.val) == 0);
}

#[test]
fn can_retrieve_data_into_local_var() {
    let desynced = Desync::new(TestData { val: 42 });
    let mut val = 0;

    desynced.sync(|data| val = data.val);

    assert!(val == 42);
}

#[test]
fn can_update_data_asynchronously() {
    let desynced = Desync::new(TestData { val: 0 });

    desynced.async(|data| {
        sleep(Duration::from_millis(100));
        data.val = 42;
    });

    assert!(desynced.sync(|data| data.val) == 42);
}

#[test]
fn can_update_data_asynchronously_1000_times() {
    for _i in 0..1000 {
        timeout(|| {
            let desynced = Desync::new(TestData { val: 0 });

            desynced.async(|data| {
                data.val = 42;
            });
            desynced.async(|data| {
                data.val = 43;
            });

            assert!(desynced.sync(|data| data.val) == 43);
        }, 500);
    }
}

#[test]
fn can_update_data_with_future() {
    timeout(|| {
        use futures::executor;

        let desynced = Desync::new(TestData { val: 0 });

        desynced.async(|data| {
            sleep(Duration::from_millis(100));
            data.val = 42;
        });

        let mut future = executor::spawn(desynced.future(|data| {
            data.val
        }));

        assert!(future.wait_future().unwrap() == 42);
    }, 500);
}

#[test]
fn can_update_data_with_future_1000_times() {
    // Seems to timeout fairly reliably after signalling the future
    use futures::executor;

    for _i in 0..1000 {
        timeout(|| {
            let desynced = Desync::new(TestData { val: 0 });

            desynced.async(|data| {
                data.val = 42;
            });
            desynced.async(|data| {
                data.val = 43;
            });

            let mut future = executor::spawn(desynced.future(|data| data.val));

            assert!(future.wait_future().unwrap() == 43);
        }, 500);
    }
}

#[test]
fn dropping_while_running_isnt_obviously_bad() {
    let desynced = Desync::new(TestData { val: 0 });

    desynced.async(|data| {
        sleep(Duration::from_millis(100));
        data.val = 42;
    });
    desynced.async(|data| {
        sleep(Duration::from_millis(100));
        data.val = 42;
    });
}

#[test]
fn can_wait_for_future() {
    // TODO: occasional test failure that happens if the future 'arrives' before the queue is empty
    // (Because we need a future that arrives when the queue is actually suspended)
    timeout(|| {
        use futures::executor;
        use futures::sync::oneshot;

        // We use a oneshot as our future, and a mpsc channel to track progress
        let desynced = Desync::new(0);
        let (future_tx, future_rx)  = oneshot::channel();

        // First value 0 -> 1
        desynced.async(|val| {
            // Sleep here so the future should be waiting for us
            sleep(Duration::from_millis(100));
            assert!(*val == 0);
            *val = 1;
        });

        // Future should go 1 -> 2, but takes whatever future_tx sends
        let future = desynced.after(future_rx, |val, future_result| {
            assert!(*val == 1);
            *val = future_result.unwrap();

            // Return '4' to anything listening for this future
            Ok(4)
        });

        // Finally, 3
        desynced.async(move |val| { assert!(*val == 2); *val = 3 });

        // Send '2' to the future
        future_tx.send(2).unwrap();
        let mut future  = executor::spawn(future);

        // Future should resolve to 4
        assert!(future.wait_future().unwrap() == 4);

        // Final value should be 3
        assert!(desynced.sync(|val| *val) == 3);
    }, 500);
}
<|endoftext|>


<commit_before>#[cfg(feature = "acpi")]
use acpi;
use syscall::io::{Io, Pio};

#[no_mangle]
pub unsafe extern fn kreset() -> ! {
    println!("kreset");

    // 8042 reset
    {
        println!("Reset with 8042");
        let mut port = Pio::<u8>::new(0x64);
        while port.readf(2) {}
        port.write(0xFE);
    }

    // TODO: Use triple fault to guarantee reset

    unreachable!();
}

#[no_mangle]
pub unsafe extern fn kstop() -> ! {
    println!("kstop");

    #[cfg(feature = "acpi")]
    acpi::set_global_s_state(5);

    // Magic shutdown code for bochs and qemu (older versions).
    for c in "Shutdown".bytes() {
        let port = 0x8900;
        println!("Shutdown with outb(0x{:X}, '{}')", port, c as char);
        Pio::<u8>::new(port).write(c);
    }

    // Magic code for VMWare. Also a hard lock.
    println!("Shutdown with cli hlt");
    asm!("cli; hlt" : : : : "intel", "volatile");

    unreachable!();
}
<commit_msg>Fix TODO: Use triple fault to guarantee reboot<commit_after>#[cfg(feature = "acpi")]
use acpi;
use syscall::io::{Io, Pio};

#[no_mangle]
pub unsafe extern fn kreset() -> ! {
    println!("kreset");

    // 8042 reset
    {
        println!("Reset with 8042");
        let mut port = Pio::<u8>::new(0x64);
        while port.readf(2) {}
        port.write(0xFE);
    }

    // Use triple fault to guarantee reset
    asm!("cli" : : : : "intel", "volatile");
    asm!("lidt cs:0" : : : : "intel", "volatile");
    asm!("int $$3" : : : : "intel", "volatile");

    unreachable!();
}

#[no_mangle]
pub unsafe extern fn kstop() -> ! {
    println!("kstop");

    #[cfg(feature = "acpi")]
    acpi::set_global_s_state(5);

    // Magic shutdown code for bochs and qemu (older versions).
    for c in "Shutdown".bytes() {
        let port = 0x8900;
        println!("Shutdown with outb(0x{:X}, '{}')", port, c as char);
        Pio::<u8>::new(port).write(c);
    }

    // Magic code for VMWare. Also a hard lock.
    println!("Shutdown with cli hlt");
    asm!("cli; hlt" : : : : "intel", "volatile");

    unreachable!();
}
<|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/. */

use std::fs;
use std::fs::File;
use std::io::{Read, Write};
use std::path;

use bindgen::config::{Config, Language};
use bindgen::ir::{
    Constant, Function, ItemContainer, ItemMap, Path as BindgenPath, Static, Struct,
};
use bindgen::writer::{Source, SourceWriter};

/// A bindings header that can be written.
pub struct Bindings {
    pub config: Config,
    /// The map from path to struct, used to lookup whether a given type is a
    /// transparent struct. This is needed to generate code for constants.
    struct_map: ItemMap<Struct>,
    globals: Vec<Static>,
    constants: Vec<Constant>,
    items: Vec<ItemContainer>,
    functions: Vec<Function>,
}

impl Bindings {
    pub(crate) fn new(
        config: Config,
        struct_map: ItemMap<Struct>,
        constants: Vec<Constant>,
        globals: Vec<Static>,
        items: Vec<ItemContainer>,
        functions: Vec<Function>,
    ) -> Bindings {
        Bindings {
            config,
            struct_map,
            globals,
            constants,
            items,
            functions,
        }
    }

    // FIXME(emilio): What to do when the configuration doesn't match?
    pub fn struct_is_transparent(&self, path: &BindgenPath) -> bool {
        let mut any = false;
        self.struct_map.for_items(path, |s| any |= s.is_transparent);
        any
    }

    pub fn struct_exists(&self, path: &BindgenPath) -> bool {
        let mut any = false;
        self.struct_map.for_items(path, |_| any = true);
        any
    }

    pub fn write_to_file<P: AsRef<path::Path>>(&self, path: P) -> bool {
        // Don't compare files if we've never written this file before
        if !path.as_ref().is_file() {
            if let Some(parent) = path::Path::new(path.as_ref()).parent() {
                fs::create_dir_all(parent).unwrap();
            }
            self.write(File::create(path).unwrap());
            return true;
        }

        let mut new_file_contents = Vec::new();
        self.write(&mut new_file_contents);

        let mut old_file_contents = Vec::new();
        {
            let mut old_file = File::open(&path).unwrap();
            old_file.read_to_end(&mut old_file_contents).unwrap();
        }

        if old_file_contents != new_file_contents {
            let mut new_file = File::create(&path).unwrap();
            new_file.write_all(&new_file_contents).unwrap();
            true
        } else {
            false
        }
    }

    pub fn write_headers<F: Write>(&self, out: &mut SourceWriter<F>) {
        if let Some(ref f) = self.config.header {
            out.new_line_if_not_start();
            write!(out, "{}", f);
            out.new_line();
        }
        if let Some(ref f) = self.config.include_guard {
            out.new_line_if_not_start();
            write!(out, "#ifndef {}", f);
            out.new_line();
            write!(out, "#define {}", f);
            out.new_line();
        }
        if self.config.include_version {
            out.new_line_if_not_start();
            write!(
                out,
                "/* Generated with cbindgen:{} */",
                ::bindgen::config::VERSION
            );
            out.new_line();
        }
        if let Some(ref f) = self.config.autogen_warning {
            out.new_line_if_not_start();
            write!(out, "{}", f);
            out.new_line();
        }

        if self.config.no_includes
            && self.config.sys_includes.is_empty()
            && self.config.includes.is_empty()
        {
            return;
        }

        out.new_line_if_not_start();

        if !self.config.no_includes {
            if self.config.language == Language::C {
                out.write("#include <stdarg.h>");
                out.new_line();
                out.write("#include <stdbool.h>");
                out.new_line();
                out.write("#include <stdint.h>");
                out.new_line();
                out.write("#include <stdlib.h>");
                out.new_line();
            } else {
                out.write("#include <cstdarg>");
                out.new_line();
                out.write("#include <cstdint>");
                out.new_line();
                out.write("#include <cstdlib>");
                out.new_line();
                out.write("#include <new>");
                out.new_line();
                if self.config.enumeration.cast_assert_name.is_none()
                    && (self.config.enumeration.derive_mut_casts
                        || self.config.enumeration.derive_const_casts)
                {
                    out.write("#include <cassert>");
                    out.new_line();
                }
            }
        }

        for include in &self.config.sys_includes {
            write!(out, "#include <{}>", include);
            out.new_line();
        }

        for include in &self.config.includes {
            write!(out, "#include \"{}\"", include);
            out.new_line();
        }
    }

    pub fn write<F: Write>(&self, file: F) {
        let mut out = SourceWriter::new(file, self);

        self.write_headers(&mut out);

        if self.config.language == Language::Cxx || self.config.cpp_compat {
            self.open_namespaces(&mut out);
        }

        for constant in &self.constants {
            if constant.ty.is_primitive_or_ptr_primitive() {
                out.new_line_if_not_start();
                constant.write(&self.config, &mut out, None);
                out.new_line();
            }
        }

        for item in &self.items {
            if item
                .deref()
                .annotations()
                .bool("no-export")
                .unwrap_or(false)
            {
                continue;
            }

            out.new_line_if_not_start();
            match *item {
                ItemContainer::Constant(..) => unreachable!(),
                ItemContainer::Static(..) => unreachable!(),
                ItemContainer::Enum(ref x) => x.write(&self.config, &mut out),
                ItemContainer::Struct(ref x) => x.write(&self.config, &mut out),
                ItemContainer::Union(ref x) => x.write(&self.config, &mut out),
                ItemContainer::OpaqueItem(ref x) => x.write(&self.config, &mut out),
                ItemContainer::Typedef(ref x) => x.write(&self.config, &mut out),
            }
            out.new_line();
        }

        for constant in &self.constants {
            if !constant.ty.is_primitive_or_ptr_primitive() {
                out.new_line_if_not_start();
                constant.write(&self.config, &mut out, None);
                out.new_line();
            }
        }

        if !self.functions.is_empty() || !self.globals.is_empty() {
            if self.config.language == Language::C && self.config.cpp_compat {
                out.new_line_if_not_start();
                out.write("#ifdef __cplusplus");
            }

            if self.config.language == Language::Cxx {
                if let Some(ref using_namespaces) = self.config.using_namespaces {
                    for namespace in using_namespaces {
                        out.new_line();
                        write!(out, "using namespace {};", namespace);
                    }
                    out.new_line();
                }
            }

            if self.config.language == Language::Cxx || self.config.cpp_compat {
                out.new_line();
                out.write("extern \"C\" {");
                out.new_line();
            }

            if self.config.language == Language::C && self.config.cpp_compat {
                out.write("#endif // __cplusplus");
                out.new_line();
            }

            for global in &self.globals {
                out.new_line_if_not_start();
                global.write(&self.config, &mut out);
                out.new_line();
            }

            for function in &self.functions {
                out.new_line_if_not_start();
                function.write(&self.config, &mut out);
                out.new_line();
            }

            if self.config.language == Language::C && self.config.cpp_compat {
                out.new_line();
                out.write("#ifdef __cplusplus");
            }

            if self.config.language == Language::Cxx || self.config.cpp_compat {
                out.new_line();
                out.write("} // extern \"C\"");
                out.new_line();
            }

            if self.config.language == Language::C && self.config.cpp_compat {
                out.write("#endif // __cplusplus");
                out.new_line();
            }
        }

        if self.config.language == Language::Cxx || self.config.cpp_compat {
            self.close_namespaces(&mut out);
        }

        if let Some(ref f) = self.config.include_guard {
            out.new_line_if_not_start();
            if self.config.language == Language::C {
                write!(out, "#endif /* {} */", f);
            } else {
                write!(out, "#endif // {}", f);
            }
            out.new_line();
        }
        if let Some(ref f) = self.config.trailer {
            out.new_line_if_not_start();
            write!(out, "{}", f);
            out.new_line();
        }
    }

    pub(crate) fn open_namespaces<F: Write>(&self, out: &mut SourceWriter<F>) {
        let mut wrote_namespace: bool = false;
        if let Some(ref namespace) = self.config.namespace {
            wrote_namespace = true;

            if self.config.language == Language::C && self.config.cpp_compat {
                out.new_line_if_not_start();
                out.write("#ifdef __cplusplus");
            }

            out.new_line();
            write!(out, "namespace {} {{", namespace);
        }
        if let Some(ref namespaces) = self.config.namespaces {
            if !wrote_namespace && self.config.language == Language::C && self.config.cpp_compat {
                out.new_line_if_not_start();
                out.write("#ifdef __cplusplus");
            }

            wrote_namespace = true;

            for namespace in namespaces {
                out.new_line();
                write!(out, "namespace {} {{", namespace);
            }
        }
        if wrote_namespace {
            out.new_line();
            if self.config.language == Language::C && self.config.cpp_compat {
                out.write("#endif // __cplusplus");
                out.new_line();
            }
        }
    }

    pub(crate) fn close_namespaces<F: Write>(&self, out: &mut SourceWriter<F>) {
        let mut wrote_namespace: bool = false;
        if let Some(ref namespaces) = self.config.namespaces {
            wrote_namespace = true;

            if self.config.language == Language::C && self.config.cpp_compat {
                out.new_line_if_not_start();
                out.write("#ifdef __cplusplus");
            }

            for namespace in namespaces.iter().rev() {
                out.new_line_if_not_start();
                write!(out, "}} // namespace {}", namespace);
            }
        }
        if let Some(ref namespace) = self.config.namespace {
            if !wrote_namespace && self.config.language == Language::C && self.config.cpp_compat {
                out.new_line_if_not_start();
                out.write("#ifdef __cplusplus");
            }

            wrote_namespace = true;

            out.new_line_if_not_start();
            write!(out, "}} // namespace {}", namespace);
        }
        if wrote_namespace {
            out.new_line();
            if self.config.language == Language::C && self.config.cpp_compat {
                out.write("#endif // __cplusplus");
                out.new_line();
            }
        }
    }
}
<commit_msg>Minor refactoring to the namespaces logic.<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/. */

use std::fs;
use std::fs::File;
use std::io::{Read, Write};
use std::path;

use bindgen::config::{Config, Language};
use bindgen::ir::{
    Constant, Function, ItemContainer, ItemMap, Path as BindgenPath, Static, Struct,
};
use bindgen::writer::{Source, SourceWriter};

/// A bindings header that can be written.
pub struct Bindings {
    pub config: Config,
    /// The map from path to struct, used to lookup whether a given type is a
    /// transparent struct. This is needed to generate code for constants.
    struct_map: ItemMap<Struct>,
    globals: Vec<Static>,
    constants: Vec<Constant>,
    items: Vec<ItemContainer>,
    functions: Vec<Function>,
}

#[derive(PartialEq)]
enum NamespaceOperation {
    Open,
    Close,
}

impl Bindings {
    pub(crate) fn new(
        config: Config,
        struct_map: ItemMap<Struct>,
        constants: Vec<Constant>,
        globals: Vec<Static>,
        items: Vec<ItemContainer>,
        functions: Vec<Function>,
    ) -> Bindings {
        Bindings {
            config,
            struct_map,
            globals,
            constants,
            items,
            functions,
        }
    }

    // FIXME(emilio): What to do when the configuration doesn't match?
    pub fn struct_is_transparent(&self, path: &BindgenPath) -> bool {
        let mut any = false;
        self.struct_map.for_items(path, |s| any |= s.is_transparent);
        any
    }

    pub fn struct_exists(&self, path: &BindgenPath) -> bool {
        let mut any = false;
        self.struct_map.for_items(path, |_| any = true);
        any
    }

    pub fn write_to_file<P: AsRef<path::Path>>(&self, path: P) -> bool {
        // Don't compare files if we've never written this file before
        if !path.as_ref().is_file() {
            if let Some(parent) = path::Path::new(path.as_ref()).parent() {
                fs::create_dir_all(parent).unwrap();
            }
            self.write(File::create(path).unwrap());
            return true;
        }

        let mut new_file_contents = Vec::new();
        self.write(&mut new_file_contents);

        let mut old_file_contents = Vec::new();
        {
            let mut old_file = File::open(&path).unwrap();
            old_file.read_to_end(&mut old_file_contents).unwrap();
        }

        if old_file_contents != new_file_contents {
            let mut new_file = File::create(&path).unwrap();
            new_file.write_all(&new_file_contents).unwrap();
            true
        } else {
            false
        }
    }

    pub fn write_headers<F: Write>(&self, out: &mut SourceWriter<F>) {
        if let Some(ref f) = self.config.header {
            out.new_line_if_not_start();
            write!(out, "{}", f);
            out.new_line();
        }
        if let Some(ref f) = self.config.include_guard {
            out.new_line_if_not_start();
            write!(out, "#ifndef {}", f);
            out.new_line();
            write!(out, "#define {}", f);
            out.new_line();
        }
        if self.config.include_version {
            out.new_line_if_not_start();
            write!(
                out,
                "/* Generated with cbindgen:{} */",
                ::bindgen::config::VERSION
            );
            out.new_line();
        }
        if let Some(ref f) = self.config.autogen_warning {
            out.new_line_if_not_start();
            write!(out, "{}", f);
            out.new_line();
        }

        if self.config.no_includes
            && self.config.sys_includes.is_empty()
            && self.config.includes.is_empty()
        {
            return;
        }

        out.new_line_if_not_start();

        if !self.config.no_includes {
            if self.config.language == Language::C {
                out.write("#include <stdarg.h>");
                out.new_line();
                out.write("#include <stdbool.h>");
                out.new_line();
                out.write("#include <stdint.h>");
                out.new_line();
                out.write("#include <stdlib.h>");
                out.new_line();
            } else {
                out.write("#include <cstdarg>");
                out.new_line();
                out.write("#include <cstdint>");
                out.new_line();
                out.write("#include <cstdlib>");
                out.new_line();
                out.write("#include <new>");
                out.new_line();
                if self.config.enumeration.cast_assert_name.is_none()
                    && (self.config.enumeration.derive_mut_casts
                        || self.config.enumeration.derive_const_casts)
                {
                    out.write("#include <cassert>");
                    out.new_line();
                }
            }
        }

        for include in &self.config.sys_includes {
            write!(out, "#include <{}>", include);
            out.new_line();
        }

        for include in &self.config.includes {
            write!(out, "#include \"{}\"", include);
            out.new_line();
        }
    }

    pub fn write<F: Write>(&self, file: F) {
        let mut out = SourceWriter::new(file, self);

        self.write_headers(&mut out);

        self.open_namespaces(&mut out);

        for constant in &self.constants {
            if constant.ty.is_primitive_or_ptr_primitive() {
                out.new_line_if_not_start();
                constant.write(&self.config, &mut out, None);
                out.new_line();
            }
        }

        for item in &self.items {
            if item
                .deref()
                .annotations()
                .bool("no-export")
                .unwrap_or(false)
            {
                continue;
            }

            out.new_line_if_not_start();
            match *item {
                ItemContainer::Constant(..) => unreachable!(),
                ItemContainer::Static(..) => unreachable!(),
                ItemContainer::Enum(ref x) => x.write(&self.config, &mut out),
                ItemContainer::Struct(ref x) => x.write(&self.config, &mut out),
                ItemContainer::Union(ref x) => x.write(&self.config, &mut out),
                ItemContainer::OpaqueItem(ref x) => x.write(&self.config, &mut out),
                ItemContainer::Typedef(ref x) => x.write(&self.config, &mut out),
            }
            out.new_line();
        }

        for constant in &self.constants {
            if !constant.ty.is_primitive_or_ptr_primitive() {
                out.new_line_if_not_start();
                constant.write(&self.config, &mut out, None);
                out.new_line();
            }
        }

        if !self.functions.is_empty() || !self.globals.is_empty() {
            if self.config.language == Language::C && self.config.cpp_compat {
                out.new_line_if_not_start();
                out.write("#ifdef __cplusplus");
            }

            if self.config.language == Language::Cxx {
                if let Some(ref using_namespaces) = self.config.using_namespaces {
                    for namespace in using_namespaces {
                        out.new_line();
                        write!(out, "using namespace {};", namespace);
                    }
                    out.new_line();
                }
            }

            if self.config.language == Language::Cxx || self.config.cpp_compat {
                out.new_line();
                out.write("extern \"C\" {");
                out.new_line();
            }

            if self.config.language == Language::C && self.config.cpp_compat {
                out.write("#endif // __cplusplus");
                out.new_line();
            }

            for global in &self.globals {
                out.new_line_if_not_start();
                global.write(&self.config, &mut out);
                out.new_line();
            }

            for function in &self.functions {
                out.new_line_if_not_start();
                function.write(&self.config, &mut out);
                out.new_line();
            }

            if self.config.language == Language::C && self.config.cpp_compat {
                out.new_line();
                out.write("#ifdef __cplusplus");
            }

            if self.config.language == Language::Cxx || self.config.cpp_compat {
                out.new_line();
                out.write("} // extern \"C\"");
                out.new_line();
            }

            if self.config.language == Language::C && self.config.cpp_compat {
                out.write("#endif // __cplusplus");
                out.new_line();
            }
        }

        self.close_namespaces(&mut out);

        if let Some(ref f) = self.config.include_guard {
            out.new_line_if_not_start();
            if self.config.language == Language::C {
                write!(out, "#endif /* {} */", f);
            } else {
                write!(out, "#endif // {}", f);
            }
            out.new_line();
        }
        if let Some(ref f) = self.config.trailer {
            out.new_line_if_not_start();
            write!(out, "{}", f);
            out.new_line();
        }
    }

    fn all_namespaces(&self) -> Vec<&str> {
        if self.config.language != Language::Cxx && !self.config.cpp_compat {
            return vec![];
        }
        let mut ret = vec![];
        if let Some(ref namespace) = self.config.namespace {
            ret.push(&**namespace);
        }
        if let Some(ref namespaces) = self.config.namespaces {
            for namespace in namespaces {
                ret.push(&**namespace);
            }
        }
        ret
    }

    fn open_close_namespaces<F: Write>(&self, op: NamespaceOperation, out: &mut SourceWriter<F>) {
        let mut namespaces = self.all_namespaces();
        if namespaces.is_empty() {
            return;
        }

        if op == NamespaceOperation::Close {
            namespaces.reverse();
        }

        let write_ifdefs = self.config.cpp_compat && self.config.language == Language::C;
        if write_ifdefs {
            out.new_line_if_not_start();
            out.write("#ifdef __cplusplus");
        }

        for namespace in namespaces {
            out.new_line();
            match op {
                NamespaceOperation::Open => write!(out, "namespace {} {{", namespace),
                NamespaceOperation::Close => write!(out, "}} // namespace {}", namespace),
            }
        }

        out.new_line();
        if write_ifdefs {
            out.write("#endif // __cplusplus");
            out.new_line();
        }
    }

    pub(crate) fn open_namespaces<F: Write>(&self, out: &mut SourceWriter<F>) {
        self.open_close_namespaces(NamespaceOperation::Open, out);
    }

    pub(crate) fn close_namespaces<F: Write>(&self, out: &mut SourceWriter<F>) {
        self.open_close_namespaces(NamespaceOperation::Close, out);
    }
}
<|endoftext|>


<commit_before>//! Runs rustfmt on the repository.

use crate::Build;
use build_helper::t;
use ignore::WalkBuilder;
use std::path::Path;
use std::process::Command;

fn rustfmt(src: &Path, rustfmt: &Path, path: &Path, check: bool) {
    let mut cmd = Command::new(&rustfmt);
    // avoid the submodule config paths from coming into play,
    // we only allow a single global config for the workspace for now
    cmd.arg("--config-path").arg(&src.canonicalize().unwrap());
    cmd.arg("--edition").arg("2018");
    cmd.arg("--unstable-features");
    cmd.arg("--skip-children");
    if check {
        cmd.arg("--check");
    }
    cmd.arg(&path);
    let cmd_debug = format!("{:?}", cmd);
    let status = cmd.status().expect("executing rustfmt");
    assert!(status.success(), "running {} successful", cmd_debug);
}

#[derive(serde::Deserialize)]
struct RustfmtConfig {
    ignore: Vec<String>,
}

pub fn format(build: &Build, check: bool) {
    let mut builder = ignore::types::TypesBuilder::new();
    builder.add_defaults();
    builder.select("rust");
    let matcher = builder.build().unwrap();
    let rustfmt_config = build.src.join("rustfmt.toml");
    if !rustfmt_config.exists() {
        eprintln!("Not running formatting checks; rustfmt.toml does not exist.");
        eprintln!("This may happen in distributed tarballs.");
        return;
    }
    let rustfmt_config = t!(std::fs::read_to_string(&rustfmt_config));
    let rustfmt_config: RustfmtConfig = t!(toml::from_str(&rustfmt_config));
    let mut ignore_fmt = ignore::overrides::OverrideBuilder::new(&build.src);
    for ignore in rustfmt_config.ignore {
        ignore_fmt.add(&format!("!{}", ignore)).expect(&ignore);
    }
    let ignore_fmt = ignore_fmt.build().unwrap();

    let rustfmt_path = build.config.initial_rustfmt.as_ref().unwrap_or_else(|| {
        eprintln!("./x.py fmt is not supported on this channel");
        std::process::exit(1);
    });
    let src = build.src.clone();
    let walker = WalkBuilder::new(&build.src).types(matcher).overrides(ignore_fmt).build_parallel();
    walker.run(|| {
        let src = src.clone();
        let rustfmt_path = rustfmt_path.clone();
        Box::new(move |entry| {
            let entry = t!(entry);
            if entry.file_type().map_or(false, |t| t.is_file()) {
                rustfmt(&src, &rustfmt_path, &entry.path(), check);
            }
            ignore::WalkState::Continue
        })
    });
}
<commit_msg>Tweak assertion note in fmt<commit_after>//! Runs rustfmt on the repository.

use crate::Build;
use build_helper::t;
use ignore::WalkBuilder;
use std::path::Path;
use std::process::Command;

fn rustfmt(src: &Path, rustfmt: &Path, path: &Path, check: bool) {
    let mut cmd = Command::new(&rustfmt);
    // avoid the submodule config paths from coming into play,
    // we only allow a single global config for the workspace for now
    cmd.arg("--config-path").arg(&src.canonicalize().unwrap());
    cmd.arg("--edition").arg("2018");
    cmd.arg("--unstable-features");
    cmd.arg("--skip-children");
    if check {
        cmd.arg("--check");
    }
    cmd.arg(&path);
    let cmd_debug = format!("{:?}", cmd);
    let status = cmd.status().expect("executing rustfmt");
    if !status.success() {
        eprintln!(
            "Running `{}` failed.\nIf you're running `tidy`, \
            try again with `--bless` flag. Or, you just want to format \
            code, run `./x.py fmt` instead.",
            cmd_debug,
        );
        std::process::exit(1);
    }
}

#[derive(serde::Deserialize)]
struct RustfmtConfig {
    ignore: Vec<String>,
}

pub fn format(build: &Build, check: bool) {
    let mut builder = ignore::types::TypesBuilder::new();
    builder.add_defaults();
    builder.select("rust");
    let matcher = builder.build().unwrap();
    let rustfmt_config = build.src.join("rustfmt.toml");
    if !rustfmt_config.exists() {
        eprintln!("Not running formatting checks; rustfmt.toml does not exist.");
        eprintln!("This may happen in distributed tarballs.");
        return;
    }
    let rustfmt_config = t!(std::fs::read_to_string(&rustfmt_config));
    let rustfmt_config: RustfmtConfig = t!(toml::from_str(&rustfmt_config));
    let mut ignore_fmt = ignore::overrides::OverrideBuilder::new(&build.src);
    for ignore in rustfmt_config.ignore {
        ignore_fmt.add(&format!("!{}", ignore)).expect(&ignore);
    }
    let ignore_fmt = ignore_fmt.build().unwrap();

    let rustfmt_path = build.config.initial_rustfmt.as_ref().unwrap_or_else(|| {
        eprintln!("./x.py fmt is not supported on this channel");
        std::process::exit(1);
    });
    let src = build.src.clone();
    let walker = WalkBuilder::new(&build.src).types(matcher).overrides(ignore_fmt).build_parallel();
    walker.run(|| {
        let src = src.clone();
        let rustfmt_path = rustfmt_path.clone();
        Box::new(move |entry| {
            let entry = t!(entry);
            if entry.file_type().map_or(false, |t| t.is_file()) {
                rustfmt(&src, &rustfmt_path, &entry.path(), check);
            }
            ignore::WalkState::Continue
        })
    });
}
<|endoftext|>


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

// Test that a field can have the same name in different variants
// of an enum
// FIXME #27889

pub enum Foo {
    X { foo: u32 },
    Y { foo: u32 }
}

pub fn foo(mut x: Foo) {
    let mut y = None;
    let mut z = None;
    if let Foo::X { ref foo } = x {
        z = Some(foo);
    }
    if let Foo::Y { ref mut foo } = x {
        y = Some(foo);
    }
}

fn main() {}
<commit_msg>remove FIXME(#27889) since the issue is already fixed<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Test that a field can have the same name in different variants
// of an enum

pub enum Foo {
    X { foo: u32 },
    Y { foo: u32 }
}

pub fn foo(mut x: Foo) {
    let mut y = None;
    let mut z = None;
    if let Foo::X { ref foo } = x {
        z = Some(foo);
    }
    if let Foo::Y { ref mut foo } = x {
        y = Some(foo);
    }
}

fn main() {}
<|endoftext|>