<commit_before>#[derive(Clone)]
#[derive(Debug)]
pub enum CellState
{
	Dead,
	Alive
}

pub struct Simulator {
	iteration_num: u32,
	height: usize,
	width: usize,
	output_dir: String,
	starting_states: Vec<Vec<CellState>>,
	current_iteration: u32,
}

impl<'a> Simulator {
	pub fn new(iteration_num: u32, output_dir: String,
		starting_states: Vec<Vec<CellState>>) -> Simulator {
		// TODO: modify so starting_states dimensions are verified correct
		Simulator {
			iteration_num: iteration_num,
			height: starting_states.len(),
			width: starting_states[0].len(),
			output_dir: output_dir,
			starting_states: starting_states,
			current_iteration: 0,
		}
	}

	pub fn run_simulation(&mut self) {
		// Set up first cells
		let mut current_states = Vec::new();
		for x in 0..self.starting_states.len() {
			let mut row = Vec::new();
			for y in 0..self.starting_states[x].len() {
				row.push(Cell {
					state: self.starting_states[x][y].clone(),
					row: x,
					col: y,
				});
			}
			current_states.push(row);
		}
		loop {
			println!("");
			// Create new states
			let mut new_states = Vec::new();
			for x in 0..self.height {
				let mut new_row = Vec::new();
				for y in 0..self.width {
					let cell = current_states[x][y].clone();
					let new_cell = cell.iterate(&current_states);
					new_row.push(new_cell);
				}
				new_states.push(new_row);
			}
			// Set current states
			current_states = new_states;
			// TODO: Output
			// DEBUG: print current states
			let debug_states = current_states.clone();
			println!("States at end of iteration: {}", self.current_iteration);
			for row in debug_states.clone() {
				for cell in row {
					print!("{:?}, ", cell.state);
				}
				println!("");
			}
			// Increment iteration
			self.current_iteration += 1;
			if self.current_iteration == self.iteration_num {
				break;
			}
		}
	}
}

#[derive(Clone)]
struct Cell {
	state: CellState,
	row: usize,
	col: usize,
}

impl Cell {
	fn iterate(self, prev_state: &Vec<Vec<Cell>>) -> Cell {
		// TODO: write rules for Conways Game of Life
		return Cell {
			state: match self.state {
				CellState::Dead => CellState::Alive,
				CellState::Alive => CellState::Dead,
			},
			row: self.row,
			col: self.col,
		};
	}
}<commit_msg>Added starting states dimensions checking<commit_after>#[derive(Clone)]
#[derive(Debug)]
pub enum CellState
{
	Dead,
	Alive
}

pub struct Simulator {
	iteration_num: u32,
	height: usize,
	width: usize,
	output_dir: String,
	starting_states: Vec<Vec<CellState>>,
	current_iteration: u32,
}

impl<'a> Simulator {
	pub fn new(iteration_num: u32, output_dir: String,
		starting_states: Vec<Vec<CellState>>) -> Simulator {
		if starting_states.len() < 1 {
			panic!("not enough rows");
		}
		let row_length = starting_states[0].len();
		for row in &starting_states {
			if row.len() != row_length {
				panic!("row lengths do not match");
			}
		}
		Simulator {
			iteration_num: iteration_num,
			height: starting_states.len(),
			width: starting_states[0].len(),
			output_dir: output_dir,
			starting_states: starting_states,
			current_iteration: 0,
		}
	}

	pub fn run_simulation(&mut self) {
		// Set up first cells
		let mut current_states = Vec::new();
		for x in 0..self.starting_states.len() {
			let mut row = Vec::new();
			for y in 0..self.starting_states[x].len() {
				row.push(Cell {
					state: self.starting_states[x][y].clone(),
					row: x,
					col: y,
				});
			}
			current_states.push(row);
		}
		loop {
			println!("");
			// Create new states
			let mut new_states = Vec::new();
			for x in 0..self.height {
				let mut new_row = Vec::new();
				for y in 0..self.width {
					let cell = current_states[x][y].clone();
					let new_cell = cell.iterate(&current_states);
					new_row.push(new_cell);
				}
				new_states.push(new_row);
			}
			// Set current states
			current_states = new_states;
			// TODO: Output
			// DEBUG: print current states
			let debug_states = current_states.clone();
			println!("States at end of iteration: {}", self.current_iteration);
			for row in debug_states.clone() {
				for cell in row {
					print!("{:?}, ", cell.state);
				}
				println!("");
			}
			// Increment iteration
			self.current_iteration += 1;
			if self.current_iteration == self.iteration_num {
				break;
			}
		}
	}
}

#[derive(Clone)]
struct Cell {
	state: CellState,
	row: usize,
	col: usize,
}

impl Cell {
	fn iterate(self, prev_state: &Vec<Vec<Cell>>) -> Cell {
		// TODO: write rules for Conways Game of Life
		return Cell {
			state: match self.state {
				CellState::Dead => CellState::Alive,
				CellState::Alive => CellState::Dead,
			},
			row: self.row,
			col: self.col,
		};
	}
}<|endoftext|>


<commit_before>use termion::{async_stdin, AsyncReader};
use std::collections::VecDeque;
use std::io::Read;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Key {
    Printable(char),
    Up,
    Down,
    Left,
    Right,
    Ins,
    Del,
    Home,
    End,
    PageUp,
    PageDown,
    Close,
    Backspace,
    Return,
    Esc,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Modifier {
    None(Key),
    Alt(Key),
    Ctrl(Key),
    Shift(Key),
    Meta(Key),
}

pub enum Utf8 {
    Parsing(Option<u8>, Option<u8>, Option<u8>),
    Done(char),
    Invalid,
}

impl Utf8 {
    fn new() -> Utf8 { Utf8::Parsing(None, None, None) }
    fn extend(&self, byte: u8) -> Utf8 {
        match *self {
            Utf8::Parsing(None, None, None) => {
                if byte & 0x80 == 0 {
                    ::std::char::from_u32(byte as u32).map(|x|Utf8::Done(x)).unwrap_or(Utf8::Invalid)
                } else if byte & 0xE0 == 0xC0 ||
                    byte & 0xF0 == 0xE0 ||
                    byte & 0xF8 == 0xF0
                {
                    Utf8::Parsing(Some(byte), None, None)
                } else {
                    Utf8::Invalid
                }
            },
            Utf8::Parsing(Some(b), None, None) => {
                if byte & 0xC0 != 0x80 {
                    Utf8::Invalid
                } else if b & 0xE0 == 0xC0 {
                    let val = ((b as u32 & 0x1F) << 6) | (byte as u32 & 0x3F);
                    ::std::char::from_u32(val).map(|x|Utf8::Done(x)).unwrap_or(Utf8::Invalid)
                } else {
                    Utf8::Parsing(Some(b), Some(byte), None)
                }
            },
            Utf8::Parsing(Some(b), Some(b1), None) => {
                if byte & 0xC0 != 0x80 {
                    Utf8::Invalid
                } else if b & 0xF0 == 0xE0 {
                    let val = ((b as u32 & 0x0F) << 12) |
                        ((b1 as u32 & 0x3F) << 6) |
                        (byte as u32 & 0x3F);
                    ::std::char::from_u32(val).map(|x|Utf8::Done(x)).unwrap_or(Utf8::Invalid)
                } else {
                    Utf8::Parsing(Some(b), Some(byte), None)
                }
            },
            Utf8::Parsing(Some(b), Some(b1), Some(b2)) => {
                if byte & 0xC0 != 0x80 {
                    Utf8::Invalid
                } else if b & 0xF8 == 0xF0 {
                    let val = ((b as u32 & 0x07) << 18) |
                        ((b1 as u32 & 0x3F) << 12) |
                        ((b2 as u32 & 0x3F) << 6) |
                        (byte as u32 & 0x3F);
                    ::std::char::from_u32(val).map(|x|Utf8::Done(x)).unwrap_or(Utf8::Invalid)
                } else {
                    Utf8::Invalid
                }
            },
            _ => Utf8::Invalid,
        }
    }
}

fn is_printable(c: char) -> bool {
    let c = c as u32;
    !(c < 0x20 || (c >= 0x7f &&  c < 0xa0))
}

pub struct TermIterator {
    stream: AsyncReader,
    buffer: VecDeque<u8>,
}

impl TermIterator {
    fn new() -> Self {
        TermIterator {
            stream: async_stdin(),
            buffer: VecDeque::new(),
        }
    }
}

impl Iterator for TermIterator {
    type Item = u8;

    fn next(&mut self) -> Option<Self::Item> {
        match self.buffer.pop_front() {
            next @ Some(..) => next,
            None => {
                let mut buf = [0; 1024];
                if let Ok(bytes) = self.stream.read(&mut buf) {
                    self.buffer.extend(&buf[0..bytes])
                }
                self.buffer.pop_front()
            }
        }
    }
}

pub struct Utf8Iterator<T> {
    state: Utf8,
    stream: T,
}

impl<T> Utf8Iterator<T> where T: Iterator<Item=u8> {
    fn new(stream: T) -> Self {
        Utf8Iterator {
            state: Utf8::new(),
            stream: stream,
        }
    }
}

impl<T> Iterator for Utf8Iterator<T> where T: Iterator<Item=u8> {
    type Item = char;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            let c = self.stream.next();
            if c.is_none() {
                return None;
            }
            let c = c.unwrap();

            self.state = self.state.extend(c);
            match self.state {
                Utf8::Parsing(..) => continue,
                Utf8::Invalid => {
                    error!("Invalid");
                    self.state = Utf8::new();
                    continue
                },
                Utf8::Done(c) => {
                    self.state = Utf8::new();
                    return Some(c);
                },
            }
        }
    }
}

pub struct KeyIterator<T> {
    stream: T,
    escape_buffer: String,
    escaping: bool,
    alt: bool,
}

pub type KeyReader = KeyIterator<Utf8Iterator<TermIterator>>;
impl<T> KeyIterator<T> {
    pub fn stdin() -> KeyIterator<Utf8Iterator<TermIterator>> {
        KeyIterator {
            stream: Utf8Iterator::new(TermIterator::new()),
            escape_buffer: String::new(),
            escaping: false,
            alt: false,
        }
    }
}

