<commit_before>use crate::convert::*;
use core::hash::{Hasher};

///Just a simple bit pattern.
const PAD : u128 = 0xF0E1_D2C3_B4A5_9687_7869_5A4B_3C2D_1E0F;

/// A `Hasher` for hashing an arbitrary stream of bytes.
///
/// Instances of [AHasher] represent state that is updated while hashing data.
///
/// Each method updates the internal state based on the new data provided. Once
/// all of the data has been provided, the resulting hash can be obtained by calling
/// `finish()`
///
/// [Clone] is also provided in case you wish to calculate hashes for two different items that
/// start with the same data.
///
#[derive(Debug, Clone)]
pub struct AHasher {
    buffer: [u64; 2],
}

impl AHasher {
    /// Creates a new hasher keyed to the provided keys.
    /// # Example
    ///
    /// ```
    /// use std::hash::Hasher;
    /// use ahash::AHasher;
    ///
    /// let mut hasher = AHasher::new_with_keys(123, 456);
    ///
    /// hasher.write_u32(1989);
    /// hasher.write_u8(11);
    /// hasher.write_u8(9);
    /// hasher.write(b"Huh?");
    ///
    /// println!("Hash is {:x}!", hasher.finish());
    /// ```
    #[inline]
    pub(crate) fn new_with_keys(key0: u64, key1: u64) -> AHasher {
        AHasher { buffer: [key0, key1] }
    }

    #[inline]
    pub(crate) fn new_with_key(key: [u64; 2], loc: usize) -> AHasher {
        AHasher { buffer: [key[0], key[1] ^ (loc as u64)] }
    }
}

#[inline(never)]
#[no_mangle]
fn hash_test_aes(input: &[u8]) -> u64 {
    let mut a = AHasher::new_with_keys(67, 87);
    a.write(input);
    a.finish()
}

/// Provides methods to hash all of the primitive types.
impl Hasher for AHasher {
    #[inline]
    fn write_u8(&mut self, i: u8) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write_u16(&mut self, i: u16) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write_u32(&mut self, i: u32) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write_u128(&mut self, i: u128) {
        self.buffer = aeshash(self.buffer.convert(),i).convert();
    }

    #[inline]
    fn write_usize(&mut self, i: usize) {
        self.write_u64(i as u64);
    }

    #[inline]
    fn write_u64(&mut self, i: u64) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write(&mut self, input: &[u8]) {
        let mut data = input;
        let length = data.len() as u64;
        //This will be scrambled by the first AES round in any branch.
        self.buffer[1] ^= length;
        //A 'binary search' on sizes reduces the number of comparisons.
        if data.len() > 8 {
            if data.len() > 32 {
                if data.len() > 64 {
                    let (_, tail) = data.split_at(data.len() - 32);
                    let mut par_block: u128 = self.buffer.convert();
                    while data.len() > 64 {
                        let (b1, rest) = data.read_u128();
                        par_block = aeshash(par_block, b1);
                        data = rest;
                        let (b2, rest) = data.read_u128();
                        self.buffer = aeshash(self.buffer.convert(), b2).convert();
                        data = rest;
                    }
                    let (b1, rest) = tail.read_u128();
                    par_block = aeshash(par_block, b1);
                    let (b2, _) = rest.read_u128();
                    self.buffer = aeshash(self.buffer.convert(), b2).convert();
                    self.buffer = aeshash(self.buffer.convert(), par_block).convert();
                } else {
                    //len 33-64
                    let (head, _) = data.split_at(32);
                    let (_, tail) = data.split_at(data.len() - 32);
                    self.buffer = aeshash(self.buffer.convert(), head.read_u128().0).convert();
                    self.buffer = aeshash(self.buffer.convert(), head.read_last_u128()).convert();
                    self.buffer = aeshash(self.buffer.convert(), tail.read_u128().0).convert();
                    self.buffer = aeshash(self.buffer.convert(), tail.read_last_u128()).convert();
                }
            } else {
                if data.len() > 16 {
                    //len 17-32
                    self.buffer = aeshash(self.buffer.convert(), data.read_u128().0).convert();
                    self.buffer = aeshash(self.buffer.convert(), data.read_last_u128()).convert();
                } else {
                    //len 9-16
                    self.buffer = aeshash(self.buffer.convert(), data.read_u64().0 as u128).convert();
                    self.buffer = aeshash(self.buffer.convert(), data.read_last_u64() as u128).convert();
                }
            }
        } else {
            if data.len() >= 2 {
                if data.len() >= 4 {
                    //len 4-8
                    self.buffer = aeshash(self.buffer.convert(),data.read_u32().0 as u128).convert();
                    self.buffer = aeshash(self.buffer.convert(),data.read_last_u32() as u128).convert();
                } else {
                    //len 2-3
                    self.buffer = aeshash(self.buffer.convert(),data.read_u16().0 as u128).convert();
                    self.buffer = aeshash(self.buffer.convert(),data[data.len()-1] as u128).convert();
                }
            } else {
                let value;
                if data.len() > 0 {
                    value = data[0]; //len 1
                } else {
                    value = 0;
                }
                self.buffer = aeshash(self.buffer.convert(), value as u128).convert();
            }
        }
    }
    #[inline]
    fn finish(&self) -> u64 {
        let result: [u64; 2] = aeshash(aeshash(self.buffer.convert(), PAD), PAD).convert();
        result[0]//.wrapping_add(result[1])
    }
}

