<commit_before>#![feature(env, fs, io, old_io, path)]
use std::fs;
use std::io;
use std::io::ReadExt;
use std::old_io::stdio;
use std::path::Path;

const MEMSIZE: usize = 4096;

enum ParserResult {
    Something(Op),
    Nothing,
    EOF
}

use ParserResult::*;

#[derive(Debug)]
enum Op {
    Add(u8),
    Mov(usize),
    In,
    Out,
    Loop(OpStream)
}

use Op::*;

#[derive(Debug)]
struct OpStream {
    ops: Vec<Op>
}

impl OpStream {
    fn add(&mut self, op: Op) {
        self.ops.push(op);
    }

    fn optimize(&mut self) {
        let mut i = 0;
        while i < self.ops.len() {
            match &self.ops[i..] {
                [Add(a), Add(b), ..] => {
                    self.ops[i] = Add(a + b);
                    self.ops.remove(i + 1);
                }
                [Mov(a), Mov(b), ..] => {
                    self.ops[i] = Mov(a + b);
                    self.ops.remove(i + 1);
                }
                [Add(0), ..] | [Mov(0), ..] => {
                    self.ops.remove(i);
                }
                _ => i += 1
            }
        }
        for op in &mut self.ops[..] {
            if let &mut Loop(ref mut stream) = op {
                stream.optimize()
            }
        }
    }

    fn get(&self) -> &[Op] {
        &self.ops[..]
    }

    fn new() -> OpStream {
        OpStream { ops: Vec::new() }
    }
}

struct State {
    index: usize,
    memory: [u8; MEMSIZE]
}

impl State {
    fn new() -> State {
        State { index: 0, memory: [0; MEMSIZE] }
    }

    fn peek(&self) -> u8 {
        self.memory[self.index % MEMSIZE]
    }

    fn poke(&mut self, value: u8) {
        self.memory[self.index % MEMSIZE] = value;
    }

    fn step(&mut self, op: &Op) {
        match op {
            &Add(i) => {
                let x = self.peek();
                self.poke(x + i);
            }
            &Mov(n) => {
                self.index += n
            }
            &In => {
                self.poke(stdio::stdin().read_u8().unwrap());
            }
            &Out => {
                stdio::stdout().write_u8(self.peek()).unwrap();
            }
            &Loop(ref ops) => {
                while self.peek() != 0 {
                    self.run(ops.get());
                }
            }
        }
    }

    fn run(&mut self, ops: &[Op]) {
        for op in ops {
            self.step(op);
        }
    }
}

#[test]
fn test_state_peek() {
    let mut state = State::new();
    state.memory[state.index] = 23;
    assert_eq!(23, state.peek());
    state.index = 5;
    state.memory[state.index] = 42;
    assert_eq!(42, state.peek());
}

#[test]
fn test_state_poke() {
    let mut state = State::new();
    state.poke(23);
    assert_eq!(23, state.memory[state.index]);
    state.index = 5;
    state.poke(42);
    assert_eq!(42, state.memory[state.index]);
}

fn main() {
    let filenames: Vec<String> = std::iter::FromIterator::from_iter(std::env::args());

    for filename in &filenames[1..] {
        let reader = reader(&Path::new(filename));
        let mut chars = reader.chars().peekable();

        let mut opstream = OpStream::new();
        loop {
            match parse(&mut chars) {
                Something(op) => opstream.add(op),
                EOF => break,
                _ => {}
            }
        }

        opstream.optimize();

        State::new().run(opstream.get());
    }
}

fn parse<T: io::Read>(mut chars: &mut std::iter::Peekable<io::Chars<T>>) -> ParserResult {
    match chars.next() {
        Some(Ok(c)) => match c {
            '+' => Something(Add(1)),
            '-' => Something(Add(-1)),
            '<' => Something(Mov(-1)),
            '>' => Something(Mov(1)),
            ',' => Something(In),
            '.' => Something(Out),
            '[' => {
                let mut childstream = OpStream::new();
                while chars.peek() != Some(&Ok(']')) {
                    match parse(&mut chars) {
                        Something(op) => childstream.add(op),
                        Nothing => {},
                        EOF => panic!()
                    }
                }
                chars.next();
                Something(Loop(childstream))
            },
            _ => Nothing  // other characters
        },
        _ => EOF
    }
}

fn reader(path: &Path) -> io::BufReader<fs::File> {
    io::BufReader::new(fs::File::open(path).unwrap())
}
<commit_msg>test: more State tests<commit_after>#![feature(env, fs, io, old_io, path)]
use std::fs;
use std::io;
use std::io::ReadExt;
use std::old_io::stdio;
use std::path::Path;

const MEMSIZE: usize = 4096;

enum ParserResult {
    Something(Op),
    Nothing,
    EOF
}

use ParserResult::*;

#[derive(Debug)]
enum Op {
    Add(u8),
    Mov(usize),
    In,
    Out,
    Loop(OpStream)
}

use Op::*;

#[derive(Debug)]
struct OpStream {
    ops: Vec<Op>
}

impl OpStream {
    fn add(&mut self, op: Op) {
        self.ops.push(op);
    }

    fn optimize(&mut self) {
        let mut i = 0;
        while i < self.ops.len() {
            match &self.ops[i..] {
                [Add(a), Add(b), ..] => {
                    self.ops[i] = Add(a + b);
                    self.ops.remove(i + 1);
                }
                [Mov(a), Mov(b), ..] => {
                    self.ops[i] = Mov(a + b);
                    self.ops.remove(i + 1);
                }
                [Add(0), ..] | [Mov(0), ..] => {
                    self.ops.remove(i);
                }
                _ => i += 1
            }
        }
        for op in &mut self.ops[..] {
            if let &mut Loop(ref mut stream) = op {
                stream.optimize()
            }
        }
    }

    fn get(&self) -> &[Op] {
        &self.ops[..]
    }

    fn new() -> OpStream {
        OpStream { ops: Vec::new() }
    }
}

struct State {
    index: usize,
    memory: [u8; MEMSIZE]
}

impl State {
    fn new() -> State {
        State { index: 0, memory: [0; MEMSIZE] }
    }

    fn peek(&self) -> u8 {
        self.memory[self.index % MEMSIZE]
    }

    fn poke(&mut self, value: u8) {
        self.memory[self.index % MEMSIZE] = value;
    }

    fn step(&mut self, op: &Op) {
        match op {
            &Add(i) => {
                let x = self.peek();
                self.poke(x + i);
            }
            &Mov(n) => {
                self.index += n
            }
            &In => {
                self.poke(stdio::stdin().read_u8().unwrap());
            }
            &Out => {
                stdio::stdout().write_u8(self.peek()).unwrap();
            }
            &Loop(ref ops) => {
                while self.peek() != 0 {
                    self.run(ops.get());
                }
            }
        }
    }

    fn run(&mut self, ops: &[Op]) {
        for op in ops {
            self.step(op);
        }
    }
}

fn main() {
    let filenames: Vec<String> = std::iter::FromIterator::from_iter(std::env::args());

    for filename in &filenames[1..] {
        let reader = reader(&Path::new(filename));
        let mut chars = reader.chars().peekable();

        let mut opstream = OpStream::new();
        loop {
            match parse(&mut chars) {
                Something(op) => opstream.add(op),
                EOF => break,
                _ => {}
            }
        }

        opstream.optimize();

        State::new().run(opstream.get());
    }
}

fn parse<T: io::Read>(mut chars: &mut std::iter::Peekable<io::Chars<T>>) -> ParserResult {
    match chars.next() {
        Some(Ok(c)) => match c {
            '+' => Something(Add(1)),
            '-' => Something(Add(-1)),
            '<' => Something(Mov(-1)),
            '>' => Something(Mov(1)),
            ',' => Something(In),
            '.' => Something(Out),
            '[' => {
                let mut childstream = OpStream::new();
                while chars.peek() != Some(&Ok(']')) {
                    match parse(&mut chars) {
                        Something(op) => childstream.add(op),
                        Nothing => {},
                        EOF => panic!()
                    }
                }
                chars.next();
                Something(Loop(childstream))
            },
            _ => Nothing  // other characters
        },
        _ => EOF
    }
}

fn reader(path: &Path) -> io::BufReader<fs::File> {
    io::BufReader::new(fs::File::open(path).unwrap())
}

#[cfg(test)]
mod tests {
    use super::{State, OpStream};
    use super::Op::*;

    #[test]
    fn state_peek() {
        let mut state = State::new();
        state.memory[state.index] = 23;
        assert_eq!(23, state.peek());
        state.index = 5;
        state.memory[state.index] = 42;
        assert_eq!(42, state.peek());
    }

    #[test]
    fn state_poke() {
        let mut state = State::new();
        state.poke(23);
        assert_eq!(23, state.memory[state.index]);
        state.index = 5;
        state.poke(42);
        assert_eq!(42, state.memory[state.index]);
    }

    #[test]
    fn state_step_add() {
        let mut state = State::new();
        state.step(&Add(23));
        assert_eq!(23, state.peek());
        state.step(&Add(42));
        assert_eq!(65, state.peek());
        state.step(&Add(-66));
        assert_eq!(-1, state.peek());
    }

    #[test]
    fn state_step_mov() {
        let mut state = State::new();
        state.step(&Mov(1));
        assert_eq!(1, state.index);
        state.step(&Mov(42));
        assert_eq!(43, state.index);
        state.step(&Mov(-1));
        assert_eq!(42, state.index);
    }

    #[test]
    fn state_step_loop() {
        let mut state = State::new();
        state.poke(23);
        state.step(&Loop(OpStream { ops: vec![Add(1)] }));
        assert_eq!(0, state.peek());
    }
}
<|endoftext|>


<commit_before>use std::io::{Read, Seek};

use Result;
use band::{Band, Value};
use primitive::*;
use table::*;

macro_rules! tag(
    ($value:expr) => (unsafe {
        let mut value: [u8; 4] = ::std::mem::transmute($value);
        value.swap(0, 3);
        value.swap(1, 2);
        value
    })
);

/// A font.
pub struct Font {
    pub offset_table: OffsetTable,
    pub char_mapping: CharMapping,
    pub font_header: FontHeader,
    pub horizontal_header: HorizontalHeader,
    pub maximum_profile: MaximumProfile,
}

macro_rules! some(
    ($option:expr, $object:expr) => (
        match $option {
            Some(value) => value,
            _ => raise!(concat!($object, " is missing")),
        }
    );
);

impl Font {
    pub fn read<T: Read + Seek>(reader: &mut T) -> Result<Font> {
        let offset_table = try!(read_offset_table(reader));

        let mut font_header = None;
        let mut horizontal_header = None;
        let mut maximum_profile = None;
        let mut char_mapping = None;

        for record in offset_table.records.iter() {
            match &tag!(record.tag) {
                b"cmap" => char_mapping = Some(try!(read_char_mapping(reader, record))),
                b"head" => font_header = Some(try!(read_font_header(reader, record))),
                b"hhea" => horizontal_header = Some(try!(read_horizontal_header(reader, record))),
                b"maxp" => maximum_profile = Some(try!(read_maximum_profile(reader, record))),
                _ => (),
            }
        }

        Ok(Font {
            offset_table: offset_table,
            char_mapping: some!(char_mapping, "the character-to-glyph mapping"),
            font_header: some!(font_header, "the font header"),
            horizontal_header: some!(horizontal_header, "the horizontal header"),
            maximum_profile: some!(maximum_profile, "the maximum profile"),
        })
    }
}

fn read_offset_table<T: Band>(band: &mut T) -> Result<OffsetTable> {
    const CFF_TAG: &'static [u8; 4] = b"OTTO";

    let header = try!(OffsetTableHeader::read(band));
    if &tag!(header.version) != CFF_TAG {
        raise!("the format of a font is not supported");
    }
    let mut records = vec![];
    for _ in 0..header.numTables {
        records.push(try!(OffsetTableRecord::read(band)));
    }

    Ok(OffsetTable { header: header, records: records })
}

