<commit_before>use board::sjadam_board::BitBoard;
use board::sjadam_board::SjadamBoard;
use board::std_board::ChessBoard;
use board::std_board::Square;
use board::std_board::Piece;
use board::std_board::PieceType::*;
use search_algorithms::board::Color::*;
use search_algorithms::board::EvalBoard;
use uci::UciBoard;

#[test]
fn rotate() {
    let empty = BitBoard::empty();
    assert_eq!(empty, empty.rotate());

    let mut board = BitBoard::from_board(&ChessBoard::start_board(), |p| !p.is_empty());

    assert_eq!(board, board.rotate().rotate());

    assert_eq!(board, board.rotate().rotate().rotate().rotate());

    board = board.rotate();
    for rank in 0..8 {
        for &file in [0, 1, 6, 7].iter() {
            assert!(board.get(Square::from_ints(file, rank)));
        }
        for &file in [2, 3, 4, 5].iter() {
            assert!(!board.get(Square::from_ints(file, rank)),
            "Found piece in the middle of board \n{:?}", board);
        }
    }
}

use quickcheck::Arbitrary;
use quickcheck::Gen;

impl Arbitrary for BitBoard {
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        BitBoard::from_u64(g.next_u64())
    }
}

quickcheck! {
    fn rotation_45_preserves_pieces(bitboard: BitBoard) -> bool {
        bitboard.rotate_45().board.count_ones() == bitboard.board.count_ones()
    }

    fn diagonals_preserve_pieces(bitboard: BitBoard) -> bool {
        (0..15).map(|n| bitboard.diagonal(n)).map(u8::count_ones).sum::<u32>() == bitboard.popcount()
    }

    fn rotation_315_preserves_pieces(bitboard: BitBoard) -> bool {
        bitboard.rotate_315().board.count_ones() == bitboard.board.count_ones()
    }

    fn antidiagonals_preserve_pieces(bitboard: BitBoard) -> bool {
        (-7..8).map(|n| bitboard.antidiagonal(n))
            .map(u8::count_ones)
            .sum::<u32>() == bitboard.popcount()
    }

    fn rotate_315_back(bitboard: BitBoard) -> bool {
        (0..8).fold(bitboard, |board, _| board.rotate_315()) == bitboard
    }

    fn rotate_45_back(bitboard: BitBoard) -> bool {
        (0..8).fold(bitboard, |board, _| board.rotate_45()) == bitboard
    }
}

#[test]
fn rank() {
    let start_board = BitBoard::all_from_board(&ChessBoard::start_board());
    assert_eq!(start_board.rank(0), 255);
    assert_eq!(start_board.rank(1), 255);
    assert_eq!(start_board.rank(2), 0);
    assert_eq!(start_board.rank(6), 255);
}

#[test]
fn file() {
    let start_board = BitBoard::all_from_board(&ChessBoard::start_board());
    assert_eq!(start_board.file(0), 0b1100_0011);
    let mut board = ChessBoard::start_board();
    let mv = board.from_alg("a2a4").unwrap();
    board.do_move(mv);
    let bit_board = BitBoard::all_from_board(&board);
    assert_eq!(bit_board.file(0), 0b1100_1001);
}

#[test]
fn rotate_45() {
    let board = BitBoard::all_from_board(&ChessBoard::start_board());
    let board2 = (0..8).fold(board, |b, _| b.rotate_45());
    assert_eq!(board, board2);
}

#[test]
fn long_diagonal() {
    let board = BitBoard::all_from_board(&ChessBoard::start_board()).rotate_45();
    assert_eq!(board.diagonal(7), 0b1100_0011, "\nDiagonal: {:b}\n{:?}",
               board.diagonal(7), BitBoard::from_u64(board.board));
    assert_eq!(board.diagonal(8), 0b0100_0011, "\nDiagonal: {:b}\n{:?}",
               board.diagonal(8), BitBoard::from_u64(board.board));
    assert_eq!(board.diagonal(9), 0b11, "\n{:?}", board);
    assert_eq!(board.diagonal(13), 0b11, "\n{:?}", board);
    assert_eq!(board.diagonal(14), 1);
    assert_eq!(board.diagonal(0), 1);
    assert_eq!(board.diagonal(1), 0b11);
    assert_eq!(board.diagonal(2), 0b110);
}

#[test]
fn long_antidiagonal() {
    let board = BitBoard::all_from_board(&ChessBoard::start_board()).rotate_315();
    assert_eq!(board.antidiagonal(0), 0b1100_0011, "\nDiagonal: {:b}\n{:?}",
               board.antidiagonal(0), BitBoard::from_u64(board.board));
    assert_eq!(board.antidiagonal(1), 0b0110_0001, "\nDiagonal: {:b}\n{:?}",
               board.antidiagonal(1), board);
    assert_eq!(board.antidiagonal(2), 0b11_0000, "\n{:?}", board);
    assert_eq!(board.antidiagonal(6), 0b11, "\n{:?}", board);
    assert_eq!(board.antidiagonal(7), 1);
    assert_eq!(board.antidiagonal(-7), 1);
    assert_eq!(board.antidiagonal(-6), 0b11);
    assert_eq!(board.antidiagonal(-5), 0b011);
}

#[test]
fn diagonal_neighbours() {
    let a8_neighbours = BitBoard::diagonal_neighbours(Square(0));
    assert_eq!(a8_neighbours.popcount(), 1,
               "Neighbours of square 0:\n{:?}",
               BitBoard::diagonal_neighbours(Square(0)));
    assert_eq!(BitBoard::diagonal_neighbours(Square(8)).popcount(), 2);
    assert_eq!(BitBoard::diagonal_neighbours(Square(9)).popcount(), 4);

    let mut board = BitBoard::empty();
    board.set(Square(9));
    assert_eq!(BitBoard::from_u64(a8_neighbours.board & board.board).popcount(), 1);
}

#[test]
fn first_piece() {
    let start_board = SjadamBoard::start_board();
    let white_kings = start_board.get_piece(Piece::new(King, White));
    let black_kings = start_board.get_piece(Piece::new(King, Black));

    assert_eq!(white_kings.first_piece(), Some(Square(60)));
    assert_eq!(black_kings.first_piece(), Some(Square(4)));
}
<commit_msg>add tests for bitboard iterators<commit_after>use board::sjadam_board::BitBoard;
use board::sjadam_board::SjadamBoard;
use board::std_board::ChessBoard;
use board::std_board::Square;
use board::std_board::Piece;
use board::std_board::PieceType::*;
use search_algorithms::board::Color::*;
use search_algorithms::board::EvalBoard;
use uci::UciBoard;

#[test]
fn rotate() {
    let empty = BitBoard::empty();
    assert_eq!(empty, empty.rotate());

    let mut board = BitBoard::from_board(&ChessBoard::start_board(), |p| !p.is_empty());

    assert_eq!(board, board.rotate().rotate());

    assert_eq!(board, board.rotate().rotate().rotate().rotate());

    board = board.rotate();
    for rank in 0..8 {
        for &file in [0, 1, 6, 7].iter() {
            assert!(board.get(Square::from_ints(file, rank)));
        }
        for &file in [2, 3, 4, 5].iter() {
            assert!(!board.get(Square::from_ints(file, rank)),
            "Found piece in the middle of board \n{:?}", board);
        }
    }
}

use quickcheck::Arbitrary;
use quickcheck::Gen;

impl Arbitrary for BitBoard {
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        BitBoard::from_u64(g.next_u64())
    }
}

quickcheck! {
    fn rotation_45_preserves_pieces(bitboard: BitBoard) -> bool {
        bitboard.rotate_45().board.count_ones() == bitboard.board.count_ones()
    }

    fn diagonals_preserve_pieces(bitboard: BitBoard) -> bool {
        (0..15).map(|n| bitboard.diagonal(n)).map(u8::count_ones).sum::<u32>() == bitboard.popcount()
    }

    fn rotation_315_preserves_pieces(bitboard: BitBoard) -> bool {
        bitboard.rotate_315().board.count_ones() == bitboard.board.count_ones()
    }

    fn antidiagonals_preserve_pieces(bitboard: BitBoard) -> bool {
        (-7..8).map(|n| bitboard.antidiagonal(n))
            .map(u8::count_ones)
            .sum::<u32>() == bitboard.popcount()
    }

    fn rotate_315_back(bitboard: BitBoard) -> bool {
        (0..8).fold(bitboard, |board, _| board.rotate_315()) == bitboard
    }

    fn rotate_45_back(bitboard: BitBoard) -> bool {
        (0..8).fold(bitboard, |board, _| board.rotate_45()) == bitboard
    }

    fn iterator_iterates_all(bitboard: BitBoard) -> bool {
        bitboard.into_iter().count() == bitboard.popcount() as usize
    }

    fn iterator(bitboard: BitBoard) -> bool {
        let mut board = BitBoard::empty();
        for square in bitboard {
            board.set(square);
        }
        board == bitboard
    }
}

#[test]
fn rank() {
    let start_board = BitBoard::all_from_board(&ChessBoard::start_board());
    assert_eq!(start_board.rank(0), 255);
    assert_eq!(start_board.rank(1), 255);
    assert_eq!(start_board.rank(2), 0);
    assert_eq!(start_board.rank(6), 255);
}

#[test]
fn file() {
    let start_board = BitBoard::all_from_board(&ChessBoard::start_board());
    assert_eq!(start_board.file(0), 0b1100_0011);
    let mut board = ChessBoard::start_board();
    let mv = board.from_alg("a2a4").unwrap();
    board.do_move(mv);
    let bit_board = BitBoard::all_from_board(&board);
    assert_eq!(bit_board.file(0), 0b1100_1001);
}

#[test]
fn rotate_45() {
    let board = BitBoard::all_from_board(&ChessBoard::start_board());
    let board2 = (0..8).fold(board, |b, _| b.rotate_45());
    assert_eq!(board, board2);
}

#[test]
fn long_diagonal() {
    let board = BitBoard::all_from_board(&ChessBoard::start_board()).rotate_45();
    assert_eq!(board.diagonal(7), 0b1100_0011, "\nDiagonal: {:b}\n{:?}",
               board.diagonal(7), BitBoard::from_u64(board.board));
    assert_eq!(board.diagonal(8), 0b0100_0011, "\nDiagonal: {:b}\n{:?}",
               board.diagonal(8), BitBoard::from_u64(board.board));
    assert_eq!(board.diagonal(9), 0b11, "\n{:?}", board);
    assert_eq!(board.diagonal(13), 0b11, "\n{:?}", board);
    assert_eq!(board.diagonal(14), 1);
    assert_eq!(board.diagonal(0), 1);
    assert_eq!(board.diagonal(1), 0b11);
    assert_eq!(board.diagonal(2), 0b110);
}

#[test]
fn long_antidiagonal() {
    let board = BitBoard::all_from_board(&ChessBoard::start_board()).rotate_315();
    assert_eq!(board.antidiagonal(0), 0b1100_0011, "\nDiagonal: {:b}\n{:?}",
               board.antidiagonal(0), BitBoard::from_u64(board.board));
    assert_eq!(board.antidiagonal(1), 0b0110_0001, "\nDiagonal: {:b}\n{:?}",
               board.antidiagonal(1), board);
    assert_eq!(board.antidiagonal(2), 0b11_0000, "\n{:?}", board);
    assert_eq!(board.antidiagonal(6), 0b11, "\n{:?}", board);
    assert_eq!(board.antidiagonal(7), 1);
    assert_eq!(board.antidiagonal(-7), 1);
    assert_eq!(board.antidiagonal(-6), 0b11);
    assert_eq!(board.antidiagonal(-5), 0b011);
}