#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
#[inline(always)]
fn aeshash(value: u128, xor: u128) -> u128 {
    use core::mem::transmute;
    #[cfg(target_arch = "x86")]
    use core::arch::x86::*;
    #[cfg(target_arch = "x86_64")]
    use core::arch::x86_64::*;
    unsafe {
        let value = transmute(value);
        transmute(_mm_aesdec_si128(value, transmute(xor)))
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use std::hash::{BuildHasherDefault};
    use crate::convert::Convert;
    use crate::aes_hash::*;

    #[test]
    fn test_builder() {
        let mut map = HashMap::<u32, u64, BuildHasherDefault<AHasher>>::default();
        map.insert(1, 3);
    }

    #[test]
    fn test_default() {
        let hasher_a = AHasher::default();
        assert_ne!(0, hasher_a.buffer[0]);
        assert_ne!(0, hasher_a.buffer[1]);
        assert_ne!(hasher_a.buffer[0], hasher_a.buffer[1]);
        let hasher_b = AHasher::default();
        assert_eq!(hasher_a.buffer[0], hasher_b.buffer[0]);
        assert_eq!(hasher_a.buffer[1], hasher_b.buffer[1]);
    }

    #[test]
    fn test_hash() {
        let mut result: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
        let value: [u64; 2] = [1 << 32, 0xFEDCBA9876543210];
        result = aeshash(value.convert(), result.convert()).convert();
        result = aeshash(result.convert(), result.convert()).convert();
        let mut result2: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
        let value2: [u64; 2] = [1, 0xFEDCBA9876543210];
        result2 = aeshash(value2.convert(), result2.convert()).convert();
        result2 = aeshash(result2.convert(), result.convert()).convert();
        let result: [u8; 16] = result.convert();
        let result2: [u8; 16] = result2.convert();
        assert_ne!(hex::encode(result), hex::encode(result2));
    }

    #[test]
    fn test_conversion() {
        let input: &[u8] = "dddddddd".as_bytes();
        let bytes: u64 = as_array!(input, 8).convert();
        assert_eq!(bytes, 0x6464646464646464);
    }
}
<commit_msg>* Fix bug in reading tail of long string. * Invert IF block to improve branch prediction. * Change to adding length rather than xoring<commit_after>use crate::convert::*;
use core::hash::{Hasher};

///Just a simple bit pattern.
const PAD : u128 = 0xF0E1_D2C3_B4A5_9687_7869_5A4B_3C2D_1E0F;

/// A `Hasher` for hashing an arbitrary stream of bytes.
///
/// Instances of [AHasher] represent state that is updated while hashing data.
///
/// Each method updates the internal state based on the new data provided. Once
/// all of the data has been provided, the resulting hash can be obtained by calling
/// `finish()`
///
/// [Clone] is also provided in case you wish to calculate hashes for two different items that
/// start with the same data.
///
#[derive(Debug, Clone)]
pub struct AHasher {
    buffer: [u64; 2],
}

impl AHasher {
    /// Creates a new hasher keyed to the provided keys.
    /// # Example
    ///
    /// ```
    /// use std::hash::Hasher;
    /// use ahash::AHasher;
    ///
    /// let mut hasher = AHasher::new_with_keys(123, 456);
    ///
    /// hasher.write_u32(1989);
    /// hasher.write_u8(11);
    /// hasher.write_u8(9);
    /// hasher.write(b"Huh?");
    ///
    /// println!("Hash is {:x}!", hasher.finish());
    /// ```
    #[inline]
    pub(crate) fn new_with_keys(key0: u64, key1: u64) -> AHasher {
        AHasher { buffer: [key0, key1] }
    }

    #[inline]
    pub(crate) fn new_with_key(key: [u64; 2], loc: usize) -> AHasher {
        AHasher { buffer: [key[0], key[1] ^ (loc as u64)] }
    }
}

#[inline(never)]
#[no_mangle]
fn hash_test_aes(input: &[u8]) -> u64 {
    let mut a = AHasher::new_with_keys(67, 87);
    a.write(input);
    a.finish()
}

/// Provides methods to hash all of the primitive types.
impl Hasher for AHasher {
    #[inline]
    fn write_u8(&mut self, i: u8) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write_u16(&mut self, i: u16) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write_u32(&mut self, i: u32) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write_u128(&mut self, i: u128) {
        self.buffer = aeshash(self.buffer.convert(),i).convert();
    }

    #[inline]
    fn write_usize(&mut self, i: usize) {
        self.write_u64(i as u64);
    }

    #[inline]
    fn write_u64(&mut self, i: u64) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write(&mut self, input: &[u8]) {
        let mut data = input;
        let length = data.len() as u64;
        //This will be scrambled by the first AES round in any branch.
        self.buffer[1] = self.buffer[1].wrapping_add(length);
        //A 'binary search' on sizes reduces the number of comparisons.
        if data.len() <= 8 {
            if data.len() >= 2 {
                if data.len() >= 4 {
                    //len 4-8
                    self.buffer = aeshash(self.buffer.convert(),data.read_u32().0 as u128).convert();
                    self.buffer = aeshash(self.buffer.convert(),data.read_last_u32() as u128).convert();
                } else {
                    //len 2-3
                    self.buffer = aeshash(self.buffer.convert(),data.read_u16().0 as u128).convert();
                    self.buffer = aeshash(self.buffer.convert(),data[data.len()-1] as u128).convert();
                }
            } else {
                let value;
                if data.len() > 0 {
                    value = data[0]; //len 1
                } else {
                    value = 0;
                }
                self.buffer = aeshash(self.buffer.convert(), value as u128).convert();
            }
        } else {
            if data.len() > 32 {
                if data.len() > 64 {
                    let (_, tail) = data.split_at(data.len() - 32);
                    let mut par_block: u128 = self.buffer.convert();
                    while data.len() > 32 {
                        let (b1, rest) = data.read_u128();
                        self.buffer = aeshash(self.buffer.convert(), b1).convert();
                        data = rest;
                        let (b2, rest) = data.read_u128();
                        par_block = aeshash(par_block, b2);
                        data = rest;
                    }
                    let (b1, rest) = tail.read_u128();
                    self.buffer = aeshash(self.buffer.convert(), b1).convert();
                    let (b2, _) = rest.read_u128();
                    par_block = aeshash(par_block, b2);
                    self.buffer = aeshash(self.buffer.convert(), par_block).convert();
                } else {
                    //len 33-64
                    let (head, _) = data.split_at(32);
                    let (_, tail) = data.split_at(data.len() - 32);
                    self.buffer = aeshash(self.buffer.convert(), head.read_u128().0).convert();
                    self.buffer = aeshash(self.buffer.convert(), head.read_last_u128()).convert();
                    self.buffer = aeshash(self.buffer.convert(), tail.read_u128().0).convert();
                    self.buffer = aeshash(self.buffer.convert(), tail.read_last_u128()).convert();
                }
            } else {
                if data.len() > 16 {
                    //len 17-32
                    self.buffer = aeshash(self.buffer.convert(), data.read_u128().0).convert();
                    self.buffer = aeshash(self.buffer.convert(), data.read_last_u128()).convert();
                } else {
                    //len 9-16
                    self.buffer = aeshash(self.buffer.convert(), data.read_u64().0 as u128).convert();
                    self.buffer = aeshash(self.buffer.convert(), data.read_last_u64() as u128).convert();
                }
            }
        }
    }
    #[inline]
    fn finish(&self) -> u64 {
        let result: [u64; 2] = aeshash(aeshash(self.buffer.convert(), PAD), PAD).convert();
        result[0]//.wrapping_add(result[1])
    }
}

#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
#[inline(always)]
fn aeshash(value: u128, xor: u128) -> u128 {
    use core::mem::transmute;
    #[cfg(target_arch = "x86")]
    use core::arch::x86::*;
    #[cfg(target_arch = "x86_64")]
    use core::arch::x86_64::*;
    unsafe {
        let value = transmute(value);
        transmute(_mm_aesdec_si128(value, transmute(xor)))
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use std::hash::{BuildHasherDefault};
    use crate::convert::Convert;
    use crate::aes_hash::*;

    #[test]
    fn test_builder() {
        let mut map = HashMap::<u32, u64, BuildHasherDefault<AHasher>>::default();
        map.insert(1, 3);
    }

    #[test]
    fn test_default() {
        let hasher_a = AHasher::default();
        assert_ne!(0, hasher_a.buffer[0]);
        assert_ne!(0, hasher_a.buffer[1]);
        assert_ne!(hasher_a.buffer[0], hasher_a.buffer[1]);
        let hasher_b = AHasher::default();
        assert_eq!(hasher_a.buffer[0], hasher_b.buffer[0]);
        assert_eq!(hasher_a.buffer[1], hasher_b.buffer[1]);
    }

    #[test]
    fn test_hash() {
        let mut result: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
        let value: [u64; 2] = [1 << 32, 0xFEDCBA9876543210];
        result = aeshash(value.convert(), result.convert()).convert();
        result = aeshash(result.convert(), result.convert()).convert();
        let mut result2: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
        let value2: [u64; 2] = [1, 0xFEDCBA9876543210];
        result2 = aeshash(value2.convert(), result2.convert()).convert();
        result2 = aeshash(result2.convert(), result.convert()).convert();
        let result: [u8; 16] = result.convert();
        let result2: [u8; 16] = result2.convert();
        assert_ne!(hex::encode(result), hex::encode(result2));
    }

    #[test]
    fn test_conversion() {
        let input: &[u8] = "dddddddd".as_bytes();
        let bytes: u64 = as_array!(input, 8).convert();
        assert_eq!(bytes, 0x6464646464646464);
    }
}
<|endoftext|>


<commit_before>pub type Time = f32;

pub struct Behavior<'a, A> where A: 'a {
  closure: Box<Fn(Time) -> A + 'a>,
}

impl<'a, A> Behavior<'a, A> {
  pub fn new<F>(act: F) -> Self where F: Fn(Time) -> A + 'a {
    Behavior {
      closure: Box::new(act),
    }
  }

  pub fn run(&self, t: Time) -> A {
    (self.closure)(t)
  }
}

pub struct Node<'a, A> where A: 'a {
  behavior: &'a Behavior<'a, A>,
  next: Option<(Time, &'a Node<'a, A>)>
}

impl<'a, A> Node<'a, A> {
  pub fn new(behavior: &'a Behavior<'a, A>, next: Option<(Time, &'a Self)>) -> Self {
    Node {
      behavior: behavior,
      next: next
    }
  }

  pub fn run(&'a self, t: Time) -> (A, &'a Self) {
    let next = self.next;

    match next {
      Some((t_node, node)) if t >= t_node => node.run(t),
      _ => (self.behavior.run(t), self)
    }
  }
}
<commit_msg>Simplified the whole shit.<commit_after>pub type Time = f32;

pub struct Behavior<'a, A> where A: 'a {
  closure: Box<Fn(Time) -> A + 'a>,
  next: Option<(Time, &'a Behavior<'a, A>)>
}

impl<'a, A> Behavior<'a, A> {
  pub fn new<F>(act: F, next: Option<(Time, &'a Self)>) -> Self where F: Fn(Time) -> A + 'a {
    Behavior {
      closure: Box::new(act),
      next: next
    }
  }

  pub fn run(&'a self, t: Time) -> (A, &'a Self) {
    let next = self.next;

    match next {
      Some((node_t, node)) if t >= node_t => node.run(t),
      _ => ((self.closure)(t), self)
    }
  }
}
<|endoftext|>


<commit_before>#![warn(unused, bad_style,
        unused_qualifications, unused_typecasts, unused_results)]

#![feature(slicing_syntax)]

extern crate common;
extern crate integer;

use std::iter::{mod, AdditiveIterator, MultiplicativeIterator, Repeat};
use common::Solver;
use integer::Integer;

const RADIX: uint = 10;

struct Pandigimal {
    used: [ bool, .. RADIX ],
    num:  [ uint, .. RADIX ],
    len:  uint
}

impl Pandigimal {
    fn new() -> Pandigimal {
        Pandigimal {
            used: [ false, .. RADIX ],
            num:  [ 0, .. RADIX ],
            len:  0
        }
    }

    fn from_uint(n: uint, len: uint) -> Option<Pandigimal> {
        let it = n.into_digits(RADIX).chain(Repeat::new(0));
        Pandigimal::new().join_all(it.take(len))
    }

    fn to_uint(&self) -> uint {
        Integer::from_digits(self.num().iter().map(|&x| x), RADIX)
    }

    fn is_used(&self, n: uint) -> bool {
        assert!(n < RADIX);
        self.used[n]
    }

    fn num<'a>(&'a self) -> &'a [uint] { self.num[.. self.len] }

    fn join(&self, d: uint) -> Option<Pandigimal> {
        assert!(d < RADIX);
        if self.is_used(d) { return None }

        let mut new_pd = *self;
        new_pd.used[d] = true;
        new_pd.num[new_pd.len] = d;
        new_pd.len += 1;
        Some(new_pd)
    }

    fn join_all<T: Iterator<uint>>(&self, mut ds: T) -> Option<Pandigimal> {
        let mut pd = *self;
        for d in ds {
            match pd.join(d) {
                None    => return None,
                Some(x) => pd = x
            }
        }
        Some(pd)
    }
}

fn create_pandigimal_list(base: uint, len: uint) -> Vec<Pandigimal> {
    assert!(len > 0);
    let max = Repeat::new(RADIX).take(len).product() - 1;
    iter::range_inclusive(0, max / base)
        .filter_map(|n| Pandigimal::from_uint(base * n, len))
        .collect()
}

fn update_pandigimal_list(list: Vec<Pandigimal>, base: uint, len: uint) -> Vec<Pandigimal> {
    assert!(len > 0);
    let ord = Repeat::new(RADIX).take(len - 1).product();

    let mut result = Vec::new();
    for pd in list.iter() {
        let num = pd.num();
        let ds = num[num.len() - (len - 1) ..];
        let lower = Integer::from_digits(ds.iter().map(|&x| x), RADIX);
        let it = range(0, RADIX)
            .filter(|&d| !pd.is_used(d))
            .filter(|&d| (d * ord + lower) % base == 0)
            .map(|d| pd.join(d).unwrap());
        result.extend(it);
    }
    result
}

fn solve() -> String {
    let mut result = create_pandigimal_list(17, 3);
    for &base in [13, 11, 7, 5, 3, 2, 1].iter() {
        result = update_pandigimal_list(result, base, 3);
    }

    result
        .iter()
        .map(|pd| pd.to_uint())
        .sum()
        .to_string()
}

fn main() { Solver::new("16695334890", solve).run(); }

#[cfg(test)]
mod tests {

    mod pandigimal {
        use super::super::Pandigimal;

        #[test]
        fn from_uint() {
            let pd = Pandigimal::from_uint(123, 3).unwrap();
            assert_eq!(false, pd.is_used(0));
            assert_eq!(true, pd.is_used(1));
            assert_eq!(true, pd.is_used(2));
            assert_eq!(true, pd.is_used(3));
            assert_eq!(false, pd.is_used(4));
            assert_eq!([3, 2, 1][], pd.num())

            let pd = Pandigimal::from_uint(123, 4).unwrap();
            assert_eq!(true, pd.is_used(0));
            assert_eq!(true, pd.is_used(1));
            assert_eq!(true, pd.is_used(2));
            assert_eq!(true, pd.is_used(3));
            assert_eq!(false, pd.is_used(4));
            assert_eq!([3, 2, 1, 0][], pd.num());

            let pd = Pandigimal::from_uint(123, 2).unwrap();
            assert_eq!(false, pd.is_used(0));
            assert_eq!(false, pd.is_used(1));
            assert_eq!(true, pd.is_used(2));
            assert_eq!(true, pd.is_used(3));
            assert_eq!(false, pd.is_used(4));
            assert_eq!([3, 2][], pd.num());

            assert!(Pandigimal::from_uint(11, 2).is_none());
        }

        #[test]
        fn join() {
            let pd = Pandigimal::from_uint(123, 3).unwrap();

            let pd2 = pd.join(5).unwrap();
            assert_eq!(false, pd2.is_used(0));
            assert_eq!(true, pd2.is_used(1));
            assert_eq!(true, pd2.is_used(2));
            assert_eq!(true, pd2.is_used(3));
            assert_eq!(false, pd2.is_used(4));
            assert_eq!(true, pd2.is_used(5));
            assert_eq!([3, 2, 1, 5][], pd2.num());

            assert!(pd.join(1).is_none());
        }
    }

    #[test]
    fn create_pandigimal_list() {
        assert_eq!(0, super::create_pandigimal_list(11, 2).len());

        let pds = super::create_pandigimal_list(11, 3);
        assert_eq!([2, 3, 1][], pds[0].num());
        assert_eq!([3, 4, 1][], pds[1].num());
        assert_eq!([4, 5, 1][], pds[2].num());
        assert_eq!([5, 6, 1][], pds[3].num());
        assert_eq!([6, 7, 1][], pds[4].num());
        assert_eq!([7, 8, 1][], pds[5].num());
        assert_eq!([8, 9, 1][], pds[6].num());
        assert_eq!([9, 0, 2][], pds[7].num());
        assert_eq!([1, 3, 2][], pds[8].num());

        let pds = super::create_pandigimal_list(9, 2);
        assert_eq!(10, pds.len());
        assert_eq!([9, 0][], pds[0].num());
        assert_eq!([8, 1][], pds[1].num());
        assert_eq!([7, 2][], pds[2].num());
        assert_eq!([6, 3][], pds[3].num());
        assert_eq!([5, 4][], pds[4].num());
        assert_eq!([4, 5][], pds[5].num());
        assert_eq!([3, 6][], pds[6].num());
        assert_eq!([2, 7][], pds[7].num());
        assert_eq!([1, 8][], pds[8].num());
        assert_eq!([0, 9][], pds[9].num());
    }

    #[test]
    fn update_pandigimal_list() {
        let pd = super::create_pandigimal_list(9, 2);
        let pd = super::update_pandigimal_list(pd, 5, 2);
        assert_eq!(16, pd.len());
        assert_eq!([9, 0, 1][], pd[0].num());
        assert_eq!([9, 0, 2][], pd[1].num());
        // snip
        assert_eq!([9, 0, 8][], pd[7].num());
        assert_eq!([4, 5, 0][], pd[8].num());
        assert_eq!([4, 5, 1][], pd[9].num());
        assert_eq!([4, 5, 2][], pd[10].num());
        assert_eq!([4, 5, 3][], pd[11].num());
        assert_eq!([4, 5, 6][], pd[12].num());
        assert_eq!([4, 5, 7][], pd[13].num());
        assert_eq!([4, 5, 8][], pd[14].num());
        assert_eq!([4, 5, 9][], pd[15].num());
    }
}
<commit_msg>Fix i686 breakage<commit_after>#![warn(unused, bad_style,
        unused_qualifications, unused_typecasts, unused_results)]