fn read_char_mapping<T: Band>(band: &mut T, table: &OffsetTableRecord) -> Result<CharMapping> {
    const VERSION_0_0: USHORT = 0;

    if !try!(table.check(band, |_, chunk| chunk)) {
        raise!("the character-to-glyph mapping is corrupted");
    }

    try!(band.jump(table.offset as u64));
    let header = try!(CharMappingHeader::read(band));
    if header.version != VERSION_0_0 {
        raise!("the format of the character-to-glyph mapping header is not supported");
    }
    let mut records = vec![];
    for _ in 0..header.numTables {
        records.push(try!(CharMappingRecord::read(band)));
    }
    let mut encodings = vec![];
    for encoding in records.iter() {
        try!(band.jump(table.offset as u64 + encoding.offset as u64));
        encodings.push(match try!(band.peek::<USHORT>()) {
            4 => CharMappingEncoding::Format4(try!(Value::read(band))),
            6 => CharMappingEncoding::Format6(try!(Value::read(band))),
            _ => raise!("the format of a character-to-glyph mapping is not supported"),
        });
    }

    Ok(CharMapping { header: header, records: records, encodings: encodings })
}

fn read_font_header<T: Band>(band: &mut T, record: &OffsetTableRecord) -> Result<FontHeader> {
    const MAGIC_NUMBER: ULONG = 0x5F0F3CF5;
    const VERSION_1_0: Fixed = Fixed(0x00010000);

    if !try!(record.check(band, |i, chunk| if i == 2 { 0 } else { chunk })) {
        raise!("the font header is corrupted");
    }

    try!(band.jump(record.offset as u64));
    let header = try!(FontHeader::read(band));
    if header.version != VERSION_1_0 {
        raise!("the format of the font header is not supported");
    }
    if header.magicNumber != MAGIC_NUMBER {
        raise!("the font header is malformed");
    }

    Ok(header)
}

fn read_horizontal_header<T: Band>(band: &mut T, record: &OffsetTableRecord)
                                    -> Result<HorizontalHeader> {

    const VERSION_1_0: Fixed = Fixed(0x00010000);

    if !try!(record.check(band, |_, chunk| chunk)) {
        raise!("the horizontal header is corrupted");
    }

    try!(band.jump(record.offset as u64));
    let header = try!(HorizontalHeader::read(band));
    if header.version != VERSION_1_0 {
        raise!("the format of the horizontal header is not supported");
    }

    Ok(header)
}

fn read_maximum_profile<T: Band>(band: &mut T, record: &OffsetTableRecord)
                                 -> Result<MaximumProfile> {

    const VERSION_0_5: Fixed = Fixed(0x00005000);
    const VERSION_1_0: Fixed = Fixed(0x00010000);

    if !try!(record.check(band, |_, chunk| chunk)) {
        raise!("the maximum profile is corrupted");
    }

    try!(band.jump(record.offset as u64));
    Ok(match try!(band.peek::<Fixed>()) {
        VERSION_0_5 => MaximumProfile::Version05(try!(Value::read(band))),
        VERSION_1_0 => MaximumProfile::Version10(try!(Value::read(band))),
        _ => {
            raise!("the format of the maximum profile is not supported");
        },
    })
}
<commit_msg>Process tables alphabetically<commit_after>use std::io::{Read, Seek};
use std::mem;

use Result;
use band::{Band, Value};
use primitive::*;
use table::*;

/// A font.
pub struct Font {
    pub offset_table: OffsetTable,
    pub char_mapping: CharMapping,
    pub font_header: FontHeader,
    pub horizontal_header: HorizontalHeader,
    pub maximum_profile: MaximumProfile,
}

macro_rules! some(
    ($option:expr, $object:expr) => (
        match $option {
            Some(value) => value,
            _ => raise!(concat!($object, " is missing")),
        }
    );
);

macro_rules! sort_by_tag(
    ($records:expr) => ({
        let mut records = $records.iter().collect::<Vec<_>>();
        records.sort_by(|one, other| tag!(one.tag).cmp(&tag!(other.tag)));
        records
    });
);

#[cfg(target_endian = "big")]
macro_rules! tag(
    ($value:expr) => (unsafe {
        mem::transmute($value);
    })
);

#[cfg(target_endian = "little")]
macro_rules! tag(
    ($value:expr) => (unsafe {
        let mut value: [u8; 4] = mem::transmute($value);
        value.reverse();
        value
    })
);

impl Font {
    pub fn read<T: Read + Seek>(reader: &mut T) -> Result<Font> {
        let offset_table = try!(read_offset_table(reader));

        let mut font_header = None;
        let mut horizontal_header = None;
        let mut maximum_profile = None;
        let mut char_mapping = None;

        for record in sort_by_tag!(offset_table.records) {
            match &tag!(record.tag) {
                b"cmap" => char_mapping = Some(try!(read_char_mapping(reader, record))),
                b"head" => font_header = Some(try!(read_font_header(reader, record))),
                b"hhea" => horizontal_header = Some(try!(read_horizontal_header(reader, record))),
                b"maxp" => maximum_profile = Some(try!(read_maximum_profile(reader, record))),
                _ => (),
            }
        }

        Ok(Font {
            offset_table: offset_table,
            char_mapping: some!(char_mapping, "the character-to-glyph mapping"),
            font_header: some!(font_header, "the font header"),
            horizontal_header: some!(horizontal_header, "the horizontal header"),
            maximum_profile: some!(maximum_profile, "the maximum profile"),
        })
    }
}

fn read_offset_table<T: Band>(band: &mut T) -> Result<OffsetTable> {
    const CFF_TAG: &'static [u8; 4] = b"OTTO";

    let header = try!(OffsetTableHeader::read(band));
    if &tag!(header.version) != CFF_TAG {
        raise!("the format of a font is not supported");
    }
    let mut records = vec![];
    for _ in 0..header.numTables {
        records.push(try!(OffsetTableRecord::read(band)));
    }

    Ok(OffsetTable { header: header, records: records })
}

fn read_char_mapping<T: Band>(band: &mut T, table: &OffsetTableRecord) -> Result<CharMapping> {
    const VERSION_0_0: USHORT = 0;

    if !try!(table.check(band, |_, chunk| chunk)) {
        raise!("the character-to-glyph mapping is corrupted");
    }

    try!(band.jump(table.offset as u64));
    let header = try!(CharMappingHeader::read(band));
    if header.version != VERSION_0_0 {
        raise!("the format of the character-to-glyph mapping header is not supported");
    }
    let mut records = vec![];
    for _ in 0..header.numTables {
        records.push(try!(CharMappingRecord::read(band)));
    }
    let mut encodings = vec![];
    for encoding in records.iter() {
        try!(band.jump(table.offset as u64 + encoding.offset as u64));
        encodings.push(match try!(band.peek::<USHORT>()) {
            4 => CharMappingEncoding::Format4(try!(Value::read(band))),
            6 => CharMappingEncoding::Format6(try!(Value::read(band))),
            _ => raise!("the format of a character-to-glyph mapping is not supported"),
        });
    }

    Ok(CharMapping { header: header, records: records, encodings: encodings })
}

fn read_font_header<T: Band>(band: &mut T, record: &OffsetTableRecord) -> Result<FontHeader> {
    const MAGIC_NUMBER: ULONG = 0x5F0F3CF5;
    const VERSION_1_0: Fixed = Fixed(0x00010000);

    if !try!(record.check(band, |i, chunk| if i == 2 { 0 } else { chunk })) {
        raise!("the font header is corrupted");
    }

    try!(band.jump(record.offset as u64));
    let header = try!(FontHeader::read(band));
    if header.version != VERSION_1_0 {
        raise!("the format of the font header is not supported");
    }
    if header.magicNumber != MAGIC_NUMBER {
        raise!("the font header is malformed");
    }

    Ok(header)
}

fn read_horizontal_header<T: Band>(band: &mut T, record: &OffsetTableRecord)
                                    -> Result<HorizontalHeader> {

    const VERSION_1_0: Fixed = Fixed(0x00010000);

    if !try!(record.check(band, |_, chunk| chunk)) {
        raise!("the horizontal header is corrupted");
    }

    try!(band.jump(record.offset as u64));
    let header = try!(HorizontalHeader::read(band));
    if header.version != VERSION_1_0 {
        raise!("the format of the horizontal header is not supported");
    }

    Ok(header)
}

fn read_maximum_profile<T: Band>(band: &mut T, record: &OffsetTableRecord)
                                 -> Result<MaximumProfile> {

    const VERSION_0_5: Fixed = Fixed(0x00005000);
    const VERSION_1_0: Fixed = Fixed(0x00010000);

    if !try!(record.check(band, |_, chunk| chunk)) {
        raise!("the maximum profile is corrupted");
    }

    try!(band.jump(record.offset as u64));
    Ok(match try!(band.peek::<Fixed>()) {
        VERSION_0_5 => MaximumProfile::Version05(try!(Value::read(band))),
        VERSION_1_0 => MaximumProfile::Version10(try!(Value::read(band))),
        _ => {
            raise!("the format of the maximum profile is not supported");
        },
    })
}
<|endoftext|>


<commit_before>//! Free functions that create iterator adaptors or call iterator methods.
//!
//! The benefit of free functions is that they accept any [`IntoIterator`] as
//! argument, so the resulting code may be easier to read.

#[cfg(feature = "use_alloc")]
use std::fmt::Display;
use std::iter::{self, Zip};
#[cfg(feature = "use_alloc")]
type VecIntoIter<T> = alloc::vec::IntoIter<T>;

#[cfg(feature = "use_alloc")]
use alloc::{
    string::String,
};

use crate::Itertools;
use crate::intersperse::{Intersperse, IntersperseWith};

pub use crate::adaptors::{
    interleave,
    merge,
    put_back,
};
#[cfg(feature = "use_alloc")]
pub use crate::put_back_n_impl::put_back_n;
#[cfg(feature = "use_alloc")]
pub use crate::multipeek_impl::multipeek;
#[cfg(feature = "use_alloc")]
pub use crate::peek_nth::peek_nth;
#[cfg(feature = "use_alloc")]
pub use crate::kmerge_impl::kmerge;
pub use crate::zip_eq_impl::zip_eq;
pub use crate::merge_join::merge_join_by;
#[cfg(feature = "use_alloc")]
pub use crate::rciter_impl::rciter;

/// Iterate `iterable` with a particular value inserted between each element.
///
/// [`IntoIterator`] enabled version of [`Iterator::intersperse`].
///
/// ```
/// use itertools::intersperse;
///
/// itertools::assert_equal(intersperse((0..3), 8), vec![0, 8, 1, 8, 2]);
/// ```
pub fn intersperse<I>(iterable: I, element: I::Item) -> Intersperse<I::IntoIter>
    where I: IntoIterator,
          <I as IntoIterator>::Item: Clone
{
    Itertools::intersperse(iterable.into_iter(), element)
}

/// Iterate `iterable` with a particular value created by a function inserted
/// between each element.
///
/// [`IntoIterator`] enabled version of [`Iterator::intersperse_with`].
///
/// ```
/// use itertools::intersperse_with;
///
/// let mut i = 10;
/// itertools::assert_equal(intersperse_with((0..3), || { i -= 1; i }), vec![0, 9, 1, 8, 2]);
/// assert_eq!(i, 8);
/// ```
pub fn intersperse_with<I, F>(iterable: I, element: F) -> IntersperseWith<I::IntoIter, F>
    where I: IntoIterator,
          F: FnMut() -> I::Item
{
    Itertools::intersperse_with(iterable.into_iter(), element)
}

/// Iterate `iterable` with a running index.
///
/// [`IntoIterator`] enabled version of [`Iterator::enumerate`].
///
/// ```
/// use itertools::enumerate;
///
/// for (i, elt) in enumerate(&[1, 2, 3]) {
///     /* loop body */
/// }
/// ```
pub fn enumerate<I>(iterable: I) -> iter::Enumerate<I::IntoIter>
    where I: IntoIterator
{
    iterable.into_iter().enumerate()
}

/// Iterate `iterable` in reverse.
///
/// [`IntoIterator`] enabled version of [`Iterator::rev`].
///
/// ```
/// use itertools::rev;
///
/// for elt in rev(&[1, 2, 3]) {
///     /* loop body */
/// }
/// ```
pub fn rev<I>(iterable: I) -> iter::Rev<I::IntoIter>
    where I: IntoIterator,
          I::IntoIter: DoubleEndedIterator
{
    iterable.into_iter().rev()
}