#[test]
fn diagonal_neighbours() {
    let a8_neighbours = BitBoard::diagonal_neighbours(Square(0));
    assert_eq!(a8_neighbours.popcount(), 1,
               "Neighbours of square 0:\n{:?}",
               BitBoard::diagonal_neighbours(Square(0)));
    assert_eq!(BitBoard::diagonal_neighbours(Square(8)).popcount(), 2);
    assert_eq!(BitBoard::diagonal_neighbours(Square(9)).popcount(), 4);

    let mut board = BitBoard::empty();
    board.set(Square(9));
    assert_eq!(BitBoard::from_u64(a8_neighbours.board & board.board).popcount(), 1);
}

#[test]
fn first_piece() {
    let start_board = SjadamBoard::start_board();
    let white_kings = start_board.get_piece(Piece::new(King, White));
    let black_kings = start_board.get_piece(Piece::new(King, Black));

    assert_eq!(white_kings.first_piece(), Some(Square(60)));
    assert_eq!(black_kings.first_piece(), Some(Square(4)));
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
// spell-checker:ignore (change!) each's
// spell-checker:ignore (ToDO) LONGHELP FORMATSTRING templating parameterizing formatstr

use clap::{crate_version, App, AppSettings, Arg};
use uucore::error::{UResult, UUsageError};
use uucore::memo;
use uucore::InvalidEncodingHandling;

const VERSION: &str = "version";
const HELP: &str = "help";
const USAGE: &str = "printf FORMATSTRING [ARGUMENT]...";
const ABOUT: &str = "Print output based off of the format string and proceeding arguments.";
static LONGHELP_LEAD: &str = "printf

USAGE: printf FORMATSTRING [ARGUMENT]...

basic anonymous string templating:

prints format string at least once, repeating as long as there are remaining arguments
output prints escaped literals in the format string as character literals
output replaces anonymous fields with the next unused argument, formatted according to the field.

Options:
    --help              display this help and exit
    --version           output version information and exit

";
static LONGHELP_BODY: &str = "
Prints the , replacing escaped character sequences with character literals
  and substitution field sequences with passed arguments

literally, with the exception of the below
  escaped character sequences, and the substitution sequences described further down.

ESCAPE SEQUENCES

The following escape sequences, organized here in alphabetical order,
will print the corresponding character literal:

\"   double quote

\\\\    backslash

\\a  alert (BEL)

\\b  backspace

\\c  End-of-Input

\\e  escape

\\f  form feed

\\n  new line

\\r  carriage return

\\t  horizontal tab

\\v  vertical tab

\\NNN byte with value expressed in octal value NNN (1 to 3 digits)
      values greater than 256 will be treated

\\xHH byte with value expressed in hexadecimal value NN (1 to 2 digits)

\\uHHHH Unicode (IEC 10646) character with value expressed in hexadecimal value HHHH (4 digits)

\\uHHHH Unicode character with value expressed in hexadecimal value HHHH (8 digits)

%% a single %

SUBSTITUTIONS

SUBSTITUTION QUICK REFERENCE

Fields

%s - string
%b - string parsed for literals
  second parameter is max length

%c - char
  no second parameter

%i or %d - 64-bit integer
%u - 64 bit unsigned integer
%x or %X - 64-bit unsigned integer as hex
%o - 64-bit unsigned integer as octal
  second parameter is min-width, integer
   output below that width is padded with leading zeroes

%f or %F - decimal floating point value
%e or %E - scientific notation floating point value
%g or %G - shorter of specially interpreted decimal or SciNote floating point value.
  second parameter is
    -max places after decimal point for floating point output
    -max number of significant digits for scientific notation output

parameterizing fields

examples:

printf '%4.3i' 7
has a first parameter of 4
   and a second parameter of 3
will result in ' 007'

printf '%.1s' abcde
has no first parameter
   and a second parameter of 1
will result in 'a'

printf '%4c' q
has a first parameter of 4
   and no second parameter
will result in  '   q'

The first parameter of a field is the minimum width to pad the output to
 if the output is less than this absolute value of this width,
 it will be padded with leading spaces, or, if the argument is negative,
 with trailing spaces. the default is zero.

The second parameter of a field is particular to the output field type.
 defaults can be found in the full substitution help below

special prefixes to numeric arguments
  0 (e.g. 010) - interpret argument as octal (integer output fields only)
  0x (e.g. 0xABC) - interpret argument as hex (numeric output fields only)
  \' (e.g. \'a) - interpret argument as a character constant

HOW TO USE SUBSTITUTIONS

Substitutions are used to pass additional argument(s) into the FORMAT string, to be formatted a
particular way. E.g.

    printf 'the letter %X comes before the letter %X' 10 11

will print

   'the letter A comes before the letter B'

because the substitution field %X means
'take an integer argument and write it as a hexadecimal number'

Passing more arguments than are in the format string will cause the format string to be
 repeated for the remaining substitutions

   printf 'it is %i F in %s \n' 22 Portland 25 Boston 27 New York

will print

   'it is 22 F in Portland
    it is 25 F in Boston
    it is 27 F in Boston
   '
If a format string is printed but there are less arguments remaining
 than there are substitution fields, substitution fields without
 an argument will default to empty strings, or for numeric fields
 the value 0

AVAILABLE SUBSTITUTIONS

This program, like GNU coreutils printf,
interprets a modified subset of the POSIX C printf spec,
a quick reference to substitutions is below.

 STRING SUBSTITUTIONS
  All string fields have a 'max width' parameter
  %.3s means 'print no more than three characters of the original input'

 %s - string

 %b - escaped string - the string will be checked for any escaped literals from
       the escaped literal list above, and translate them to literal characters.
       e.g. \\n will be transformed into a newline character.

      One special rule about %b mode is that octal literals are interpreted differently
      In arguments passed by %b, pass octal-interpreted literals must be in the form of \\0NNN
      instead of \\NNN. (Although, for legacy reasons, octal literals in the form of \\NNN will
      still be interpreted and not throw a warning, you will have problems if you use this for a
      literal whose code begins with zero, as it will be viewed as in \\0NNN form.)

 CHAR SUBSTITUTIONS
  The character field does not have a secondary parameter.

 %c - a single character

 INTEGER SUBSTITUTIONS
  All integer fields have a 'pad with zero' parameter
  %.4i means an integer which if it is less than 4 digits in length,
  is padded with leading zeros until it is 4 digits in length.

 %d or %i - 64-bit integer

 %u - 64 bit unsigned integer

 %x or %X - 64 bit unsigned integer printed in Hexadecimal (base 16)
          %X instead of %x means to use uppercase letters for 'a' through 'f'

 %o - 64 bit unsigned integer printed in octal (base 8)

 FLOATING POINT SUBSTITUTIONS

  All floating point fields have a 'max decimal places / max significant digits' parameter
  %.10f means a decimal floating point with 7 decimal places past 0
  %.10e means a scientific notation number with 10 significant digits
  %.10g means the same behavior for decimal and Sci. Note, respectively, and provides the shorter
        of each's output.

  Like with GNU coreutils, the value after the decimal point is these outputs is parsed as a
  double first before being rendered to text. For both implementations do not expect meaningful
  precision past the 18th decimal place. When using a number of decimal places that is 18 or
  higher, you can expect variation in output between GNU coreutils printf and this printf at the
  18th decimal place of +/- 1

 %f - floating point value presented in decimal, truncated and displayed to 6 decimal places by
      default. There is not past-double behavior parity with Coreutils printf, values are not
      estimated or adjusted beyond input values.

 %e or %E - floating point value presented in scientific notation
          7 significant digits by default
          %E means use to use uppercase E for the mantissa.

 %g or %G - floating point value presented in the shorter of decimal and scientific notation
          behaves differently from %f and %E, please see posix printf spec for full details,
          some examples of different behavior:

          Sci Note has 6 significant digits by default
          Trailing zeroes are removed
          Instead of being truncated, digit after last is rounded

 Like other behavior in this utility, the design choices of floating point
  behavior in this utility is selected to reproduce in exact
  the behavior of GNU coreutils' printf from an inputs and outputs standpoint.

USING PARAMETERS
 Most substitution fields can be parameterized using up to 2 numbers that can
 be passed to the field, between the % sign and the field letter.

 The 1st parameter always indicates the minimum width of output, it is useful for creating
   columnar output. Any output that would be less than this minimum width is padded with
   leading spaces
 The 2nd parameter is proceeded by a dot.
 You do not have to use parameters

SPECIAL FORMS OF INPUT
 For numeric input, the following additional forms of input are accepted besides decimal:

  Octal (only with integer): if the argument begins with a 0 the proceeding characters
    will be interpreted as octal (base 8) for integer fields

  Hexadecimal: if the argument begins with 0x the proceeding characters will be interpreted
    will be interpreted as hex (base 16) for any numeric fields
    for float fields, hexadecimal input results in a precision
    limit (in converting input past the decimal point) of 10^-15

  Character Constant: if the argument begins with a single quote character, the first byte
    of the next character will be interpreted as an 8-bit unsigned integer. If there are
    additional bytes, they will throw an error (unless the environment variable POSIXLY_CORRECT
    is set)

WRITTEN BY :
  Nathan E. Ross, et al. for the uutils project

MORE INFO :
  https://github.com/uutils/coreutils

COPYRIGHT :
  Copyright 2015 uutils project.
  Licensed under the MIT License, please see LICENSE file for details

";

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let args = args
        .collect_str(InvalidEncodingHandling::Ignore)
        .accept_any();

    if args.len() <= 1 {
        return Err(UUsageError::new(1, "missing operand"));
    }
    let formatstr = &args[1];

    if formatstr == "--help" {
        print!("{} {}", LONGHELP_LEAD, LONGHELP_BODY);
    } else if formatstr == "--version" {
        println!("{} {}", uucore::util_name(), crate_version!());
    } else {
        let printf_args = &args[2..];
        memo::Memo::run_all(formatstr, printf_args);
    }
    Ok(())
}

pub fn uu_app<'a>() -> App<'a> {
    App::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .override_usage(USAGE)
        .arg(Arg::new(HELP).long(HELP).help("Print help information"))
        .arg(
            Arg::new(VERSION)
                .long(VERSION)
                .help("Print version information"),
        )
        .setting(AppSettings::InferLongArgs)
}
<commit_msg>printf: use clap default help and version<commit_after>#![allow(dead_code)]
// spell-checker:ignore (change!) each's
// spell-checker:ignore (ToDO) LONGHELP FORMATSTRING templating parameterizing formatstr

use clap::{crate_version, App, AppSettings, Arg};
use uucore::error::{UResult, UUsageError};
use uucore::memo;
use uucore::InvalidEncodingHandling;

const VERSION: &str = "version";
const HELP: &str = "help";
const USAGE: &str = "printf FORMATSTRING [ARGUMENT]...";
const ABOUT: &str = "Print output based off of the format string and proceeding arguments.";
const AFTER_HELP: &str = "
basic anonymous string templating:

prints format string at least once, repeating as long as there are remaining arguments
output prints escaped literals in the format string as character literals
output replaces anonymous fields with the next unused argument, formatted according to the field.

Prints the , replacing escaped character sequences with character literals
  and substitution field sequences with passed arguments