#![feature(slicing_syntax)]

extern crate common;
extern crate integer;

use std::iter::{mod, AdditiveIterator, MultiplicativeIterator, Repeat};
use common::Solver;
use integer::Integer;

const RADIX: uint = 10;

struct Pandigimal {
    used: [ bool, .. RADIX ],
    num:  [ uint, .. RADIX ],
    len:  uint
}

impl Pandigimal {
    fn new() -> Pandigimal {
        Pandigimal {
            used: [ false, .. RADIX ],
            num:  [ 0, .. RADIX ],
            len:  0
        }
    }

    fn from_u64(n: u64, len: uint) -> Option<Pandigimal> {
        let it = n.into_digits(RADIX as u64).chain(Repeat::new(0));
        Pandigimal::new().join_all(it.map(|x| x as uint).take(len))
    }

    fn to_u64(&self) -> u64 {
        Integer::from_digits(self.num().iter().map(|&x| x as u64), RADIX as u64)
    }

    fn is_used(&self, n: uint) -> bool {
        assert!(n < RADIX);
        self.used[n]
    }

    fn num<'a>(&'a self) -> &'a [uint] { self.num[.. self.len] }

    fn join(&self, d: uint) -> Option<Pandigimal> {
        assert!(d < RADIX);
        if self.is_used(d) { return None }

        let mut new_pd = *self;
        new_pd.used[d] = true;
        new_pd.num[new_pd.len] = d;
        new_pd.len += 1;
        Some(new_pd)
    }

    fn join_all<T: Iterator<uint>>(&self, mut ds: T) -> Option<Pandigimal> {
        let mut pd = *self;
        for d in ds {
            match pd.join(d) {
                None    => return None,
                Some(x) => pd = x
            }
        }
        Some(pd)
    }
}

fn create_pandigimal_list(base: u64, len: uint) -> Vec<Pandigimal> {
    assert!(len > 0);
    let max = Repeat::new(RADIX as u64).take(len).product() - 1;
    iter::range_inclusive(0, max / base)
        .filter_map(|n| Pandigimal::from_u64(base * n, len))
        .collect()
}

fn update_pandigimal_list(list: Vec<Pandigimal>, base: u64, len: uint) -> Vec<Pandigimal> {
    assert!(len > 0);
    let ord = Repeat::new(RADIX as u64).take(len - 1).product();

    let mut result = Vec::new();
    for pd in list.iter() {
        let num = pd.num();
        let ds = num[num.len() - (len - 1) ..];
        let lower = Integer::from_digits(ds.iter().map(|&x| x as u64), RADIX as u64);
        let it = range(0, RADIX)
            .filter(|&d| !pd.is_used(d))
            .filter(|&d| ((d as u64) * ord + lower) % base == 0)
            .map(|d| pd.join(d).unwrap());
        result.extend(it);
    }
    result
}

fn solve() -> String {
    let mut result = create_pandigimal_list(17, 3);
    for &base in [13, 11, 7, 5, 3, 2, 1].iter() {
        result = update_pandigimal_list(result, base, 3);
    }

    result
        .iter()
        .map(|pd| pd.to_u64())
        .sum()
        .to_string()
}

fn main() { Solver::new("16695334890", solve).run(); }

#[cfg(test)]
mod tests {

    mod pandigimal {
        use super::super::Pandigimal;

        #[test]
        fn from_u64() {
            let pd = Pandigimal::from_u64(123, 3).unwrap();
            assert_eq!(false, pd.is_used(0));
            assert_eq!(true, pd.is_used(1));
            assert_eq!(true, pd.is_used(2));
            assert_eq!(true, pd.is_used(3));
            assert_eq!(false, pd.is_used(4));
            assert_eq!([3, 2, 1][], pd.num())

            let pd = Pandigimal::from_u64(123, 4).unwrap();
            assert_eq!(true, pd.is_used(0));
            assert_eq!(true, pd.is_used(1));
            assert_eq!(true, pd.is_used(2));
            assert_eq!(true, pd.is_used(3));
            assert_eq!(false, pd.is_used(4));
            assert_eq!([3, 2, 1, 0][], pd.num());

            let pd = Pandigimal::from_u64(123, 2).unwrap();
            assert_eq!(false, pd.is_used(0));
            assert_eq!(false, pd.is_used(1));
            assert_eq!(true, pd.is_used(2));
            assert_eq!(true, pd.is_used(3));
            assert_eq!(false, pd.is_used(4));
            assert_eq!([3, 2][], pd.num());

            assert!(Pandigimal::from_u64(11, 2).is_none());
        }

        #[test]
        fn join() {
            let pd = Pandigimal::from_u64(123, 3).unwrap();

            let pd2 = pd.join(5).unwrap();
            assert_eq!(false, pd2.is_used(0));
            assert_eq!(true, pd2.is_used(1));
            assert_eq!(true, pd2.is_used(2));
            assert_eq!(true, pd2.is_used(3));
            assert_eq!(false, pd2.is_used(4));
            assert_eq!(true, pd2.is_used(5));
            assert_eq!([3, 2, 1, 5][], pd2.num());

            assert!(pd.join(1).is_none());
        }
    }

    #[test]
    fn create_pandigimal_list() {
        assert_eq!(0, super::create_pandigimal_list(11, 2).len());

        let pds = super::create_pandigimal_list(11, 3);
        assert_eq!([2, 3, 1][], pds[0].num());
        assert_eq!([3, 4, 1][], pds[1].num());
        assert_eq!([4, 5, 1][], pds[2].num());
        assert_eq!([5, 6, 1][], pds[3].num());
        assert_eq!([6, 7, 1][], pds[4].num());
        assert_eq!([7, 8, 1][], pds[5].num());
        assert_eq!([8, 9, 1][], pds[6].num());
        assert_eq!([9, 0, 2][], pds[7].num());
        assert_eq!([1, 3, 2][], pds[8].num());

        let pds = super::create_pandigimal_list(9, 2);
        assert_eq!(10, pds.len());
        assert_eq!([9, 0][], pds[0].num());
        assert_eq!([8, 1][], pds[1].num());
        assert_eq!([7, 2][], pds[2].num());
        assert_eq!([6, 3][], pds[3].num());
        assert_eq!([5, 4][], pds[4].num());
        assert_eq!([4, 5][], pds[5].num());
        assert_eq!([3, 6][], pds[6].num());
        assert_eq!([2, 7][], pds[7].num());
        assert_eq!([1, 8][], pds[8].num());
        assert_eq!([0, 9][], pds[9].num());
    }

    #[test]
    fn update_pandigimal_list() {
        let pd = super::create_pandigimal_list(9, 2);
        let pd = super::update_pandigimal_list(pd, 5, 2);
        assert_eq!(16, pd.len());
        assert_eq!([9, 0, 1][], pd[0].num());
        assert_eq!([9, 0, 2][], pd[1].num());
        // snip
        assert_eq!([9, 0, 8][], pd[7].num());
        assert_eq!([4, 5, 0][], pd[8].num());
        assert_eq!([4, 5, 1][], pd[9].num());
        assert_eq!([4, 5, 2][], pd[10].num());
        assert_eq!([4, 5, 3][], pd[11].num());
        assert_eq!([4, 5, 6][], pd[12].num());
        assert_eq!([4, 5, 7][], pd[13].num());
        assert_eq!([4, 5, 8][], pd[14].num());
        assert_eq!([4, 5, 9][], pd[15].num());
    }
}
<|endoftext|>


<commit_before>use core::raw::Slice;
use core::mem::transmute;

pub struct VBE {
    control_info: u32,
    mode_info   : u32,
    mode        : u16,
    iface_seg   : u16,
    iface_off   : u16,
    iface_len   : u16,
}

pub struct FB {
    addr        : u64,
    pitch       : u32,
    width       : u32,
    height      : u32,
    bpp         : u8,
    fbtype      : u8,
    colors      : [u8; 6],
}

#[allow(dead_code)]
pub enum FBType {
    Indexed = 0,
    RGB = 1,
    Text = 2,
}

#[allow(dead_code)]
pub struct FBPalette {
    addr        : u32,
    count       : u16,
}

#[allow(dead_code)]
pub struct FBPixelFormat {
    red_shift   : u8,
    red_mask    : u8,
    green_shift : u8,
    green_mask  : u8,
    blue_shift  : u8,
    blue_mask   : u8,
}

pub enum InfoFlags {
    MemorySize = 1,
    BootDevice = 2,
    CommandLine = 4,
    Modules = 8,
    // There are two formats for the symbol bit of the info struct, not sure
    // what they are though.
    Symbols = 16 | 32,
    Symbols1 = 16,
    Symbols2 = 32,
    MemoryMap = 64,
    Drives = 128,
    ConfigTable = 256,
    LoaderName = 512,
    APMTable = 1024,
    VBEInfo = 2048
}

pub struct Info {
    pub flags   : u32,
// if has(MemorySize)
    pub mem_lower   : u32,
    pub mem_upper   : u32,
// if flags[1]:
    pub boot_devices: u32,

// if has(CommandLine)
    pub cmdline     : u32,

// if has(Modules)
    pub mods_count  : u32,
    pub mods_addr   : u32,

//
    syms        : [u32; 4],

// if has(MMap)
    pub mmap_length : u32,
    pub mmap_addr   : u32,

    drives_length: u32,
    drives_addr : u32,

    config_table: u32,

    boot_loader : u32,
    apm_table   : u32,

    vbe         : VBE,
    fb          : FB,
}

impl Info {
    pub fn has(&self, flag : InfoFlags) -> bool {
        self.flags & (flag as u32) != 0
    }

    pub fn modules(&self, make_ptr : |uint| -> *const Module) -> &[Module] {
        unsafe { transmute(Slice {
            data : make_ptr(self.mods_addr as uint),
            len : self.mods_count as uint
        }) }
    }
}

#[allow(dead_code)] // Spurious dead-code warning?
pub struct Module {
    pub start   : u32,
    pub end     : u32,
    pub string  : u32,
    reserved    : u32,
}

#[repr(packed)]
pub struct MemoryMapItem {
    // Size of item (bytes), *not* including the item_size field
    pub item_size   : u32,
    pub start       : u64,
    pub length      : u64,
    // See values from MemoryTypes
    pub item_type   : u32,
}