/// Iterate `i` and `j` in lock step.
///
/// [`IntoIterator`] enabled version of [`Iterator::zip`].
///
/// ```
/// use itertools::zip;
///
/// let data_1 = [1, 2, 3, 4, 5];
/// let data_2 = ['a', 'b', 'c'];
/// let mut result: Vec<(i32, char)> = Vec::new();
///
/// for (a, b) in zip(&data_1, &data_2) {
///     result.push((*a, *b));
/// }
/// assert_eq!(result, vec![(1, 'a'),(2, 'b'),(3, 'c')]);
/// ```
pub fn zip<I, J>(i: I, j: J) -> Zip<I::IntoIter, J::IntoIter>
    where I: IntoIterator,
          J: IntoIterator
{
    i.into_iter().zip(j)
}

/// Create an iterator that first iterates `i` and then `j`.
///
/// [`IntoIterator`] enabled version of [`Iterator::chain`].
///
/// ```
/// use itertools::chain;
///
/// for elt in chain(&[1, 2, 3], &[4]) {
///     /* loop body */
/// }
/// ```
pub fn chain<I, J>(i: I, j: J) -> iter::Chain<<I as IntoIterator>::IntoIter, <J as IntoIterator>::IntoIter>
    where I: IntoIterator,
          J: IntoIterator<Item = I::Item>
{
    i.into_iter().chain(j)
}

/// Create an iterator that clones each element from &T to T
///
/// [`IntoIterator`] enabled version of [`Iterator::cloned`].
///
/// ```
/// use itertools::cloned;
///
/// assert_eq!(cloned(b"abc").next(), Some(b'a'));
/// ```
pub fn cloned<'a, I, T: 'a>(iterable: I) -> iter::Cloned<I::IntoIter>
    where I: IntoIterator<Item=&'a T>,
          T: Clone,
{
    iterable.into_iter().cloned()
}

/// Perform a fold operation over the iterable.
///
/// [`IntoIterator`] enabled version of [`Iterator::fold`].
///
/// ```
/// use itertools::fold;
///
/// assert_eq!(fold(&[1., 2., 3.], 0., |a, &b| f32::max(a, b)), 3.);
/// ```
pub fn fold<I, B, F>(iterable: I, init: B, f: F) -> B
    where I: IntoIterator,
          F: FnMut(B, I::Item) -> B
{
    iterable.into_iter().fold(init, f)
}

/// Test whether the predicate holds for all elements in the iterable.
///
/// [`IntoIterator`] enabled version of [`Iterator::all`].
///
/// ```
/// use itertools::all;
///
/// assert!(all(&[1, 2, 3], |elt| *elt > 0));
/// ```
pub fn all<I, F>(iterable: I, f: F) -> bool
    where I: IntoIterator,
          F: FnMut(I::Item) -> bool
{
    iterable.into_iter().all(f)
}

/// Test whether the predicate holds for any elements in the iterable.
///
/// [`IntoIterator`] enabled version of [`Iterator::any`].
///
/// ```
/// use itertools::any;
///
/// assert!(any(&[0, -1, 2], |elt| *elt > 0));
/// ```
pub fn any<I, F>(iterable: I, f: F) -> bool
    where I: IntoIterator,
          F: FnMut(I::Item) -> bool
{
    iterable.into_iter().any(f)
}

/// Return the maximum value of the iterable.
///
/// [`IntoIterator`] enabled version of [`Iterator::max`].
///
/// ```
/// use itertools::max;
///
/// assert_eq!(max(0..10), Some(9));
/// ```
pub fn max<I>(iterable: I) -> Option<I::Item>
    where I: IntoIterator,
          I::Item: Ord
{
    iterable.into_iter().max()
}

/// Return the minimum value of the iterable.
///
/// [`IntoIterator`] enabled version of [`Iterator::min`].
///
/// ```
/// use itertools::min;
///
/// assert_eq!(min(0..10), Some(0));
/// ```
pub fn min<I>(iterable: I) -> Option<I::Item>
    where I: IntoIterator,
          I::Item: Ord
{
    iterable.into_iter().min()
}

/// Combine all iterator elements into one String, separated by `sep`.
///
/// [`IntoIterator`] enabled version of [`Itertools::join`].
///
/// ```
/// use itertools::join;
///
/// assert_eq!(join(&[1, 2, 3], ", "), "1, 2, 3");
/// ```
#[cfg(feature = "use_alloc")]
pub fn join<I>(iterable: I, sep: &str) -> String
    where I: IntoIterator,
          I::Item: Display
{
    iterable.into_iter().join(sep)
}

/// Sort all iterator elements into a new iterator in ascending order.
///
/// [`IntoIterator`] enabled version of [`Itertools::sorted`].
///
/// ```
/// use itertools::sorted;
/// use itertools::assert_equal;
///
/// assert_equal(sorted("rust".chars()), "rstu".chars());
/// ```
#[cfg(feature = "use_alloc")]
pub fn sorted<I>(iterable: I) -> VecIntoIter<I::Item>
    where I: IntoIterator,
          I::Item: Ord
{
    iterable.into_iter().sorted()
}

<commit_msg>Docstring improvement: Added explanation of function<commit_after>//! Free functions that create iterator adaptors or call iterator methods.
//!
//! The benefit of free functions is that they accept any [`IntoIterator`] as
//! argument, so the resulting code may be easier to read.

#[cfg(feature = "use_alloc")]
use std::fmt::Display;
use std::iter::{self, Zip};
#[cfg(feature = "use_alloc")]
type VecIntoIter<T> = alloc::vec::IntoIter<T>;

#[cfg(feature = "use_alloc")]
use alloc::{
    string::String,
};

use crate::Itertools;
use crate::intersperse::{Intersperse, IntersperseWith};

pub use crate::adaptors::{
    interleave,
    merge,
    put_back,
};
#[cfg(feature = "use_alloc")]
pub use crate::put_back_n_impl::put_back_n;
#[cfg(feature = "use_alloc")]
pub use crate::multipeek_impl::multipeek;
#[cfg(feature = "use_alloc")]
pub use crate::peek_nth::peek_nth;
#[cfg(feature = "use_alloc")]
pub use crate::kmerge_impl::kmerge;
pub use crate::zip_eq_impl::zip_eq;
pub use crate::merge_join::merge_join_by;
#[cfg(feature = "use_alloc")]
pub use crate::rciter_impl::rciter;

/// Iterate `iterable` with a particular value inserted between each element.
///
/// [`IntoIterator`] enabled version of [`Iterator::intersperse`].
///
/// ```
/// use itertools::intersperse;
///
/// itertools::assert_equal(intersperse((0..3), 8), vec![0, 8, 1, 8, 2]);
/// ```
pub fn intersperse<I>(iterable: I, element: I::Item) -> Intersperse<I::IntoIter>
    where I: IntoIterator,
          <I as IntoIterator>::Item: Clone
{
    Itertools::intersperse(iterable.into_iter(), element)
}

/// Iterate `iterable` with a particular value created by a function inserted
/// between each element.
///
/// [`IntoIterator`] enabled version of [`Iterator::intersperse_with`].
///
/// ```
/// use itertools::intersperse_with;
///
/// let mut i = 10;
/// itertools::assert_equal(intersperse_with((0..3), || { i -= 1; i }), vec![0, 9, 1, 8, 2]);
/// assert_eq!(i, 8);
/// ```
pub fn intersperse_with<I, F>(iterable: I, element: F) -> IntersperseWith<I::IntoIter, F>
    where I: IntoIterator,
          F: FnMut() -> I::Item
{
    Itertools::intersperse_with(iterable.into_iter(), element)
}

/// Iterate `iterable` with a running index.
///
/// [`IntoIterator`] enabled version of [`Iterator::enumerate`].
///
/// ```
/// use itertools::enumerate;
///
/// for (i, elt) in enumerate(&[1, 2, 3]) {
///     /* loop body */
/// }
/// ```
pub fn enumerate<I>(iterable: I) -> iter::Enumerate<I::IntoIter>
    where I: IntoIterator
{
    iterable.into_iter().enumerate()
}

/// Iterate `iterable` in reverse.
///
/// [`IntoIterator`] enabled version of [`Iterator::rev`].
///
/// ```
/// use itertools::rev;
///
/// for elt in rev(&[1, 2, 3]) {
///     /* loop body */
/// }
/// ```
pub fn rev<I>(iterable: I) -> iter::Rev<I::IntoIter>
    where I: IntoIterator,
          I::IntoIter: DoubleEndedIterator
{
    iterable.into_iter().rev()
}

/// Converts the arguments to iterators and zips them.
///
/// [`IntoIterator`] enabled version of [`Iterator::zip`].
///
/// ## Example
///
/// ```
/// use itertools::zip;
///
/// let mut result: Vec<(i32, char)> = Vec::new();
///
/// for (a, b) in zip(&[1, 2, 3, 4, 5], &['a', 'b', 'c']) {
///     result.push((*a, *b));
/// }
/// assert_eq!(result, vec![(1, 'a'),(2, 'b'),(3, 'c')]);
/// ```
#[deprecated(note="Use [std::iter::zip](https://doc.rust-lang.org/std/iter/fn.zip.html) instead", since="0.10.4")]
pub fn zip<I, J>(i: I, j: J) -> Zip<I::IntoIter, J::IntoIter>
    where I: IntoIterator,
          J: IntoIterator
{
    i.into_iter().zip(j)
}

/// Create an iterator that first iterates `i` and then `j`.
///
/// [`IntoIterator`] enabled version of [`Iterator::chain`].
///
/// ```
/// use itertools::chain;
///
/// for elt in chain(&[1, 2, 3], &[4]) {
///     /* loop body */
/// }
/// ```
pub fn chain<I, J>(i: I, j: J) -> iter::Chain<<I as IntoIterator>::IntoIter, <J as IntoIterator>::IntoIter>
    where I: IntoIterator,
          J: IntoIterator<Item = I::Item>
{
    i.into_iter().chain(j)
}

/// Create an iterator that clones each element from &T to T
///
/// [`IntoIterator`] enabled version of [`Iterator::cloned`].
///
/// ```
/// use itertools::cloned;
///
/// assert_eq!(cloned(b"abc").next(), Some(b'a'));
/// ```
pub fn cloned<'a, I, T: 'a>(iterable: I) -> iter::Cloned<I::IntoIter>
    where I: IntoIterator<Item=&'a T>,
          T: Clone,
{
    iterable.into_iter().cloned()
}

/// Perform a fold operation over the iterable.
///
/// [`IntoIterator`] enabled version of [`Iterator::fold`].
///
/// ```
/// use itertools::fold;
///
/// assert_eq!(fold(&[1., 2., 3.], 0., |a, &b| f32::max(a, b)), 3.);
/// ```
pub fn fold<I, B, F>(iterable: I, init: B, f: F) -> B
    where I: IntoIterator,
          F: FnMut(B, I::Item) -> B
{
    iterable.into_iter().fold(init, f)
}

/// Test whether the predicate holds for all elements in the iterable.
///
/// [`IntoIterator`] enabled version of [`Iterator::all`].
///
/// ```
/// use itertools::all;
///
/// assert!(all(&[1, 2, 3], |elt| *elt > 0));
/// ```
pub fn all<I, F>(iterable: I, f: F) -> bool
    where I: IntoIterator,
          F: FnMut(I::Item) -> bool
{
    iterable.into_iter().all(f)
}

/// Test whether the predicate holds for any elements in the iterable.
///
/// [`IntoIterator`] enabled version of [`Iterator::any`].
///
/// ```
/// use itertools::any;
///
/// assert!(any(&[0, -1, 2], |elt| *elt > 0));
/// ```
pub fn any<I, F>(iterable: I, f: F) -> bool
    where I: IntoIterator,
          F: FnMut(I::Item) -> bool
{
    iterable.into_iter().any(f)
}

/// Return the maximum value of the iterable.
///
/// [`IntoIterator`] enabled version of [`Iterator::max`].
///
/// ```
/// use itertools::max;
///
/// assert_eq!(max(0..10), Some(9));
/// ```
pub fn max<I>(iterable: I) -> Option<I::Item>
    where I: IntoIterator,
          I::Item: Ord
{
    iterable.into_iter().max()
}

/// Return the minimum value of the iterable.
///
/// [`IntoIterator`] enabled version of [`Iterator::min`].
///
/// ```
/// use itertools::min;
///
/// assert_eq!(min(0..10), Some(0));
/// ```
pub fn min<I>(iterable: I) -> Option<I::Item>
    where I: IntoIterator,
          I::Item: Ord
{
    iterable.into_iter().min()
}