impl<T> Iterator for KeyIterator<T> where T: Iterator<Item=char> {
    type Item = Modifier;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            let next = if !self.escaping && self.escape_buffer.len() != 0 {
                self.escape_buffer.remove(0)
            } else {
                let next = self.stream.next();
                if next.is_none() {
                    if self.escape_buffer == "\x1b" {
                        self.escaping = false;
                        self.escape_buffer.clear();
                        if self.alt {
                            self.alt = false;
                            return Some(Modifier::Alt(Key::Esc));
                        } else {
                            return Some(Modifier::None(Key::Esc));
                        }
                    } else {
                        return None;
                    }
                } else {
                    next.unwrap()
                }
            };

            if next == '\x1b' { self.escaping = true; }

            if self.escaping {
                self.escaping = false;
                self.escape_buffer.push(next);
                let escaped_key = match &*self.escape_buffer {
                    "\x1b"   | "\x1b["  | "\x1b[2" |
                    "\x1b[3" | "\x1b[5" | "\x1b[6" |
                    "\x1b[7" | "\x1b[8" => {
                        self.escaping = true;
                        None
                    },
                    "\x1b[A" => Some(Key::Up),
                    "\x1b[B" => Some(Key::Down),
                    "\x1b[C" => Some(Key::Right),
                    "\x1b[D" => Some(Key::Left),
                    "\x1b[2~" => Some(Key::Ins),
                    "\x1b[3~" => Some(Key::Del),
                    "\x1b[5~" => Some(Key::PageUp),
                    "\x1b[6~" => Some(Key::PageDown),
                    "\x1b[7~" => Some(Key::Home),
                    "\x1b[8~" => Some(Key::End),
                    _ => None,
                };

                if escaped_key.is_some() {
                    self.escape_buffer.clear();
                    return if self.alt {
                        self.alt = false;
                        escaped_key.map(|k| Modifier::Alt(k))
                    } else {
                        escaped_key.map(|k| Modifier::None(k))
                    }
                }

                if !self.escaping {
                    self.escape_buffer.remove(0);
                    self.alt = true;
                }

                continue;
            }

            let key = match next {
                '\x03' => Some(Key::Close),
                '\x7F' => Some(Key::Backspace),
                '\x0D' => Some(Key::Return),
                '\x0A' => None,
                key => {
                    if is_printable(key) {
                        Some(Key::Printable(key))
                    } else {
                        None
                    }
                },
            };

            if key.is_none() { continue; }

            return if self.alt {
                self.alt = false;
                Some(Modifier::Alt(key.unwrap()))
            } else {
                Some(Modifier::None(key.unwrap()))
            }
        }
    }
}

<commit_msg>Add basic Ctrl modifier<commit_after>use termion::{async_stdin, AsyncReader};
use std::collections::VecDeque;
use std::io::Read;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Key {
    Printable(char),
    Up,
    Down,
    Left,
    Right,
    Ins,
    Del,
    Home,
    End,
    PageUp,
    PageDown,
    Close,
    Backspace,
    Return,
    Esc,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Modifier {
    None(Key),
    Alt(Key),
    Ctrl(Key),
    Shift(Key),
    Meta(Key),
}

pub enum Utf8 {
    Parsing(Option<u8>, Option<u8>, Option<u8>),
    Done(char),
    Invalid,
}

impl Utf8 {
    fn new() -> Utf8 { Utf8::Parsing(None, None, None) }
    fn extend(&self, byte: u8) -> Utf8 {
        match *self {
            Utf8::Parsing(None, None, None) => {
                if byte & 0x80 == 0 {
                    ::std::char::from_u32(byte as u32).map(|x|Utf8::Done(x)).unwrap_or(Utf8::Invalid)
                } else if byte & 0xE0 == 0xC0 ||
                    byte & 0xF0 == 0xE0 ||
                    byte & 0xF8 == 0xF0
                {
                    Utf8::Parsing(Some(byte), None, None)
                } else {
                    Utf8::Invalid
                }
            },
            Utf8::Parsing(Some(b), None, None) => {
                if byte & 0xC0 != 0x80 {
                    Utf8::Invalid
                } else if b & 0xE0 == 0xC0 {
                    let val = ((b as u32 & 0x1F) << 6) | (byte as u32 & 0x3F);
                    ::std::char::from_u32(val).map(|x|Utf8::Done(x)).unwrap_or(Utf8::Invalid)
                } else {
                    Utf8::Parsing(Some(b), Some(byte), None)
                }
            },
            Utf8::Parsing(Some(b), Some(b1), None) => {
                if byte & 0xC0 != 0x80 {
                    Utf8::Invalid
                } else if b & 0xF0 == 0xE0 {
                    let val = ((b as u32 & 0x0F) << 12) |
                        ((b1 as u32 & 0x3F) << 6) |
                        (byte as u32 & 0x3F);
                    ::std::char::from_u32(val).map(|x|Utf8::Done(x)).unwrap_or(Utf8::Invalid)
                } else {
                    Utf8::Parsing(Some(b), Some(byte), None)
                }
            },
            Utf8::Parsing(Some(b), Some(b1), Some(b2)) => {
                if byte & 0xC0 != 0x80 {
                    Utf8::Invalid
                } else if b & 0xF8 == 0xF0 {
                    let val = ((b as u32 & 0x07) << 18) |
                        ((b1 as u32 & 0x3F) << 12) |
                        ((b2 as u32 & 0x3F) << 6) |
                        (byte as u32 & 0x3F);
                    ::std::char::from_u32(val).map(|x|Utf8::Done(x)).unwrap_or(Utf8::Invalid)
                } else {
                    Utf8::Invalid
                }
            },
            _ => Utf8::Invalid,
        }
    }
}

fn is_printable(c: char) -> bool {
    let c = c as u32;
    !(c < 0x20 || (c >= 0x7f &&  c < 0xa0))
}

pub struct TermIterator {
    stream: AsyncReader,
    buffer: VecDeque<u8>,
}

impl TermIterator {
    fn new() -> Self {
        TermIterator {
            stream: async_stdin(),
            buffer: VecDeque::new(),
        }
    }
}

impl Iterator for TermIterator {
    type Item = u8;

    fn next(&mut self) -> Option<Self::Item> {
        match self.buffer.pop_front() {
            next @ Some(..) => next,
            None => {
                let mut buf = [0; 1024];
                if let Ok(bytes) = self.stream.read(&mut buf) {
                    self.buffer.extend(&buf[0..bytes])
                }
                self.buffer.pop_front()
            }
        }
    }
}

pub struct Utf8Iterator<T> {
    state: Utf8,
    stream: T,
}

impl<T> Utf8Iterator<T> where T: Iterator<Item=u8> {
    fn new(stream: T) -> Self {
        Utf8Iterator {
            state: Utf8::new(),
            stream: stream,
        }
    }
}

impl<T> Iterator for Utf8Iterator<T> where T: Iterator<Item=u8> {
    type Item = char;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            let c = self.stream.next();
            if c.is_none() {
                return None;
            }
            let c = c.unwrap();

            self.state = self.state.extend(c);
            match self.state {
                Utf8::Parsing(..) => continue,
                Utf8::Invalid => {
                    self.state = Utf8::new();
                    continue
                },
                Utf8::Done(c) => {
                    self.state = Utf8::new();
                    return Some(c);
                },
            }
        }
    }
}

pub struct KeyIterator<T> {
    stream: T,
    escape_buffer: String,
    escaping: bool,
    alt: bool,
}

pub type KeyReader = KeyIterator<Utf8Iterator<TermIterator>>;
impl<T> KeyIterator<T> {
    pub fn stdin() -> KeyIterator<Utf8Iterator<TermIterator>> {
        KeyIterator {
            stream: Utf8Iterator::new(TermIterator::new()),
            escape_buffer: String::new(),
            escaping: false,
            alt: false,
        }
    }
}

impl<T> Iterator for KeyIterator<T> where T: Iterator<Item=char> {
    type Item = Modifier;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            let next = if !self.escaping && self.escape_buffer.len() != 0 {
                self.escape_buffer.remove(0)
            } else {
                let next = self.stream.next();
                if next.is_none() {
                    if self.escape_buffer == "\x1b" {
                        self.escaping = false;
                        self.escape_buffer.clear();
                        if self.alt {
                            self.alt = false;
                            return Some(Modifier::Alt(Key::Esc));
                        } else {
                            return Some(Modifier::None(Key::Esc));
                        }
                    } else {
                        return None;
                    }
                } else {
                    next.unwrap()
                }
            };

            if next == '\x1b' { self.escaping = true; }

            if self.escaping {
                self.escaping = false;
                self.escape_buffer.push(next);
                let escaped_key = match &*self.escape_buffer {
                    "\x1b"   | "\x1b["  | "\x1b[2" |
                    "\x1b[3" | "\x1b[5" | "\x1b[6" |
                    "\x1b[7" | "\x1b[8" => {
                        self.escaping = true;
                        None
                    },
                    "\x1b[A" => Some(Key::Up),
                    "\x1b[B" => Some(Key::Down),
                    "\x1b[C" => Some(Key::Right),
                    "\x1b[D" => Some(Key::Left),
                    "\x1b[2~" => Some(Key::Ins),
                    "\x1b[3~" => Some(Key::Del),
                    "\x1b[5~" => Some(Key::PageUp),
                    "\x1b[6~" => Some(Key::PageDown),
                    "\x1b[7~" => Some(Key::Home),
                    "\x1b[8~" => Some(Key::End),
                    _ => None,
                };

                if escaped_key.is_some() {
                    self.escape_buffer.clear();
                    return if self.alt {
                        self.alt = false;
                        escaped_key.map(|k| Modifier::Alt(k))
                    } else {
                        escaped_key.map(|k| Modifier::None(k))
                    }
                }

                if !self.escaping {
                    self.escape_buffer.remove(0);
                    self.alt = true;
                }

                continue;
            }