pub enum MemoryTypes {
    MemoryTypeMemory = 1,
    MemoryTypeReserved = 2,
    MemoryTypeACPIRCL = 3,
    MemoryTypeACPISomething = 4,
}
<commit_msg>Unboxed closure???<commit_after>use core::raw::Slice;
use core::mem::transmute;

pub struct VBE {
    control_info: u32,
    mode_info   : u32,
    mode        : u16,
    iface_seg   : u16,
    iface_off   : u16,
    iface_len   : u16,
}

pub struct FB {
    addr        : u64,
    pitch       : u32,
    width       : u32,
    height      : u32,
    bpp         : u8,
    fbtype      : u8,
    colors      : [u8; 6],
}

#[allow(dead_code)]
pub enum FBType {
    Indexed = 0,
    RGB = 1,
    Text = 2,
}

#[allow(dead_code)]
pub struct FBPalette {
    addr        : u32,
    count       : u16,
}

#[allow(dead_code)]
pub struct FBPixelFormat {
    red_shift   : u8,
    red_mask    : u8,
    green_shift : u8,
    green_mask  : u8,
    blue_shift  : u8,
    blue_mask   : u8,
}

pub enum InfoFlags {
    MemorySize = 1,
    BootDevice = 2,
    CommandLine = 4,
    Modules = 8,
    // There are two formats for the symbol bit of the info struct, not sure
    // what they are though.
    Symbols = 16 | 32,
    Symbols1 = 16,
    Symbols2 = 32,
    MemoryMap = 64,
    Drives = 128,
    ConfigTable = 256,
    LoaderName = 512,
    APMTable = 1024,
    VBEInfo = 2048
}

pub struct Info {
    pub flags   : u32,
// if has(MemorySize)
    pub mem_lower   : u32,
    pub mem_upper   : u32,
// if flags[1]:
    pub boot_devices: u32,

// if has(CommandLine)
    pub cmdline     : u32,

// if has(Modules)
    pub mods_count  : u32,
    pub mods_addr   : u32,

//
    syms        : [u32; 4],

// if has(MMap)
    pub mmap_length : u32,
    pub mmap_addr   : u32,

    drives_length: u32,
    drives_addr : u32,

    config_table: u32,

    boot_loader : u32,
    apm_table   : u32,

    vbe         : VBE,
    fb          : FB,
}

impl Info {
    pub fn has(&self, flag : InfoFlags) -> bool {
        self.flags & (flag as u32) != 0
    }

    pub fn modules(&self, make_ptr : Fn(uint) -> *const Module) -> &[Module] {
        unsafe { transmute(Slice {
            data : make_ptr(self.mods_addr as uint),
            len : self.mods_count as uint
        }) }
    }
}

#[allow(dead_code)] // Spurious dead-code warning?
pub struct Module {
    pub start   : u32,
    pub end     : u32,
    pub string  : u32,
    reserved    : u32,
}

#[repr(packed)]
pub struct MemoryMapItem {
    // Size of item (bytes), *not* including the item_size field
    pub item_size   : u32,
    pub start       : u64,
    pub length      : u64,
    // See values from MemoryTypes
    pub item_type   : u32,
}

pub enum MemoryTypes {
    MemoryTypeMemory = 1,
    MemoryTypeReserved = 2,
    MemoryTypeACPIRCL = 3,
    MemoryTypeACPISomething = 4,
}
<|endoftext|>


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

//!
//! # Regular language
//!
//! This provides a data structure representing a regular language. This is a more generalised form of a regular
//! expression (it supports symbol types other than simple strings). A regular language using the `u8` symbol forms
//! a simple regular expression.
//!

use super::phrase::*;
use std::ops::Range;

///
/// A Pattern represents a matching pattern in a regular language
///
#[derive(Clone)]
pub enum Pattern<Symbol> {
    ///
    /// Matches nothing
    ///
    Nothing,

    ///
    /// Matches a specific literal phrase
    ///
    Phrase(Vec<Symbol>),

    ///
    /// Matches at least a particular number of repetitions of a pattern
    ///
    /// `RepeatInfinite(0, X)` is the equivalent of the regular expression `X*`, `RepeatInfinite(1, X)` is the equivalent of the regular expression `X+`
    ///
    RepeatInfinite(u32, Box<Pattern<Symbol>>),

    ///
    /// Matches a range of repetitions of a pattern
    ///
    Repeat(Range<u32>, Box<Pattern<Symbol>>),

    ///
    /// Matches a set of sub-patterns in order
    ///
    And(Vec<Pattern<Symbol>>),

    ///
    /// Matches any one of a set of patterns
    ///
    Or(Vec<Pattern<Symbol>>)
}
<commit_msg>Import the pattern enum values into the module<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Regular language
//!
//! This provides a data structure representing a regular language. This is a more generalised form of a regular
//! expression (it supports symbol types other than simple strings). A regular language using the `u8` symbol forms
//! a simple regular expression.
//!

use super::phrase::*;
use std::ops::Range;

///
/// A Pattern represents a matching pattern in a regular language
///
#[derive(Clone)]
pub enum Pattern<Symbol> {
    ///
    /// Matches nothing
    ///
    Epsilon,

    ///
    /// Matches a specific literal phrase
    ///
    Match(Vec<Symbol>),

    ///
    /// Matches at least a particular number of repetitions of a pattern
    ///
    /// `RepeatInfinite(0, X)` is the equivalent of the regular expression `X*`, `RepeatInfinite(1, X)` is the equivalent of the regular expression `X+`
    ///
    RepeatInfinite(u32, Box<Pattern<Symbol>>),

    ///
    /// Matches a range of repetitions of a pattern
    ///
    Repeat(Range<u32>, Box<Pattern<Symbol>>),

    ///
    /// Matches a set of sub-patterns in order
    ///
    MatchAll(Vec<Pattern<Symbol>>),

    ///
    /// Matches any one of a set of patterns
    ///
    MatchAny(Vec<Pattern<Symbol>>)
}

pub use Pattern::*;
<|endoftext|>


<commit_before>use parser::HttpParser;

pub enum CallbackDecision {
    Nothing,
    SkipBody,
}

pub type CallbackResult = Result<CallbackDecision, String>;

pub trait HttpParserCallback {
    fn on_message_begin(&mut self, parser : &mut HttpParser) -> CallbackResult {
        Ok(CallbackDecision::Nothing)
    }

    #[allow(unused_variables)]
    fn on_url(&mut self, parser : &mut HttpParser, data : &[u8],) -> CallbackResult {
        Ok(CallbackDecision::Nothing)
    }

    #[allow(unused_variables)]
    fn on_status(&mut self, parser : &mut HttpParser, data : &[u8]) -> CallbackResult {
        Ok(CallbackDecision::Nothing)
    }

    #[allow(unused_variables)]
    fn on_header_field(&mut self, parser : &mut HttpParser, data : &[u8]) -> CallbackResult {
        Ok(CallbackDecision::Nothing)
    }

    #[allow(unused_variables)]
    fn on_header_value(&mut self, parser : &mut HttpParser, data : &[u8]) -> CallbackResult {
        Ok(CallbackDecision::Nothing)
    }

    fn on_headers_complete(&mut self, parser : &mut HttpParser) -> CallbackResult {
        Ok(CallbackDecision::Nothing)
    }

    #[allow(unused_variables)]
    fn on_body(&mut self, parser : &mut HttpParser, data : &[u8]) -> CallbackResult {
        Ok(CallbackDecision::Nothing)
    }

    fn on_message_complete(&mut self, parser : &mut HttpParser) -> CallbackResult {
        Ok(CallbackDecision::Nothing)
    }
}
<commit_msg>suppress warning in callback<commit_after>use parser::HttpParser;

#[derive(Copy)]
pub enum CallbackDecision {
    Nothing,
    SkipBody,
}

pub type CallbackResult = Result<CallbackDecision, String>;

pub trait HttpParserCallback {
    #[allow(unused_variables)]
    fn on_message_begin(&mut self, parser : &mut HttpParser) -> CallbackResult {
        Ok(CallbackDecision::Nothing)
    }

    #[allow(unused_variables)]
    fn on_url(&mut self, parser : &mut HttpParser, data : &[u8],) -> CallbackResult {
        Ok(CallbackDecision::Nothing)
    }

    #[allow(unused_variables)]
    fn on_status(&mut self, parser : &mut HttpParser, data : &[u8]) -> CallbackResult {
        Ok(CallbackDecision::Nothing)
    }

    #[allow(unused_variables)]
    fn on_header_field(&mut self, parser : &mut HttpParser, data : &[u8]) -> CallbackResult {
        Ok(CallbackDecision::Nothing)
    }

    #[allow(unused_variables)]
    fn on_header_value(&mut self, parser : &mut HttpParser, data : &[u8]) -> CallbackResult {
        Ok(CallbackDecision::Nothing)
    }

    #[allow(unused_variables)]
    fn on_headers_complete(&mut self, parser : &mut HttpParser) -> CallbackResult {
        Ok(CallbackDecision::Nothing)
    }

    #[allow(unused_variables)]
    fn on_body(&mut self, parser : &mut HttpParser, data : &[u8]) -> CallbackResult {
        Ok(CallbackDecision::Nothing)
    }

    #[allow(unused_variables)]
    fn on_message_complete(&mut self, parser : &mut HttpParser) -> CallbackResult {
        Ok(CallbackDecision::Nothing)
    }
}
<|endoftext|>


<commit_before>// TODO: use Impls https://github.com/iron/iron/blob/master/src/iron.rs

extern crate collections;

use collections::dlist::DList;
use collections::Deque;

use std::cmp::min;

static CHB_MIN_SIZE:uint = 32u;

// TODO: move to utils
fn blit<T:Clone>(src: &[T], src_ofs: uint, dst: &mut [T], dst_ofs: uint, len: uint) {
    if (src_ofs > src.len() - len) || (dst_ofs > dst.len() - len) {
        fail!("blit: invalid argument!");
    }
    let sd = dst.slice_mut(dst_ofs, dst_ofs + len);
    let ss = src.slice(src_ofs, src_ofs + len);
    let _ = sd.clone_from_slice(ss);
}

/// Chained buffer of bytes.
/// Consists of linked list of nodes.
pub struct Chain {
    head: DList<Box<Node>>,
    length: uint
}

impl Chain {
    pub fn new() -> Chain {
        return Chain{
            head: DList::new(),
            length: 0
        }
    }

    pub fn len(&self) -> uint {
        self.length
    }

    // XXX: maybe DEDUP append/prepend?
    // TODO: test: length, capacity, node size
    pub fn append_bytes(&mut self, data: &[u8]) {
        let size = data.len();
        // XXX: Damn, https://github.com/rust-lang/rust/issues/6393
        let should_create = match self.head.back() {
            Some(nd) => {
                // Check is READONLY
                nd.room() < size
            }
            None => {
                true
            }
        };
        if should_create {
            let nsize = if size < CHB_MIN_SIZE { size << 1 } else { size };
            let node = Node::new(DataHolder::new(nsize)); // Box<Node>
            self.add_node_tail(node);
        }
        // node could not be None here
        let node = self.head.back_mut().unwrap();
        node.append_from(data, 0, size);
        self.length += size;
    }