literally, with the exception of the below
  escaped character sequences, and the substitution sequences described further down.

ESCAPE SEQUENCES

The following escape sequences, organized here in alphabetical order,
will print the corresponding character literal:

\"   double quote

\\\\    backslash

\\a  alert (BEL)

\\b  backspace

\\c  End-of-Input

\\e  escape

\\f  form feed

\\n  new line

\\r  carriage return

\\t  horizontal tab

\\v  vertical tab

\\NNN byte with value expressed in octal value NNN (1 to 3 digits)
      values greater than 256 will be treated

\\xHH byte with value expressed in hexadecimal value NN (1 to 2 digits)

\\uHHHH Unicode (IEC 10646) character with value expressed in hexadecimal value HHHH (4 digits)

\\uHHHH Unicode character with value expressed in hexadecimal value HHHH (8 digits)

%% a single %

SUBSTITUTIONS

SUBSTITUTION QUICK REFERENCE

Fields

%s - string
%b - string parsed for literals
  second parameter is max length

%c - char
  no second parameter

%i or %d - 64-bit integer
%u - 64 bit unsigned integer
%x or %X - 64-bit unsigned integer as hex
%o - 64-bit unsigned integer as octal
  second parameter is min-width, integer
   output below that width is padded with leading zeroes

%f or %F - decimal floating point value
%e or %E - scientific notation floating point value
%g or %G - shorter of specially interpreted decimal or SciNote floating point value.
  second parameter is
    -max places after decimal point for floating point output
    -max number of significant digits for scientific notation output

parameterizing fields

examples:

printf '%4.3i' 7
has a first parameter of 4
   and a second parameter of 3
will result in ' 007'

printf '%.1s' abcde
has no first parameter
   and a second parameter of 1
will result in 'a'

printf '%4c' q
has a first parameter of 4
   and no second parameter
will result in  '   q'

The first parameter of a field is the minimum width to pad the output to
 if the output is less than this absolute value of this width,
 it will be padded with leading spaces, or, if the argument is negative,
 with trailing spaces. the default is zero.

The second parameter of a field is particular to the output field type.
 defaults can be found in the full substitution help below

special prefixes to numeric arguments
  0 (e.g. 010) - interpret argument as octal (integer output fields only)
  0x (e.g. 0xABC) - interpret argument as hex (numeric output fields only)
  \' (e.g. \'a) - interpret argument as a character constant

HOW TO USE SUBSTITUTIONS

Substitutions are used to pass additional argument(s) into the FORMAT string, to be formatted a
particular way. E.g.

    printf 'the letter %X comes before the letter %X' 10 11

will print

   'the letter A comes before the letter B'

because the substitution field %X means
'take an integer argument and write it as a hexadecimal number'

Passing more arguments than are in the format string will cause the format string to be
 repeated for the remaining substitutions

   printf 'it is %i F in %s \n' 22 Portland 25 Boston 27 New York

will print

   'it is 22 F in Portland
    it is 25 F in Boston
    it is 27 F in Boston
   '
If a format string is printed but there are less arguments remaining
 than there are substitution fields, substitution fields without
 an argument will default to empty strings, or for numeric fields
 the value 0

AVAILABLE SUBSTITUTIONS

This program, like GNU coreutils printf,
interprets a modified subset of the POSIX C printf spec,
a quick reference to substitutions is below.

 STRING SUBSTITUTIONS
  All string fields have a 'max width' parameter
  %.3s means 'print no more than three characters of the original input'

 %s - string

 %b - escaped string - the string will be checked for any escaped literals from
       the escaped literal list above, and translate them to literal characters.
       e.g. \\n will be transformed into a newline character.

      One special rule about %b mode is that octal literals are interpreted differently
      In arguments passed by %b, pass octal-interpreted literals must be in the form of \\0NNN
      instead of \\NNN. (Although, for legacy reasons, octal literals in the form of \\NNN will
      still be interpreted and not throw a warning, you will have problems if you use this for a
      literal whose code begins with zero, as it will be viewed as in \\0NNN form.)

 CHAR SUBSTITUTIONS
  The character field does not have a secondary parameter.

 %c - a single character

 INTEGER SUBSTITUTIONS
  All integer fields have a 'pad with zero' parameter
  %.4i means an integer which if it is less than 4 digits in length,
  is padded with leading zeros until it is 4 digits in length.

 %d or %i - 64-bit integer

 %u - 64 bit unsigned integer

 %x or %X - 64 bit unsigned integer printed in Hexadecimal (base 16)
          %X instead of %x means to use uppercase letters for 'a' through 'f'

 %o - 64 bit unsigned integer printed in octal (base 8)

 FLOATING POINT SUBSTITUTIONS

  All floating point fields have a 'max decimal places / max significant digits' parameter
  %.10f means a decimal floating point with 7 decimal places past 0
  %.10e means a scientific notation number with 10 significant digits
  %.10g means the same behavior for decimal and Sci. Note, respectively, and provides the shorter
        of each's output.

  Like with GNU coreutils, the value after the decimal point is these outputs is parsed as a
  double first before being rendered to text. For both implementations do not expect meaningful
  precision past the 18th decimal place. When using a number of decimal places that is 18 or
  higher, you can expect variation in output between GNU coreutils printf and this printf at the
  18th decimal place of +/- 1

 %f - floating point value presented in decimal, truncated and displayed to 6 decimal places by
      default. There is not past-double behavior parity with Coreutils printf, values are not
      estimated or adjusted beyond input values.

 %e or %E - floating point value presented in scientific notation
          7 significant digits by default
          %E means use to use uppercase E for the mantissa.

 %g or %G - floating point value presented in the shorter of decimal and scientific notation
          behaves differently from %f and %E, please see posix printf spec for full details,
          some examples of different behavior:

          Sci Note has 6 significant digits by default
          Trailing zeroes are removed
          Instead of being truncated, digit after last is rounded

 Like other behavior in this utility, the design choices of floating point
  behavior in this utility is selected to reproduce in exact
  the behavior of GNU coreutils' printf from an inputs and outputs standpoint.

USING PARAMETERS
 Most substitution fields can be parameterized using up to 2 numbers that can
 be passed to the field, between the % sign and the field letter.

 The 1st parameter always indicates the minimum width of output, it is useful for creating
   columnar output. Any output that would be less than this minimum width is padded with
   leading spaces
 The 2nd parameter is proceeded by a dot.
 You do not have to use parameters

SPECIAL FORMS OF INPUT
 For numeric input, the following additional forms of input are accepted besides decimal:

  Octal (only with integer): if the argument begins with a 0 the proceeding characters
    will be interpreted as octal (base 8) for integer fields

  Hexadecimal: if the argument begins with 0x the proceeding characters will be interpreted
    will be interpreted as hex (base 16) for any numeric fields
    for float fields, hexadecimal input results in a precision
    limit (in converting input past the decimal point) of 10^-15

  Character Constant: if the argument begins with a single quote character, the first byte
    of the next character will be interpreted as an 8-bit unsigned integer. If there are
    additional bytes, they will throw an error (unless the environment variable POSIXLY_CORRECT
    is set)

WRITTEN BY :
  Nathan E. Ross, et al. for the uutils project

MORE INFO :
  https://github.com/uutils/coreutils

COPYRIGHT :
  Copyright 2015 uutils project.
  Licensed under the MIT License, please see LICENSE file for details

";

mod options {
    pub const FORMATSTRING: &str = "FORMATSTRING";
    pub const ARGUMENT: &str = "ARGUMENT";
}

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let args = args
        .collect_str(InvalidEncodingHandling::Ignore)
        .accept_any();
    let matches = uu_app().get_matches_from(args);

    let format_string = matches
        .value_of(options::FORMATSTRING)
        .ok_or_else(|| UUsageError::new(1, "missing operand"))?;
    let values: Vec<String> = match matches.values_of(options::ARGUMENT) {
        Some(s) => s.map(|s| s.to_string()).collect(),
        None => vec![],
    };

    memo::Memo::run_all(format_string, &values[..]);
    Ok(())
}

pub fn uu_app<'a>() -> App<'a> {
    App::new(uucore::util_name())
        .setting(AppSettings::AllowHyphenValues)
        .version(crate_version!())
        .about(ABOUT)
        .after_help(AFTER_HELP)
        .override_usage(USAGE)
        .arg(Arg::new(HELP).long(HELP).help("Print help information"))
        .arg(
            Arg::new(VERSION)
                .long(VERSION)
                .help("Print version information"),
        )
        .arg(Arg::new(options::FORMATSTRING))
        .arg(Arg::new(options::ARGUMENT).multiple_occurrences(true))
}
<|endoftext|>


<commit_before>//! websockets client
use std::marker::PhantomData;

use actix_net::codec::Framed;
use actix_net::connector::{ConnectorError, DefaultConnector};
use actix_net::service::Service;
use base64;
use futures::future::{err, Either, FutureResult};
use futures::{Async, Future, Poll, Sink, Stream};
use http::header::{self, HeaderValue};
use http::{HttpTryFrom, StatusCode};
use rand;
use sha1::Sha1;
use tokio_io::{AsyncRead, AsyncWrite};

use client::ClientResponse;
use h1;
use ws::Codec;

use super::{ClientError, Connect, Protocol};

/// Default client, uses default connector.
pub type DefaultClient = Client<DefaultConnector<String>>;

/// WebSocket's client
pub struct Client<T>
where
    T: Service<Error = ConnectorError>,
    T::Response: AsyncRead + AsyncWrite,
{
    connector: T,
}

impl<T> Client<T>
where
    T: Service<Request = String, Error = ConnectorError>,
    T::Response: AsyncRead + AsyncWrite,
{
    /// Create new websocket's client factory
    pub fn new(connector: T) -> Self {
        Client { connector }
    }
}

impl Default for Client<DefaultConnector<String>> {
    fn default() -> Self {
        Client::new(DefaultConnector::default())
    }
}

impl<T> Clone for Client<T>
where
    T: Service<Request = String, Error = ConnectorError> + Clone,
    T::Response: AsyncRead + AsyncWrite,
{
    fn clone(&self) -> Self {
        Client {
            connector: self.connector.clone(),
        }
    }
}