/// Combine all iterator elements into one String, separated by `sep`.
///
/// [`IntoIterator`] enabled version of [`Itertools::join`].
///
/// ```
/// use itertools::join;
///
/// assert_eq!(join(&[1, 2, 3], ", "), "1, 2, 3");
/// ```
#[cfg(feature = "use_alloc")]
pub fn join<I>(iterable: I, sep: &str) -> String
    where I: IntoIterator,
          I::Item: Display
{
    iterable.into_iter().join(sep)
}

/// Sort all iterator elements into a new iterator in ascending order.
///
/// [`IntoIterator`] enabled version of [`Itertools::sorted`].
///
/// ```
/// use itertools::sorted;
/// use itertools::assert_equal;
///
/// assert_equal(sorted("rust".chars()), "rstu".chars());
/// ```
#[cfg(feature = "use_alloc")]
pub fn sorted<I>(iterable: I) -> VecIntoIter<I::Item>
    where I: IntoIterator,
          I::Item: Ord
{
    iterable.into_iter().sorted()
}

<|endoftext|>


<commit_before>//! Game loop.

// Local crate.
use GameEvent;
use GameWindow = game_window::GameWindow;
use GameIteratorSettings;
use GameIterator;
use KeyPress;
use KeyPressArgs;
use KeyRelease;
use KeyReleaseArgs;
use MouseMove;
use MouseMoveArgs;
use MouseRelativeMove;
use MouseRelativeMoveArgs;
use MousePress;
use MousePressArgs;
use MouseRelease;
use MouseReleaseArgs;
use MouseScroll;
use MouseScrollArgs;
use Render;
use RenderArgs;
use Update;
use UpdateArgs;

/// Implemented by game applications.
pub trait Game {
    /// Render graphics.
    fn render(&mut self, _args: &RenderArgs) {}

    /// Update the physical state of the game.
    fn update(&mut self, _args: &UpdateArgs) {}

    /// Perform tasks for loading before showing anything.
    fn load(&mut self) {}

    /// User pressed a key.
    ///
    /// This can be overridden to handle key pressed events.
    fn key_press(&mut self, _args: &KeyPressArgs) {}

    /// User released a key.
    ///
    /// This can be overridden to handle key released events.
    fn key_release(&mut self, _args: &KeyReleaseArgs) {}

    /// Pressed a mouse button.
    fn mouse_press(&mut self, _args: &MousePressArgs) {}

    /// Released a mouse button.
    fn mouse_release(&mut self, _args: &MouseReleaseArgs) {}

    /// Moved mouse cursor.
    fn mouse_move(&mut self, _args: &MouseMoveArgs) {}

    /// Moved mouse relative, not bounded by cursor.
    fn mouse_relative_move(&mut self, _args: &MouseRelativeMoveArgs) {}

    /// Scrolled mouse.
    fn mouse_scroll(&mut self, _args: &MouseScrollArgs) {}

    /// Handles a game event.
    fn event(&mut self, event: &mut GameEvent) {
        match *event {
            Render(ref mut args) => self.render(args),
            Update(ref mut args) => self.update(args),
            KeyPress(ref args) => self.key_press(args),
            KeyRelease(ref args) => self.key_release(args),
            MousePress(ref args) => self.mouse_press(args),
            MouseRelease(ref args) => self.mouse_release(args),
            MouseMove(ref args) => self.mouse_move(args),
            MouseRelativeMove(ref args) => self.mouse_relative_move(args),
            MouseScroll(ref args) => self.mouse_scroll(args),
        }
    }

    /// Executes a game loop.
    fn run<W: GameWindow>(
        &mut self,
        game_window: &mut W,
        game_iter_settings: &GameIteratorSettings
    ) {
        let mut game_iter = GameIterator::new(
            game_window,
            game_iter_settings
        );

        self.load();

        loop {
            match game_iter.next() {
                None => break,
                Some(mut e) => self.event(&mut e)
            }
        }
    }
}

<commit_msg>Added `should_capture_cursor` method on `Game` trait<commit_after>//! Game loop.

// Local crate.
use GameEvent;
use GameWindow = game_window::GameWindow;
use GameIteratorSettings;
use GameIterator;
use KeyPress;
use KeyPressArgs;
use KeyRelease;
use KeyReleaseArgs;
use MouseMove;
use MouseMoveArgs;
use MouseRelativeMove;
use MouseRelativeMoveArgs;
use MousePress;
use MousePressArgs;
use MouseRelease;
use MouseReleaseArgs;
use MouseScroll;
use MouseScrollArgs;
use Render;
use RenderArgs;
use Update;
use UpdateArgs;

/// Implemented by game applications.
pub trait Game {
    /// Render graphics.
    fn render(&mut self, _args: &RenderArgs) {}

    /// Update the physical state of the game.
    fn update(&mut self, _args: &UpdateArgs) {}

    /// Perform tasks for loading before showing anything.
    fn load(&mut self) {}

    /// User pressed a key.
    ///
    /// This can be overridden to handle key pressed events.
    fn key_press(&mut self, _args: &KeyPressArgs) {}

    /// User released a key.
    ///
    /// This can be overridden to handle key released events.
    fn key_release(&mut self, _args: &KeyReleaseArgs) {}

    /// Pressed a mouse button.
    fn mouse_press(&mut self, _args: &MousePressArgs) {}

    /// Released a mouse button.
    fn mouse_release(&mut self, _args: &MouseReleaseArgs) {}

    /// Moved mouse cursor.
    fn mouse_move(&mut self, _args: &MouseMoveArgs) {}

    /// Moved mouse relative, not bounded by cursor.
    fn mouse_relative_move(&mut self, _args: &MouseRelativeMoveArgs) {}

    /// Scrolled mouse.
    fn mouse_scroll(&mut self, _args: &MouseScrollArgs) {}

    /// Whether the cursor should be captured.
    ///
    /// When the cursor is captured, it is hidden from view
    /// and the cursor position does not change.
    /// Only relative mouse movements are registered.
    fn should_capture_cursor(&mut self) -> bool { false }

    /// Handles a game event.
    fn event(&mut self, event: &mut GameEvent) {
        match *event {
            Render(ref mut args) => self.render(args),
            Update(ref mut args) => self.update(args),
            KeyPress(ref args) => self.key_press(args),
            KeyRelease(ref args) => self.key_release(args),
            MousePress(ref args) => self.mouse_press(args),
            MouseRelease(ref args) => self.mouse_release(args),
            MouseMove(ref args) => self.mouse_move(args),
            MouseRelativeMove(ref args) => self.mouse_relative_move(args),
            MouseScroll(ref args) => self.mouse_scroll(args),
        }
    }

    /// Executes a game loop.
    fn run<W: GameWindow>(
        &mut self,
        game_window: &mut W,
        game_iter_settings: &GameIteratorSettings
    ) {
        let mut game_iter = GameIterator::new(
            game_window,
            game_iter_settings
        );

        self.load();

        loop {
            match game_iter.next() {
                None => break,
                Some(mut e) => self.event(&mut e)
            }
        }
    }
}

<|endoftext|>


<commit_before>use macroquad::rand::gen_range;

use crate::colour::*;

pub struct Grid {
    pub number_of_rows: usize,
    pub number_of_columns: usize,

    pub cells: Vec<Colour>,
}

impl Grid {
    pub fn generate(size: usize) -> Self {
        let mut cells = vec![Colour::Red; size*size];
        for i in 0..size {
            for j in 0..size {
                cells[size * i + j] = AllColours[gen_range(0, AllColours.len())];
            }
        }

        Self {
            number_of_columns: size,
            number_of_rows: size,
            cells,
        }
    }
}
<commit_msg>Test Grid::generate<commit_after>use macroquad::rand::gen_range;

use crate::colour::*;

pub struct Grid {
    pub number_of_rows: usize,
    pub number_of_columns: usize,

    pub cells: Vec<Colour>,
}

impl Grid {
    pub fn generate(size: usize) -> Self {
        let mut cells = vec![Colour::Red; size*size];
        for i in 0..size {
            for j in 0..size {
                cells[size * i + j] = AllColours[gen_range(0, AllColours.len())];
            }
        }

        Self {
            number_of_columns: size,
            number_of_rows: size,
            cells,
        }
    }
}

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

    #[test]
    pub fn generates_grid_of_correct_size() {
        let size = 3;

        let grid = Grid::generate(size);

        assert_eq!(grid.number_of_rows, size);
        assert_eq!(grid.number_of_columns, size);
        assert_eq!(grid.cells.len(), size*size);
    }
}
<|endoftext|>


<commit_before>use Options;
use std::sync::{Arc, RwLock};
use std::thread::sleep_ms;
use hyper::client::Client;
use hyper::method::Method;
use time::{now_utc, strftime};
use std::io::{stderr, Read, Write};
use bear_lib_terminal::terminal;
use bear_lib_terminal::geometry::{Size, Rect, Point};
use chattium_oxide_lib::ChatMessage;
use chattium_oxide_lib::json::{ToJsonnable, FromJsonnable};

pub struct ResponseRequester {
	server: String,
	client: Arc<Client>,
	keep_going: Arc<RwLock<bool>>,
	messages: Vec<ChatMessage>,
}

impl ResponseRequester {
	pub fn new(options: Options, client: Arc<Client>, keep_going: Arc<RwLock<bool>>) -> ResponseRequester {
		ResponseRequester{
			server: options.server,
			client: client,
			keep_going: keep_going,
			messages: Vec::new(),
		}
	}

	pub fn call(mut self) {
		self.draw_line();

		let mut newest = now_utc();
		while *self.keep_going.read().unwrap() {
			self.draw_line();

			let just_before = now_utc();
			match newest.to_json_string() {
				Ok(json) =>
					match self.client.request(Method::Trace, &*&self.server).body(&*&json).send() {
						Ok(mut res) => {
							let mut resbody = String::new();
							match res.read_to_string(&mut resbody) {
								Ok(_) =>
									match Vec::<ChatMessage>::from_json_string(&resbody) {
										Ok(ref mut messages) => {
											self.messages.append(messages);
											self.print_messages();
										},
										Err(error) =>
											{let _ = stderr().write_fmt(format_args!("Server at {} replied with invalid JSON: {}\n", self.server, error));},
									},
								Err(error) => {let _ = stderr().write_fmt(format_args!("Failed reading request from server at {}: {}\n", res.url, error));},
							}
						},
						Err(error) =>
							{let _ = stderr().write_fmt(format_args!("GETing new (before {}) messages failed: {}\n", strftime("%D %T", &newest).unwrap(), error));},
					},
				Err(error) => {let _ = stderr().write_fmt(format_args!("Couldn't serialize message: {}\n", error));},
			}

			newest = just_before;
			sleep_ms(500);
		}
	}

	fn print_messages(&self) {
		let size = terminal::state::size();
		terminal::clear(Some(Rect::from_size(Point::new(0, 0), Size::new(size.width, size.height - 2))));
		for (i, message) in self.messages.iter().rev().take((size.height - 2) as usize).enumerate() {
			terminal::print_xy(0, size.height - 3 - i as i32,
			                   &*&format!("{} | {}: {}", strftime("%T", &message.time_posted).unwrap(), message.sender.name, message.value));
		}
		terminal::refresh();
	}

	fn draw_line(&self) {
		let size = terminal::state::size();
		for x in 0..size.width {
			terminal::put_xy(x, size.height - 2, '—')
		}
		terminal::refresh();
	}
}
<commit_msg>Send message ids<commit_after>use Options;
use std::io::{stderr, Read, Write};
use std::sync::{Arc, RwLock};
use std::thread::sleep_ms;
use time::strftime;
use hyper::client::Client;
use hyper::method::Method;
use bear_lib_terminal::terminal;
use bear_lib_terminal::geometry::{Size, Rect, Point};
use chattium_oxide_lib::ChatMessage;
use chattium_oxide_lib::json::{ToJsonnable, FromJsonnable, JsonError};

pub struct ResponseRequester {
	server: String,
	client: Arc<Client>,
	keep_going: Arc<RwLock<bool>>,
	messages: Vec<ChatMessage>,
}