    // TODO: test: length, capacity, node size
    pub fn prepend_bytes(&mut self, data: &[u8]) {
        let size = data.len();
        // XXX: Damn, https://github.com/rust-lang/rust/issues/6393
        let should_create = match self.head.front() {
            Some(nd) => {
                // Check is READONLY
                size > nd.start
            }
            None => {
                true
            }
        };
        if should_create {
            let nsize = if size < CHB_MIN_SIZE { size << 1 } else { size };
            let mut node = Node::new(DataHolder::new(nsize)); // Box<Node>
            let r = node.room();
            node.start = r;
            node.end = r;
            self.add_node_head(node);
        }
        // node could not be None here
        let node = self.head.front_mut().unwrap();
        node.prepend_from(data, 0, size);
        self.length += size;
    }

    pub fn pullup(&mut self, size: uint) -> Option<&[u8]> {
        if size == 0 || size > self.len() {
            return None
        }
        // could not fail, because self.size() > 0 => has node
        if self.head.front().unwrap().size() >= size {
            let node = self.head.front().unwrap();
            return Some(node.data_range(node.start, node.start + size));
        }

        let mut newn = Node::new(DataHolder::new(size));
        let mut msize = size;
        while msize > 0 {
            {
                let node = self.head.front_mut().unwrap();
                let csize = min(node.size(), size);
                newn.append_from(node.data(), node.start, csize);

                if node.size() > size {
                    node.start += size;
                    self.length -= size;
                    break
                }
            }
            // infailable
            let n = self.head.pop_front().unwrap();
            msize -= n.size();
            // XXX: free node?
        }
        self.add_node_head(newn);
        // Now first node.size >= size, so we recurse
        return self.pullup(size)
    }

    // XXX: private
    fn add_node_tail(&mut self, node: Box<Node>) {
        self.length += node.size();
        self.head.push(node);
    }

    fn add_node_head(&mut self, node: Box<Node>) {
        self.length += node.size();
        self.head.push_front(node);
    }
}

/// Node of chain buffer.
/// Owned by Chain.
struct Node {
    dh: Box<DataHolder>, // можно заменить на RC
    start: uint,
    end: uint
}

impl Node {
    fn new(dh: Box<DataHolder>) -> Box<Node> {
        let n = box Node {
            dh: dh,
            start: 0,
            end: 0
        };
        // TODO: ref dh ? auto, when using RC
        return n;
    }

    fn size(&self) -> uint {
        self.end - self.start
    }

    fn room(&self) -> uint {
        self.dh.size - self.end
    }

    fn data(&self) -> &[u8] {
        self.dh.data.as_slice()
    }

    fn data_range(&self, start:uint, end:uint) -> &[u8] {
        self.data().slice(start, end)
    }

    fn mut_data(&mut self) -> &mut [u8] {
        self.dh.data.as_mut_slice()
    }

    fn append_from(&mut self, data: &[u8], offs: uint, size: uint) {
        // XXX: Damn, https://github.com/rust-lang/rust/issues/6268
        let e = self.end;
        blit(data, offs,
             self.mut_data(), e,
             size);
        self.end += size
    }

    fn prepend_from(&mut self, data: &[u8], offs: uint, size: uint) {
        let s = self.start;
        blit(data, offs,
             self.mut_data(), s - size,
             size);
        self.start -= size;
    }
}

/// Data holder
/// TODO: can be shared among different chains
/// TODO: implement other storages: shmem, mmap
struct DataHolder{
    size: uint,
    data: Vec<u8>
}

impl DataHolder {
    fn new(size: uint) -> Box<DataHolder> {
        let dh = box DataHolder {
            size: size,
            data: Vec::from_elem(size, 0)
        };
        return dh;
    }
}

#[cfg(test)]
mod test {
    use super::Chain;
    use std::rand::{task_rng, Rng};

    #[test]
    fn test_append_bytes_changes_length() {
        let mut chain = Chain::new();
        let s = "HelloWorld";
        let ls = s.len();
        chain.append_bytes(s.as_bytes());
        assert_eq!(chain.len(), ls);
    }

    #[test]
    fn test_prepend_bytes_changes_length() {
        let mut chain = Chain::new();
        let s = "HelloWorld".as_bytes();
        let ls = s.len();
        chain.prepend_bytes(s);
        assert_eq!(chain.len(), ls);
    }

    #[test]
    fn test_pullup_return_none_on_empty_chain() {
        let mut chain = Chain::new();
        assert_eq!(chain.pullup(1), None);
    }

    #[test]
    fn test_pullup_return_what_has_been_appended() {
        let mut chain = Chain::new();
        let s = "HelloWorld".as_bytes();
        let ls = s.len();
        chain.append_bytes(s);
        let res = chain.pullup(ls);
        assert!(res.is_some());
        assert_eq!(res.unwrap(), s);
    }

    #[test]
    fn test_pullup_does_not_change_length() {
        let mut chain = Chain::new();
        let s = "HelloWorld".as_bytes();
        let ls = s.len();
        chain.append_bytes(s);
        let olds = chain.len();
        chain.pullup(ls / 2);
        assert_eq!(chain.len(), olds);
    }

    #[test]
    fn test_pullup_works_on_large_sequences() {
        let mut chain = Chain::new();
        let total = 2048u;
        let mut t = total;
        let one_seq = 128u;
        let mut buf = Vec::new();
        while t > 0 {
            let s:String = task_rng().gen_ascii_chars().take(one_seq).collect();
            let b = s.as_bytes();
            buf = buf.append(b);
            chain.append_bytes(b);
            t -= one_seq;
        }
        let ret = chain.pullup(total);
        assert!(ret.is_some());
        assert_eq!(ret.unwrap(), buf.as_slice());
    }
}
<commit_msg>[add] chb.concat(other_chb)<commit_after>// TODO: use Impls https://github.com/iron/iron/blob/master/src/iron.rs

extern crate collections;

use collections::dlist::DList;
use collections::Deque;

use std::cmp::min;

static CHB_MIN_SIZE:uint = 32u;

// TODO: move to utils
fn blit<T:Clone>(src: &[T], src_ofs: uint, dst: &mut [T], dst_ofs: uint, len: uint) {
    if (src_ofs > src.len() - len) || (dst_ofs > dst.len() - len) {
        fail!("blit: invalid argument!");
    }
    let sd = dst.slice_mut(dst_ofs, dst_ofs + len);
    let ss = src.slice(src_ofs, src_ofs + len);
    let _ = sd.clone_from_slice(ss);
}

/// Chained buffer of bytes.
/// Consists of linked list of nodes.
pub struct Chain {
    head: DList<Box<Node>>,
    length: uint
}

impl Chain {
    pub fn new() -> Chain {
        return Chain{
            head: DList::new(),
            length: 0
        }
    }

    pub fn len(&self) -> uint {
        self.length
    }

    // XXX: maybe DEDUP append/prepend?
    // TODO: test: length, capacity, node size
    pub fn append_bytes(&mut self, data: &[u8]) {
        let size = data.len();
        // XXX: Damn, https://github.com/rust-lang/rust/issues/6393
        let should_create = match self.head.back() {
            Some(nd) => {
                // Check is READONLY
                nd.room() < size
            }
            None => {
                true
            }
        };
        if should_create {
            let nsize = if size < CHB_MIN_SIZE { size << 1 } else { size };
            let node = Node::new(DataHolder::new(nsize)); // Box<Node>
            self.add_node_tail(node);
        }
        // node could not be None here
        let node = self.head.back_mut().unwrap();
        node.append_from(data, 0, size);
        self.length += size;
    }

    // TODO: test: length, capacity, node size
    pub fn prepend_bytes(&mut self, data: &[u8]) {
        let size = data.len();
        // XXX: Damn, https://github.com/rust-lang/rust/issues/6393
        let should_create = match self.head.front() {
            Some(nd) => {
                // Check is READONLY
                size > nd.start
            }
            None => {
                true
            }
        };
        if should_create {
            let nsize = if size < CHB_MIN_SIZE { size << 1 } else { size };
            let mut node = Node::new(DataHolder::new(nsize)); // Box<Node>
            let r = node.room();
            node.start = r;
            node.end = r;
            self.add_node_head(node);
        }
        // node could not be None here
        let node = self.head.front_mut().unwrap();
        node.prepend_from(data, 0, size);
        self.length += size;
    }

    pub fn pullup(&mut self, size: uint) -> Option<&[u8]> {
        if size == 0 || size > self.len() {
            return None
        }
        // could not fail, because self.size() > 0 => has node
        if self.head.front().unwrap().size() >= size {
            let node = self.head.front().unwrap();
            return Some(node.data_range(node.start, node.start + size));
        }

        let mut newn = Node::new(DataHolder::new(size));
        let mut msize = size;
        while msize > 0 {
            {
                let node = self.head.front_mut().unwrap();
                let csize = min(node.size(), size);
                newn.append_from(node.data(), node.start, csize);

                if node.size() > size {
                    node.start += size;
                    self.length -= size;
                    break
                }
            }
            // infailable
            let n = self.head.pop_front().unwrap();
            msize -= n.size();
            // XXX: free node?
        }
        self.add_node_head(newn);
        // Now first node.size >= size, so we recurse
        return self.pullup(size)
    }

    pub fn concat(&mut self, src: &mut Chain) {
        use std::mem::replace;
        self.length += src.length;
        let sh = replace(&mut src.head, DList::new());
        self.head.append(sh);
        src.length = 0;
    }

    // XXX: private
    fn add_node_tail(&mut self, node: Box<Node>) {
        self.length += node.size();
        self.head.push(node);
    }

    fn add_node_head(&mut self, node: Box<Node>) {
        self.length += node.size();
        self.head.push_front(node);
    }
}

/// Node of chain buffer.
/// Owned by Chain.
struct Node {
    dh: Box<DataHolder>, // можно заменить на RC
    start: uint,
    end: uint
}

impl Node {
    fn new(dh: Box<DataHolder>) -> Box<Node> {
        let n = box Node {
            dh: dh,
            start: 0,
            end: 0
        };
        // TODO: ref dh ? auto, when using RC
        return n;
    }

    fn size(&self) -> uint {
        self.end - self.start
    }

    fn room(&self) -> uint {
        self.dh.size - self.end
    }

    fn data(&self) -> &[u8] {
        self.dh.data.as_slice()
    }

    fn data_range(&self, start:uint, end:uint) -> &[u8] {
        self.data().slice(start, end)
    }

    fn mut_data(&mut self) -> &mut [u8] {
        self.dh.data.as_mut_slice()
    }

    fn append_from(&mut self, data: &[u8], offs: uint, size: uint) {
        // XXX: Damn, https://github.com/rust-lang/rust/issues/6268
        let e = self.end;
        blit(data, offs,
             self.mut_data(), e,
             size);
        self.end += size
    }

    fn prepend_from(&mut self, data: &[u8], offs: uint, size: uint) {
        let s = self.start;
        blit(data, offs,
             self.mut_data(), s - size,
             size);
        self.start -= size;
    }
}

/// Data holder
/// TODO: can be shared among different chains
/// TODO: implement other storages: shmem, mmap
struct DataHolder{
    size: uint,
    data: Vec<u8>
}

impl DataHolder {
    fn new(size: uint) -> Box<DataHolder> {
        let dh = box DataHolder {
            size: size,
            data: Vec::from_elem(size, 0)
        };
        return dh;
    }
}

#[cfg(test)]
mod test {
    use super::Chain;
    use std::rand::{task_rng, Rng};

    #[test]
    fn test_append_bytes_changes_length() {
        let mut chain = Chain::new();
        let s = "HelloWorld";
        let ls = s.len();
        chain.append_bytes(s.as_bytes());
        assert_eq!(chain.len(), ls);
    }