            let key = match next {
                '\x03' => Some(Key::Close),
                '\x7F' => Some(Key::Backspace),
                '\x0D' => Some(Key::Return),
                '\x0A' => None,
                key => {
                    if is_printable(key) {
                        Some(Key::Printable(key))
                    } else {
                        let key32 = key as u32;
                        if key32 < 0x20 {
                            let key = (key32 as u8 + 0x60) as char;
                            return Some(Modifier::Ctrl(Key::Printable(key)));
                        } else {
                            None
                        }
                    }
                },
            };

            if key.is_none() { continue; }

            return if self.alt {
                self.alt = false;
                Some(Modifier::Alt(key.unwrap()))
            } else {
                Some(Modifier::None(key.unwrap()))
            }
        }
    }
}

<|endoftext|>


<commit_before>#[test]
use core::num::{Zero, One};
#[test]
use core::rand::{random};
#[test]
use core::vec::{all, all2};
#[test]
use std::cmp::FuzzyEq;
#[test]
use dim3::vec3::Vec3;
#[test]
use dim2::vec2::Vec2;
#[test]
use dim1::vec1::Vec1;
#[test]
use ndim::nvec::NVec;
#[test]
use traits::dim::d7;
#[test]
use traits::basis::Basis;

#[test]
fn test_cross_vec3()
{
  for uint::range(0u, 10000u) |_|
  {
    let v1 : Vec3<f64> = random();
    let v2 : Vec3<f64> = random();
    let v3 : Vec3<f64> = v1.cross(&v2);

    assert!(v3.dot(&v2).fuzzy_eq(&Zero::zero()));
    assert!(v3.dot(&v1).fuzzy_eq(&Zero::zero()));
  }
}

#[test]
fn test_dot_nvec()
{
  for uint::range(0u, 10000u) |_|
  {
    let v1 : NVec<d7, f64> = random();
    let v2 : NVec<d7, f64> = random();

    assert!(v1.dot(&v2).fuzzy_eq(&v2.dot(&v1)));
  }
}

#[test]
fn test_commut_dot_vec3()
{
  for uint::range(0u, 10000u) |_|
  {
    let v1 : Vec3<f64> = random();
    let v2 : Vec3<f64> = random();

    assert!(v1.dot(&v2).fuzzy_eq(&v2.dot(&v1)));
  }
}

#[test]
fn test_commut_dot_vec2()
{
  for uint::range(0u, 10000u) |_|
  {
    let v1 : Vec2<f64> = random();
    let v2 : Vec2<f64> = random();

    assert!(v1.dot(&v2).fuzzy_eq(&v2.dot(&v1)));
  }
}

#[test]
fn test_commut_dot_vec1()
{
  for uint::range(0u, 10000u) |_|
  {
    let v1 : Vec1<f64> = random();
    let v2 : Vec1<f64> = random();

    assert!(v1.dot(&v2).fuzzy_eq(&v2.dot(&v1)));
  }
}

#[test]
fn test_basis_vec1()
{
  for uint::range(0u, 10000u) |_|
  {
    let basis = Basis::canonical_basis::<Vec1<f64>>();

    // check vectors form an ortogonal basis
    assert!(all2(basis, basis, |e1, e2| e1 == e2 || e1.dot(e2).fuzzy_eq(&Zero::zero())));
    // check vectors form an orthonormal basis
    assert!(all(basis, |e| e.norm().fuzzy_eq(&One::one())));
  }
}

#[test]
fn test_basis_vec2()
{
  for uint::range(0u, 10000u) |_|
  {
    let basis = Basis::canonical_basis::<Vec2<f64>>();

    // check vectors form an ortogonal basis
    assert!(all2(basis, basis, |e1, e2| e1 == e2 || e1.dot(e2).fuzzy_eq(&Zero::zero())));
    // check vectors form an orthonormal basis
    assert!(all(basis, |e| e.norm().fuzzy_eq(&One::one())));
  }
}

#[test]
fn test_basis_vec3()
{
  for uint::range(0u, 10000u) |_|
  {
    let basis = Basis::canonical_basis::<Vec3<f64>>();

    // check vectors form an ortogonal basis
    assert!(all2(basis, basis, |e1, e2| e1 == e2 || e1.dot(e2).fuzzy_eq(&Zero::zero())));
    // check vectors form an orthonormal basis
    assert!(all(basis, |e| e.norm().fuzzy_eq(&One::one())));
  }
}

#[test]
fn test_basis_nvec()
{
  for uint::range(0u, 10000u) |_|
  {
    let basis = Basis::canonical_basis::<NVec<d7, f64>>();

    // check vectors form an ortogonal basis
    assert!(all2(basis, basis, |e1, e2| e1 == e2 || e1.dot(e2).fuzzy_eq(&Zero::zero())));
    // check vectors form an orthonormal basis
    assert!(all(basis, |e| e.norm().fuzzy_eq(&One::one())));
  }
}

#[test]
fn test_subspace_basis_vec1()
{
  for uint::range(0u, 10000u) |_|
  {
    let v : Vec1<f64> = random();
    let v1 = v.normalized();
    let subbasis = v1.orthogonal_subspace_basis();

    // check vectors are orthogonal to v1
    assert!(all(subbasis, |e| v1.dot(e).fuzzy_eq(&Zero::zero())));
    // check vectors form an ortogonal basis
    assert!(all2(subbasis, subbasis, |e1, e2| e1 == e2 || e1.dot(e2).fuzzy_eq(&Zero::zero())));
    // check vectors form an orthonormal basis
    assert!(all(subbasis, |e| e.norm().fuzzy_eq(&One::one())));
  }
}

#[test]
fn test_subspace_basis_vec2()
{
  for uint::range(0u, 10000u) |_|
  {
    let v : Vec2<f64> = random();
    let v1 = v.normalized();
    let subbasis = v1.orthogonal_subspace_basis();

    // check vectors are orthogonal to v1
    assert!(all(subbasis, |e| v1.dot(e).fuzzy_eq(&Zero::zero())));
    // check vectors form an ortogonal basis
    assert!(all2(subbasis, subbasis, |e1, e2| e1 == e2 || e1.dot(e2).fuzzy_eq(&Zero::zero())));
    // check vectors form an orthonormal basis
    assert!(all(subbasis, |e| e.norm().fuzzy_eq(&One::one())));
  }
}

#[test]
fn test_subspace_basis_vec3()
{
  for uint::range(0u, 10000u) |_|
  {
    let v : Vec3<f64> = random();
    let v1 = v.normalized();
    let subbasis = v1.orthogonal_subspace_basis();

    // check vectors are orthogonal to v1
    assert!(all(subbasis, |e| v1.dot(e).fuzzy_eq(&Zero::zero())));
    // check vectors form an ortogonal basis
    assert!(all2(subbasis, subbasis, |e1, e2| e1 == e2 || e1.dot(e2).fuzzy_eq(&Zero::zero())));
    // check vectors form an orthonormal basis
    assert!(all(subbasis, |e| e.norm().fuzzy_eq(&One::one())));
  }
}

// ICE
//
// #[test]
// fn test_subspace_basis_vecn()
// {
//   for uint::range(0u, 10000u) |_|
//   {
//     let v : NVec<d7, f64> = random();
//     let v1 = v.normalized();
//     let subbasis = v1.orthogonal_subspace_basis();
//
//     // check vectors are orthogonal to v1
//     assert!(all(subbasis, |e| v1.dot(e).fuzzy_eq(&Zero::zero())));
//     // check vectors form an ortogonal basis
//     assert!(all2(subbasis, subbasis, |e1, e2| e1 == e2 || e1.dot(e2).fuzzy_eq(&Zero::zero())));
//     // check vectors form an orthonormal basis
//     assert!(all(subbasis, |e| e.norm().fuzzy_eq(&One::one())));
//   }
// }
<commit_msg>Removed useless loops on basis test.<commit_after>#[test]
use core::num::{Zero, One};
#[test]
use core::rand::{random};
#[test]
use core::vec::{all, all2};
#[test]
use std::cmp::FuzzyEq;
#[test]
use dim3::vec3::Vec3;
#[test]
use dim2::vec2::Vec2;
#[test]
use dim1::vec1::Vec1;
#[test]
use ndim::nvec::NVec;
#[test]
use traits::dim::d7;
#[test]
use traits::basis::Basis;

#[test]
fn test_cross_vec3()
{
  for uint::range(0u, 10000u) |_|
  {
    let v1 : Vec3<f64> = random();
    let v2 : Vec3<f64> = random();
    let v3 : Vec3<f64> = v1.cross(&v2);

    assert!(v3.dot(&v2).fuzzy_eq(&Zero::zero()));
    assert!(v3.dot(&v1).fuzzy_eq(&Zero::zero()));
  }
}

#[test]
fn test_dot_nvec()
{
  for uint::range(0u, 10000u) |_|
  {
    let v1 : NVec<d7, f64> = random();
    let v2 : NVec<d7, f64> = random();

    assert!(v1.dot(&v2).fuzzy_eq(&v2.dot(&v1)));
  }
}

#[test]
fn test_commut_dot_vec3()
{
  for uint::range(0u, 10000u) |_|
  {
    let v1 : Vec3<f64> = random();
    let v2 : Vec3<f64> = random();

    assert!(v1.dot(&v2).fuzzy_eq(&v2.dot(&v1)));
  }
}

#[test]
fn test_commut_dot_vec2()
{
  for uint::range(0u, 10000u) |_|
  {
    let v1 : Vec2<f64> = random();
    let v2 : Vec2<f64> = random();

    assert!(v1.dot(&v2).fuzzy_eq(&v2.dot(&v1)));
  }
}

#[test]
fn test_commut_dot_vec1()
{
  for uint::range(0u, 10000u) |_|
  {
    let v1 : Vec1<f64> = random();
    let v2 : Vec1<f64> = random();

    assert!(v1.dot(&v2).fuzzy_eq(&v2.dot(&v1)));
  }
}