impl ResponseRequester {
	pub fn new(options: Options, client: Arc<Client>, keep_going: Arc<RwLock<bool>>) -> ResponseRequester {
		ResponseRequester{
			server: options.server,
			client: client,
			keep_going: keep_going,
			messages: Vec::new(),
		}
	}

	pub fn call(mut self) {
		self.draw_line();

		while *self.keep_going.read().unwrap() {
			self.draw_line();

			match self.request_message() {
				Ok(json) =>
					match self.client.request(Method::Trace, &*&self.server).body(&*&json).send() {
						Ok(mut res) => {
							let mut resbody = String::new();
							match res.read_to_string(&mut resbody) {
								Ok(_) =>
									match Vec::<ChatMessage>::from_json_string(&resbody) {
										Ok(ref mut messages) => {
											self.messages.append(messages);
											self.print_messages();
										},
										Err(error) =>
											{let _ = stderr().write_fmt(format_args!("Server at {} replied with invalid JSON: {}\n", self.server, error));},
									},
								Err(error) => {let _ = stderr().write_fmt(format_args!("Failed reading request from server at {}: {}\n", res.url, error));},
							}
						},
						Err(error) =>
							{let _ = stderr().write_fmt(format_args!("GETing new (before #{}) messages failed: {}\n", json, error));},
					},
				Err(error) => {let _ = stderr().write_fmt(format_args!("Couldn't serialize message: {}\n", error));},
			}

			sleep_ms(500);
		}
	}

	fn print_messages(&self) {
		let size = terminal::state::size();
		terminal::clear(Some(Rect::from_size(Point::new(0, 0), Size::new(size.width, size.height - 2))));
		for (i, message) in self.messages.iter().rev().take((size.height - 2) as usize).enumerate() {
			terminal::print_xy(0, size.height - 3 - i as i32,
			                   &*&format!("{} | {}: {}", strftime("%T", &message.time_posted).unwrap(), message.sender.name, message.value));
		}
		terminal::refresh();
	}

	fn draw_line(&self) {
		let size = terminal::state::size();
		for x in 0..size.width {
			terminal::put_xy(x, size.height - 2, '—')
		}
		terminal::refresh();
	}

	fn request_message(&self) -> Result<String, JsonError> {
		self.messages.iter().rev().next().map(|ref m| m.id).unwrap_or(0).to_json_string()
	}
}
<|endoftext|>


<commit_before>/*
 * diosix microkernel 'menchi'
 *
 * Provide dynamic memory allocation for the kernel
 *
 * Maintainer: Chris Williams (diosix.org)
 *
 */

use errors::KernelInternalError;
use ::hardware::physmem;

use spin::Mutex;
use core::ptr;
use core::mem::size_of;

/* heap design notes
 *
 * Plan is to use a fixed-block allocator - not because it's trivial
 * but because this microkernel is likely to allocate memory for a
 * small set of structures - control blocks for process, thread,
 * compartment, and interrupt management. we'll start with blocks
 * of 32 bytes, and use the diagnostic stats to figure out if this
 * needs changing. 32 bytes is nice because 128 x 32-byte blocks
 * fits inside a 4096-byte page, and the header will take up 32
 * bytes too.
 *
 * One worry is fragmentation, with small blocks trapped between
 * groups of blocks.
 *
 * Blocks are grouped into allocations, which are tracked using
 * a double-linked list. When an allocation is requested, we
 * scan the free pool for a block, or group of blocks, and
 * hopefully remove one from the pool and return that address.
 * If we can't find a suitable block, grab a 4K page of memory,
 * take the block from the first part of the page, and then
 * add the rest of the page to the free pool.
 *
 * If you need more than 4064 bytes (4096 - header size) then
 * just ask for a page from the system.
 *
 */

const HEADER_SIZE:      usize = 32; /* can't use size_of here, it's 32 bytes */
const BLOCK_SIZE:       usize = 32; /* see above discussion for block size */
const BLOCK_MAGIC_IN_USE: u64 = 0x4c69766548656170; /* LiveHeap */
const BLOCK_MAGIC_FREE:   u64 = 0x4465616448656170; /* DeadHeap */

/* there are a maximum of 128 x 32-byte blocks in a 4K page, minus space for the header */
const BLOCKS_PER_PAGE:  usize = (::hardware::physmem::SMALL_PAGE_SIZE - HEADER_SIZE) / BLOCK_SIZE;

pub static KERNEL: Mutex<Heap> = Mutex::new(Heap
                                    {
                                        free: 0 as *mut _,
                                        blocks_in_use:     0,
                                        free_pool_blocks:  0,
                                        total_bytes_requested:   0,
                                        total_alloc_requests: 0,
                                    });

pub struct Heap
{
    /* pointer to free list */
    free: *mut HeapAllocation,

    /* usage stats - not including allocations' headers */
    blocks_in_use: usize, /* blocks in use right now */
    free_pool_blocks: usize, /* blocks sitting in the free pool */

    /* diagnostic stats so we can calculate the
     * average size of the kernel's allocs. */
    total_bytes_requested: usize, /* running total of bytes allocated */
    total_alloc_requests: usize, /* running total of alloc requests */
}

/* change HEADER_SIZE if you change this structure */
pub struct HeapAllocation
{
    magic: u64, /* must be BLOCK_MAGIC_IN_USE or BLOCK_MAGIC_FREE */
    blocks: usize, /* number of blocks in this allocation not including the header */

    /* linked list pointers for the free list */
    previous: *mut HeapAllocation,
    next: *mut HeapAllocation,
}

/* wrap a nice interface around the default KERNEL heap */
macro_rules! kalloc
{
    ($size:expr) => ($crate::heap::KERNEL.lock().alloc($size))
}

macro_rules! kalloc_debug
{
    () => ($crate::heap::KERNEL.lock().debug_stats())
}

impl Heap
{
    /* top_up_free_pool
     *
     * Dump a page of RAM into the pool to provide some free blocks.
     * <= error code on failure.
     */
    fn top_up_free_pool(&mut self) -> Result<(), KernelInternalError>
    {
        /* grab a page to add to the free list to get us started */
        let free_block = try!(::hardware::physmem::get_page());

        self.add_to_free(free_block, ::hardware::physmem::SMALL_PAGE_SIZE);
        self.free_pool_blocks = self.free_pool_blocks + BLOCKS_PER_PAGE;

        Ok(())
    }

    /* alloc
     *
     * Allocate some memory for the kernel. This code is written defensively,
     * it can probably be optimized later if it proves to be a bottleneck.
     * => size = bytes to allocate from the heap. Must be non-zero.
     * <= pointer to memory, or an error code on failure.
     */
    pub fn alloc(&mut self, size: usize) -> Result<*mut u8, KernelInternalError>
    {
        if size == 0 { return Err(KernelInternalError::HeapBadAllocReq); }

        let mut blocks_req: usize = size / BLOCK_SIZE;
        if(size % BLOCK_SIZE) > 0
        {
            blocks_req = blocks_req + 1; /* round up to nearest whole block */
        }

        let mut block = self.free;
        let mut block_size = 0;

        /* make two passes: first time looking at the free pool, and
         * second time after priming the pool with new blocks */
        for attempts in 0..2
        {
            /* inspect the free list for a suitable block or group of blocks */
            loop
            {
                /* give up when we hit a null pointer */
                if block == 0 as *mut _ { break; }

                unsafe
                {
                    /* sanity check */
                    if (*block).magic != BLOCK_MAGIC_FREE
                    {
                        kprintln!("[mem] BUG! Non-free heap block {:p} in free pool", block);
                        return Err(KernelInternalError::HeapCorruption);
                    }

                    /* is this block big enough? */
                    block_size = (*block).blocks;
                    if block_size >= blocks_req { break; }

                    /* try the next block */
                    block = (*block).next;
                }
            }

            /* if we're coming up short in our search, reflll the pool and try again */
            if block == 0 as *mut _
            {
                try!(self.top_up_free_pool());
            }
            else
            {
                break;
            }

            block = self.free;
        }

        /* if we're still drawing dead, then bail out - the request is probably too big */
        if block == 0 as *mut _ { return Err(KernelInternalError::HeapBadAllocReq); }

        /* we may have to split a group of blocks */
        if block_size > blocks_req
        {
            let split_addr = (block as usize) + HEADER_SIZE + (blocks_req * BLOCK_SIZE);
            self.add_to_free(split_addr, (block_size - blocks_req) * BLOCK_SIZE);
        }

        /* detach the block from the free list */
        unsafe
        {
            /* remove from head of the linked list */
            if self.free == block
            {
                self.free = (*block).next;
            }

            /* connect the previous block in the chain to the next block */
            let mut previous = (*block).previous;
            if previous != 0 as *mut _
            {
                (*previous).next = (*block).next;
                (*block).previous = 0 as *mut _;
            }

            /* connect the next block in the chain to the previous block */
            let mut next = (*block).next;
            if next != 0 as *mut _
            {
                (*next).previous = (*block).previous;
                (*block).next = 0 as *mut _;
            }

            /* update block metadata */
            (*block).magic = BLOCK_MAGIC_IN_USE;
            (*block).blocks = blocks_req;
        }

        /* the easy part - fill out the statistics */
        self.blocks_in_use = self.blocks_in_use + blocks_req;
        self.total_alloc_requests = self.total_alloc_requests + 1;
        self.total_bytes_requested = self.total_bytes_requested + size;
        self.free_pool_blocks = self.free_pool_blocks - blocks_req;

        /* skip over the header when handing back a pointer */
        Ok(((block as usize) + HEADER_SIZE) as *mut _)
    }

    /* add_to_free
     *
     * Add a headerless-block (or group of them) to the free pool.
     * This does not update the heap's accounting variables because
     * add_to_free() may be called during a block split. It's up
     * to the caller to update the heap's accounting.
     * => ptr = address of start of block(s)
     *    size = number of bytes in group
     */
    fn add_to_free(&mut self, ptr: usize, size: usize)
    {
        let mut new = ptr as *mut HeapAllocation;
        let usable_blocks = (size - HEADER_SIZE) / BLOCK_SIZE;

        unsafe
        {
            /* add a header */
            (*new).next = self.free;
            (*new).previous = 0 as *mut _;
            (*new).blocks = usable_blocks;
            (*new).magic = BLOCK_MAGIC_FREE;

            /* attach to head of the free list */
            self.free = new;

            /* make old head of the list point back to this new block */
            if (*new).next != 0 as *mut _
            {
                let mut old_head = (*new).next;
                (*old_head).previous = new;
            }
        }
    }

    pub fn debug_stats(&self)
    {
        if self.total_alloc_requests == 0
        {
            kprintln!("[mem] kernel heap statistics: nothing to report");
            return;
        }

        kprintln!("[mem] kernel heap statistics:");
        kprintln!("... {} bytes allocated in {} blocks", self.blocks_in_use * BLOCK_SIZE, self.blocks_in_use);
        kprintln!("... {} bytes in free pool in {} blocks", self.free_pool_blocks * BLOCK_SIZE, self.free_pool_blocks);
        kprintln!("... {} allocation rquests, {} bytes requested, average request size is {} bytes",
                  self.total_alloc_requests, self.total_bytes_requested, self.total_bytes_requested / self.total_alloc_requests);

        /* walk the free list */
        kprintln!("[mem] kernel heap free pool:");
        let mut block = self.free;
        loop
        {
            if block == 0 as *mut _ { break; }
            unsafe
            {
                kprint!("... {} blocks [previous {:x} next {:x}] ",
                          (*block).blocks, (*block).previous as usize, (*block).next as usize);
                if (*block).magic == BLOCK_MAGIC_FREE
                {
                    kprintln!("[good magic]");
                }
                else
                {
                    kprintln!("[BAD MAGIC]");
                }

                block = (*block).next;
            }
        }
    }
}

<commit_msg>Tighten up dynamic allocator's accounting, also clarify comments and variable names to distinguish between a block (a unit of memory) and an allocation (a group of one or more blocks that fulfill an allocation request)<commit_after>/*
 * diosix microkernel 'menchi'
 *
 * Provide dynamic memory allocation for the kernel
 *
 * Maintainer: Chris Williams (diosix.org)
 *
 */

use errors::KernelInternalError;
use ::hardware::physmem;

use spin::Mutex;
use core::ptr;
use core::mem::size_of;