impl<T> Service for Client<T>
where
    T: Service<Request = String, Error = ConnectorError>,
    T::Response: AsyncRead + AsyncWrite + 'static,
    T::Future: 'static,
{
    type Request = Connect;
    type Response = Framed<T::Response, Codec>;
    type Error = ClientError;
    type Future = Either<
        FutureResult<Self::Response, Self::Error>,
        ClientResponseFut<T::Response>,
    >;

    fn poll_ready(&mut self) -> Poll<(), Self::Error> {
        self.connector.poll_ready().map_err(ClientError::from)
    }

    fn call(&mut self, mut req: Self::Request) -> Self::Future {
        if let Some(e) = req.err.take() {
            Either::A(err(e))
        } else if let Some(e) = req.http_err.take() {
            Either::A(err(e.into()))
        } else {
            // origin
            if let Some(origin) = req.origin.take() {
                req.request.set_header(header::ORIGIN, origin);
            }

            req.request.upgrade();
            req.request.set_header(header::UPGRADE, "websocket");
            req.request.set_header(header::CONNECTION, "upgrade");
            req.request.set_header(header::SEC_WEBSOCKET_VERSION, "13");

            if let Some(protocols) = req.protocols.take() {
                req.request
                    .set_header(header::SEC_WEBSOCKET_PROTOCOL, protocols.as_str());
            }
            let mut request = match req.request.finish() {
                Ok(req) => req,
                Err(e) => return Either::A(err(e.into())),
            };

            if request.uri().host().is_none() {
                return Either::A(err(ClientError::InvalidUrl));
            }

            // supported protocols
            let proto = if let Some(scheme) = request.uri().scheme_part() {
                match Protocol::from(scheme.as_str()) {
                    Some(proto) => proto,
                    None => return Either::A(err(ClientError::InvalidUrl)),
                }
            } else {
                return Either::A(err(ClientError::InvalidUrl));
            };

            // Generate a random key for the `Sec-WebSocket-Key` header.
            // a base64-encoded (see Section 4 of [RFC4648]) value that,
            // when decoded, is 16 bytes in length (RFC 6455)
            let sec_key: [u8; 16] = rand::random();
            let key = base64::encode(&sec_key);

            request.headers_mut().insert(
                header::SEC_WEBSOCKET_KEY,
                HeaderValue::try_from(key.as_str()).unwrap(),
            );

            // prep connection
            let host = {
                let uri = request.uri();
                format!(
                    "{}:{}",
                    uri.host().unwrap(),
                    uri.port().unwrap_or_else(|| proto.port())
                )
            };

            let fut = Box::new(
                self.connector
                    .call(host)
                    .map_err(|e| ClientError::from(e))
                    .and_then(move |io| {
                        // h1 protocol
                        let framed = Framed::new(io, h1::ClientCodec::default());
                        framed
                            .send(request.into())
                            .map_err(|e| ClientError::from(e))
                            .and_then(|framed| {
                                framed
                                    .into_future()
                                    .map_err(|(e, _)| ClientError::from(e))
                            })
                    }),
            );

            // start handshake
            Either::B(ClientResponseFut {
                key,
                fut,
                max_size: req.max_size,
                server_mode: req.server_mode,
                _t: PhantomData,
            })
        }
    }
}

/// Future that implementes client websocket handshake process.
///
/// It resolves to a `Framed<T, ws::Codec>` instance.
pub struct ClientResponseFut<T>
where
    T: AsyncRead + AsyncWrite,
{
    fut: Box<
        Future<
            Item = (
                Option<h1::Message<ClientResponse>>,
                Framed<T, h1::ClientCodec>,
            ),
            Error = ClientError,
        >,
    >,
    key: String,
    max_size: usize,
    server_mode: bool,
    _t: PhantomData<T>,
}

impl<T> Future for ClientResponseFut<T>
where
    T: AsyncRead + AsyncWrite,
{
    type Item = Framed<T, Codec>;
    type Error = ClientError;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let (item, framed) = try_ready!(self.fut.poll());

        let res = match item {
            Some(h1::Message::Item(res)) => res,
            Some(h1::Message::Chunk(_)) => unreachable!(),
            None => return Err(ClientError::Disconnected),
        };

        // verify response
        if res.status() != StatusCode::SWITCHING_PROTOCOLS {
            return Err(ClientError::InvalidResponseStatus(res.status()));
        }
        // Check for "UPGRADE" to websocket header
        let has_hdr = if let Some(hdr) = res.headers().get(header::UPGRADE) {
            if let Ok(s) = hdr.to_str() {
                s.to_lowercase().contains("websocket")
            } else {
                false
            }
        } else {
            false
        };
        if !has_hdr {
            trace!("Invalid upgrade header");
            return Err(ClientError::InvalidUpgradeHeader);
        }
        // Check for "CONNECTION" header
        if let Some(conn) = res.headers().get(header::CONNECTION) {
            if let Ok(s) = conn.to_str() {
                if !s.to_lowercase().contains("upgrade") {
                    trace!("Invalid connection header: {}", s);
                    return Err(ClientError::InvalidConnectionHeader(conn.clone()));
                }
            } else {
                trace!("Invalid connection header: {:?}", conn);
                return Err(ClientError::InvalidConnectionHeader(conn.clone()));
            }
        } else {
            trace!("Missing connection header");
            return Err(ClientError::MissingConnectionHeader);
        }

        if let Some(key) = res.headers().get(header::SEC_WEBSOCKET_ACCEPT) {
            // field is constructed by concatenating /key/
            // with the string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" (RFC 6455)
            const WS_GUID: &[u8] = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
            let mut sha1 = Sha1::new();
            sha1.update(self.key.as_ref());
            sha1.update(WS_GUID);
            let encoded = base64::encode(&sha1.digest().bytes());
            if key.as_bytes() != encoded.as_bytes() {
                trace!(
                    "Invalid challenge response: expected: {} received: {:?}",
                    encoded,
                    key
                );
                return Err(ClientError::InvalidChallengeResponse(encoded, key.clone()));
            }
        } else {
            trace!("Missing SEC-WEBSOCKET-ACCEPT header");
            return Err(ClientError::MissingWebSocketAcceptHeader);
        };

        // websockets codec
        let codec = if self.server_mode {
            Codec::new().max_size(self.max_size)
        } else {
            Codec::new().max_size(self.max_size).client_mode()
        };

        Ok(Async::Ready(framed.into_framed(codec)))
    }
}
<commit_msg>update Connector usage<commit_after>//! websockets client
use std::marker::PhantomData;

use actix_net::codec::Framed;
use actix_net::connector::{Connect as TcpConnect, ConnectorError, DefaultConnector};
use actix_net::service::Service;
use base64;
use futures::future::{err, Either, FutureResult};
use futures::{Async, Future, Poll, Sink, Stream};
use http::header::{self, HeaderValue};
use http::{HttpTryFrom, StatusCode};
use rand;
use sha1::Sha1;
use tokio_io::{AsyncRead, AsyncWrite};

use client::ClientResponse;
use h1;
use ws::Codec;

use super::{ClientError, Connect, Protocol};

/// Default client, uses default connector.
pub type DefaultClient = Client<DefaultConnector>;

/// WebSocket's client
pub struct Client<T>
where
    T: Service<Error = ConnectorError>,
    T::Response: AsyncRead + AsyncWrite,
{
    connector: T,
}

impl<T> Client<T>
where
    T: Service<Request = TcpConnect, Error = ConnectorError>,
    T::Response: AsyncRead + AsyncWrite,
{
    /// Create new websocket's client factory
    pub fn new(connector: T) -> Self {
        Client { connector }
    }
}

impl Default for Client<DefaultConnector> {
    fn default() -> Self {
        Client::new(DefaultConnector::default())
    }
}

impl<T> Clone for Client<T>
where
    T: Service<Request = TcpConnect, Error = ConnectorError> + Clone,
    T::Response: AsyncRead + AsyncWrite,
{
    fn clone(&self) -> Self {
        Client {
            connector: self.connector.clone(),
        }
    }
}

impl<T> Service for Client<T>
where
    T: Service<Request = TcpConnect, Error = ConnectorError>,
    T::Response: AsyncRead + AsyncWrite + 'static,
    T::Future: 'static,
{
    type Request = Connect;
    type Response = Framed<T::Response, Codec>;
    type Error = ClientError;
    type Future = Either<
        FutureResult<Self::Response, Self::Error>,
        ClientResponseFut<T::Response>,
    >;

    fn poll_ready(&mut self) -> Poll<(), Self::Error> {
        self.connector.poll_ready().map_err(ClientError::from)
    }

    fn call(&mut self, mut req: Self::Request) -> Self::Future {
        if let Some(e) = req.err.take() {
            Either::A(err(e))
        } else if let Some(e) = req.http_err.take() {
            Either::A(err(e.into()))
        } else {
            // origin
            if let Some(origin) = req.origin.take() {
                req.request.set_header(header::ORIGIN, origin);
            }

            req.request.upgrade();
            req.request.set_header(header::UPGRADE, "websocket");
            req.request.set_header(header::CONNECTION, "upgrade");
            req.request.set_header(header::SEC_WEBSOCKET_VERSION, "13");

            if let Some(protocols) = req.protocols.take() {
                req.request
                    .set_header(header::SEC_WEBSOCKET_PROTOCOL, protocols.as_str());
            }
            let mut request = match req.request.finish() {
                Ok(req) => req,
                Err(e) => return Either::A(err(e.into())),
            };

            if request.uri().host().is_none() {
                return Either::A(err(ClientError::InvalidUrl));
            }

            // supported protocols
            let proto = if let Some(scheme) = request.uri().scheme_part() {
                match Protocol::from(scheme.as_str()) {
                    Some(proto) => proto,
                    None => return Either::A(err(ClientError::InvalidUrl)),
                }
            } else {
                return Either::A(err(ClientError::InvalidUrl));
            };

            // Generate a random key for the `Sec-WebSocket-Key` header.
            // a base64-encoded (see Section 4 of [RFC4648]) value that,
            // when decoded, is 16 bytes in length (RFC 6455)
            let sec_key: [u8; 16] = rand::random();
            let key = base64::encode(&sec_key);

            request.headers_mut().insert(
                header::SEC_WEBSOCKET_KEY,
                HeaderValue::try_from(key.as_str()).unwrap(),
            );

            // prep connection
            let connect = TcpConnect::new(
                request.uri().host().unwrap(),
                request.uri().port().unwrap_or_else(|| proto.port()),
            );

            let fut = Box::new(
                self.connector
                    .call(connect)
                    .map_err(|e| ClientError::from(e))
                    .and_then(move |io| {
                        // h1 protocol
                        let framed = Framed::new(io, h1::ClientCodec::default());
                        framed
                            .send(request.into())
                            .map_err(|e| ClientError::from(e))
                            .and_then(|framed| {
                                framed
                                    .into_future()
                                    .map_err(|(e, _)| ClientError::from(e))
                            })
                    }),
            );

            // start handshake
            Either::B(ClientResponseFut {
                key,
                fut,
                max_size: req.max_size,
                server_mode: req.server_mode,
                _t: PhantomData,
            })
        }
    }
}

/// Future that implementes client websocket handshake process.
///
/// It resolves to a `Framed<T, ws::Codec>` instance.
pub struct ClientResponseFut<T>
where
    T: AsyncRead + AsyncWrite,
{
    fut: Box<
        Future<
            Item = (
                Option<h1::Message<ClientResponse>>,
                Framed<T, h1::ClientCodec>,
            ),
            Error = ClientError,
        >,
    >,
    key: String,
    max_size: usize,
    server_mode: bool,
    _t: PhantomData<T>,
}