#[test]
fn test_basis_vec1()
{
  let basis = Basis::canonical_basis::<Vec1<f64>>();

  // check vectors form an ortogonal basis
  assert!(all2(basis, basis, |e1, e2| e1 == e2 || e1.dot(e2).fuzzy_eq(&Zero::zero())));
  // check vectors form an orthonormal basis
  assert!(all(basis, |e| e.norm().fuzzy_eq(&One::one())));
}

#[test]
fn test_basis_vec2()
{
  let basis = Basis::canonical_basis::<Vec2<f64>>();

  // check vectors form an ortogonal basis
  assert!(all2(basis, basis, |e1, e2| e1 == e2 || e1.dot(e2).fuzzy_eq(&Zero::zero())));
  // check vectors form an orthonormal basis
  assert!(all(basis, |e| e.norm().fuzzy_eq(&One::one())));
}

#[test]
fn test_basis_vec3()
{
  let basis = Basis::canonical_basis::<Vec3<f64>>();

  // check vectors form an ortogonal basis
  assert!(all2(basis, basis, |e1, e2| e1 == e2 || e1.dot(e2).fuzzy_eq(&Zero::zero())));
  // check vectors form an orthonormal basis
  assert!(all(basis, |e| e.norm().fuzzy_eq(&One::one())));
}

#[test]
fn test_basis_nvec()
{
  let basis = Basis::canonical_basis::<NVec<d7, f64>>();

  // check vectors form an ortogonal basis
  assert!(all2(basis, basis, |e1, e2| e1 == e2 || e1.dot(e2).fuzzy_eq(&Zero::zero())));
  // check vectors form an orthonormal basis
  assert!(all(basis, |e| e.norm().fuzzy_eq(&One::one())));
}

#[test]
fn test_subspace_basis_vec1()
{
  for uint::range(0u, 10000u) |_|
  {
    let v : Vec1<f64> = random();
    let v1 = v.normalized();
    let subbasis = v1.orthogonal_subspace_basis();

    // check vectors are orthogonal to v1
    assert!(all(subbasis, |e| v1.dot(e).fuzzy_eq(&Zero::zero())));
    // check vectors form an ortogonal basis
    assert!(all2(subbasis, subbasis, |e1, e2| e1 == e2 || e1.dot(e2).fuzzy_eq(&Zero::zero())));
    // check vectors form an orthonormal basis
    assert!(all(subbasis, |e| e.norm().fuzzy_eq(&One::one())));
  }
}

#[test]
fn test_subspace_basis_vec2()
{
  for uint::range(0u, 10000u) |_|
  {
    let v : Vec2<f64> = random();
    let v1 = v.normalized();
    let subbasis = v1.orthogonal_subspace_basis();

    // check vectors are orthogonal to v1
    assert!(all(subbasis, |e| v1.dot(e).fuzzy_eq(&Zero::zero())));
    // check vectors form an ortogonal basis
    assert!(all2(subbasis, subbasis, |e1, e2| e1 == e2 || e1.dot(e2).fuzzy_eq(&Zero::zero())));
    // check vectors form an orthonormal basis
    assert!(all(subbasis, |e| e.norm().fuzzy_eq(&One::one())));
  }
}

#[test]
fn test_subspace_basis_vec3()
{
  for uint::range(0u, 10000u) |_|
  {
    let v : Vec3<f64> = random();
    let v1 = v.normalized();
    let subbasis = v1.orthogonal_subspace_basis();

    // check vectors are orthogonal to v1
    assert!(all(subbasis, |e| v1.dot(e).fuzzy_eq(&Zero::zero())));
    // check vectors form an ortogonal basis
    assert!(all2(subbasis, subbasis, |e1, e2| e1 == e2 || e1.dot(e2).fuzzy_eq(&Zero::zero())));
    // check vectors form an orthonormal basis
    assert!(all(subbasis, |e| e.norm().fuzzy_eq(&One::one())));
  }
}

// ICE
//
// #[test]
// fn test_subspace_basis_vecn()
// {
//   for uint::range(0u, 10000u) |_|
//   {
//     let v : NVec<d7, f64> = random();
//     let v1 = v.normalized();
//     let subbasis = v1.orthogonal_subspace_basis();
//
//     // check vectors are orthogonal to v1
//     assert!(all(subbasis, |e| v1.dot(e).fuzzy_eq(&Zero::zero())));
//     // check vectors form an ortogonal basis
//     assert!(all2(subbasis, subbasis, |e1, e2| e1 == e2 || e1.dot(e2).fuzzy_eq(&Zero::zero())));
//     // check vectors form an orthonormal basis
//     assert!(all(subbasis, |e| e.norm().fuzzy_eq(&One::one())));
//   }
// }
<|endoftext|>


<commit_before>pub enum Token {
    Comma,
    Number(f64),
    ParenClose,
    ParenOpen,
    Word(String),
}

pub fn tokenize(input: &str) -> Tokenizer {
    Tokenizer {text: String::from_str(input)}
}

fn is_whitespace(c: char) -> bool {
    match c {
        '\n' | '\r' | '\t' | ' ' => true,
        _                        => false,
    }
}

struct Tokenizer {
    text: String
}

impl Iterator<Token> for Tokenizer {
    fn next(&mut self) -> Option<Token> {
        let popped_char = self.pop_char();
        if popped_char.is_none() {
            return None
        }
        let next_char = popped_char.unwrap();

        match next_char {
            '\0' => None,
            '(' => Some(Token::ParenOpen),
            ')' => Some(Token::ParenClose),
            ',' => Some(Token::Comma),
            c if is_whitespace(c) => self.next(),
            c if c.is_numeric() => {
                let x: f64 = from_str(c.to_string().as_slice()).unwrap();
                Some(Token::Number(x))
            }
            c => {
                let word = c.to_string() + self.finish_word().as_slice();
                Some(Token::Word(word))
            }
        }
    }
}

impl Tokenizer {
    fn pop_char(&mut self) -> Option<char> {
        if self.text.is_empty() {
            None
        } else {
            self.text.remove(0)
        }
    }

    fn finish_word(&mut self) -> String {
        let popped_char = self.pop_char();
        if popped_char.is_none() {
            return "".to_string()
        }
        let next_char = popped_char.unwrap();

        match next_char {
            '\0' | '(' | ')' | ',' => {
                self.text.insert(0, next_char);
                "".to_string()
            }
            c if is_whitespace(c) => "".to_string(),
            _ => next_char.to_string() + self.finish_word().as_slice(),
        }
    }

    /*
    fn finish_number(&mut self) -> String {
    }
    */
}

#[test]
fn test_tokenizer() {
    let test_str = "hello";
    match tokenize(test_str).next().unwrap() {
        Token::Word(n) => assert_eq!(n, test_str.to_string()),
        _ => panic!("fail")
    }
}
<commit_msg>Expand tests<commit_after>pub enum Token {
    Comma,
    Number(f64),
    ParenClose,
    ParenOpen,
    Word(String),
}

pub fn tokenize(input: &str) -> Tokenizer {
    Tokenizer {text: String::from_str(input)}
}

fn is_whitespace(c: char) -> bool {
    match c {
        '\n' | '\r' | '\t' | ' ' => true,
        _                        => false,
    }
}

struct Tokenizer {
    text: String
}

impl Iterator<Token> for Tokenizer {
    fn next(&mut self) -> Option<Token> {
        let popped_char = self.pop_char();
        if popped_char.is_none() {
            return None
        }
        let next_char = popped_char.unwrap();

        match next_char {
            '\0' => None,
            '(' => Some(Token::ParenOpen),
            ')' => Some(Token::ParenClose),
            ',' => Some(Token::Comma),
            c if is_whitespace(c) => self.next(),
            c if c.is_numeric() => {
                let x: f64 = from_str(c.to_string().as_slice()).unwrap();
                Some(Token::Number(x))
            }
            c => {
                let word = c.to_string() + self.finish_word().as_slice();
                Some(Token::Word(word))
            }
        }
    }
}

impl Tokenizer {
    fn pop_char(&mut self) -> Option<char> {
        if self.text.is_empty() {
            None
        } else {
            self.text.remove(0)
        }
    }

    fn finish_word(&mut self) -> String {
        let popped_char = self.pop_char();
        if popped_char.is_none() {
            return "".to_string()
        }
        let next_char = popped_char.unwrap();

        match next_char {
            '\0' | '(' | ')' | ',' => {
                self.text.insert(0, next_char);
                "".to_string()
            }
            c if is_whitespace(c) => "".to_string(),
            _ => next_char.to_string() + self.finish_word().as_slice(),
        }
    }

    /*
    fn finish_number(&mut self) -> String {
    }
    */
}

#[test]
fn test_tokenizer_1word() {
    let test_str = "hello";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Word(n) => assert_eq!(n, "hello".to_string()),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}

#[test]
fn test_tokenizer_2words() {
    let test_str = "hello world";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Word(n) => assert_eq!(n, "hello".to_string()),
        _ => panic!("fail")
    }
    match tokens.next().unwrap() {
        Token::Word(n) => assert_eq!(n, "world".to_string()),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}
<|endoftext|>


<commit_before>use super::audio::Audio;
use super::error::Error;
use super::PlayerAction;
use super::state::{PlayerState, PlayerStatus};

use ao;
use pandora::{Pandora, Station, Track};

use std::collections::VecDeque;
use std::thread;
use std::thread::JoinHandle;
use std::sync::{Arc, Mutex, Condvar};
use std::sync::mpsc::{channel, Sender, Receiver};