/* heap design notes
 *
 * Plan is to use a fixed-block allocator - not because it's trivial
 * but because this microkernel is likely to allocate memory for a
 * small set of structures - control blocks for process, thread,
 * compartment, and interrupt management. we'll start with blocks
 * of 32 bytes, and use the diagnostic stats to figure out if this
 * needs changing. 32 bytes is nice because 128 x 32-byte blocks
 * fits inside a 4096-byte page, and the header will take up 32
 * bytes too.
 *
 * One worry is fragmentation, with small blocks trapped between
 * groups of blocks.
 *
 * Blocks are grouped into allocations, which are tracked using
 * a double-linked list. When an allocation is requested, we
 * scan the free pool for a block, or group of blocks, and
 * hopefully remove one from the pool and return that address.
 * If we can't find a suitable block, grab a 4K page of memory,
 * take the block from the first part of the page, and then
 * add the rest of the page to the free pool.
 *
 * If you need more than 4064 bytes (4096 - header size) then
 * just ask for a page from the system.
 *
 */

const HEADER_SIZE:      usize = 32; /* can't use size_of here, it's 32 bytes */
const BLOCK_SIZE:       usize = 32; /* see above discussion for block size */
const BLOCK_MAGIC_IN_USE: u64 = 0x4c69766548656170; /* LiveHeap */
const BLOCK_MAGIC_FREE:   u64 = 0x4465616448656170; /* DeadHeap */

const BLOCK_NULL_PTR: *mut HeapAllocation = 0 as *mut HeapAllocation;

pub static KERNEL: Mutex<Heap> = Mutex::new(Heap
                                    {
                                        free:                  BLOCK_NULL_PTR,
                                        blocks_in_use:         0,
                                        allocations_in_use:    0,
                                        free_pool_blocks:      0,
                                        total_bytes_requested: 0,
                                        total_alloc_requests:  0,
                                    });

pub struct Heap
{
    /* pointer to head of the free list */
    free: *mut HeapAllocation,

    /* usage stats - not including allocations' headers */
    blocks_in_use: usize, /* blocks in use right now */
    free_pool_blocks: usize, /* blocks sitting in the free pool */
    allocations_in_use: usize, /* number of allocations */

    /* diagnostic stats so we can calculate the
     * average size of the kernel's allocs. */
    total_bytes_requested: usize, /* running total of bytes allocated */
    total_alloc_requests: usize, /* running total of allocatio requests */
}

/* change HEADER_SIZE if you change this structure */
pub struct HeapAllocation
{
    magic: u64, /* must be BLOCK_MAGIC_IN_USE or BLOCK_MAGIC_FREE */
    blocks: usize, /* number of blocks in this allocation not including the header */

    /* linked list pointers for the free list */
    previous: *mut HeapAllocation,
    next: *mut HeapAllocation,
}

/* wrap a nice interface around the default KERNEL heap */
macro_rules! kalloc
{
    ($size:expr) => ($crate::heap::KERNEL.lock().alloc($size))
}

macro_rules! kalloc_debug
{
    () => ($crate::heap::KERNEL.lock().debug_stats())
}

impl Heap
{
    /* top_up_free_pool
     *
     * Add a page of RAM to the pool to provide some free blocks.
     * <= returns an error code on failure.
     */
    fn top_up_free_pool(&mut self) -> Result<(), KernelInternalError>
    {
        /* grab a page to add to the free list to get us started */
        let free_block = try!(::hardware::physmem::get_page());

        /* the page is headerless, so add it using add_raw_mem_to_free(),
         * which gives us a count of usable blocks in the memory area. */
        let block_count = self.add_raw_mem_to_free(free_block, ::hardware::physmem::SMALL_PAGE_SIZE);
        self.free_pool_blocks = self.free_pool_blocks + block_count;

        Ok(())
    }

    /* alloc
     *
     * Allocate some memory for the kernel. This code is written defensively,
     * it can probably be optimized later if it proves to be a bottleneck.
     * => size = bytes to allocate from the heap. Must be non-zero.
     * <= pointer to memory, or an error code on failure.
     */
    pub fn alloc(&mut self, size: usize) -> Result<*mut u8, KernelInternalError>
    {
        if size == 0 { return Err(KernelInternalError::HeapBadAllocReq); }

        /* calculate nr of blocks required to fulfill this alocation request,
         * not including the header */
        let mut blocks_req: usize = size / BLOCK_SIZE;
        if(size % BLOCK_SIZE) > 0
        {
            blocks_req = blocks_req + 1; /* round up to nearest whole block */
        }

        /* start search for suitable group of free block(s) to fulfill request */
        let mut found = self.free; /* search forward through the free list */
        let mut found_blocks = 0; /* size of found block */

        /* make two passes: first time looking at the free pool, and
         * second time after priming the pool with new blocks */
        for attempts in 0..2
        {
            /* inspect the free list for a suitable block or group of blocks */
            loop
            {
                /* give up when we hit a null pointer */
                if found == BLOCK_NULL_PTR { break; }

                unsafe
                {
                    /* sanity check */
                    if (*found).magic != BLOCK_MAGIC_FREE
                    {
                        kprintln!("[mem] BUG! Non-free heap block {:p} in free pool", found);
                        return Err(KernelInternalError::HeapCorruption);
                    }

                    /* is this allocation of free block(s) big enough for the request? */
                    found_blocks = (*found).blocks;
                    if found_blocks >= blocks_req { break; }

                    /* try the next block if the group of free block(s) wasn't big enough */
                    found = (*found).next;
                }
            }

            /* end the search if we've found a suitable group of block(s) */
            if found != BLOCK_NULL_PTR { break; }

            /* if we're still here, reflll the pool and try again */
            try!(self.top_up_free_pool());
            found = self.free;
        }

        /* if we're still drawing dead, then bail out - the request is probably too big */
        if found == BLOCK_NULL_PTR { return Err(KernelInternalError::HeapBadAllocReq); }

        /* we may have to split a group of blocks: snap off the unneeded part of the
         * group and put it back into the free pool with a new header. the current
         * header is going to be repurposed for the allocated block(s). */
        if found_blocks > blocks_req
        {
            let split_addr = (found as usize) + HEADER_SIZE + (blocks_req * BLOCK_SIZE);
            self.free_pool_blocks = self.free_pool_blocks - found_blocks;
            let added_blocks = self.add_raw_mem_to_free(split_addr, (found_blocks - blocks_req) * BLOCK_SIZE);
            self.free_pool_blocks = self.free_pool_blocks + added_blocks;
        }

        /* detach the found group of block(s) from the free list */
        unsafe
        {
            /* remove from head of the linked list */
            if self.free == found
            {
                self.free = (*found).next;
            }

            /* connect the previous block in the chain to the next block */
            let mut previous = (*found).previous;
            if previous != BLOCK_NULL_PTR
            {
                (*previous).next = (*found).next;
                (*found).previous = BLOCK_NULL_PTR;
            }

            /* connect the next block in the chain to the previous block */
            let mut next = (*found).next;
            if next != BLOCK_NULL_PTR
            {
                (*next).previous = (*found).previous;
                (*found).next = BLOCK_NULL_PTR;
            }

            /* update block metadata */
            (*found).magic = BLOCK_MAGIC_IN_USE;
            (*found).blocks = blocks_req;
        }

        /* the easy part: update the accounting */
        self.blocks_in_use = self.blocks_in_use + blocks_req;
        self.allocations_in_use = self.allocations_in_use + 1;
        self.total_alloc_requests = self.total_alloc_requests + 1;
        self.total_bytes_requested = self.total_bytes_requested + size;

        /* skip over the header when handing back a pointer */
        Ok(((found as usize) + HEADER_SIZE) as *mut _)
    }

    /* add_raw_mem_to_free
     *
     * Add a headerless-block (or group of them) to the free pool.
     * This does not update the heap's accounting variables because
     * add_to_free() may be called during a block split. It's up
     * to the caller to update the heap's accounting.
     * => ptr = address of start of block(s)
     *    size = number of bytes in group
     * <= number of usable blocks in size
     */
    fn add_raw_mem_to_free(&mut self, ptr: usize, size: usize) -> usize
    {
        let mut new = ptr as *mut HeapAllocation;
        let usable_blocks = (size - HEADER_SIZE) / BLOCK_SIZE;

        /* don't put an empty space into the free pool */
        if size == 0 { return 0; }

        unsafe
        {
            /* add a header */
            (*new).next = self.free;
            (*new).previous = BLOCK_NULL_PTR;
            (*new).blocks = usable_blocks;
            (*new).magic = BLOCK_MAGIC_FREE;

            /* attach to head of the free list */
            self.free = new;

            /* make old head of the list point back to this new block */
            if (*new).next != BLOCK_NULL_PTR
            {
                let mut old_head = (*new).next;
                (*old_head).previous = new;
            }
        }

        return usable_blocks;
    }

    pub fn debug_stats(&self)
    {
        if self.total_alloc_requests == 0
        {
            kprintln!("[mem] kernel heap statistics: nothing to report");
            return;
        }

        kprintln!("[mem] kernel heap statistics:");

        kprintln!("... {} bytes in {} allocations, {} blocks in use, plus {} bytes overhead",
                  self.blocks_in_use * BLOCK_SIZE, self.allocations_in_use, self.blocks_in_use,
                  HEADER_SIZE * self.allocations_in_use);

        kprintln!("... {} bytes in free pool in {} blocks",
                  self.free_pool_blocks * BLOCK_SIZE, self.free_pool_blocks);

        kprintln!("... {} allocation rquests, {} bytes requested, average request size is {} bytes",
                  self.total_alloc_requests, self.total_bytes_requested,
                  self.total_bytes_requested / self.total_alloc_requests);

        /* walk the free list */
        kprintln!("[mem] kernel heap free pool:");
        let mut block = self.free;
        loop
        {
            if block == BLOCK_NULL_PTR { break; }
            unsafe
            {
                kprint!("... {} blocks [{:x} <--- {:x} --> {:x}] ",
                          (*block).blocks, (*block).previous as usize, block as usize, (*block).next as usize);
                if (*block).magic == BLOCK_MAGIC_FREE
                {
                    kprintln!("[good magic]");
                }
                else
                {
                    kprintln!("[BAD MAGIC]");
                }

                block = (*block).next;
            }
        }
    }
}

<|endoftext|>


<commit_before>//! Module for creating HMAC digests.
use core::ops::Deref;
use sha2::{HashFunction, MAX_DIGEST_SIZE, Sha224, Sha256, Sha384, Sha512};

const IPAD: u8 = 0x36;
const OPAD: u8 = 0x5c;

/// A function for creating HMAC digests given a hash function `H`.
///
/// # Examples
///
/// ```
/// use crypto_pure::hmac::Hmac;
/// use crypto_pure::sha2::{HashFunction, Sha512};
/// # let key = b"This should be generated securely.";
/// let mut digest = [0; Sha512::DIGEST_SIZE];
/// let mut hmac = Hmac::<Sha512>::new(key);
/// hmac.update(b"part one");
/// hmac.update(b"part two");
/// let digest = hmac.digest();
/// ```
pub struct Hmac<H> {
    inner_hash_function: H,
    outer_hash_function: H,
}

/// A digest result that derefs into a slice of bytes.
pub struct Digest {
    buffer: [u8; MAX_DIGEST_SIZE],
    size: usize,
}

macro_rules! impl_wrapper { ($function:ident, $key:expr, $message:expr) => {{
    let mut digest = [0; $function::DIGEST_SIZE];
    let mut hmac = Hmac::<$function>::new($key);
    hmac.update($message);
    hmac.write_digest(&mut digest);
    digest
}}}

/// Wrapper for obtaining the HMAC-SHA-512 digest for a complete message.
pub fn hmac_sha512(key: &[u8], message: &[u8]) -> [u8; Sha512::DIGEST_SIZE] {
    impl_wrapper!(Sha512, key, message)
}

/// Wrapper for obtaining the HMAC-SHA-384 digest for a complete message.
pub fn hmac_sha384(key: &[u8], message: &[u8]) -> [u8; Sha384::DIGEST_SIZE] {
    impl_wrapper!(Sha384, key, message)
}

/// Wrapper for obtaining the HMAC-SHA-256 digest for a complete message.
pub fn hmac_sha256(key: &[u8], message: &[u8]) -> [u8; Sha256::DIGEST_SIZE] {
    impl_wrapper!(Sha256, key, message)
}