impl<T> Future for ClientResponseFut<T>
where
    T: AsyncRead + AsyncWrite,
{
    type Item = Framed<T, Codec>;
    type Error = ClientError;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let (item, framed) = try_ready!(self.fut.poll());

        let res = match item {
            Some(h1::Message::Item(res)) => res,
            Some(h1::Message::Chunk(_)) => unreachable!(),
            None => return Err(ClientError::Disconnected),
        };

        // verify response
        if res.status() != StatusCode::SWITCHING_PROTOCOLS {
            return Err(ClientError::InvalidResponseStatus(res.status()));
        }
        // Check for "UPGRADE" to websocket header
        let has_hdr = if let Some(hdr) = res.headers().get(header::UPGRADE) {
            if let Ok(s) = hdr.to_str() {
                s.to_lowercase().contains("websocket")
            } else {
                false
            }
        } else {
            false
        };
        if !has_hdr {
            trace!("Invalid upgrade header");
            return Err(ClientError::InvalidUpgradeHeader);
        }
        // Check for "CONNECTION" header
        if let Some(conn) = res.headers().get(header::CONNECTION) {
            if let Ok(s) = conn.to_str() {
                if !s.to_lowercase().contains("upgrade") {
                    trace!("Invalid connection header: {}", s);
                    return Err(ClientError::InvalidConnectionHeader(conn.clone()));
                }
            } else {
                trace!("Invalid connection header: {:?}", conn);
                return Err(ClientError::InvalidConnectionHeader(conn.clone()));
            }
        } else {
            trace!("Missing connection header");
            return Err(ClientError::MissingConnectionHeader);
        }

        if let Some(key) = res.headers().get(header::SEC_WEBSOCKET_ACCEPT) {
            // field is constructed by concatenating /key/
            // with the string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" (RFC 6455)
            const WS_GUID: &[u8] = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
            let mut sha1 = Sha1::new();
            sha1.update(self.key.as_ref());
            sha1.update(WS_GUID);
            let encoded = base64::encode(&sha1.digest().bytes());
            if key.as_bytes() != encoded.as_bytes() {
                trace!(
                    "Invalid challenge response: expected: {} received: {:?}",
                    encoded,
                    key
                );
                return Err(ClientError::InvalidChallengeResponse(encoded, key.clone()));
            }
        } else {
            trace!("Missing SEC-WEBSOCKET-ACCEPT header");
            return Err(ClientError::MissingWebSocketAcceptHeader);
        };

        // websockets codec
        let codec = if self.server_mode {
            Codec::new().max_size(self.max_size)
        } else {
            Codec::new().max_size(self.max_size).client_mode()
        };

        Ok(Async::Ready(framed.into_framed(codec)))
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate bencher;
extern crate redis;

extern crate futures;
extern crate tokio;

use futures::Future;
use tokio::runtime::current_thread::Runtime;

use bencher::Bencher;

use redis::PipelineCommands;

fn get_client() -> redis::Client {
    redis::Client::open("redis://127.0.0.1:6379").unwrap()
}

fn bench_simple_getsetdel(b: &mut Bencher) {
    let client = get_client();
    let con = client.get_connection().unwrap();

    b.iter(|| {
        let key = "test_key";
        redis::cmd("SET").arg(key).arg(42).execute(&con);
        let _: isize = redis::cmd("GET").arg(key).query(&con).unwrap();
        redis::cmd("DEL").arg(key).execute(&con);
    });
}

fn bench_simple_getsetdel_async(b: &mut Bencher) {
    let client = get_client();
    let mut runtime = Runtime::new().unwrap();
    let con = client.get_async_connection();
    let mut opt_con = Some(runtime.block_on(con).unwrap());

    b.iter(|| {
        let con = opt_con.take().expect("No connection");

        let key = "test_key";
        let future = redis::cmd("SET")
            .arg(key)
            .arg(42)
            .query_async(con)
            .and_then(|(con, ())| redis::cmd("GET").arg(key).query_async(con))
            .and_then(|(con, _): (_, isize)| redis::cmd("DEL").arg(key).query_async(con));
        let (con, ()) = runtime.block_on(future).unwrap();

        opt_con = Some(con);
    });
}

fn bench_simple_getsetdel_pipeline(b: &mut Bencher) {
    let client = get_client();
    let con = client.get_connection().unwrap();

    b.iter(|| {
        let key = "test_key";
        let _: (usize,) = redis::pipe()
            .cmd("SET")
            .arg(key)
            .arg(42)
            .ignore()
            .cmd("GET")
            .arg(key)
            .cmd("DEL")
            .arg(key)
            .ignore()
            .query(&con)
            .unwrap();
    });
}

fn bench_simple_getsetdel_pipeline_precreated(b: &mut Bencher) {
    let client = get_client();
    let con = client.get_connection().unwrap();
    let key = "test_key";
    let mut pipe = redis::pipe();
    pipe.cmd("SET")
        .arg(key)
        .arg(42)
        .ignore()
        .cmd("GET")
        .arg(key)
        .cmd("DEL")
        .arg(key)
        .ignore();

    b.iter(|| {
        let _: (usize,) = pipe.query(&con).unwrap();
    });
}

fn bench_long_pipeline(b: &mut Bencher) {
    let client = get_client();
    let con = client.get_connection().unwrap();
    let mut pipe = redis::pipe();

    for _ in 0..1_000 {
        pipe.set("foo", "bar").ignore();
    }

    b.iter(|| {
        let _: () = pipe.query(&con).unwrap();
    });
}

fn bench_encode_pipeline(b: &mut Bencher) {
    b.iter(|| {
        let mut pipe = redis::pipe();

        for _ in 0..1_000 {
            pipe.set("foo", "bar").ignore();
        }
        pipe
    });
}

fn bench_encode_pipeline_nested(b: &mut Bencher) {
    b.iter(|| {
        let mut pipe = redis::pipe();

        for _ in 0..200 {
            pipe.set(
                "foo",
                ("bar", 123, b"1231279712", &["test", "test", "test"][..]),
            ).ignore();
        }
        pipe
    });
}

benchmark_group!(
    bench,
    bench_simple_getsetdel,
    bench_simple_getsetdel_async,
    bench_simple_getsetdel_pipeline,
    bench_simple_getsetdel_pipeline_precreated,
    bench_long_pipeline,
    bench_encode_pipeline,
    bench_encode_pipeline_nested
);
benchmark_main!(bench);
<commit_msg>Add a benchmark for using the shared connection<commit_after>#[macro_use]
extern crate bencher;
extern crate redis;

extern crate futures;
extern crate tokio;

use futures::{future, stream, Future, Stream};

use tokio::runtime::current_thread::Runtime;

use bencher::Bencher;

use redis::PipelineCommands;

fn get_client() -> redis::Client {
    redis::Client::open("redis://127.0.0.1:6379").unwrap()
}

fn bench_simple_getsetdel(b: &mut Bencher) {
    let client = get_client();
    let con = client.get_connection().unwrap();

    b.iter(|| {
        let key = "test_key";
        redis::cmd("SET").arg(key).arg(42).execute(&con);
        let _: isize = redis::cmd("GET").arg(key).query(&con).unwrap();
        redis::cmd("DEL").arg(key).execute(&con);
    });
}

fn bench_simple_getsetdel_async(b: &mut Bencher) {
    let client = get_client();
    let mut runtime = Runtime::new().unwrap();
    let con = client.get_async_connection();
    let mut opt_con = Some(runtime.block_on(con).unwrap());

    b.iter(|| {
        let con = opt_con.take().expect("No connection");

        let key = "test_key";
        let future = redis::cmd("SET")
            .arg(key)
            .arg(42)
            .query_async(con)
            .and_then(|(con, ())| redis::cmd("GET").arg(key).query_async(con))
            .and_then(|(con, _): (_, isize)| redis::cmd("DEL").arg(key).query_async(con));
        let (con, ()) = runtime.block_on(future).unwrap();

        opt_con = Some(con);
    });
}

fn bench_simple_getsetdel_pipeline(b: &mut Bencher) {
    let client = get_client();
    let con = client.get_connection().unwrap();

    b.iter(|| {
        let key = "test_key";
        let _: (usize,) = redis::pipe()
            .cmd("SET")
            .arg(key)
            .arg(42)
            .ignore()
            .cmd("GET")
            .arg(key)
            .cmd("DEL")
            .arg(key)
            .ignore()
            .query(&con)
            .unwrap();
    });
}

fn bench_simple_getsetdel_pipeline_precreated(b: &mut Bencher) {
    let client = get_client();
    let con = client.get_connection().unwrap();
    let key = "test_key";
    let mut pipe = redis::pipe();
    pipe.cmd("SET")
        .arg(key)
        .arg(42)
        .ignore()
        .cmd("GET")
        .arg(key)
        .cmd("DEL")
        .arg(key)
        .ignore();

    b.iter(|| {
        let _: (usize,) = pipe.query(&con).unwrap();
    });
}

fn bench_long_pipeline(b: &mut Bencher) {
    let client = get_client();
    let con = client.get_connection().unwrap();
    let mut pipe = redis::pipe();

    for _ in 0..1_000 {
        pipe.set("foo", "bar").ignore();
    }

    b.iter(|| {
        let _: () = pipe.query(&con).unwrap();
    });
}

fn bench_encode_pipeline(b: &mut Bencher) {
    b.iter(|| {
        let mut pipe = redis::pipe();

        for _ in 0..1_000 {
            pipe.set("foo", "bar").ignore();
        }
        pipe
    });
}

fn bench_encode_pipeline_nested(b: &mut Bencher) {
    b.iter(|| {
        let mut pipe = redis::pipe();

        for _ in 0..200 {
            pipe.set(
                "foo",
                ("bar", 123, b"1231279712", &["test", "test", "test"][..]),
            ).ignore();
        }
        pipe
    });
}

fn bench_async_implicit_pipeline(b: &mut Bencher) {
    let client = get_client();
    let mut runtime = Runtime::new().unwrap();
    let con = runtime
        .block_on(client.get_shared_async_connection())
        .unwrap();

    let cmd = redis::cmd("SET").arg("foo").arg("bar").clone();
    b.iter(|| {
        let _: () = runtime
            .block_on(future::lazy(|| {
                stream::futures_unordered((0..1_000).map(|_| cmd.query_async(con.clone())))
                    .for_each(|(_, ())| Ok(()))
            }))
            .unwrap();
    });
}

benchmark_group!(
    bench,
    bench_simple_getsetdel,
    bench_simple_getsetdel_async,
    bench_simple_getsetdel_pipeline,
    bench_simple_getsetdel_pipeline_precreated,
    bench_long_pipeline,
    bench_encode_pipeline,
    bench_encode_pipeline_nested,
    bench_async_implicit_pipeline
);
benchmark_main!(bench);
<|endoftext|>


<commit_before>// Copyright 2016 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.

// An implementation of the Blake2b cryptographic hash function.
// The implementation closely follows: https://tools.ietf.org/html/rfc7693
//
// "BLAKE2 is a cryptographic hash function faster than MD5, SHA-1, SHA-2, and
//  SHA-3, yet is at least as secure as the latest standard SHA-3."
// according to their own website :)
//
// Indeed this implementation is two to three times as fast as our SHA-256
// implementation. If you have the luxury of being able to use crates from
// crates.io, you can go there and find still faster implementations.

use std::mem;
use std::slice;

pub struct Blake2bCtx {
    b: [u8; 128],
    h: [u64; 8],
    t: [u64; 2],
    c: usize,
    outlen: u16,
    finalized: bool,

    //#[cfg(debug_assertions)]
    fnv_hash: u64,
}

#[cfg(debug_assertions)]
impl ::std::fmt::Debug for Blake2bCtx {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(fmt, "{:x}", self.fnv_hash)
    }
}

#[cfg(not(debug_assertions))]
impl ::std::fmt::Debug for Blake2bCtx {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(fmt, "Enable debug_assertions() for more info.")
    }
}

#[inline(always)]
fn b2b_g(v: &mut [u64; 16],
         a: usize,
         b: usize,
         c: usize,
         d: usize,
         x: u64,
         y: u64)
{
    v[a] = v[a].wrapping_add(v[b]).wrapping_add(x);
    v[d] = (v[d] ^ v[a]).rotate_right(32);
    v[c] = v[c].wrapping_add(v[d]);
    v[b] = (v[b] ^ v[c]).rotate_right(24);
    v[a] = v[a].wrapping_add(v[b]).wrapping_add(y);
    v[d] = (v[d] ^ v[a]).rotate_right(16);
    v[c] = v[c].wrapping_add(v[d]);
    v[b] = (v[b] ^ v[c]).rotate_right(63);
}