/// This function starts the event and player thread.
pub fn spawn_player(
    pandora: &Arc<Pandora>,
    main_state: &Arc<Mutex<PlayerState>>,
    main_sender: Sender<Result<PlayerStatus, Error>>,
    main_receiver: Receiver<PlayerAction>) -> JoinHandle<()> {

    // The Condvar used for pausing the player thread.
    let main_pause_pair: Arc<(Mutex<bool>, Condvar)> = Arc::new((Mutex::new(false), Condvar::new()));

    // Sender and receiver for communication between the event thread and
    // the player thread.
    let (event_sender, event_receiver) = channel();

    // Thread is dedicated to receive the events from the main thread and
    // forward player events to the player thread.
    let state = main_state.clone();
    let pause_pair = main_pause_pair.clone();
    let receiver = main_receiver;
    let sender = main_sender.clone();

    let event_handle = {
        thread::Builder::new().name("event".to_string()).spawn(move || {
            while let Ok(action) = receiver.recv() {
                match action {
                    PlayerAction::Pause => {
                        let &(ref lock, _) = &*pause_pair;
                        let mut paused = lock.lock().unwrap();
                        *paused = true;
                    },
                    PlayerAction::Unpause => {
                        let &(ref lock, ref cvar) = &*pause_pair;
                        let mut paused = lock.lock().unwrap();
                        *paused = false;
                        cvar.notify_one();
                    },

                    PlayerAction::Report => {
                        sender.send(Ok(state.lock().unwrap().status().clone())).unwrap();
                    },

                    PlayerAction::Exit => {
                        event_sender.send(PlayerAction::Exit).unwrap();
                        break;
                    },

                    action => {
                        event_sender.send(action).unwrap();
                    }
                }
            }
        }).unwrap()
    };

    // The 'player' thread runs while the Player is in scope. It plays the given station
    // and takes care of fetching the tracks. All the events this thread receives are
    // the events forwarded from the 'event' thread.
    let pandora = pandora.clone();
    let state = main_state.clone();
    let pause_pair = main_pause_pair.clone();
    let sender = main_sender.clone();

    thread::Builder::new().name("player".to_string()).spawn(move || {

        // Context of our player.
        let mut ctx = ThreadContext {
            pandora: pandora,
            state: state,
            pause_pair: pause_pair,
            sender: sender,
            receiver: event_receiver,
        };

        // Finite state machine loop.
        let mut fsm = ThreadState::new();
        ctx.send_status(PlayerStatus::Standby);
        while !fsm.is_shutdown() {
            fsm = fsm.update(&mut ctx);
        }
        event_handle.join().unwrap();
    }).unwrap()
}

// ----------------
// Finite State Machine
// ----------------

/// Context struct for our finite state machine.
struct ThreadContext {
    pub pandora: Arc<Pandora>,
    pub state: Arc<Mutex<PlayerState>>,
    pub pause_pair: Arc<(Mutex<bool>, Condvar)>,
    pub sender: Sender<Result<PlayerStatus, Error>>,
    pub receiver: Receiver<PlayerAction>,
}

impl ThreadContext {
    /// Sends a status through the sender channel.
    pub fn send_status(&mut self, status: PlayerStatus) {
        self.state.lock().unwrap().set_status(status.clone());
        self.sender.send(Ok(status)).unwrap();
    }

    /// Sends an error through the sender channel.
    pub fn send_error(&self, error: Error) {
        self.sender.send(Err(error)).unwrap();
    }

    /// Blocks the current thread and returns the next available
    /// action.
    pub fn action(&mut self) -> Option<PlayerAction> {
        self.receiver.recv().ok()
    }

    /// Checks for a pending action without blocking the current
    /// thread.
    pub fn try_action(&mut self) -> Option<PlayerAction> {
        self.receiver.try_recv().ok()
    }
}

/// Finite state machine for the thread.
enum ThreadState {
    Shutdown,

    Standby,

    Station {
        station: Station
    },

    Track {
        station: Station,
        tracklist: VecDeque<Track>,
    },

    Playing {
        station: Station,
        tracklist: VecDeque<Track>,
        track: Track,
        audio: Audio,
    },
}

impl ThreadState {
    /// Creates a new state machine in Standby state.
    pub fn new() -> ThreadState {
        ThreadState::Standby
    }

    /// Returns true if the current state is Standby state.
    pub fn is_standby(&self) -> bool {
        match *self {
            ThreadState::Standby => true,
            _ => false,
        }
    }

    /// Returns true if the current state is Shutdown state.
    pub fn is_shutdown(&self) -> bool {
        match *self {
            ThreadState::Shutdown => true,
            _ => false,
        }
    }

    // ----------------
    // Updating.
    // ----------------

    /// Consumes the current state and returns a new state.
    pub fn update(self, ctx: &mut ThreadContext) -> ThreadState {
        match self {
            ThreadState::Standby =>
                Self::update_standby(ctx),

            ThreadState::Station { station } =>
                Self::update_station(ctx, station),

            ThreadState::Track { station, tracklist } =>
                Self::update_track(ctx, station, tracklist),

            ThreadState::Playing { station, tracklist, track, audio} =>
                Self::update_playing(ctx, station, tracklist, track, audio),

            _ =>
                self,
        }
    }

    fn update_standby(ctx: &mut ThreadContext) -> ThreadState {
        if let Some(PlayerAction::Play(station)) = ctx.action() {
            ctx.state.lock().unwrap().set_station(station.clone());
            ctx.send_status(PlayerStatus::Started(station.clone()));
            return Self::new_station(station);
        }

        // Stay in Standby state.
        Self::new()
    }

    fn update_station(ctx: &mut ThreadContext, station: Station) -> ThreadState {
        ctx.send_status(PlayerStatus::Fetching(station.clone()));
        match ctx.pandora.stations().playlist(&station).list() {
            Ok(tracklist) => {
                Self::new_track(station, tracklist.into_iter().collect())
            },
            Err(e) => {
                ctx.send_error(e.into());
                Self::new_station(station)
            },
        }
    }

    fn update_track(
        ctx: &mut ThreadContext,
        station: Station,
        mut tracklist: VecDeque<Track>
    ) -> ThreadState {
        if let Some((track, audio)) = tracklist.pop_front().and_then(|track| {
            track.track_audio.clone().map(|audio| (track, audio))
        }) {
            let audio = match Audio::new(&audio.high_quality.audio_url) {
                Ok(audio) => audio,
                Err(e) => {
                    ctx.send_error(e.into());
                    return Self::new_track(station, tracklist);
                }
            };

            ctx.state.lock().unwrap().set_track(track.clone());
            ctx.send_status(PlayerStatus::Playing(track.clone()));
            return Self::new_playing(station, tracklist, track, audio);
        }
        else {
            Self::new_station(station)
        }
    }

    fn update_playing(
        ctx: &mut ThreadContext,
        station: Station,
        tracklist: VecDeque<Track>,
        track: Track,
        mut audio: Audio,
    ) -> ThreadState {
        // Pauses.
        {
            let &(ref lock, ref cvar) = &*ctx.pause_pair.clone();
            let mut paused = lock.lock().unwrap();
            while *paused {
                ctx.send_status(PlayerStatus::Paused(track.clone()));
                paused = cvar.wait(paused).unwrap();
                ctx.send_status(PlayerStatus::Playing(track.clone()));
            }
        }

        // Actions.
        if let Some(action) = ctx.try_action() {
            match action {
                PlayerAction::Play(new_station) => {
                    ctx.state.lock().unwrap().clear_info();
                    ctx.state.lock().unwrap().set_station(new_station.clone());
                    ctx.send_status(PlayerStatus::Finished(track.clone()));
                    ctx.send_status(PlayerStatus::Stopped(station.clone()));
                    ctx.send_status(PlayerStatus::Started(new_station.clone()));
                    return Self::new_station(new_station);
                },
                PlayerAction::Stop => {
                    ctx.state.lock().unwrap().clear_info();
                    ctx.send_status(PlayerStatus::Finished(track.clone()));
                    ctx.send_status(PlayerStatus::Stopped(station.clone()));
                    ctx.send_status(PlayerStatus::Standby);
                    return Self::new();
                },

                PlayerAction::Skip => {
                    ctx.state.lock().unwrap().clear_track();
                    ctx.state.lock().unwrap().clear_progress();
                    ctx.send_status(PlayerStatus::Finished(track.clone()));
                    return Self::new_track(station, tracklist);
                },

                PlayerAction::Exit => {
                    ctx.state.lock().unwrap().clear_info();
                    ctx.send_status(PlayerStatus::Finished(track.clone()));
                    ctx.send_status(PlayerStatus::Stopped(station.clone()));
                    ctx.send_status(PlayerStatus::Shutdown);
                    return Self::new_shutdown();
                },

                _ => (),
            }
        }

        // Playback.
        if let Ok((current, duration)) = audio.play() {
            ctx.state.lock().unwrap().set_progress(current.seconds(), duration.seconds());
        }
        else {
            ctx.state.lock().unwrap().clear_track();
            ctx.state.lock().unwrap().clear_progress();
            ctx.send_status(PlayerStatus::Finished(track.clone()));
            return Self::new_track(station, tracklist);
        }

        return Self::new_playing(station, tracklist, track, audio);
    }

    // ----------------
    // Creation of different states.
    // ----------------

    fn new_shutdown() -> ThreadState {
        ThreadState::Shutdown
    }

    fn new_station(station: Station) -> ThreadState {
        ThreadState::Station {
            station: station,
        }
    }

    fn new_track(station: Station, tracklist: VecDeque<Track>) -> ThreadState {
        ThreadState::Track {
            station: station,
            tracklist: tracklist,
        }
    }

    fn new_playing(station: Station, tracklist: VecDeque<Track>, track: Track, audio: Audio)
    -> ThreadState {
        ThreadState::Playing {
            station: station,
            tracklist: tracklist,
            track: track,
            audio: audio,
        }
    }
}
<commit_msg>Fixed typo<commit_after>use super::audio::Audio;
use super::error::Error;
use super::PlayerAction;
use super::state::{PlayerState, PlayerStatus};

use ao;
use pandora::{Pandora, Station, Track};

use std::collections::VecDeque;
use std::thread;
use std::thread::JoinHandle;
use std::sync::{Arc, Mutex, Condvar};
use std::sync::mpsc::{channel, Sender, Receiver};