    #[test]
    fn test_prepend_bytes_changes_length() {
        let mut chain = Chain::new();
        let s = "HelloWorld".as_bytes();
        let ls = s.len();
        chain.prepend_bytes(s);
        assert_eq!(chain.len(), ls);
    }

    #[test]
    fn test_pullup_return_none_on_empty_chain() {
        let mut chain = Chain::new();
        assert_eq!(chain.pullup(1), None);
    }

    #[test]
    fn test_pullup_return_what_has_been_appended() {
        let mut chain = Chain::new();
        let s = "HelloWorld".as_bytes();
        let ls = s.len();
        chain.append_bytes(s);
        let res = chain.pullup(ls);
        assert!(res.is_some());
        assert_eq!(res.unwrap(), s);
    }

    #[test]
    fn test_pullup_does_not_change_length() {
        let mut chain = Chain::new();
        let s = "HelloWorld".as_bytes();
        let ls = s.len();
        chain.append_bytes(s);
        let olds = chain.len();
        chain.pullup(ls / 2);
        assert_eq!(chain.len(), olds);
    }

    #[test]
    fn test_pullup_works_on_large_sequences() {
        let mut chain = Chain::new();
        let total = 2048u;
        let mut t = total;
        let one_seq = 128u;
        let mut buf = Vec::new();
        while t > 0 {
            let s:String = task_rng().gen_ascii_chars().take(one_seq).collect();
            let b = s.as_bytes();
            buf = buf.append(b);
            chain.append_bytes(b);
            t -= one_seq;
        }
        let ret = chain.pullup(total);
        assert!(ret.is_some());
        assert_eq!(ret.unwrap(), buf.as_slice());
    }

    #[test]
    fn test_concat_increase_dst_length() {
        let mut chain1 = Chain::new();
        let mut chain2 = Chain::new();
        chain1.append_bytes("HelloWorld".as_bytes());
        let l1 = chain1.len();
        chain2.append_bytes("HelloWorld".as_bytes());
        let l2 = chain2.len();
        chain1.concat(&mut chain2);
        assert_eq!(chain1.len(), l1+l2);
    }

    #[test]
    fn test_concat_destroy_src() {
        let mut chain1 = Chain::new();
        let mut chain2 = Chain::new();
        chain2.append_bytes("HelloWorld".as_bytes());
        chain1.concat(&mut chain2);
        assert_eq!(chain2.len(), 0);
    }

    #[test]
    fn test_concat_appends_content() {
        let mut chain1 = Chain::new();
        let mut chain2 = Chain::new();
        let b = "HelloWorld".as_bytes();
        let bl = b.len();
        chain2.append_bytes(b);
        chain1.concat(&mut chain2);
        let res = chain1.pullup(bl);
        assert!(res.is_some());
        assert_eq!(res.unwrap(), b);
    }

}
<|endoftext|>


<commit_before>pub static RUSTUP_HELP: &str = r"DISCUSSION:
    rustup installs The Rust Programming Language from the official
    release channels, enabling you to easily switch between stable,
    beta, and nightly compilers and keep them updated. It makes
    cross-compiling simpler with binary builds of the standard library
    for common platforms.

    If you are new to Rust consider running `rustup doc --book` to
    learn Rust.";

pub static SHOW_HELP: &str = r"DISCUSSION:
    Shows the name of the active toolchain and the version of `rustc`.

    If the active toolchain has installed support for additional
    compilation targets, then they are listed as well.

    If there are multiple toolchains installed then all installed
    toolchains are listed as well.";

pub static SHOW_ACTIVE_TOOLCHAIN_HELP: &str = r"DISCUSSION:
    Shows the name of the active toolchain.

    This is useful for figuring out the active tool chain from
    scripts.

    You should use `rustc --print sysroot` to get the sysroot, or
    `rustc --version` to get the toolchain version.";

pub static UPDATE_HELP: &str = r"DISCUSSION:
    With no toolchain specified, the `update` command updates each of
    the installed toolchains from the official release channels, then
    updates rustup itself.

    If given a toolchain argument then `update` updates that
    toolchain, the same as `rustup toolchain install`.";

pub static INSTALL_HELP: &str = r"DISCUSSION:
    Installs a specific rust toolchain.

    The 'install' command is an alias for 'rustup update <toolchain>'.";

pub static DEFAULT_HELP: &str = r"DISCUSSION:
    Sets the default toolchain to the one specified. If the toolchain
    is not already installed then it is installed first.";

pub static TOOLCHAIN_HELP: &str = r"DISCUSSION:
    Many `rustup` commands deal with *toolchains*, a single
    installation of the Rust compiler. `rustup` supports multiple
    types of toolchains. The most basic track the official release
    channels: 'stable', 'beta' and 'nightly'; but `rustup` can also
    install toolchains from the official archives, for alternate host
    platforms, and from local builds.

    Standard release channel toolchain names have the following form:

        <channel>[-<date>][-<host>]

        <channel>       = stable|beta|nightly|<major.minor>|<major.minor.patch>
        <date>          = YYYY-MM-DD
        <host>          = <target-triple>

    'channel' is a named release channel, a major and minor version
    number such as `1.42`, or a fully specified version number, such
    as `1.42.0`. Channel names can be optionally appended with an
    archive date, as in `nightly-2014-12-18`, in which case the
    toolchain is downloaded from the archive for that date.

    The host may be specified as a target triple. This is most useful
    for installing a 32-bit compiler on a 64-bit platform, or for
    installing the [MSVC-based toolchain] on Windows. For example:

        $ rustup toolchain install stable-x86_64-pc-windows-msvc

    For convenience, omitted elements of the target triple will be
    inferred, so the above could be written:

        $ rustup toolchain install stable-msvc

    The `rustup default` command may be used to both install and set
    the desired toolchain as default in a single command:

        $ rustup default stable-msvc

    rustup can also manage symlinked local toolchain builds, which are
    often used for developing Rust itself. For more information see
    `rustup toolchain help link`.";

pub static TOOLCHAIN_LINK_HELP: &str = r"DISCUSSION:
    'toolchain' is the custom name to be assigned to the new toolchain.
    Any name is permitted as long as it does not fully match an initial
    substring of a standard release channel. For example, you can use
    the names 'latest' or '2017-04-01' but you cannot use 'stable' or
    'beta-i686' or 'nightly-x86_64-unknown-linux-gnu'.

    'path' specifies the directory where the binaries and libraries for
    the custom toolchain can be found. For example, when used for
    development of Rust itself, toolchains can be linked directly out of
    the build directory. After building, you can test out different
    compiler versions as follows:

        $ rustup toolchain link latest-stage1 build/x86_64-unknown-linux-gnu/stage1
        $ rustup override set latest-stage1

    If you now compile a crate in the current directory, the custom
    toolchain 'latest-stage1' will be used.";

pub static OVERRIDE_HELP: &str = r"DISCUSSION:
    Overrides configure rustup to use a specific toolchain when
    running in a specific directory.

    Directories can be assigned their own Rust toolchain with `rustup
    override`. When a directory has an override then any time `rustc`
    or `cargo` is run inside that directory, or one of its child
    directories, the override toolchain will be invoked.

    To pin to a specific nightly:

        $ rustup override set nightly-2014-12-18

    Or a specific stable release:

        $ rustup override set 1.0.0

    To see the active toolchain use `rustup show`. To remove the
    override and use the default toolchain again, `rustup override
    unset`.";

pub static OVERRIDE_UNSET_HELP: &str = r"DISCUSSION:
    If `--path` argument is present, removes the override toolchain
    for the specified directory. If `--nonexistent` argument is
    present, removes the override toolchain for all nonexistent
    directories. Otherwise, removes the override toolchain for the
    current directory.";

pub static RUN_HELP: &str = r"DISCUSSION:
    Configures an environment to use the given toolchain and then runs
    the specified program. The command may be any program, not just
    rustc or cargo. This can be used for testing arbitrary toolchains
    without setting an override.

    Commands explicitly proxied by `rustup` (such as `rustc` and
    `cargo`) also have a shorthand for this available. The toolchain
    can be set by using `+toolchain` as the first argument. These are
    equivalent:

        $ cargo +nightly build

        $ rustup run nightly cargo build";

pub static DOC_HELP: &str = r"DISCUSSION:
    Opens the documentation for the currently active toolchain with
    the default browser.

    By default, it opens the documentation index. Use the various
    flags to open specific pieces of documentation.";