/// Wrapper for obtaining the HMAC-SHA-224 digest for a complete message.
pub fn hmac_sha224(key: &[u8], message: &[u8]) -> [u8; Sha224::DIGEST_SIZE] {
    impl_wrapper!(Sha224, key, message)
}

impl<H: HashFunction> Hmac<H> {
    /// Initializes an HMAC function given a key.
    pub fn new(key: &[u8]) -> Self {
        let mut hashed_key;
        let new_key;
        if key.len() > H::BLOCK_SIZE {
            hashed_key = [0; MAX_DIGEST_SIZE];
            let mut hash_function = H::default();
            hash_function.update(key);
            hash_function.write_digest(&mut hashed_key[..H::DIGEST_SIZE]);
            new_key = &hashed_key[..H::DIGEST_SIZE];
        } else {
            new_key = key;
        }
        Self {
            inner_hash_function: Self::keyed_hash_function(new_key, IPAD),
            outer_hash_function: Self::keyed_hash_function(new_key, OPAD),
        }
    }

    /// Feeds input into the function to update its state.
    pub fn update(&mut self, input: &[u8]) {
        self.inner_hash_function.update(input);
    }

    /// Outputs a `Digest` containing the HMAC result.
    pub fn digest(self) -> Digest {
        let mut buffer = [0; MAX_DIGEST_SIZE];
        self.write_digest(&mut buffer[..H::DIGEST_SIZE]);
        Digest {
            buffer: buffer,
            size: H::DIGEST_SIZE,
        }
    }

    pub(crate) fn write_digest(mut self, output: &mut [u8]) {
        assert_eq!(H::DIGEST_SIZE, output.len());
        self.inner_hash_function.write_digest(output);
        self.outer_hash_function.update(output);
        self.outer_hash_function.write_digest(output);
    }

    fn keyed_hash_function(key: &[u8], pad: u8) -> H {
        let mut hash_function = H::default();
        for byte in key {
            hash_function.update(&[byte ^ pad]);
        }
        for _ in key.len()..H::BLOCK_SIZE {
            hash_function.update(&[pad]);
        }
        hash_function
    }
}

impl Deref for Digest {
    type Target = [u8];

    fn deref(&self) -> &Self::Target {
        &self.buffer[..self.size]
    }
}

impl AsRef<[u8]> for Digest {
    fn as_ref(&self) -> &[u8] {
        &self
    }
}

#[cfg(test)]
mod tests {
    use std::vec::Vec;
    use super::*;
    use test_helpers::*;

    fn check(exp512: &str, exp384: &str, exp256: &str, exp224: &str, key: &[u8], data: &[u8]) {
        macro_rules! check { ($function:ident, $wrapper:path, $expected:expr) => (
            let expected = h2b($expected);
            let actual = $wrapper(key, data);
            assert_eq!(expected, actual.to_vec());

            let actual = &mut vec![0; expected.len()];
            let mut hmac = Hmac::<$function>::new(key);
            for word in data.chunks(4) {
                hmac.update(word);
            }
            hmac.write_digest(actual);
            assert_eq!(expected, actual.to_vec());
        )}

        check!(Sha512, hmac_sha512, exp512);
        check!(Sha384, hmac_sha384, exp384);
        check!(Sha256, hmac_sha256, exp256);
        check!(Sha224, hmac_sha224, exp224);
    }

    #[test]
    fn test_digest() {
        let key = &h2b("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
        let data = b"Hi There";
        let exp512 = "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cde\
                      daa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854";
        let exp384 = "afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59c\
                      faea9ea9076ede7f4af152e8b2fa9cb6";
        let exp256 = "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7";
        let exp224 = "896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22";
        check(exp512, exp384, exp256, exp224, key, data);

        let key = b"Jefe";
        let data = b"what do ya want for nothing?";
        let exp512 = "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea250554\
                      9758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737";
        let exp384 = "af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e\
                      8e2240ca5e69e2c78b3239ecfab21649";
        let exp256 = "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843";
        let exp224 = "a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44";
        check(exp512, exp384, exp256, exp224, key, data);

        let key = &[0xaa; 20];
        let data = &[0xdd; 50];
        let exp512 = "fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39\
                      bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb";
        let exp384 = "88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e55966144b\
                      2a5ab39dc13814b94e3ab6e101a34f27";
        let exp256 = "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe";
        let exp224 = "7fb3cb3588c6c1f6ffa9694d7d6ad2649365b0c1f65d69d1ec8333ea";
        check(exp512, exp384, exp256, exp224, key, data);

        let key: &Vec<_> = &(0x01..0x1a).collect();
        let data = &[0xcd; 50];
        let exp512 = "b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3db\
                      a91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd";
        let exp384 = "3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e1f573b4e\
                      6801dd23c4a7d679ccf8a386c674cffb";
        let exp256 = "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b";
        let exp224 = "6c11506874013cac6a2abc1bb382627cec6a90d86efc012de7afec5a";
        check(exp512, exp384, exp256, exp224, key, data);

        let key = &[0xaa; 131];
        let data = b"Test Using Larger Than Block-Size Key - Hash Key First";
        let exp512 = "80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f352\
                      6b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598";
        let exp384 = "4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05033ac4c6\
                      0c2ef6ab4030fe8296248df163f44952";
        let exp256 = "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54";
        let exp224 = "95e9a0db962095adaebe9b2d6f0dbce2d499f112f2d2b7273fa6870e";
        check(exp512, exp384, exp256, exp224, key, data);

        let data =
            b"This is a test using a larger than block-size key and a larger than block-\
              size data. The key needs to be hashed before being used by the HMAC algorithm.";
        let exp512 = "e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944\
                      b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58";
        let exp384 = "6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82461e99c5\
                      a678cc31e799176d3860e6110c46523e";
        let exp256 = "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2";
        let exp224 = "3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1";
        check(exp512, exp384, exp256, exp224, key, data);
    }
}
<commit_msg>hmac: remove stray documentation line<commit_after>//! Module for creating HMAC digests.
use core::ops::Deref;
use sha2::{HashFunction, MAX_DIGEST_SIZE, Sha224, Sha256, Sha384, Sha512};

const IPAD: u8 = 0x36;
const OPAD: u8 = 0x5c;

/// A function for creating HMAC digests given a hash function `H`.
///
/// # Examples
///
/// ```
/// use crypto_pure::hmac::Hmac;
/// use crypto_pure::sha2::{HashFunction, Sha512};
/// # let key = b"This should be generated securely.";
/// let mut hmac = Hmac::<Sha512>::new(key);
/// hmac.update(b"part one");
/// hmac.update(b"part two");
/// let digest = hmac.digest();
/// ```
pub struct Hmac<H> {
    inner_hash_function: H,
    outer_hash_function: H,
}

/// A digest result that derefs into a slice of bytes.
pub struct Digest {
    buffer: [u8; MAX_DIGEST_SIZE],
    size: usize,
}

macro_rules! impl_wrapper { ($function:ident, $key:expr, $message:expr) => {{
    let mut digest = [0; $function::DIGEST_SIZE];
    let mut hmac = Hmac::<$function>::new($key);
    hmac.update($message);
    hmac.write_digest(&mut digest);
    digest
}}}

/// Wrapper for obtaining the HMAC-SHA-512 digest for a complete message.
pub fn hmac_sha512(key: &[u8], message: &[u8]) -> [u8; Sha512::DIGEST_SIZE] {
    impl_wrapper!(Sha512, key, message)
}

/// Wrapper for obtaining the HMAC-SHA-384 digest for a complete message.
pub fn hmac_sha384(key: &[u8], message: &[u8]) -> [u8; Sha384::DIGEST_SIZE] {
    impl_wrapper!(Sha384, key, message)
}

/// Wrapper for obtaining the HMAC-SHA-256 digest for a complete message.
pub fn hmac_sha256(key: &[u8], message: &[u8]) -> [u8; Sha256::DIGEST_SIZE] {
    impl_wrapper!(Sha256, key, message)
}

/// Wrapper for obtaining the HMAC-SHA-224 digest for a complete message.
pub fn hmac_sha224(key: &[u8], message: &[u8]) -> [u8; Sha224::DIGEST_SIZE] {
    impl_wrapper!(Sha224, key, message)
}

impl<H: HashFunction> Hmac<H> {
    /// Initializes an HMAC function given a key.
    pub fn new(key: &[u8]) -> Self {
        let mut hashed_key;
        let new_key;
        if key.len() > H::BLOCK_SIZE {
            hashed_key = [0; MAX_DIGEST_SIZE];
            let mut hash_function = H::default();
            hash_function.update(key);
            hash_function.write_digest(&mut hashed_key[..H::DIGEST_SIZE]);
            new_key = &hashed_key[..H::DIGEST_SIZE];
        } else {
            new_key = key;
        }
        Self {
            inner_hash_function: Self::keyed_hash_function(new_key, IPAD),
            outer_hash_function: Self::keyed_hash_function(new_key, OPAD),
        }
    }

    /// Feeds input into the function to update its state.
    pub fn update(&mut self, input: &[u8]) {
        self.inner_hash_function.update(input);
    }

    /// Outputs a `Digest` containing the HMAC result.
    pub fn digest(self) -> Digest {
        let mut buffer = [0; MAX_DIGEST_SIZE];
        self.write_digest(&mut buffer[..H::DIGEST_SIZE]);
        Digest {
            buffer: buffer,
            size: H::DIGEST_SIZE,
        }
    }

    pub(crate) fn write_digest(mut self, output: &mut [u8]) {
        assert_eq!(H::DIGEST_SIZE, output.len());
        self.inner_hash_function.write_digest(output);
        self.outer_hash_function.update(output);
        self.outer_hash_function.write_digest(output);
    }

    fn keyed_hash_function(key: &[u8], pad: u8) -> H {
        let mut hash_function = H::default();
        for byte in key {
            hash_function.update(&[byte ^ pad]);
        }
        for _ in key.len()..H::BLOCK_SIZE {
            hash_function.update(&[pad]);
        }
        hash_function
    }
}

impl Deref for Digest {
    type Target = [u8];

    fn deref(&self) -> &Self::Target {
        &self.buffer[..self.size]
    }
}

impl AsRef<[u8]> for Digest {
    fn as_ref(&self) -> &[u8] {
        &self
    }
}

#[cfg(test)]
mod tests {
    use std::vec::Vec;
    use super::*;
    use test_helpers::*;

    fn check(exp512: &str, exp384: &str, exp256: &str, exp224: &str, key: &[u8], data: &[u8]) {
        macro_rules! check { ($function:ident, $wrapper:path, $expected:expr) => (
            let expected = h2b($expected);
            let actual = $wrapper(key, data);
            assert_eq!(expected, actual.to_vec());

            let actual = &mut vec![0; expected.len()];
            let mut hmac = Hmac::<$function>::new(key);
            for word in data.chunks(4) {
                hmac.update(word);
            }
            hmac.write_digest(actual);
            assert_eq!(expected, actual.to_vec());
        )}

        check!(Sha512, hmac_sha512, exp512);
        check!(Sha384, hmac_sha384, exp384);
        check!(Sha256, hmac_sha256, exp256);
        check!(Sha224, hmac_sha224, exp224);
    }