/// This function starts the event and player thread.
pub fn spawn_player(
    pandora: &Arc<Pandora>,
    main_state: &Arc<Mutex<PlayerState>>,
    main_sender: Sender<Result<PlayerStatus, Error>>,
    main_receiver: Receiver<PlayerAction>) -> JoinHandle<()> {

    // The Condvar used for pausing the player thread.
    let main_pause_pair: Arc<(Mutex<bool>, Condvar)> = Arc::new((Mutex::new(false), Condvar::new()));

    // Sender and receiver for communication between the event thread and
    // the player thread.
    let (event_sender, event_receiver) = channel();

    // Thread is dedicated to receive the events from the main thread and
    // forward player events to the player thread.
    let state = main_state.clone();
    let pause_pair = main_pause_pair.clone();
    let receiver = main_receiver;
    let sender = main_sender.clone();

    let event_handle = {
        thread::Builder::new().name("event".to_string()).spawn(move || {
            while let Ok(action) = receiver.recv() {
                match action {
                    PlayerAction::Pause => {
                        let &(ref lock, _) = &*pause_pair;
                        let mut paused = lock.lock().unwrap();
                        *paused = true;
                    },
                    PlayerAction::Unpause => {
                        let &(ref lock, ref cvar) = &*pause_pair;
                        let mut paused = lock.lock().unwrap();
                        *paused = false;
                        cvar.notify_one();
                    },

                    PlayerAction::Report => {
                        sender.send(Ok(state.lock().unwrap().status().clone())).unwrap();
                    },

                    PlayerAction::Exit => {
                        event_sender.send(PlayerAction::Exit).unwrap();
                        break;
                    },

                    action => {
                        event_sender.send(action).unwrap();
                    }
                }
            }
        }).unwrap()
    };

    // The 'player' thread runs while the Player is in scope. It plays the given station
    // and takes care of fetching the tracks. All the events this thread receives are
    // the events forwarded from the 'event' thread.
    let pandora = pandora.clone();
    let state = main_state.clone();
    let pause_pair = main_pause_pair.clone();
    let sender = main_sender.clone();

    thread::Builder::new().name("player".to_string()).spawn(move || {
        // Context of our player.
        let mut ctx = ThreadContext {
            pandora: pandora,
            state: state,
            pause_pair: pause_pair,
            sender: sender,
            receiver: event_receiver,
        };

        // Finite state machine loop.
        let mut fsm = ThreadState::new();
        ctx.send_status(PlayerStatus::Standby);
        while !fsm.is_shutdown() {
            fsm = fsm.update(&mut ctx);
        }

        event_handle.join().unwrap();
    }).unwrap()
}

// ----------------
// Finite State Machine
// ----------------

/// Context struct for our finite state machine.
struct ThreadContext {
    pub pandora: Arc<Pandora>,
    pub state: Arc<Mutex<PlayerState>>,
    pub pause_pair: Arc<(Mutex<bool>, Condvar)>,
    pub sender: Sender<Result<PlayerStatus, Error>>,
    pub receiver: Receiver<PlayerAction>,
}

impl ThreadContext {
    /// Sends a status through the sender channel.
    pub fn send_status(&mut self, status: PlayerStatus) {
        self.state.lock().unwrap().set_status(status.clone());
        self.sender.send(Ok(status)).unwrap();
    }

    /// Sends an error through the sender channel.
    pub fn send_error(&self, error: Error) {
        self.sender.send(Err(error)).unwrap();
    }

    /// Blocks the current thread and returns the next available
    /// action.
    pub fn action(&mut self) -> Option<PlayerAction> {
        self.receiver.recv().ok()
    }

    /// Checks for a pending action without blocking the current
    /// thread.
    pub fn try_action(&mut self) -> Option<PlayerAction> {
        self.receiver.try_recv().ok()
    }
}

/// Finite state machine for the thread.
enum ThreadState {
    Shutdown,

    Standby,

    Station {
        station: Station
    },

    Track {
        station: Station,
        tracklist: VecDeque<Track>,
    },

    Playing {
        station: Station,
        tracklist: VecDeque<Track>,
        track: Track,
        audio: Audio,
    },
}

impl ThreadState {
    /// Creates a new state machine in Standby state.
    pub fn new() -> ThreadState {
        ThreadState::Standby
    }

    /// Returns true if the current state is Standby state.
    pub fn is_standby(&self) -> bool {
        match *self {
            ThreadState::Standby => true,
            _ => false,
        }
    }

    /// Returns true if the current state is Shutdown state.
    pub fn is_shutdown(&self) -> bool {
        match *self {
            ThreadState::Shutdown => true,
            _ => false,
        }
    }

    // ----------------
    // Updating.
    // ----------------

    /// Consumes the current state and returns a new state.
    pub fn update(self, ctx: &mut ThreadContext) -> ThreadState {
        match self {
            ThreadState::Standby =>
                Self::update_standby(ctx),

            ThreadState::Station { station } =>
                Self::update_station(ctx, station),

            ThreadState::Track { station, tracklist } =>
                Self::update_track(ctx, station, tracklist),

            ThreadState::Playing { station, tracklist, track, audio} =>
                Self::update_playing(ctx, station, tracklist, track, audio),

            _ =>
                self,
        }
    }

    fn update_standby(ctx: &mut ThreadContext) -> ThreadState {
        if let Some(PlayerAction::Play(station)) = ctx.action() {
            ctx.state.lock().unwrap().set_station(station.clone());
            ctx.send_status(PlayerStatus::Started(station.clone()));
            return Self::new_station(station);
        }

        // Stay in Standby state.
        Self::new()
    }

    fn update_station(ctx: &mut ThreadContext, station: Station) -> ThreadState {
        ctx.send_status(PlayerStatus::Fetching(station.clone()));
        match ctx.pandora.stations().playlist(&station).list() {
            Ok(tracklist) => {
                Self::new_track(station, tracklist.into_iter().collect())
            },
            Err(e) => {
                ctx.send_error(e.into());
                Self::new_station(station)
            },
        }
    }

    fn update_track(
        ctx: &mut ThreadContext,
        station: Station,
        mut tracklist: VecDeque<Track>
    ) -> ThreadState {
        if let Some((track, audio)) = tracklist.pop_front().and_then(|track| {
            track.track_audio.clone().map(|audio| (track, audio))
        }) {
            let audio = match Audio::new(&audio.high_quality.audio_url) {
                Ok(audio) => audio,
                Err(e) => {
                    ctx.send_error(e.into());
                    return Self::new_track(station, tracklist);
                }
            };

            ctx.state.lock().unwrap().set_track(track.clone());
            ctx.send_status(PlayerStatus::Playing(track.clone()));
            return Self::new_playing(station, tracklist, track, audio);
        }
        else {
            Self::new_station(station)
        }
    }

    fn update_playing(
        ctx: &mut ThreadContext,
        station: Station,
        tracklist: VecDeque<Track>,
        track: Track,
        mut audio: Audio,
    ) -> ThreadState {
        // Pauses.
        {
            let &(ref lock, ref cvar) = &*ctx.pause_pair.clone();
            let mut paused = lock.lock().unwrap();
            while *paused {
                ctx.send_status(PlayerStatus::Paused(track.clone()));
                paused = cvar.wait(paused).unwrap();
                ctx.send_status(PlayerStatus::Playing(track.clone()));
            }
        }

        // Actions.
        if let Some(action) = ctx.try_action() {
            match action {
                PlayerAction::Play(new_station) => {
                    ctx.state.lock().unwrap().clear_info();
                    ctx.state.lock().unwrap().set_station(new_station.clone());
                    ctx.send_status(PlayerStatus::Finished(track.clone()));
                    ctx.send_status(PlayerStatus::Stopped(station.clone()));
                    ctx.send_status(PlayerStatus::Started(new_station.clone()));
                    return Self::new_station(new_station);
                },
                PlayerAction::Stop => {
                    ctx.state.lock().unwrap().clear_info();
                    ctx.send_status(PlayerStatus::Finished(track.clone()));
                    ctx.send_status(PlayerStatus::Stopped(station.clone()));
                    ctx.send_status(PlayerStatus::Standby);
                    return Self::new();
                },

                PlayerAction::Skip => {
                    ctx.state.lock().unwrap().clear_track();
                    ctx.state.lock().unwrap().clear_progress();
                    ctx.send_status(PlayerStatus::Finished(track.clone()));
                    return Self::new_track(station, tracklist);
                },

                PlayerAction::Exit => {
                    ctx.state.lock().unwrap().clear_info();
                    ctx.send_status(PlayerStatus::Finished(track.clone()));
                    ctx.send_status(PlayerStatus::Stopped(station.clone()));
                    ctx.send_status(PlayerStatus::Shutdown);
                    return Self::new_shutdown();
                },

                _ => (),
            }
        }

        // Playback.
        if let Ok((current, duration)) = audio.play() {
            ctx.state.lock().unwrap().set_progress(current.seconds(), duration.seconds());
        }
        else {
            ctx.state.lock().unwrap().clear_track();
            ctx.state.lock().unwrap().clear_progress();
            ctx.send_status(PlayerStatus::Finished(track.clone()));
            return Self::new_track(station, tracklist);
        }

        return Self::new_playing(station, tracklist, track, audio);
    }

    // ----------------
    // Creation of different states.
    // ----------------

    fn new_shutdown() -> ThreadState {
        ThreadState::Shutdown
    }

    fn new_station(station: Station) -> ThreadState {
        ThreadState::Station {
            station: station,
        }
    }

    fn new_track(station: Station, tracklist: VecDeque<Track>) -> ThreadState {
        ThreadState::Track {
            station: station,
            tracklist: tracklist,
        }
    }