// Initialization vector
const BLAKE2B_IV: [u64; 8] = [
   0x6A09E667F3BCC908, 0xBB67AE8584CAA73B,
   0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1,
   0x510E527FADE682D1, 0x9B05688C2B3E6C1F,
   0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179
];

fn blake2b_compress(ctx: &mut Blake2bCtx, last: bool) {

    const SIGMA: [[usize; 16]; 12] = [
        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ],
        [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ],
        [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 ],
        [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 ],
        [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 ],
        [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 ],
        [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 ],
        [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 ],
        [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 ],
        [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 ],
        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ],
        [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ]
    ];

    let mut v: [u64; 16] = [
        ctx.h[0],
        ctx.h[1],
        ctx.h[2],
        ctx.h[3],
        ctx.h[4],
        ctx.h[5],
        ctx.h[6],
        ctx.h[7],

        BLAKE2B_IV[0],
        BLAKE2B_IV[1],
        BLAKE2B_IV[2],
        BLAKE2B_IV[3],
        BLAKE2B_IV[4],
        BLAKE2B_IV[5],
        BLAKE2B_IV[6],
        BLAKE2B_IV[7],
    ];

    v[12] ^= ctx.t[0]; // low 64 bits of offset
    v[13] ^= ctx.t[1]; // high 64 bits
    if last {
        v[14] = !v[14];
    }

    {
        // Re-interpret the input buffer in the state as an array
        // of little-endian u64s, converting them to machine
        // endianness. It's OK to modify the buffer in place
        // since this is the last time  this data will be accessed
        // before it's overwritten.

        let m: &mut [u64; 16] = unsafe {
            let b: &mut [u8; 128] = &mut ctx.b;
            ::std::mem::transmute(b)
        };

        if cfg!(target_endian = "big") {
            for word in &mut m[..] {
                *word = u64::from_le(*word);
            }
        }

        for i in 0 .. 12 {
            b2b_g(&mut v, 0, 4,  8, 12, m[SIGMA[i][ 0]], m[SIGMA[i][ 1]]);
            b2b_g(&mut v, 1, 5,  9, 13, m[SIGMA[i][ 2]], m[SIGMA[i][ 3]]);
            b2b_g(&mut v, 2, 6, 10, 14, m[SIGMA[i][ 4]], m[SIGMA[i][ 5]]);
            b2b_g(&mut v, 3, 7, 11, 15, m[SIGMA[i][ 6]], m[SIGMA[i][ 7]]);
            b2b_g(&mut v, 0, 5, 10, 15, m[SIGMA[i][ 8]], m[SIGMA[i][ 9]]);
            b2b_g(&mut v, 1, 6, 11, 12, m[SIGMA[i][10]], m[SIGMA[i][11]]);
            b2b_g(&mut v, 2, 7,  8, 13, m[SIGMA[i][12]], m[SIGMA[i][13]]);
            b2b_g(&mut v, 3, 4,  9, 14, m[SIGMA[i][14]], m[SIGMA[i][15]]);
        }
    }

    for i in 0 .. 8 {
        ctx.h[i] ^= v[i] ^ v[i + 8];
    }
}

fn blake2b_update(ctx: &mut Blake2bCtx, mut data: &[u8]) {
    assert!(!ctx.finalized, "Blake2bCtx already finalized");

    let mut bytes_to_copy = data.len();
    let mut space_in_buffer = ctx.b.len() - ctx.c;

    while bytes_to_copy > space_in_buffer {
        checked_mem_copy(data, &mut ctx.b[ctx.c .. ], space_in_buffer);

        ctx.t[0] = ctx.t[0].wrapping_add(ctx.b.len() as u64);
        if ctx.t[0] < (ctx.b.len() as u64) {
            ctx.t[1] += 1;
        }
        blake2b_compress(ctx, false);
        ctx.c = 0;

        data = &data[space_in_buffer .. ];
        bytes_to_copy -= space_in_buffer;
        space_in_buffer = ctx.b.len();
    }

    if bytes_to_copy > 0 {
        checked_mem_copy(data, &mut ctx.b[ctx.c .. ], bytes_to_copy);
        ctx.c += bytes_to_copy;
    }

    #[cfg(debug_assertions)]
    {
        // compute additional FNV hash for simpler to read debug output
        const MAGIC_PRIME: u64 = 0x00000100000001b3;

        for &byte in data {
            ctx.fnv_hash = (ctx.fnv_hash ^ byte as u64).wrapping_mul(MAGIC_PRIME);
        }
    }
}

fn blake2b_final(ctx: &mut Blake2bCtx)
{
    assert!(!ctx.finalized, "Blake2bCtx already finalized");

    ctx.t[0] = ctx.t[0].wrapping_add(ctx.c as u64);
    if ctx.t[0] < ctx.c as u64 {
        ctx.t[1] += 1;
    }

    while ctx.c < 128 {
        ctx.b[ctx.c] = 0;
        ctx.c += 1;
    }

    blake2b_compress(ctx, true);

    // Modify our buffer to little-endian format as it will be read
    // as a byte array. It's OK to modify the buffer in place since
    // this is the last time this data will be accessed.
    if cfg!(target_endian = "big") {
        for word in &mut ctx.h {
            *word = word.to_le();
        }
    }

    ctx.finalized = true;
}

#[inline(always)]
fn checked_mem_copy<T1, T2>(from: &[T1], to: &mut [T2], byte_count: usize) {
    let from_size = from.len() * mem::size_of::<T1>();
    let to_size = to.len() * mem::size_of::<T2>();
    assert!(from_size >= byte_count);
    assert!(to_size >= byte_count);
    let from_byte_ptr = from.as_ptr() as * const u8;
    let to_byte_ptr = to.as_mut_ptr() as * mut u8;
    unsafe {
        ::std::ptr::copy_nonoverlapping(from_byte_ptr, to_byte_ptr, byte_count);
    }
}

pub struct Blake2bHasher(Blake2bCtx);

impl ::std::hash::Hasher for Blake2bHasher {
    fn write(&mut self, bytes: &[u8]) {
        blake2b_update(&mut self.0, bytes);
    }

    fn finish(&self) -> u64 {
        assert!(self.0.outlen == 8,
                "Hasher initialized with incompatible output length");
        u64::from_le(self.0.h[0])
    }
}

impl Blake2bHasher {
    pub fn finalize(&mut self) -> &[u8] {
        if !self.0.finalized {
            blake2b_final(&mut self.0);
        }
        debug_assert!(mem::size_of_val(&self.0.h) >= self.0.outlen as usize);
        let raw_ptr = (&self.0.h[..]).as_ptr() as * const u8;
        unsafe {
            slice::from_raw_parts(raw_ptr, self.0.outlen as usize)
        }
    }
}

impl ::std::fmt::Debug for Blake2bHasher {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
        write!(fmt, "{:?}", self.0)
    }
}
<commit_msg>hide unused variable when not used<commit_after>// Copyright 2016 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.

// An implementation of the Blake2b cryptographic hash function.
// The implementation closely follows: https://tools.ietf.org/html/rfc7693
//
// "BLAKE2 is a cryptographic hash function faster than MD5, SHA-1, SHA-2, and
//  SHA-3, yet is at least as secure as the latest standard SHA-3."
// according to their own website :)
//
// Indeed this implementation is two to three times as fast as our SHA-256
// implementation. If you have the luxury of being able to use crates from
// crates.io, you can go there and find still faster implementations.

use std::mem;
use std::slice;

pub struct Blake2bCtx {
    b: [u8; 128],
    h: [u64; 8],
    t: [u64; 2],
    c: usize,
    outlen: u16,
    finalized: bool,

    #[cfg(debug_assertions)]
    fnv_hash: u64,
}

#[cfg(debug_assertions)]
impl ::std::fmt::Debug for Blake2bCtx {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(fmt, "{:x}", self.fnv_hash)
    }
}

#[cfg(not(debug_assertions))]
impl ::std::fmt::Debug for Blake2bCtx {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(fmt, "Enable debug_assertions() for more info.")
    }
}

#[inline(always)]
fn b2b_g(v: &mut [u64; 16],
         a: usize,
         b: usize,
         c: usize,
         d: usize,
         x: u64,
         y: u64)
{
    v[a] = v[a].wrapping_add(v[b]).wrapping_add(x);
    v[d] = (v[d] ^ v[a]).rotate_right(32);
    v[c] = v[c].wrapping_add(v[d]);
    v[b] = (v[b] ^ v[c]).rotate_right(24);
    v[a] = v[a].wrapping_add(v[b]).wrapping_add(y);
    v[d] = (v[d] ^ v[a]).rotate_right(16);
    v[c] = v[c].wrapping_add(v[d]);
    v[b] = (v[b] ^ v[c]).rotate_right(63);
}

// Initialization vector
const BLAKE2B_IV: [u64; 8] = [
   0x6A09E667F3BCC908, 0xBB67AE8584CAA73B,
   0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1,
   0x510E527FADE682D1, 0x9B05688C2B3E6C1F,
   0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179
];

fn blake2b_compress(ctx: &mut Blake2bCtx, last: bool) {

    const SIGMA: [[usize; 16]; 12] = [
        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ],
        [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ],
        [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 ],
        [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 ],
        [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 ],
        [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 ],
        [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 ],
        [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 ],
        [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 ],
        [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 ],
        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ],
        [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ]
    ];

    let mut v: [u64; 16] = [
        ctx.h[0],
        ctx.h[1],
        ctx.h[2],
        ctx.h[3],
        ctx.h[4],
        ctx.h[5],
        ctx.h[6],
        ctx.h[7],

        BLAKE2B_IV[0],
        BLAKE2B_IV[1],
        BLAKE2B_IV[2],
        BLAKE2B_IV[3],
        BLAKE2B_IV[4],
        BLAKE2B_IV[5],
        BLAKE2B_IV[6],
        BLAKE2B_IV[7],
    ];

    v[12] ^= ctx.t[0]; // low 64 bits of offset
    v[13] ^= ctx.t[1]; // high 64 bits
    if last {
        v[14] = !v[14];
    }

    {
        // Re-interpret the input buffer in the state as an array
        // of little-endian u64s, converting them to machine
        // endianness. It's OK to modify the buffer in place
        // since this is the last time  this data will be accessed
        // before it's overwritten.

        let m: &mut [u64; 16] = unsafe {
            let b: &mut [u8; 128] = &mut ctx.b;
            ::std::mem::transmute(b)
        };

        if cfg!(target_endian = "big") {
            for word in &mut m[..] {
                *word = u64::from_le(*word);
            }
        }

        for i in 0 .. 12 {
            b2b_g(&mut v, 0, 4,  8, 12, m[SIGMA[i][ 0]], m[SIGMA[i][ 1]]);
            b2b_g(&mut v, 1, 5,  9, 13, m[SIGMA[i][ 2]], m[SIGMA[i][ 3]]);
            b2b_g(&mut v, 2, 6, 10, 14, m[SIGMA[i][ 4]], m[SIGMA[i][ 5]]);
            b2b_g(&mut v, 3, 7, 11, 15, m[SIGMA[i][ 6]], m[SIGMA[i][ 7]]);
            b2b_g(&mut v, 0, 5, 10, 15, m[SIGMA[i][ 8]], m[SIGMA[i][ 9]]);
            b2b_g(&mut v, 1, 6, 11, 12, m[SIGMA[i][10]], m[SIGMA[i][11]]);
            b2b_g(&mut v, 2, 7,  8, 13, m[SIGMA[i][12]], m[SIGMA[i][13]]);
            b2b_g(&mut v, 3, 4,  9, 14, m[SIGMA[i][14]], m[SIGMA[i][15]]);
        }
    }

    for i in 0 .. 8 {
        ctx.h[i] ^= v[i] ^ v[i + 8];
    }
}