    #[test]
    fn test_digest() {
        let key = &h2b("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
        let data = b"Hi There";
        let exp512 = "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cde\
                      daa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854";
        let exp384 = "afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59c\
                      faea9ea9076ede7f4af152e8b2fa9cb6";
        let exp256 = "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7";
        let exp224 = "896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22";
        check(exp512, exp384, exp256, exp224, key, data);

        let key = b"Jefe";
        let data = b"what do ya want for nothing?";
        let exp512 = "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea250554\
                      9758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737";
        let exp384 = "af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e\
                      8e2240ca5e69e2c78b3239ecfab21649";
        let exp256 = "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843";
        let exp224 = "a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44";
        check(exp512, exp384, exp256, exp224, key, data);

        let key = &[0xaa; 20];
        let data = &[0xdd; 50];
        let exp512 = "fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39\
                      bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb";
        let exp384 = "88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e55966144b\
                      2a5ab39dc13814b94e3ab6e101a34f27";
        let exp256 = "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe";
        let exp224 = "7fb3cb3588c6c1f6ffa9694d7d6ad2649365b0c1f65d69d1ec8333ea";
        check(exp512, exp384, exp256, exp224, key, data);

        let key: &Vec<_> = &(0x01..0x1a).collect();
        let data = &[0xcd; 50];
        let exp512 = "b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3db\
                      a91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd";
        let exp384 = "3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e1f573b4e\
                      6801dd23c4a7d679ccf8a386c674cffb";
        let exp256 = "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b";
        let exp224 = "6c11506874013cac6a2abc1bb382627cec6a90d86efc012de7afec5a";
        check(exp512, exp384, exp256, exp224, key, data);

        let key = &[0xaa; 131];
        let data = b"Test Using Larger Than Block-Size Key - Hash Key First";
        let exp512 = "80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f352\
                      6b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598";
        let exp384 = "4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05033ac4c6\
                      0c2ef6ab4030fe8296248df163f44952";
        let exp256 = "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54";
        let exp224 = "95e9a0db962095adaebe9b2d6f0dbce2d499f112f2d2b7273fa6870e";
        check(exp512, exp384, exp256, exp224, key, data);

        let data =
            b"This is a test using a larger than block-size key and a larger than block-\
              size data. The key needs to be hashed before being used by the HMAC algorithm.";
        let exp512 = "e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944\
                      b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58";
        let exp384 = "6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82461e99c5\
                      a678cc31e799176d3860e6110c46523e";
        let exp256 = "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2";
        let exp224 = "3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1";
        check(exp512, exp384, exp256, exp224, key, data);
    }
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate xml;

use std::io::Read;

pub struct Client {
    http_client: hyper::Client,
    server_uri: String,
}

impl Client {
    pub fn new(server_uri: String) -> Client {
        Client {
            http_client: hyper::Client::new(),
            server_uri: server_uri,
        }
    }

    pub fn request(&self, function_name: String, parameters: &Vec<(String, String)>) -> String {
        let mut body = Vec::<u8>::new();
        {
            let mut writer = xml::EventWriter::new(&mut body);
            writer.write(xml::writer::XmlEvent::start_element("methodCall")).unwrap();
            writer.write(xml::writer::XmlEvent::start_element("methodName")).unwrap();
            writer.write(xml::writer::XmlEvent::characters(function_name.as_str())).unwrap();
            writer.write(xml::writer::XmlEvent::end_element()).unwrap();
            writer.write(xml::writer::XmlEvent::start_element("params")).unwrap();
            for param in parameters {
                writer.write(xml::writer::XmlEvent::start_element(param.0.as_str())).unwrap();
                writer.write(xml::writer::XmlEvent::start_element("value")).unwrap();
                writer.write(xml::writer::XmlEvent::start_element("string")).unwrap();
                writer.write(xml::writer::XmlEvent::characters(param.1.as_str())).unwrap();
                writer.write(xml::writer::XmlEvent::end_element()).unwrap();
                writer.write(xml::writer::XmlEvent::end_element()).unwrap();
                writer.write(xml::writer::XmlEvent::end_element()).unwrap();
            }
            writer.write(xml::writer::XmlEvent::end_element()).unwrap();
            writer.write(xml::writer::XmlEvent::end_element()).unwrap();
        }
        println!("{}", String::from_utf8(body.clone()).unwrap());

        let mut res = self.http_client
            .post(self.server_uri.as_str())
            .body(String::from_utf8(body).unwrap().as_str())
            .send()
            .unwrap();

        let mut buf = String::new();
        res.read_to_string(&mut buf).unwrap();
        buf
    }
}
<commit_msg>Remove debug string<commit_after>extern crate hyper;
extern crate xml;

use std::io::Read;

pub struct Client {
    http_client: hyper::Client,
    server_uri: String,
}

impl Client {
    pub fn new(server_uri: String) -> Client {
        Client {
            http_client: hyper::Client::new(),
            server_uri: server_uri,
        }
    }

    pub fn request(&self, function_name: String, parameters: &Vec<(String, String)>) -> String {
        let mut body = Vec::<u8>::new();
        {
            let mut writer = xml::EventWriter::new(&mut body);
            writer.write(xml::writer::XmlEvent::start_element("methodCall")).unwrap();
            writer.write(xml::writer::XmlEvent::start_element("methodName")).unwrap();
            writer.write(xml::writer::XmlEvent::characters(function_name.as_str())).unwrap();
            writer.write(xml::writer::XmlEvent::end_element()).unwrap();
            writer.write(xml::writer::XmlEvent::start_element("params")).unwrap();
            for param in parameters {
                writer.write(xml::writer::XmlEvent::start_element(param.0.as_str())).unwrap();
                writer.write(xml::writer::XmlEvent::start_element("value")).unwrap();
                writer.write(xml::writer::XmlEvent::start_element("string")).unwrap();
                writer.write(xml::writer::XmlEvent::characters(param.1.as_str())).unwrap();
                writer.write(xml::writer::XmlEvent::end_element()).unwrap();
                writer.write(xml::writer::XmlEvent::end_element()).unwrap();
                writer.write(xml::writer::XmlEvent::end_element()).unwrap();
            }
            writer.write(xml::writer::XmlEvent::end_element()).unwrap();
            writer.write(xml::writer::XmlEvent::end_element()).unwrap();
        }

        let mut res = self.http_client
            .post(self.server_uri.as_str())
            .body(String::from_utf8(body).unwrap().as_str())
            .send()
            .unwrap();

        let mut buf = String::new();
        res.read_to_string(&mut buf).unwrap();
        buf
    }
}
<|endoftext|>


<commit_before>extern crate getopts;
extern crate term;

extern crate otp_cop;

use std::{env, thread};
use std::sync::{mpsc, Arc};

use otp_cop::service::{CreateServiceResult, ServiceFactory};

struct ParallelIter<T> {
    count: usize,
    pos: usize,
    rx: mpsc::Receiver<T>
}

impl<T> Iterator for ParallelIter<T> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        if self.pos < self.count {
            self.count += 1;
            return self.rx.recv().ok();
        } else {
            return None;
        }
    }
}

fn parallel<T, U, F1>(objs: Vec<T>, f1: F1) -> ParallelIter<U>
        where F1: 'static + Fn(T) -> U + Send + Sync, T: 'static + Send, U: 'static + Send {
    let (tx, rx) = mpsc::channel();
    let count = objs.len();
    let shared_f1 = Arc::new(f1);
    for o in objs {
        let f1 = shared_f1.clone();
        let tx = tx.clone();
        thread::spawn(move || {
            tx.send(f1(o)).unwrap();
        });
    }

    return ParallelIter{count: count, pos: 0, rx: rx};
}

fn main() {
    let service_factories = vec![
        Box::new(otp_cop::SlackServiceFactory) as Box<ServiceFactory>,
        Box::new(otp_cop::GithubServiceFactory) as Box<ServiceFactory>,
    ];

    let mut opts = getopts::Options::new();

    for factory in service_factories.iter() {
        factory.add_options(&mut opts);
    }

    let matches = match opts.parse(env::args().skip(1)) {
        Ok(matches) => matches,
        Err(e) => panic!(e.to_string()),
    };

    let mut services = vec![];

    for factory in service_factories.iter() {
        match factory.create_service(&matches) {
            CreateServiceResult::Service(s) => services.push(s),
            CreateServiceResult::MissingArguments(arg) => panic!(format!("Missing arguments: {:?}", arg)),
            CreateServiceResult::None => continue,
        }
    }

    if services.is_empty() {
        print!("{}", opts.usage("otp-cop: <args>"));
    }

    let count = services.len();
    for (i, result) in parallel(services, |service| service.get_users()).enumerate() {
        match result {
            Ok(result) => {
                let header = format!("{} ({})", result.service_name, result.users.len());
                println!("{}", header);
                println!("{}", repeat_char("=", header.len()));
                println!("");
                for user in result.users {
                    let email = match user.email {
                        Some(email) => format!(" ({})", email),
                        None => "".to_string(),
                    };
                    let details = match user.details {
                        Some(details) => format!(" -- {}", details),
                        None => "".to_string(),
                    };
                    println!("@{}{}{}", user.name, email, details);
                }
                if i + 1 != count {
                    println!("");
                    println!("");
                }
            },
            Err(e) => {
                let mut t = term::stderr().unwrap();
                t.fg(term::color::RED).unwrap();
                writeln!(t, "{}", e.service_name).unwrap();
                writeln!(t, "{}", repeat_char("=", e.service_name.len())).unwrap();
                writeln!(t, "").unwrap();
                writeln!(t, "{}", e.error_message).unwrap();
                t.reset().unwrap();
            }
        }
    }
}

fn repeat_char(c: &'static str, length: usize) -> String {
    return c.chars().cycle().take(length).collect::<String>();
}
<commit_msg>Write to stderr like an adult instead of panicing<commit_after>extern crate getopts;
extern crate term;

extern crate otp_cop;

use std::{env, io, process, thread};
use std::io::Write;
use std::sync::{mpsc, Arc};

use otp_cop::service::{CreateServiceResult, ServiceFactory};

struct ParallelIter<T> {
    count: usize,
    pos: usize,
    rx: mpsc::Receiver<T>
}

impl<T> Iterator for ParallelIter<T> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        if self.pos < self.count {
            self.count += 1;
            return self.rx.recv().ok();
        } else {
            return None;
        }
    }
}

fn parallel<T, U, F1>(objs: Vec<T>, f1: F1) -> ParallelIter<U>
        where F1: 'static + Fn(T) -> U + Send + Sync, T: 'static + Send, U: 'static + Send {
    let (tx, rx) = mpsc::channel();
    let count = objs.len();
    let shared_f1 = Arc::new(f1);
    for o in objs {
        let f1 = shared_f1.clone();
        let tx = tx.clone();
        thread::spawn(move || {
            tx.send(f1(o)).unwrap();
        });
    }

    return ParallelIter{count: count, pos: 0, rx: rx};
}

fn main() {
    let service_factories = vec![
        Box::new(otp_cop::SlackServiceFactory) as Box<ServiceFactory>,
        Box::new(otp_cop::GithubServiceFactory) as Box<ServiceFactory>,
    ];

    let mut opts = getopts::Options::new();

    for factory in service_factories.iter() {
        factory.add_options(&mut opts);
    }

    let matches = match opts.parse(env::args().skip(1)) {
        Ok(matches) => matches,
        Err(e) => {
            writeln!(io::stderr(), "{}", e.to_string()).unwrap();
            process::exit(1);
        }
    };

    let mut services = vec![];

    for factory in service_factories.iter() {
        match factory.create_service(&matches) {
            CreateServiceResult::Service(s) => services.push(s),
            CreateServiceResult::MissingArguments(args) => {
                writeln!(io::stderr(), "Missing arguments: {:?}", args).unwrap();
                process::exit(1);
            }
            CreateServiceResult::None => continue,
        }
    }

    if services.is_empty() {
        writeln!(io::stderr(), "{}", opts.usage("otp-cop: <args>")).unwrap();
        process::exit(1);
    }

    let count = services.len();
    for (i, result) in parallel(services, |service| service.get_users()).enumerate() {
        match result {
            Ok(result) => {
                let header = format!("{} ({})", result.service_name, result.users.len());
                println!("{}", header);
                println!("{}", repeat_char("=", header.len()));
                println!("");
                for user in result.users {
                    let email = match user.email {
                        Some(email) => format!(" ({})", email),
                        None => "".to_string(),
                    };
                    let details = match user.details {
                        Some(details) => format!(" -- {}", details),
                        None => "".to_string(),
                    };
                    println!("@{}{}{}", user.name, email, details);
                }
                if i + 1 != count {
                    println!("");
                    println!("");
                }
            },
            Err(e) => {
                let mut t = term::stderr().unwrap();
                t.fg(term::color::RED).unwrap();
                writeln!(t, "{}", e.service_name).unwrap();
                writeln!(t, "{}", repeat_char("=", e.service_name.len())).unwrap();
                writeln!(t, "").unwrap();
                writeln!(t, "{}", e.error_message).unwrap();
                t.reset().unwrap();
            }
        }
    }
}

fn repeat_char(c: &'static str, length: usize) -> String {
    return c.chars().cycle().take(length).collect::<String>();
}
<|endoftext|>