    fn new_playing(station: Station, tracklist: VecDeque<Track>, track: Track, audio: Audio)
    -> ThreadState {
        ThreadState::Playing {
            station: station,
            tracklist: tracklist,
            track: track,
            audio: audio,
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::collections::HashMap;
use itertools::Itertools;
use super::Expr;
use error::*;

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Key {
	Nil,
	Bool(bool),
	Int(i64),
	Str(String),
}

impl Key {
	pub fn try_from(expr: &Expr) -> Result<Self> {
		match expr {
		    &Expr::Nil => Ok(Key::Nil),
		    &Expr::Bool(b) => Ok(Key::Bool(b)),
		    &Expr::Int(i) => Ok(Key::Int(i)),
		    &Expr::Str(ref s) => Ok(Key::Str(s.clone())),
		    _ => Err(format!("cannot use as key: {}", expr).into()),
		}
	}
}

impl fmt::Display for Key {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&Key::Nil => write!(f, "()"),
			&Key::Bool(b) => write!(f, "{}", b),
			&Key::Int(i) => write!(f, "{}", i),
			&Key::Str(ref s) => write!(f, "{}", s),
		}
	}
}

#[derive(Clone, Debug)]
pub struct Map(HashMap<Key, Expr>);

impl Map {

}

impl fmt::Display for Map {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		let pairs = self.0.iter()
			.map(|(key, val)| format!("{}: {}", key, val))
			.join(", ");
		write!(f, "{{{}}}", pairs)
	}
}
<commit_msg>Add map constructor<commit_after>#![allow(dead_code)]

use std::fmt;
use std::collections::HashMap;
use itertools::Itertools;
use super::Expr;
use error::*;

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Key {
	Nil,
	Bool(bool),
	Int(i64),
	Str(String),
}

impl Key {
	pub fn try_from(expr: &Expr) -> Result<Self> {
		match expr {
		    &Expr::Nil => Ok(Key::Nil),
		    &Expr::Bool(b) => Ok(Key::Bool(b)),
		    &Expr::Int(i) => Ok(Key::Int(i)),
		    &Expr::Str(ref s) => Ok(Key::Str(s.clone())),
		    _ => Err(format!("cannot use as key: {}", expr).into()),
		}
	}
}

impl fmt::Display for Key {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&Key::Nil => write!(f, "()"),
			&Key::Bool(b) => write!(f, "{}", b),
			&Key::Int(i) => write!(f, "{}", i),
			&Key::Str(ref s) => write!(f, "{}", s),
		}
	}
}

#[derive(Clone, Debug)]
pub struct Map(HashMap<Key, Expr>);

impl Map {
	pub fn new() -> Self {
		Map(HashMap::new())
	}
}

impl Default for Map {
	fn default() -> Self {
		Map(HashMap::new())
	}
}

impl fmt::Display for Map {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		let pairs = self.0.iter()
			.map(|(key, val)| format!("{}: {}", key, val))
			.join(", ");
		write!(f, "{{{}}}", pairs)
	}
}
<|endoftext|>


<commit_before>#![crate_name = "uu_uniq"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Chirag B Jadwani <chirag.jadwani@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 */

extern crate getopts;

#[macro_use]
extern crate uucore;

use getopts::{Matches, Options};
use std::fs::File;
use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Write};
use std::path::Path;
use std::str::FromStr;

static NAME: &'static str = "uniq";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

#[derive(PartialEq)]
enum Delimiters {
    Prepend,
    Separate,
    None,
}

struct Uniq {
    repeats_only: bool,
    uniques_only: bool,
    all_repeated: bool,
    delimiters: Delimiters,
    show_counts: bool,
    skip_fields: Option<usize>,
    slice_start: Option<usize>,
    slice_stop: Option<usize>,
    ignore_case: bool,
    zero_terminated: bool,
}

impl Uniq {
    pub fn print_uniq<R: Read, W: Write>(
        &self,
        reader: &mut BufReader<R>,
        writer: &mut BufWriter<W>,
    ) {
        let mut lines: Vec<String> = vec![];
        let mut first_line_printed = false;
        let delimiters = &self.delimiters;
        let line_terminator = self.get_line_terminator();

        for io_line in reader.split(line_terminator) {
            let line = String::from_utf8(crash_if_err!(1, io_line)).unwrap();
            if !lines.is_empty() && self.cmp_key(&lines[0]) != self.cmp_key(&line) {
                let print_delimiter = delimiters == &Delimiters::Prepend
                    || (delimiters == &Delimiters::Separate && first_line_printed);
                first_line_printed |= self.print_lines(writer, &lines, print_delimiter);
                lines.truncate(0);
            }
            lines.push(line);
        }
        if !lines.is_empty() {
            let print_delimiter = delimiters == &Delimiters::Prepend
                || (delimiters == &Delimiters::Separate && first_line_printed);
            self.print_lines(writer, &lines, print_delimiter);
        }
    }

    fn skip_fields<'a>(&self, line: &'a str) -> &'a str {
        if let Some(skip_fields) = self.skip_fields {
            if line.split_whitespace().count() > skip_fields {
                let mut field = 0;
                let mut i = 0;
                while field < skip_fields && i < line.len() {
                    while i < line.len() && line.chars().nth(i).unwrap().is_whitespace() {
                        i = i + 1;
                    }
                    while i < line.len() && !line.chars().nth(i).unwrap().is_whitespace() {
                        i = i + 1;
                    }
                    field = field + 1;
                }
                &line[i..]
            } else {
                ""
            }
        } else {
            line
        }
    }

    fn get_line_terminator(&self) -> u8 {
        if self.zero_terminated {
            0
        } else {
            '\n' as u8
        }
    }

    fn cmp_key(&self, line: &str) -> String {
        let fields_to_check = self.skip_fields(line);
        let len = fields_to_check.len();
        if len > 0 {
            fields_to_check
                .chars()
                .skip(self.slice_start.unwrap_or(0))
                .take(self.slice_stop.unwrap_or(len))
                .map(|c| match c {
                    'a'...'z' if self.ignore_case => ((c as u8) - 32) as char,
                    _ => c,
                })
                .collect()
        } else {
            fields_to_check.to_owned()
        }
    }

    fn print_lines<W: Write>(
        &self,
        writer: &mut BufWriter<W>,
        lines: &[String],
        print_delimiter: bool,
    ) -> bool {
        let mut first_line_printed = false;
        let mut count = if self.all_repeated { 1 } else { lines.len() };
        if lines.len() == 1 && !self.repeats_only || lines.len() > 1 && !self.uniques_only {
            self.print_line(writer, &lines[0], count, print_delimiter);
            first_line_printed = true;
            count += 1;
        }
        if self.all_repeated {
            for line in lines[1..].iter() {
                self.print_line(writer, line, count, print_delimiter && !first_line_printed);
                first_line_printed = true;
                count += 1;
            }
        }
        first_line_printed
    }

    fn print_line<W: Write>(
        &self,
        writer: &mut BufWriter<W>,
        line: &str,
        count: usize,
        print_delimiter: bool,
    ) {
        let line_terminator = self.get_line_terminator();

        if print_delimiter {
            crash_if_err!(1, writer.write_all(&[line_terminator]));
        }

        crash_if_err!(
            1,
            if self.show_counts {
                writer.write_all(format!("{:7} {}", count, line).as_bytes())
            } else {
                writer.write_all(line.as_bytes())
            }
        );
        crash_if_err!(1, writer.write_all(&[line_terminator]));
    }
}

fn opt_parsed<T: FromStr>(opt_name: &str, matches: &Matches) -> Option<T> {
    matches.opt_str(opt_name).map(|arg_str| {
        let opt_val: Option<T> = arg_str.parse().ok();
        opt_val.unwrap_or_else(|| crash!(1, "Invalid argument for {}: {}", opt_name, arg_str))
    })
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = Options::new();

    opts.optflag("c", "count", "prefix lines by the number of occurrences");
    opts.optflag("d", "repeated", "only print duplicate lines");
    opts.optflagopt(
        "D",
        "all-repeated",
        "print all duplicate lines delimit-method={none(default),prepend,separate} Delimiting is done with blank lines",
        "delimit-method"
    );
    opts.optopt(
        "f",
        "skip-fields",
        "avoid comparing the first N fields",
        "N",
    );
    opts.optopt(
        "s",
        "skip-chars",
        "avoid comparing the first N characters",
        "N",
    );
    opts.optopt(
        "w",
        "check-chars",
        "compare no more than N characters in lines",
        "N",
    );
    opts.optflag(
        "i",
        "ignore-case",
        "ignore differences in case when comparing",
    );
    opts.optflag("u", "unique", "only print unique lines");
    opts.optflag("z", "zero-terminated", "end lines with 0 byte, not newline");
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "{}", f),
    };

    if matches.opt_present("help") {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {0} [OPTION]... [FILE]...", NAME);
        println!("");
        print!(
            "{}",
            opts.usage(
                "Filter adjacent matching lines from INPUT (or standard input),\n\
                 writing to OUTPUT (or standard output)."
            )
        );
        println!("");
        println!(
            "Note: '{0}' does not detect repeated lines unless they are adjacent.\n\
             You may want to sort the input first, or use 'sort -u' without '{0}'.\n",
            NAME
        );
    } else if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
    } else {
        let (in_file_name, out_file_name) = match matches.free.len() {
            0 => ("-".to_owned(), "-".to_owned()),
            1 => (matches.free[0].clone(), "-".to_owned()),
            2 => (matches.free[0].clone(), matches.free[1].clone()),
            _ => {
                crash!(1, "Extra operand: {}", matches.free[2]);
            }
        };
        let uniq = Uniq {
            repeats_only: matches.opt_present("repeated") || matches.opt_present("all-repeated"),
            uniques_only: matches.opt_present("unique"),
            all_repeated: matches.opt_present("all-repeated"),
            delimiters: match matches.opt_default("all-repeated", "none") {
                Some(ref opt_arg) if opt_arg != "none" => match &(*opt_arg.as_str()) {
                    "prepend" => Delimiters::Prepend,
                    "separate" => Delimiters::Separate,
                    _ => crash!(1, "Incorrect argument for all-repeated: {}", opt_arg),
                },
                _ => Delimiters::None,
            },
            show_counts: matches.opt_present("count"),
            skip_fields: opt_parsed("skip-fields", &matches),
            slice_start: opt_parsed("skip-chars", &matches),
            slice_stop: opt_parsed("check-chars", &matches),
            ignore_case: matches.opt_present("ignore-case"),
            zero_terminated: matches.opt_present("zero-terminated"),
        };
        uniq.print_uniq(
            &mut open_input_file(in_file_name),
            &mut open_output_file(out_file_name),
        );
    }
    0
}