fn blake2b_update(ctx: &mut Blake2bCtx, mut data: &[u8]) {
    assert!(!ctx.finalized, "Blake2bCtx already finalized");

    let mut bytes_to_copy = data.len();
    let mut space_in_buffer = ctx.b.len() - ctx.c;

    while bytes_to_copy > space_in_buffer {
        checked_mem_copy(data, &mut ctx.b[ctx.c .. ], space_in_buffer);

        ctx.t[0] = ctx.t[0].wrapping_add(ctx.b.len() as u64);
        if ctx.t[0] < (ctx.b.len() as u64) {
            ctx.t[1] += 1;
        }
        blake2b_compress(ctx, false);
        ctx.c = 0;

        data = &data[space_in_buffer .. ];
        bytes_to_copy -= space_in_buffer;
        space_in_buffer = ctx.b.len();
    }

    if bytes_to_copy > 0 {
        checked_mem_copy(data, &mut ctx.b[ctx.c .. ], bytes_to_copy);
        ctx.c += bytes_to_copy;
    }

    #[cfg(debug_assertions)]
    {
        // compute additional FNV hash for simpler to read debug output
        const MAGIC_PRIME: u64 = 0x00000100000001b3;

        for &byte in data {
            ctx.fnv_hash = (ctx.fnv_hash ^ byte as u64).wrapping_mul(MAGIC_PRIME);
        }
    }
}

fn blake2b_final(ctx: &mut Blake2bCtx)
{
    assert!(!ctx.finalized, "Blake2bCtx already finalized");

    ctx.t[0] = ctx.t[0].wrapping_add(ctx.c as u64);
    if ctx.t[0] < ctx.c as u64 {
        ctx.t[1] += 1;
    }

    while ctx.c < 128 {
        ctx.b[ctx.c] = 0;
        ctx.c += 1;
    }

    blake2b_compress(ctx, true);

    // Modify our buffer to little-endian format as it will be read
    // as a byte array. It's OK to modify the buffer in place since
    // this is the last time this data will be accessed.
    if cfg!(target_endian = "big") {
        for word in &mut ctx.h {
            *word = word.to_le();
        }
    }

    ctx.finalized = true;
}

#[inline(always)]
fn checked_mem_copy<T1, T2>(from: &[T1], to: &mut [T2], byte_count: usize) {
    let from_size = from.len() * mem::size_of::<T1>();
    let to_size = to.len() * mem::size_of::<T2>();
    assert!(from_size >= byte_count);
    assert!(to_size >= byte_count);
    let from_byte_ptr = from.as_ptr() as * const u8;
    let to_byte_ptr = to.as_mut_ptr() as * mut u8;
    unsafe {
        ::std::ptr::copy_nonoverlapping(from_byte_ptr, to_byte_ptr, byte_count);
    }
}

pub struct Blake2bHasher(Blake2bCtx);

impl ::std::hash::Hasher for Blake2bHasher {
    fn write(&mut self, bytes: &[u8]) {
        blake2b_update(&mut self.0, bytes);
    }

    fn finish(&self) -> u64 {
        assert!(self.0.outlen == 8,
                "Hasher initialized with incompatible output length");
        u64::from_le(self.0.h[0])
    }
}

impl Blake2bHasher {
    pub fn finalize(&mut self) -> &[u8] {
        if !self.0.finalized {
            blake2b_final(&mut self.0);
        }
        debug_assert!(mem::size_of_val(&self.0.h) >= self.0.outlen as usize);
        let raw_ptr = (&self.0.h[..]).as_ptr() as * const u8;
        unsafe {
            slice::from_raw_parts(raw_ptr, self.0.outlen as usize)
        }
    }
}

impl ::std::fmt::Debug for Blake2bHasher {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
        write!(fmt, "{:?}", self.0)
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 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.

//! A priority queue implemented with a binary heap

use core::container::{Container, Mutable};
use core::cmp::Ord;
use core::prelude::*;
use core::ptr::addr_of;
use core::vec;

#[abi = "rust-intrinsic"]
extern "C" mod rusti {
    fn move_val_init<T>(dst: &mut T, -src: T);
    fn init<T>() -> T;
}

pub struct PriorityQueue <T: Ord>{
    priv data: ~[T],
}

impl <T: Ord> PriorityQueue<T>: Container {
    /// Returns the length of the queue
    pure fn len(&self) -> uint { self.data.len() }

    /// Returns true if a queue contains no elements
    pure fn is_empty(&self) -> bool { self.data.is_empty() }
}

impl <T: Ord> PriorityQueue<T>: Mutable {
    /// Drop all items from the queue
    fn clear(&mut self) { self.data.truncate(0) }
}

impl <T: Ord> PriorityQueue<T> {
    /// Returns the greatest item in the queue - fails if empty
    pure fn top(&self) -> &self/T { &self.data[0] }

    /// Returns the greatest item in the queue - None if empty
    pure fn maybe_top(&self) -> Option<&self/T> {
        if self.is_empty() { None } else { Some(self.top()) }
    }

    /// Returns the number of elements the queue can hold without reallocating
    pure fn capacity(&self) -> uint { vec::capacity(&self.data) }

    fn reserve(&mut self, n: uint) { vec::reserve(&mut self.data, n) }

    fn reserve_at_least(&mut self, n: uint) {
        vec::reserve_at_least(&mut self.data, n)
    }

    /// Pop the greatest item from the queue - fails if empty
    fn pop(&mut self) -> T {
        let mut item = self.data.pop();
        if !self.is_empty() { item <-> self.data[0]; self.siftdown(0); }
        item
    }

    /// Pop the greatest item from the queue - None if empty
    fn maybe_pop(&mut self) -> Option<T> {
        if self.is_empty() { None } else { Some(self.pop()) }
    }

    /// Push an item onto the queue
    fn push(&mut self, item: T) {
        self.data.push(item);
        self.siftup(0, self.len() - 1);
    }

    /// Optimized version of a push followed by a pop
    fn push_pop(&mut self, item: T) -> T {
        let mut item = item;
        if !self.is_empty() && self.data[0] > item {
            item <-> self.data[0];
            self.siftdown(0);
        }
        item
    }

    /// Optimized version of a pop followed by a push - fails if empty
    fn replace(&mut self, item: T) -> T {
        let mut item = item;
        item <-> self.data[0];
        self.siftdown(0);
        item
    }

    /// Consume the PriorityQueue and return the underlying vector
    pure fn to_vec(self) -> ~[T] { let PriorityQueue{data: v} = self; v }

    /// Consume the PriorityQueue and return a vector in sorted
    /// (ascending) order
    pure fn to_sorted_vec(self) -> ~[T] {
        let mut q = self;
        let mut end = q.len();
        while end > 1 {
            end -= 1;
            q.data[end] <-> q.data[0];
            unsafe { q.siftdown_range(0, end) } // purity-checking workaround
        }
        q.to_vec()
    }

    /// Create an empty PriorityQueue
    static pure fn new() -> PriorityQueue<T> { PriorityQueue{data: ~[],} }

    /// Create a PriorityQueue from a vector (heapify)
    static pure fn from_vec(xs: ~[T]) -> PriorityQueue<T> {
        let mut q = PriorityQueue{data: xs,};
        let mut n = q.len() / 2;
        while n > 0 {
            n -= 1;
            unsafe { q.siftdown(n) }; // purity-checking workaround
        }
        q
    }

    // The implementations of siftup and siftdown use unsafe blocks in
    // order to move an element out of the vector (leaving behind a
    // junk element), shift along the others and move it back into the
    // vector over the junk element.  This reduces the constant factor
    // compared to using swaps, which involves twice as many moves.

    priv fn siftup(&mut self, start: uint, pos: uint) {
        unsafe {
            let mut pos = pos;
            let new = move *addr_of(&self.data[pos]);

            while pos > start {
                let parent = (pos - 1) >> 1;
                if new > self.data[parent] {
                    let mut x = rusti::init();
                    x <-> self.data[parent];
                    rusti::move_val_init(&mut self.data[pos], move x);
                    pos = parent;
                    loop
                }
                break
            }
            rusti::move_val_init(&mut self.data[pos], move new);
        }
    }

    priv fn siftdown_range(&mut self, pos: uint, end: uint) {
        unsafe {
            let mut pos = pos;
            let start = pos;
            let new = move *addr_of(&self.data[pos]);

            let mut child = 2 * pos + 1;
            while child < end {
                let right = child + 1;
                if right < end && !(self.data[child] > self.data[right]) {
                    child = right;
                }
                let mut x = rusti::init();
                x <-> self.data[child];
                rusti::move_val_init(&mut self.data[pos], move x);
                pos = child;
                child = 2 * pos + 1;
            }

            rusti::move_val_init(&mut self.data[pos], move new);
            self.siftup(start, pos);
        }
    }

    priv fn siftdown(&mut self, pos: uint) {
        self.siftdown_range(pos, self.len());
    }
}

#[cfg(test)]
mod tests {
    use sort::merge_sort;
    use core::cmp::le;
    use priority_queue::PriorityQueue::{from_vec, new};