pub static COMPLETIONS_HELP: &str = r"DISCUSSION:
    Enable tab completion for Bash, Fish, Zsh, or PowerShell
    The script is output on `stdout`, allowing one to re-direct the
    output to the file of their choosing. Where you place the file
    will depend on which shell, and which operating system you are
    using. Your particular configuration may also determine where
    these scripts need to be placed.

    Here are some common set ups for the three supported shells under
    Unix and similar operating systems (such as GNU/Linux).

    BASH:

    Completion files are commonly stored in `/etc/bash_completion.d/` for
    system-wide commands, but can be stored in
    `~/.local/share/bash-completion/completions` for user-specific commands.
    Run the command:

        $ mkdir -p ~/.local/share/bash-completion/completions
        $ rustup completions bash >> ~/.local/share/bash-completion/completions/rustup

    This installs the completion script. You may have to log out and
    log back in to your shell session for the changes to take affect.

    BASH (macOS/Homebrew):

    Homebrew stores bash completion files within the Homebrew directory.
    With the `bash-completion` brew formula installed, run the command:

        $ mkdir -p $(brew --prefix)/etc/bash_completion.d
        $ rustup completions bash > $(brew --prefix)/etc/bash_completion.d/rustup.bash-completion

    FISH:

    Fish completion files are commonly stored in
    `$HOME/.config/fish/completions`. Run the command:

        $ mkdir -p ~/.config/fish/completions
        $ rustup completions fish > ~/.config/fish/completions/rustup.fish

    This installs the completion script. You may have to log out and
    log back in to your shell session for the changes to take affect.

    ZSH:

    ZSH completions are commonly stored in any directory listed in
    your `$fpath` variable. To use these completions, you must either
    add the generated script to one of those directories, or add your
    own to this list.

    Adding a custom directory is often the safest bet if you are
    unsure of which directory to use. First create the directory; for
    this example we'll create a hidden directory inside our `$HOME`
    directory:

        $ mkdir ~/.zfunc

    Then add the following lines to your `.zshrc` just before
    `compinit`:

        fpath+=~/.zfunc

    Now you can install the completions script using the following
    command:

        $ rustup completions zsh > ~/.zfunc/_rustup

    You must then either log out and log back in, or simply run

        $ exec zsh

    for the new completions to take affect.

    CUSTOM LOCATIONS:

    Alternatively, you could save these files to the place of your
    choosing, such as a custom directory inside your $HOME. Doing so
    will require you to add the proper directives, such as `source`ing
    inside your login script. Consult your shells documentation for
    how to add such directives.

    POWERSHELL:

    The powershell completion scripts require PowerShell v5.0+ (which
    comes Windows 10, but can be downloaded separately for windows 7
    or 8.1).

    First, check if a profile has already been set

        PS C:\> Test-Path $profile

    If the above command returns `False` run the following

        PS C:\> New-Item -path $profile -type file -force

    Now open the file provided by `$profile` (if you used the
    `New-Item` command it will be
    `${env:USERPROFILE}\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1`

    Next, we either save the completions file into our profile, or
    into a separate file and source it inside our profile. To save the
    completions into our profile simply use

        PS C:\> rustup completions powershell >> ${env:USERPROFILE}\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

    CARGO:

    Rustup can also generate a completion script for `cargo`. The script output
    by `rustup` will source the completion script distributed with your default
    toolchain. Not all shells are currently supported. Here are examples for
    the currently supported shells.

    BASH:

        $ rustup completions bash cargo >> ~/.local/share/bash-completion/completions/cargo

    ZSH:

        $ rustup completions zsh cargo > ~/.zfunc/_cargo";

pub static TOOLCHAIN_ARG_HELP: &str = "Toolchain name, such as 'stable', 'nightly', \
                                       or '1.8.0'. For more information see `rustup \
                                       help toolchain`";

pub static TOPIC_ARG_HELP: &str = "Topic such as 'core', 'fn', 'usize', 'eprintln!', \
                                   'core::arch', 'alloc::format!', 'std::fs', \
                                   'std::fs::read_dir', 'std::io::Bytes', \
                                   'std::iter::Sum', 'std::io::error::Result' etc...";
<commit_msg>Fixed typos in help text<commit_after>pub static RUSTUP_HELP: &str = r"DISCUSSION:
    rustup installs The Rust Programming Language from the official
    release channels, enabling you to easily switch between stable,
    beta, and nightly compilers and keep them updated. It makes
    cross-compiling simpler with binary builds of the standard library
    for common platforms.

    If you are new to Rust consider running `rustup doc --book` to
    learn Rust.";

pub static SHOW_HELP: &str = r"DISCUSSION:
    Shows the name of the active toolchain and the version of `rustc`.

    If the active toolchain has installed support for additional
    compilation targets, then they are listed as well.

    If there are multiple toolchains installed then all installed
    toolchains are listed as well.";

pub static SHOW_ACTIVE_TOOLCHAIN_HELP: &str = r"DISCUSSION:
    Shows the name of the active toolchain.

    This is useful for figuring out the active tool chain from
    scripts.

    You should use `rustc --print sysroot` to get the sysroot, or
    `rustc --version` to get the toolchain version.";

pub static UPDATE_HELP: &str = r"DISCUSSION:
    With no toolchain specified, the `update` command updates each of
    the installed toolchains from the official release channels, then
    updates rustup itself.

    If given a toolchain argument then `update` updates that
    toolchain, the same as `rustup toolchain install`.";

pub static INSTALL_HELP: &str = r"DISCUSSION:
    Installs a specific rust toolchain.

    The 'install' command is an alias for 'rustup update <toolchain>'.";

pub static DEFAULT_HELP: &str = r"DISCUSSION:
    Sets the default toolchain to the one specified. If the toolchain
    is not already installed then it is installed first.";

pub static TOOLCHAIN_HELP: &str = r"DISCUSSION:
    Many `rustup` commands deal with *toolchains*, a single
    installation of the Rust compiler. `rustup` supports multiple
    types of toolchains. The most basic track the official release
    channels: 'stable', 'beta' and 'nightly'; but `rustup` can also
    install toolchains from the official archives, for alternate host
    platforms, and from local builds.

    Standard release channel toolchain names have the following form:

        <channel>[-<date>][-<host>]

        <channel>       = stable|beta|nightly|<major.minor>|<major.minor.patch>
        <date>          = YYYY-MM-DD
        <host>          = <target-triple>

    'channel' is a named release channel, a major and minor version
    number such as `1.42`, or a fully specified version number, such
    as `1.42.0`. Channel names can be optionally appended with an
    archive date, as in `nightly-2014-12-18`, in which case the
    toolchain is downloaded from the archive for that date.

    The host may be specified as a target triple. This is most useful
    for installing a 32-bit compiler on a 64-bit platform, or for
    installing the [MSVC-based toolchain] on Windows. For example:

        $ rustup toolchain install stable-x86_64-pc-windows-msvc

    For convenience, omitted elements of the target triple will be
    inferred, so the above could be written:

        $ rustup toolchain install stable-msvc

    The `rustup default` command may be used to both install and set
    the desired toolchain as default in a single command:

        $ rustup default stable-msvc

    rustup can also manage symlinked local toolchain builds, which are
    often used for developing Rust itself. For more information see
    `rustup toolchain help link`.";

pub static TOOLCHAIN_LINK_HELP: &str = r"DISCUSSION:
    'toolchain' is the custom name to be assigned to the new toolchain.
    Any name is permitted as long as it does not fully match an initial
    substring of a standard release channel. For example, you can use
    the names 'latest' or '2017-04-01' but you cannot use 'stable' or
    'beta-i686' or 'nightly-x86_64-unknown-linux-gnu'.

    'path' specifies the directory where the binaries and libraries for
    the custom toolchain can be found. For example, when used for
    development of Rust itself, toolchains can be linked directly out of
    the build directory. After building, you can test out different
    compiler versions as follows:

        $ rustup toolchain link latest-stage1 build/x86_64-unknown-linux-gnu/stage1
        $ rustup override set latest-stage1

    If you now compile a crate in the current directory, the custom
    toolchain 'latest-stage1' will be used.";

pub static OVERRIDE_HELP: &str = r"DISCUSSION:
    Overrides configure rustup to use a specific toolchain when
    running in a specific directory.

    Directories can be assigned their own Rust toolchain with `rustup
    override`. When a directory has an override then any time `rustc`
    or `cargo` is run inside that directory, or one of its child
    directories, the override toolchain will be invoked.

    To pin to a specific nightly:

        $ rustup override set nightly-2014-12-18

    Or a specific stable release:

        $ rustup override set 1.0.0

    To see the active toolchain use `rustup show`. To remove the
    override and use the default toolchain again, `rustup override
    unset`.";

pub static OVERRIDE_UNSET_HELP: &str = r"DISCUSSION:
    If `--path` argument is present, removes the override toolchain
    for the specified directory. If `--nonexistent` argument is
    present, removes the override toolchain for all nonexistent
    directories. Otherwise, removes the override toolchain for the
    current directory.";

pub static RUN_HELP: &str = r"DISCUSSION:
    Configures an environment to use the given toolchain and then runs
    the specified program. The command may be any program, not just
    rustc or cargo. This can be used for testing arbitrary toolchains
    without setting an override.

    Commands explicitly proxied by `rustup` (such as `rustc` and
    `cargo`) also have a shorthand for this available. The toolchain
    can be set by using `+toolchain` as the first argument. These are
    equivalent:

        $ cargo +nightly build

        $ rustup run nightly cargo build";

pub static DOC_HELP: &str = r"DISCUSSION:
    Opens the documentation for the currently active toolchain with
    the default browser.

    By default, it opens the documentation index. Use the various
    flags to open specific pieces of documentation.";

pub static COMPLETIONS_HELP: &str = r"DISCUSSION:
    Enable tab completion for Bash, Fish, Zsh, or PowerShell
    The script is output on `stdout`, allowing one to re-direct the
    output to the file of their choosing. Where you place the file
    will depend on which shell, and which operating system you are
    using. Your particular configuration may also determine where
    these scripts need to be placed.

    Here are some common set ups for the three supported shells under
    Unix and similar operating systems (such as GNU/Linux).

    BASH:

    Completion files are commonly stored in `/etc/bash_completion.d/` for
    system-wide commands, but can be stored in
    `~/.local/share/bash-completion/completions` for user-specific commands.
    Run the command:

        $ mkdir -p ~/.local/share/bash-completion/completions
        $ rustup completions bash >> ~/.local/share/bash-completion/completions/rustup

    This installs the completion script. You may have to log out and
    log back in to your shell session for the changes to take effect.

    BASH (macOS/Homebrew):

    Homebrew stores bash completion files within the Homebrew directory.
    With the `bash-completion` brew formula installed, run the command:

        $ mkdir -p $(brew --prefix)/etc/bash_completion.d
        $ rustup completions bash > $(brew --prefix)/etc/bash_completion.d/rustup.bash-completion

    FISH:

    Fish completion files are commonly stored in
    `$HOME/.config/fish/completions`. Run the command:

        $ mkdir -p ~/.config/fish/completions
        $ rustup completions fish > ~/.config/fish/completions/rustup.fish

    This installs the completion script. You may have to log out and
    log back in to your shell session for the changes to take effect.

    ZSH:

    ZSH completions are commonly stored in any directory listed in
    your `$fpath` variable. To use these completions, you must either
    add the generated script to one of those directories, or add your
    own to this list.

    Adding a custom directory is often the safest bet if you are
    unsure of which directory to use. First create the directory; for
    this example we'll create a hidden directory inside our `$HOME`
    directory:

        $ mkdir ~/.zfunc

    Then add the following lines to your `.zshrc` just before
    `compinit`:

        fpath+=~/.zfunc

    Now you can install the completions script using the following
    command:

        $ rustup completions zsh > ~/.zfunc/_rustup

    You must then either log out and log back in, or simply run

        $ exec zsh

    for the new completions to take effect.

    CUSTOM LOCATIONS:

    Alternatively, you could save these files to the place of your
    choosing, such as a custom directory inside your $HOME. Doing so
    will require you to add the proper directives, such as `source`ing
    inside your login script. Consult your shells documentation for
    how to add such directives.

    POWERSHELL:

    The powershell completion scripts require PowerShell v5.0+ (which
    comes Windows 10, but can be downloaded separately for windows 7
    or 8.1).

    First, check if a profile has already been set

        PS C:\> Test-Path $profile

    If the above command returns `False` run the following

        PS C:\> New-Item -path $profile -type file -force

    Now open the file provided by `$profile` (if you used the
    `New-Item` command it will be
    `${env:USERPROFILE}\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1`

    Next, we either save the completions file into our profile, or
    into a separate file and source it inside our profile. To save the
    completions into our profile simply use

        PS C:\> rustup completions powershell >> ${env:USERPROFILE}\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

    CARGO:

    Rustup can also generate a completion script for `cargo`. The script output
    by `rustup` will source the completion script distributed with your default
    toolchain. Not all shells are currently supported. Here are examples for
    the currently supported shells.

    BASH:

        $ rustup completions bash cargo >> ~/.local/share/bash-completion/completions/cargo

    ZSH:

        $ rustup completions zsh cargo > ~/.zfunc/_cargo";

pub static TOOLCHAIN_ARG_HELP: &str = "Toolchain name, such as 'stable', 'nightly', \
                                       or '1.8.0'. For more information see `rustup \
                                       help toolchain`";

pub static TOPIC_ARG_HELP: &str = "Topic such as 'core', 'fn', 'usize', 'eprintln!', \
                                   'core::arch', 'alloc::format!', 'std::fs', \
                                   'std::fs::read_dir', 'std::io::Bytes', \
                                   'std::iter::Sum', 'std::io::error::Result' etc...";
<|endoftext|>


<commit_before>use std::io;
use time::Tm;
use time::strptime;
use time::Duration;

use http_status::HttpStatus;

#[derive(Eq, PartialEq, Clone)]
#[derive(Debug)]
pub struct Request {
    pub id: i32,
    pub time: Tm,
    pub url: String,
}

impl Request {
    pub fn new_from_log_line(log_line: &String) -> Result<Request, io::Error> {
        let parts: Vec<&str> = log_line.split(" ").collect();

        let id = parts[2];
        let url = parts[5];

        Ok(Request {
            id: id[1..id.len()-1].parse().unwrap(),
            time: strptime(parts[0], "%d/%b/%Y:%H:%M:%S").unwrap(),
            url: url.to_string()
        })
    }

    pub fn get_matching_response<'a>(&'a self, responses: &'a Vec<Response>) -> Option<&Response> {
        match responses.binary_search_by_key(&self.id, |r| r.id) {
            Ok(index) => Some(&responses[index]),
            Err(_) => None
        }
    }
}

#[derive(Eq, PartialEq, Clone)]
#[derive(Debug)]
pub struct Response {
    pub id: i32,
    pub time: Tm,
    pub mime_type: String,
    pub response_time: Duration,
    pub http_status: HttpStatus,
}

impl Response {
    pub fn new_from_log_line(log_line: &String) -> Result<Response, io::Error> {
        let parts: Vec<&str> = log_line.split(" ").collect();

        let id = parts[2];
        let response_time = parts[parts.len()-1];

        // Handle special case where the mime type sometimes contains
        // a space, so we need to re-assemble it
        let mime_type = match parts.len() {
            8 => format!("{} {}", parts[5], parts[6]),
            _ => parts[5].to_string()
        };

        let status_code = parts[4];

        Ok(Response {
            id: id[1..id.len()-1].parse().unwrap(),
            time: strptime(parts[0], "%d/%b/%Y:%H:%M:%S").unwrap(),
            response_time: Duration::milliseconds(response_time[0..response_time.len()-2].parse().unwrap()),
            mime_type: mime_type,
            http_status: HttpStatus::from_code(status_code.parse().unwrap()),
        })
    }
}

pub struct RequestResponsePair {
    pub request: Request,
    pub response: Response
}

pub fn pair_requests_responses(requests:Vec<Request>, responses: Vec<Response>) -> Vec<RequestResponsePair> {
    let mut request_response_pairs: Vec<RequestResponsePair> = Vec::new();

    for request in requests  {
        if let Some(response) = request.get_matching_response(&responses) {
            request_response_pairs.push(RequestResponsePair{
                request: request.clone(),
                response: response.clone()
            })
        }
    }

    request_response_pairs
}

#[cfg(test)]
mod tests {
	use super::*;
    use time::strptime;
    use::time::Duration;
    use http_status::HttpStatus;

    #[test]
    fn test_parse_request_line() {
        let line = "08/Apr/2016:09:58:47 +0200 [02] -> GET /content/some/other.html HTTP/1.1".to_string();

        let expected = Request {
            id: 2,
            time: strptime("08/Apr/2016:09:58:47 +0200", "%d/%b/%Y:%H:%M:%S").unwrap(),
            url: "/content/some/other.html".to_string()
        };

        let result = Request::new_from_log_line(&line);

        assert_eq!(result.unwrap(), expected)
    }

    #[test]
    fn test_parse_response_line() {
        let line = "08/Apr/2016:09:58:48 +0200 [02] <- 200 text/html 10ms".to_string();

        let expected = Response {
            id: 2,
            time: strptime("08/Apr/2016:09:58:48 +0200", "%d/%b/%Y:%H:%M:%S").unwrap(),
            mime_type: "text/html".to_string(),
            response_time: Duration::milliseconds(10),
            http_status: HttpStatus::OK,
        };

        let result = Response::new_from_log_line(&line);

        assert_eq!(result.unwrap(), expected)
    }

    #[test]
    fn test_parse_response_line_inconsistent_space() {
        let line = "06/Apr/2016:14:54:16 +0200 [200] <- 200 text/html; charset=utf-8 250ms".to_string();

        let expected = Response {
            id: 200,
            time: strptime("06/Apr/2016:14:54:16 +0200", "%d/%b/%Y:%H:%M:%S").unwrap(),
            mime_type: "text/html; charset=utf-8".to_string(),
            response_time: Duration::milliseconds(250),
            http_status: HttpStatus::OK,
        };

        let result = Response::new_from_log_line(&line);

        assert_eq!(result.unwrap(), expected)
    }

    #[test]
    fn test_get_matching_response() {
        let request = Request {
            id: 2,
            time: strptime("08/Apr/2016:09:58:47 +0200", "%d/%b/%Y:%H:%M:%S").unwrap(),
            url: "/content/some/other.html".to_string()
        };

        let responses = vec![
            Response {
                id: 1,
                time: strptime("08/Apr/2016:09:57:47 +0200", "%d/%b/%Y:%H:%M:%S").unwrap(),
                mime_type: "text/html".to_string(),
                response_time: Duration::milliseconds(7),
                http_status: HttpStatus::OK,
            },
            Response {
                id: 2,
                time: strptime("08/Apr/2016:09:58:47 +0200", "%d/%b/%Y:%H:%M:%S").unwrap(),
                mime_type: "text/html".to_string(),
                response_time: Duration::milliseconds(10),
                http_status: HttpStatus::OK,
            },
        ];

        let result = request.get_matching_response(&responses);
        assert_eq!(result.unwrap().id, 2);
    }

    #[test]
    fn test_get_matching_response_none_found() {
        let responses = vec![
            Response {
                id: 1,
                time: strptime("08/Apr/2016:09:57:47 +0200", "%d/%b/%Y:%H:%M:%S").unwrap(),
                mime_type: "text/html".to_string(),
                response_time: Duration::milliseconds(7),
                http_status: HttpStatus::OK,
            },
            Response {
                id: 2,
                time: strptime("08/Apr/2016:09:58:47 +0200", "%d/%b/%Y:%H:%M:%S").unwrap(),
                mime_type: "text/html".to_string(),
                response_time: Duration::milliseconds(10),
                http_status: HttpStatus::OK,
            },
        ];

        let request_without_matching = Request {
            id: 999,
            time: strptime("08/Apr/2016:09:58:47 +0200", "%d/%b/%Y:%H:%M:%S").unwrap(),
            url: "/content/some/other.html".to_string()
        };

        let result = request_without_matching.get_matching_response(&responses);

        assert!(result.is_none());
    }
}
<commit_msg>Keep Response fixture DRY<commit_after>use std::io;
use time::Tm;
use time::strptime;
use time::Duration;

use http_status::HttpStatus;

#[derive(Eq, PartialEq, Clone)]
#[derive(Debug)]
pub struct Request {
    pub id: i32,
    pub time: Tm,
    pub url: String,
}

impl Request {
    pub fn new_from_log_line(log_line: &String) -> Result<Request, io::Error> {
        let parts: Vec<&str> = log_line.split(" ").collect();

        let id = parts[2];
        let url = parts[5];

        Ok(Request {
            id: id[1..id.len()-1].parse().unwrap(),
            time: strptime(parts[0], "%d/%b/%Y:%H:%M:%S").unwrap(),
            url: url.to_string()
        })
    }

    pub fn get_matching_response<'a>(&'a self, responses: &'a Vec<Response>) -> Option<&Response> {
        match responses.binary_search_by_key(&self.id, |r| r.id) {
            Ok(index) => Some(&responses[index]),
            Err(_) => None
        }
    }
}