fn open_input_file(in_file_name: String) -> BufReader<Box<Read + 'static>> {
    let in_file = if in_file_name == "-" {
        Box::new(stdin()) as Box<Read>
    } else {
        let path = Path::new(&in_file_name[..]);
        let in_file = File::open(&path);
        let r = crash_if_err!(1, in_file);
        Box::new(r) as Box<Read>
    };
    BufReader::new(in_file)
}

fn open_output_file(out_file_name: String) -> BufWriter<Box<Write + 'static>> {
    let out_file = if out_file_name == "-" {
        Box::new(stdout()) as Box<Write>
    } else {
        let path = Path::new(&out_file_name[..]);
        let in_file = File::create(&path);
        let w = crash_if_err!(1, in_file);
        Box::new(w) as Box<Write>
    };
    BufWriter::new(out_file)
}
<commit_msg>uniq: avoid copying Strings all the time<commit_after>#![crate_name = "uu_uniq"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Chirag B Jadwani <chirag.jadwani@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 */

extern crate getopts;

#[macro_use]
extern crate uucore;

use getopts::{Matches, Options};
use std::fs::File;
use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Write};
use std::path::Path;
use std::str::FromStr;

static NAME: &'static str = "uniq";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

#[derive(PartialEq)]
enum Delimiters {
    Prepend,
    Separate,
    None,
}

struct Uniq {
    repeats_only: bool,
    uniques_only: bool,
    all_repeated: bool,
    delimiters: Delimiters,
    show_counts: bool,
    skip_fields: Option<usize>,
    slice_start: Option<usize>,
    slice_stop: Option<usize>,
    ignore_case: bool,
    zero_terminated: bool,
}

fn iter_ne<'a>(lhs: Box<Iterator<Item = char> + 'a>, rhs: Box<Iterator<Item = char> + 'a>) -> bool {
    lhs.ne(rhs)
}

impl Uniq {
    pub fn print_uniq<R: Read, W: Write>(
        &self,
        reader: &mut BufReader<R>,
        writer: &mut BufWriter<W>,
    ) {
        let mut lines: Vec<String> = vec![];
        let mut first_line_printed = false;
        let delimiters = &self.delimiters;
        let line_terminator = self.get_line_terminator();

        for io_line in reader.split(line_terminator) {
            let line = String::from_utf8(crash_if_err!(1, io_line)).unwrap();
            if !lines.is_empty() && self.cmp_keys(&lines[0], &line) {
                let print_delimiter = delimiters == &Delimiters::Prepend
                    || (delimiters == &Delimiters::Separate && first_line_printed);
                first_line_printed |= self.print_lines(writer, &lines, print_delimiter);
                lines.truncate(0);
            }
            lines.push(line);
        }
        if !lines.is_empty() {
            let print_delimiter = delimiters == &Delimiters::Prepend
                || (delimiters == &Delimiters::Separate && first_line_printed);
            self.print_lines(writer, &lines, print_delimiter);
        }
    }

    fn skip_fields<'a>(&self, line: &'a str) -> &'a str {
        if let Some(skip_fields) = self.skip_fields {
            if line.split_whitespace().count() > skip_fields {
                let mut field = 0;
                let mut i = 0;
                while field < skip_fields && i < line.len() {
                    while i < line.len() && line.chars().nth(i).unwrap().is_whitespace() {
                        i = i + 1;
                    }
                    while i < line.len() && !line.chars().nth(i).unwrap().is_whitespace() {
                        i = i + 1;
                    }
                    field = field + 1;
                }
                &line[i..]
            } else {
                ""
            }
        } else {
            line
        }
    }

    fn get_line_terminator(&self) -> u8 {
        if self.zero_terminated {
            0
        } else {
            '\n' as u8
        }
    }

    fn cmp_key<'a>(&'a self, line: &'a str) -> Box<Iterator<Item = char> + 'a> {
        let fields_to_check = self.skip_fields(line);
        let len = fields_to_check.len();
        if len > 0 {
            Box::new(
                fields_to_check
                    .chars()
                    .skip(self.slice_start.unwrap_or(0))
                    .take(self.slice_stop.unwrap_or(len))
                    .map(move |c| match c {
                        'a'...'z' if self.ignore_case => ((c as u8) - 32) as char,
                        _ => c,
                    }),
            )
        } else {
            Box::new(fields_to_check.chars())
        }
    }

    fn print_lines<W: Write>(
        &self,
        writer: &mut BufWriter<W>,
        lines: &[String],
        print_delimiter: bool,
    ) -> bool {
        let mut first_line_printed = false;
        let mut count = if self.all_repeated { 1 } else { lines.len() };
        if lines.len() == 1 && !self.repeats_only || lines.len() > 1 && !self.uniques_only {
            self.print_line(writer, &lines[0], count, print_delimiter);
            first_line_printed = true;
            count += 1;
        }
        if self.all_repeated {
            for line in lines[1..].iter() {
                self.print_line(writer, line, count, print_delimiter && !first_line_printed);
                first_line_printed = true;
                count += 1;
            }
        }
        first_line_printed
    }

    fn print_line<W: Write>(
        &self,
        writer: &mut BufWriter<W>,
        line: &str,
        count: usize,
        print_delimiter: bool,
    ) {
        let line_terminator = self.get_line_terminator();

        if print_delimiter {
            crash_if_err!(1, writer.write_all(&[line_terminator]));
        }

        crash_if_err!(
            1,
            if self.show_counts {
                writer.write_all(format!("{:7} {}", count, line).as_bytes())
            } else {
                writer.write_all(line.as_bytes())
            }
        );
        crash_if_err!(1, writer.write_all(&[line_terminator]));
    }
}

fn opt_parsed<T: FromStr>(opt_name: &str, matches: &Matches) -> Option<T> {
    matches.opt_str(opt_name).map(|arg_str| {
        let opt_val: Option<T> = arg_str.parse().ok();
        opt_val.unwrap_or_else(|| crash!(1, "Invalid argument for {}: {}", opt_name, arg_str))
    })
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = Options::new();

    opts.optflag("c", "count", "prefix lines by the number of occurrences");
    opts.optflag("d", "repeated", "only print duplicate lines");
    opts.optflagopt(
        "D",
        "all-repeated",
        "print all duplicate lines delimit-method={none(default),prepend,separate} Delimiting is done with blank lines",
        "delimit-method"
    );
    opts.optopt(
        "f",
        "skip-fields",
        "avoid comparing the first N fields",
        "N",
    );
    opts.optopt(
        "s",
        "skip-chars",
        "avoid comparing the first N characters",
        "N",
    );
    opts.optopt(
        "w",
        "check-chars",
        "compare no more than N characters in lines",
        "N",
    );
    opts.optflag(
        "i",
        "ignore-case",
        "ignore differences in case when comparing",
    );
    opts.optflag("u", "unique", "only print unique lines");
    opts.optflag("z", "zero-terminated", "end lines with 0 byte, not newline");
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "{}", f),
    };

    if matches.opt_present("help") {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {0} [OPTION]... [FILE]...", NAME);
        println!("");
        print!(
            "{}",
            opts.usage(
                "Filter adjacent matching lines from INPUT (or standard input),\n\
                 writing to OUTPUT (or standard output)."
            )
        );
        println!("");
        println!(
            "Note: '{0}' does not detect repeated lines unless they are adjacent.\n\
             You may want to sort the input first, or use 'sort -u' without '{0}'.\n",
            NAME
        );
    } else if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
    } else {
        let (in_file_name, out_file_name) = match matches.free.len() {
            0 => ("-".to_owned(), "-".to_owned()),
            1 => (matches.free[0].clone(), "-".to_owned()),
            2 => (matches.free[0].clone(), matches.free[1].clone()),
            _ => {
                crash!(1, "Extra operand: {}", matches.free[2]);
            }
        };
        let uniq = Uniq {
            repeats_only: matches.opt_present("repeated") || matches.opt_present("all-repeated"),
            uniques_only: matches.opt_present("unique"),
            all_repeated: matches.opt_present("all-repeated"),
            delimiters: match matches.opt_default("all-repeated", "none") {
                Some(ref opt_arg) if opt_arg != "none" => match &(*opt_arg.as_str()) {
                    "prepend" => Delimiters::Prepend,
                    "separate" => Delimiters::Separate,
                    _ => crash!(1, "Incorrect argument for all-repeated: {}", opt_arg),
                },
                _ => Delimiters::None,
            },
            show_counts: matches.opt_present("count"),
            skip_fields: opt_parsed("skip-fields", &matches),
            slice_start: opt_parsed("skip-chars", &matches),
            slice_stop: opt_parsed("check-chars", &matches),
            ignore_case: matches.opt_present("ignore-case"),
            zero_terminated: matches.opt_present("zero-terminated"),
        };
        uniq.print_uniq(
            &mut open_input_file(in_file_name),
            &mut open_output_file(out_file_name),
        );
    }
    0
}

fn open_input_file(in_file_name: String) -> BufReader<Box<Read + 'static>> {
    let in_file = if in_file_name == "-" {
        Box::new(stdin()) as Box<Read>
    } else {
        let path = Path::new(&in_file_name[..]);
        let in_file = File::open(&path);
        let r = crash_if_err!(1, in_file);
        Box::new(r) as Box<Read>
    };
    BufReader::new(in_file)
}

fn open_output_file(out_file_name: String) -> BufWriter<Box<Write + 'static>> {
    let out_file = if out_file_name == "-" {
        Box::new(stdout()) as Box<Write>
    } else {
        let path = Path::new(&out_file_name[..]);
        let in_file = File::create(&path);
        let w = crash_if_err!(1, in_file);
        Box::new(w) as Box<Write>
    };
    BufWriter::new(out_file)
}
<|endoftext|>