    #[test]
    fn test_top_and_pop() {
        let data = ~[2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
        let mut sorted = merge_sort(data, le);
        let mut heap = from_vec(data);
        while !heap.is_empty() {
            assert *heap.top() == sorted.last();
            assert heap.pop() == sorted.pop();
        }
    }

    #[test]
    fn test_push() {
        let mut heap = from_vec(~[2, 4, 9]);
        assert heap.len() == 3;
        assert *heap.top() == 9;
        heap.push(11);
        assert heap.len() == 4;
        assert *heap.top() == 11;
        heap.push(5);
        assert heap.len() == 5;
        assert *heap.top() == 11;
        heap.push(27);
        assert heap.len() == 6;
        assert *heap.top() == 27;
        heap.push(3);
        assert heap.len() == 7;
        assert *heap.top() == 27;
        heap.push(103);
        assert heap.len() == 8;
        assert *heap.top() == 103;
    }

    #[test]
    fn test_push_unique() {
        let mut heap = from_vec(~[~2, ~4, ~9]);
        assert heap.len() == 3;
        assert *heap.top() == ~9;
        heap.push(~11);
        assert heap.len() == 4;
        assert *heap.top() == ~11;
        heap.push(~5);
        assert heap.len() == 5;
        assert *heap.top() == ~11;
        heap.push(~27);
        assert heap.len() == 6;
        assert *heap.top() == ~27;
        heap.push(~3);
        assert heap.len() == 7;
        assert *heap.top() == ~27;
        heap.push(~103);
        assert heap.len() == 8;
        assert *heap.top() == ~103;
    }

    #[test]
    fn test_push_pop() {
        let mut heap = from_vec(~[5, 5, 2, 1, 3]);
        assert heap.len() == 5;
        assert heap.push_pop(6) == 6;
        assert heap.len() == 5;
        assert heap.push_pop(0) == 5;
        assert heap.len() == 5;
        assert heap.push_pop(4) == 5;
        assert heap.len() == 5;
        assert heap.push_pop(1) == 4;
        assert heap.len() == 5;
    }

    #[test]
    fn test_replace() {
        let mut heap = from_vec(~[5, 5, 2, 1, 3]);
        assert heap.len() == 5;
        assert heap.replace(6) == 5;
        assert heap.len() == 5;
        assert heap.replace(0) == 6;
        assert heap.len() == 5;
        assert heap.replace(4) == 5;
        assert heap.len() == 5;
        assert heap.replace(1) == 4;
        assert heap.len() == 5;
    }

    fn check_to_vec(data: ~[int]) {
        let heap = from_vec(data);
        assert merge_sort(heap.to_vec(), le) == merge_sort(data, le);
        assert heap.to_sorted_vec() == merge_sort(data, le);
    }

    #[test]
    fn test_to_vec() {
        check_to_vec(~[]);
        check_to_vec(~[5]);
        check_to_vec(~[3, 2]);
        check_to_vec(~[2, 3]);
        check_to_vec(~[5, 1, 2]);
        check_to_vec(~[1, 100, 2, 3]);
        check_to_vec(~[1, 3, 5, 7, 9, 2, 4, 6, 8, 0]);
        check_to_vec(~[2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
        check_to_vec(~[9, 11, 9, 9, 9, 9, 11, 2, 3, 4, 11, 9, 0, 0, 0, 0]);
        check_to_vec(~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
        check_to_vec(~[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]);
        check_to_vec(~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 1, 2]);
        check_to_vec(~[5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1]);
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn test_empty_pop() { let mut heap = new::<int>(); heap.pop(); }

    #[test]
    fn test_empty_maybe_pop() {
        let mut heap = new::<int>();
        assert heap.maybe_pop().is_none();
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn test_empty_top() { let empty = new::<int>(); empty.top(); }

    #[test]
    fn test_empty_maybe_top() {
        let empty = new::<int>();
        assert empty.maybe_top().is_none();
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn test_empty_replace() { let mut heap = new(); heap.replace(5); }
}
<commit_msg>use mut function argument syntax in priority_queue<commit_after>// Copyright 2013 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.

//! A priority queue implemented with a binary heap

use core::container::{Container, Mutable};
use core::cmp::Ord;
use core::prelude::*;
use core::ptr::addr_of;
use core::vec;

#[abi = "rust-intrinsic"]
extern "C" mod rusti {
    fn move_val_init<T>(dst: &mut T, -src: T);
    fn init<T>() -> T;
}

pub struct PriorityQueue <T: Ord>{
    priv data: ~[T],
}

impl <T: Ord> PriorityQueue<T>: Container {
    /// Returns the length of the queue
    pure fn len(&self) -> uint { self.data.len() }

    /// Returns true if a queue contains no elements
    pure fn is_empty(&self) -> bool { self.data.is_empty() }
}

impl <T: Ord> PriorityQueue<T>: Mutable {
    /// Drop all items from the queue
    fn clear(&mut self) { self.data.truncate(0) }
}

impl <T: Ord> PriorityQueue<T> {
    /// Returns the greatest item in the queue - fails if empty
    pure fn top(&self) -> &self/T { &self.data[0] }

    /// Returns the greatest item in the queue - None if empty
    pure fn maybe_top(&self) -> Option<&self/T> {
        if self.is_empty() { None } else { Some(self.top()) }
    }

    /// Returns the number of elements the queue can hold without reallocating
    pure fn capacity(&self) -> uint { vec::capacity(&self.data) }

    fn reserve(&mut self, n: uint) { vec::reserve(&mut self.data, n) }

    fn reserve_at_least(&mut self, n: uint) {
        vec::reserve_at_least(&mut self.data, n)
    }

    /// Pop the greatest item from the queue - fails if empty
    fn pop(&mut self) -> T {
        let mut item = self.data.pop();
        if !self.is_empty() { item <-> self.data[0]; self.siftdown(0); }
        item
    }

    /// Pop the greatest item from the queue - None if empty
    fn maybe_pop(&mut self) -> Option<T> {
        if self.is_empty() { None } else { Some(self.pop()) }
    }

    /// Push an item onto the queue
    fn push(&mut self, item: T) {
        self.data.push(item);
        self.siftup(0, self.len() - 1);
    }

    /// Optimized version of a push followed by a pop
    fn push_pop(&mut self, mut item: T) -> T {
        if !self.is_empty() && self.data[0] > item {
            item <-> self.data[0];
            self.siftdown(0);
        }
        item
    }

    /// Optimized version of a pop followed by a push - fails if empty
    fn replace(&mut self, mut item: T) -> T {
        item <-> self.data[0];
        self.siftdown(0);
        item
    }

    /// Consume the PriorityQueue and return the underlying vector
    pure fn to_vec(self) -> ~[T] { let PriorityQueue{data: v} = self; v }

    /// Consume the PriorityQueue and return a vector in sorted
    /// (ascending) order
    pure fn to_sorted_vec(self) -> ~[T] {
        let mut q = self;
        let mut end = q.len();
        while end > 1 {
            end -= 1;
            q.data[end] <-> q.data[0];
            unsafe { q.siftdown_range(0, end) } // purity-checking workaround
        }
        q.to_vec()
    }

    /// Create an empty PriorityQueue
    static pure fn new() -> PriorityQueue<T> { PriorityQueue{data: ~[],} }

    /// Create a PriorityQueue from a vector (heapify)
    static pure fn from_vec(xs: ~[T]) -> PriorityQueue<T> {
        let mut q = PriorityQueue{data: xs,};
        let mut n = q.len() / 2;
        while n > 0 {
            n -= 1;
            unsafe { q.siftdown(n) }; // purity-checking workaround
        }
        q
    }

    // The implementations of siftup and siftdown use unsafe blocks in
    // order to move an element out of the vector (leaving behind a
    // junk element), shift along the others and move it back into the
    // vector over the junk element.  This reduces the constant factor
    // compared to using swaps, which involves twice as many moves.

    priv fn siftup(&mut self, start: uint, mut pos: uint) {
        unsafe {
            let new = move *addr_of(&self.data[pos]);

            while pos > start {
                let parent = (pos - 1) >> 1;
                if new > self.data[parent] {
                    let mut x = rusti::init();
                    x <-> self.data[parent];
                    rusti::move_val_init(&mut self.data[pos], move x);
                    pos = parent;
                    loop
                }
                break
            }
            rusti::move_val_init(&mut self.data[pos], move new);
        }
    }

    priv fn siftdown_range(&mut self, mut pos: uint, end: uint) {
        unsafe {
            let start = pos;
            let new = move *addr_of(&self.data[pos]);

            let mut child = 2 * pos + 1;
            while child < end {
                let right = child + 1;
                if right < end && !(self.data[child] > self.data[right]) {
                    child = right;
                }
                let mut x = rusti::init();
                x <-> self.data[child];
                rusti::move_val_init(&mut self.data[pos], move x);
                pos = child;
                child = 2 * pos + 1;
            }

            rusti::move_val_init(&mut self.data[pos], move new);
            self.siftup(start, pos);
        }
    }

    priv fn siftdown(&mut self, pos: uint) {
        self.siftdown_range(pos, self.len());
    }
}

#[cfg(test)]
mod tests {
    use sort::merge_sort;
    use core::cmp::le;
    use priority_queue::PriorityQueue::{from_vec, new};

    #[test]
    fn test_top_and_pop() {
        let data = ~[2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
        let mut sorted = merge_sort(data, le);
        let mut heap = from_vec(data);
        while !heap.is_empty() {
            assert *heap.top() == sorted.last();
            assert heap.pop() == sorted.pop();
        }
    }

    #[test]
    fn test_push() {
        let mut heap = from_vec(~[2, 4, 9]);
        assert heap.len() == 3;
        assert *heap.top() == 9;
        heap.push(11);
        assert heap.len() == 4;
        assert *heap.top() == 11;
        heap.push(5);
        assert heap.len() == 5;
        assert *heap.top() == 11;
        heap.push(27);
        assert heap.len() == 6;
        assert *heap.top() == 27;
        heap.push(3);
        assert heap.len() == 7;
        assert *heap.top() == 27;
        heap.push(103);
        assert heap.len() == 8;
        assert *heap.top() == 103;
    }

    #[test]
    fn test_push_unique() {
        let mut heap = from_vec(~[~2, ~4, ~9]);
        assert heap.len() == 3;
        assert *heap.top() == ~9;
        heap.push(~11);
        assert heap.len() == 4;
        assert *heap.top() == ~11;
        heap.push(~5);
        assert heap.len() == 5;
        assert *heap.top() == ~11;
        heap.push(~27);
        assert heap.len() == 6;
        assert *heap.top() == ~27;
        heap.push(~3);
        assert heap.len() == 7;
        assert *heap.top() == ~27;
        heap.push(~103);
        assert heap.len() == 8;
        assert *heap.top() == ~103;
    }

    #[test]
    fn test_push_pop() {
        let mut heap = from_vec(~[5, 5, 2, 1, 3]);
        assert heap.len() == 5;
        assert heap.push_pop(6) == 6;
        assert heap.len() == 5;
        assert heap.push_pop(0) == 5;
        assert heap.len() == 5;
        assert heap.push_pop(4) == 5;
        assert heap.len() == 5;
        assert heap.push_pop(1) == 4;
        assert heap.len() == 5;
    }

    #[test]
    fn test_replace() {
        let mut heap = from_vec(~[5, 5, 2, 1, 3]);
        assert heap.len() == 5;
        assert heap.replace(6) == 5;
        assert heap.len() == 5;
        assert heap.replace(0) == 6;
        assert heap.len() == 5;
        assert heap.replace(4) == 5;
        assert heap.len() == 5;
        assert heap.replace(1) == 4;
        assert heap.len() == 5;
    }

    fn check_to_vec(data: ~[int]) {
        let heap = from_vec(data);
        assert merge_sort(heap.to_vec(), le) == merge_sort(data, le);
        assert heap.to_sorted_vec() == merge_sort(data, le);
    }

    #[test]
    fn test_to_vec() {
        check_to_vec(~[]);
        check_to_vec(~[5]);
        check_to_vec(~[3, 2]);
        check_to_vec(~[2, 3]);
        check_to_vec(~[5, 1, 2]);
        check_to_vec(~[1, 100, 2, 3]);
        check_to_vec(~[1, 3, 5, 7, 9, 2, 4, 6, 8, 0]);
        check_to_vec(~[2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
        check_to_vec(~[9, 11, 9, 9, 9, 9, 11, 2, 3, 4, 11, 9, 0, 0, 0, 0]);
        check_to_vec(~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
        check_to_vec(~[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]);
        check_to_vec(~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 1, 2]);
        check_to_vec(~[5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1]);
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn test_empty_pop() { let mut heap = new::<int>(); heap.pop(); }

    #[test]
    fn test_empty_maybe_pop() {
        let mut heap = new::<int>();
        assert heap.maybe_pop().is_none();
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn test_empty_top() { let empty = new::<int>(); empty.top(); }

    #[test]
    fn test_empty_maybe_top() {
        let empty = new::<int>();
        assert empty.maybe_top().is_none();
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn test_empty_replace() { let mut heap = new(); heap.replace(5); }
}
<|endoftext|>