#[derive(Eq, PartialEq, Clone)]
#[derive(Debug)]
pub struct Response {
    pub id: i32,
    pub time: Tm,
    pub mime_type: String,
    pub response_time: Duration,
    pub http_status: HttpStatus,
}

impl Response {
    pub fn new_from_log_line(log_line: &String) -> Result<Response, io::Error> {
        let parts: Vec<&str> = log_line.split(" ").collect();

        let id = parts[2];
        let response_time = parts[parts.len()-1];

        // Handle special case where the mime type sometimes contains
        // a space, so we need to re-assemble it
        let mime_type = match parts.len() {
            8 => format!("{} {}", parts[5], parts[6]),
            _ => parts[5].to_string()
        };

        let status_code = parts[4];

        Ok(Response {
            id: id[1..id.len()-1].parse().unwrap(),
            time: strptime(parts[0], "%d/%b/%Y:%H:%M:%S").unwrap(),
            response_time: Duration::milliseconds(response_time[0..response_time.len()-2].parse().unwrap()),
            mime_type: mime_type,
            http_status: HttpStatus::from_code(status_code.parse().unwrap()),
        })
    }
}

pub struct RequestResponsePair {
    pub request: Request,
    pub response: Response
}

pub fn pair_requests_responses(requests:Vec<Request>, responses: Vec<Response>) -> Vec<RequestResponsePair> {
    let mut request_response_pairs: Vec<RequestResponsePair> = Vec::new();

    for request in requests  {
        if let Some(response) = request.get_matching_response(&responses) {
            request_response_pairs.push(RequestResponsePair{
                request: request.clone(),
                response: response.clone()
            })
        }
    }

    request_response_pairs
}

#[cfg(test)]
mod tests {
	use super::*;
    use time::strptime;
    use::time::Duration;
    use http_status::HttpStatus;

    fn get_simple_responses_fixture() -> Vec<Response> {
        vec![
            Response {
                id: 1,
                time: strptime("08/Apr/2016:09:57:47 +0200", "%d/%b/%Y:%H:%M:%S").unwrap(),
                mime_type: "text/html".to_string(),
                response_time: Duration::milliseconds(7),
                http_status: HttpStatus::OK,
            },
            Response {
                id: 2,
                time: strptime("08/Apr/2016:09:58:47 +0200", "%d/%b/%Y:%H:%M:%S").unwrap(),
                mime_type: "text/html".to_string(),
                response_time: Duration::milliseconds(10),
                http_status: HttpStatus::OK,
            },
        ]
    }

    #[test]
    fn test_parse_request_line() {
        let line = "08/Apr/2016:09:58:47 +0200 [02] -> GET /content/some/other.html HTTP/1.1".to_string();

        let expected = Request {
            id: 2,
            time: strptime("08/Apr/2016:09:58:47 +0200", "%d/%b/%Y:%H:%M:%S").unwrap(),
            url: "/content/some/other.html".to_string()
        };

        let result = Request::new_from_log_line(&line);

        assert_eq!(result.unwrap(), expected)
    }

    #[test]
    fn test_parse_response_line() {
        let line = "08/Apr/2016:09:58:48 +0200 [02] <- 200 text/html 10ms".to_string();

        let expected = Response {
            id: 2,
            time: strptime("08/Apr/2016:09:58:48 +0200", "%d/%b/%Y:%H:%M:%S").unwrap(),
            mime_type: "text/html".to_string(),
            response_time: Duration::milliseconds(10),
            http_status: HttpStatus::OK,
        };

        let result = Response::new_from_log_line(&line);

        assert_eq!(result.unwrap(), expected)
    }

    #[test]
    fn test_parse_response_line_inconsistent_space() {
        let line = "06/Apr/2016:14:54:16 +0200 [200] <- 200 text/html; charset=utf-8 250ms".to_string();

        let expected = Response {
            id: 200,
            time: strptime("06/Apr/2016:14:54:16 +0200", "%d/%b/%Y:%H:%M:%S").unwrap(),
            mime_type: "text/html; charset=utf-8".to_string(),
            response_time: Duration::milliseconds(250),
            http_status: HttpStatus::OK,
        };

        let result = Response::new_from_log_line(&line);

        assert_eq!(result.unwrap(), expected)
    }

    #[test]
    fn test_get_matching_response() {
        let request = Request {
            id: 2,
            time: strptime("08/Apr/2016:09:58:47 +0200", "%d/%b/%Y:%H:%M:%S").unwrap(),
            url: "/content/some/other.html".to_string()
        };

        let responses = get_simple_responses_fixture();

        let result = request.get_matching_response(&responses);
        assert_eq!(result.unwrap().id, 2);
    }

    #[test]
    fn test_get_matching_response_none_found() {
        let responses = get_simple_responses_fixture();

        let request_without_matching = Request {
            id: 999,
            time: strptime("08/Apr/2016:09:58:47 +0200", "%d/%b/%Y:%H:%M:%S").unwrap(),
            url: "/content/some/other.html".to_string()
        };

        let result = request_without_matching.get_matching_response(&responses);

        assert!(result.is_none());
    }
}
<|endoftext|>