<commit_before>enum Operator {
  Addition,
  Substraction,
  Multiplication,
  Division
}

enum OperationElt {
  Operator(Operator),
  Operand(f32)
}

fn tokenizer(expr: &str) -> Result<Vec<OperationElt>, String> {
  expr.split_whitespace()
    .map(|el| {
      match el {
        "+" => Ok(OperationElt::Operator(Operator::Addition)),
        "-" => Ok(OperationElt::Operator(Operator::Substraction)),
        "*" => Ok(OperationElt::Operator(Operator::Multiplication)),
        "/" => Ok(OperationElt::Operator(Operator::Division)),
        operand => match operand.parse::<f32>() {
          Ok(val) => Ok(OperationElt::Operand(val)),
          Err(_) => Err(format!("Cannot parse operand \"{}\"", operand))
        }
      }
    })
    .into_iter()
    .collect()
}

/// Evaluates an RPL expression.
///
/// # Examples
/// ````
/// extern crate rpn;
///
/// let result:f32 = rpn::evaluate("5 2 +").unwrap();
/// assert_eq!(result, 7.0);
/// ````
///
/// # Errors
/// This function will return an error in case of bad expression:
///
/// - if it includes an unrecognized operator (recognized ones are +, -, * and /
/// - if it misses an operand (i.e. value)
/// - if it misses an operator
pub fn evaluate(expr: &str) -> Result<f32, String> {
  return match tokenizer(expr) {
    Ok(tokens) => {
      let mut stack:Vec<f32> = Vec::new();
      for token in tokens {
        match token {
          OperationElt::Operator(operator) => {
            if stack.len() < 2 {
              return Err("Unsufficient operands before operator".to_string());
            }
            let operand2 = stack.pop().expect("expected f32 values in stack");
            let operand1 = stack.pop().expect("expected f32 values in stack");
            let result = match operator {
              Operator::Addition        => operand1 + operand2,
              Operator::Substraction    => operand1 - operand2,
              Operator::Multiplication  => operand1 * operand2,
              Operator::Division        => operand1 / operand2
            };
            stack.push(result);
          },
          OperationElt::Operand(val) => stack.push(val)
        }
      }
      if stack.len() != 1 {
        return Err("Remaining untreated operands. Probably missing operator.".to_string());
      }
      return Ok(stack.pop().expect("expected a f32 value remaining in stack"));
    },
    Err(err) => Err(err)
  }
}

#[test]
fn it_adds() {
  let result = evaluate("1 2 +");
  assert_eq!(result.unwrap(), 3.0);
}

#[test]
fn it_substracts() {
  let result = evaluate("1 2 -");
  assert_eq!(result.unwrap(), -1.0);
}

#[test]
fn it_multiplies() {
  let result = evaluate("6 7 *");
  assert_eq!(result.unwrap(), 42.0);
}

#[test]
fn it_divides() {
  let result = evaluate("1 2 /");
  assert_eq!(result.unwrap(), 0.5);
}

#[test]
fn it_evaluates_complex_expressions() {
  // ((1+2) * 8 / (5-1) - 1) / 2
  let result = evaluate("1 2 + 8 * 5 1 - / 1 - 2 /");
  assert_eq!(result.unwrap(), 2.5);
}

#[test]
fn it_allows_multiple_shitespaces() {
  let result = evaluate("1  2 +\t3 -");
  assert_eq!(result.unwrap(), 0.0);
}

#[test]
fn it_fails_for_unsupported_characters() {
  let result = evaluate("1 2 t");
  assert_eq!(result.unwrap_err(), "Cannot parse operand \"t\"");
}

#[test]
fn it_fails_for_unsufficient_operands() {
  let result = evaluate("1 +");
  assert_eq!(result.unwrap_err(), "Unsufficient operands before operator");
}

#[test]
fn it_fails_for_unsufficient_operators() {
  let result = evaluate("1 2 3 +");
  assert_eq!(result.unwrap_err(),
    "Remaining untreated operands. Probably missing operator.");
}
<commit_msg>Add modulo support<commit_after>enum Operator {
  Addition,
  Substraction,
  Multiplication,
  Division,
  Modulo
}

enum OperationElt {
  Operator(Operator),
  Operand(f32)
}

fn tokenizer(expr: &str) -> Result<Vec<OperationElt>, String> {
  expr.split_whitespace()
    .map(|el| {
      match el {
        "+" => Ok(OperationElt::Operator(Operator::Addition)),
        "-" => Ok(OperationElt::Operator(Operator::Substraction)),
        "*" => Ok(OperationElt::Operator(Operator::Multiplication)),
        "/" => Ok(OperationElt::Operator(Operator::Division)),
        "%" => Ok(OperationElt::Operator(Operator::Modulo)),
        operand => match operand.parse::<f32>() {
          Ok(val) => Ok(OperationElt::Operand(val)),
          Err(_) => Err(format!("Cannot parse operand \"{}\"", operand))
        }
      }
    })
    .into_iter()
    .collect()
}

/// Evaluates an RPL expression.
///
/// # Examples
/// ````
/// extern crate rpn;
///
/// let result:f32 = rpn::evaluate("5 2 +").unwrap();
/// assert_eq!(result, 7.0);
/// ````
///
/// # Errors
/// This function will return an error in case of bad expression:
///
/// - if it includes an unrecognized operator (recognized ones are +, -, * and /
/// - if it misses an operand (i.e. value)
/// - if it misses an operator
pub fn evaluate(expr: &str) -> Result<f32, String> {
  return match tokenizer(expr) {
    Ok(tokens) => {
      let mut stack:Vec<f32> = Vec::new();
      for token in tokens {
        match token {
          OperationElt::Operator(operator) => {
            if stack.len() < 2 {
              return Err("Unsufficient operands before operator".to_string());
            }
            let operand2 = stack.pop().expect("expected f32 values in stack");
            let operand1 = stack.pop().expect("expected f32 values in stack");
            let result = match operator {
              Operator::Addition        => operand1 + operand2,
              Operator::Substraction    => operand1 - operand2,
              Operator::Multiplication  => operand1 * operand2,
              Operator::Division        => operand1 / operand2,
              Operator::Modulo          => operand1 % operand2
            };
            stack.push(result);
          },
          OperationElt::Operand(val) => stack.push(val)
        }
      }
      if stack.len() != 1 {
        return Err("Remaining untreated operands. Probably missing operator.".to_string());
      }
      return Ok(stack.pop().expect("expected a f32 value remaining in stack"));
    },
    Err(err) => Err(err)
  }
}

#[test]
fn it_adds() {
  let result = evaluate("1 2 +");
  assert_eq!(result.unwrap(), 3.0);
}

#[test]
fn it_substracts() {
  let result = evaluate("1 2 -");
  assert_eq!(result.unwrap(), -1.0);
}

#[test]
fn it_multiplies() {
  let result = evaluate("6 7 *");
  assert_eq!(result.unwrap(), 42.0);
}

#[test]
fn it_divides() {
  let result = evaluate("1 2 /");
  assert_eq!(result.unwrap(), 0.5);
}

#[test]
fn it_modulos() {
  let result = evaluate("4 2 %");
  assert_eq!(result.unwrap(), 0.0);
}

#[test]
fn it_evaluates_complex_expressions() {
  // ((1+2) * 8 / (5-1) - 4 % 3) / 2
  let result = evaluate("1 2 + 8 * 5 1 - / 4 3 % - 2 /");
  assert_eq!(result.unwrap(), 2.5);
}

#[test]
fn it_allows_multiple_shitespaces() {
  let result = evaluate("1  2 +\t3 -");
  assert_eq!(result.unwrap(), 0.0);
}

#[test]
fn it_fails_for_unsupported_characters() {
  let result = evaluate("1 2 t");
  assert_eq!(result.unwrap_err(), "Cannot parse operand \"t\"");
}

#[test]
fn it_fails_for_unsufficient_operands() {
  let result = evaluate("1 +");
  assert_eq!(result.unwrap_err(), "Unsufficient operands before operator");
}

#[test]
fn it_fails_for_unsufficient_operators() {
  let result = evaluate("1 2 3 +");
  assert_eq!(result.unwrap_err(),
    "Remaining untreated operands. Probably missing operator.");
}
<|endoftext|>


<commit_before>//! A simple `io::stdout` and `io::stderr` writing `Logger` implementation from the
//! `log` crate, using the `ansi_term` crate for colors and configured at runtime,
//! or at compile time with simple function calls. Designed for simple CLIs.
//!
//! This library only comes with 3 public ways to initialize the global logger.
//! Ensure you call one of these exactly once early in your rust program as shown
//! in one of the examples below.
//!
//! ## Example
//! The standard example with `clap` as the arg parser.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate clap;
//! extern crate loggerv;
//!
//! use clap::{Arg, App};
//!
//! fn main() {
//!     let args = App::new("app")
//!                    .arg(Arg::with_name("v")
//!                             .short("v")
//!                             .multiple(true)
//!                             .help("Sets the level of verbosity"))
//!                    .get_matches();
//!
//!     loggerv::init_with_verbosity(args.occurrences_of("v")).unwrap();
//!
//!     error!("this is always printed");
//!     warn!("this too, and it's printed to stderr");
//!     info!("this is optional");  // for ./app -v or higher
//!     debug!("this is optional"); // for ./app -vv or higher
//!     trace!("this is optional"); // for ./app -vvv
//! }
//! ```
//!
//! But obviously use whatever argument parsing methods you prefer.
//!
//! ## Example
//! For a compile time switch, all you really need is `log` (for the macros)
//! and `loggerv` for how to print what's being sent to the macros.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! use log::LogLevel;
//!
//! fn main() {
//!     loggerv::init_with_level(LogLevel::Info).unwrap();
//!     debug!("this is a debug {}", "message");
//!     error!("this is printed by default");
//! }
//! ```
//!
//! # Example
//! If you don't really care at all you could just use the plain `init_quiet` function
//! to only show warnings and errors:
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! fn main() {
//!     loggerv::init_quiet().unwrap();
//!     info!("hidden");
//!     error!("this is printed by default");
//! }
//! ```
//!
//!
//! See the documentation for the log crate for more information about its API.
//!

#[cfg(test)]
#[macro_use]
extern crate log;

#[cfg(not(test))]
extern crate log;

extern crate atty;
extern crate ansi_term;

use log::{Log, LogLevel, LogMetadata, LogRecord, SetLoggerError};
use std::io::{self, Write};
use ansi_term::Colour;

struct VLogger {
    log_level: LogLevel,
}

fn level_style(l: LogLevel) -> Colour {
    match l {
        LogLevel::Error => Colour::Fixed(9), // bright red
        LogLevel::Warn => Colour::Fixed(11), // bright yellow
        LogLevel::Info => Colour::Fixed(10), // bright green
        LogLevel::Debug => Colour::Fixed(7), // light grey
        LogLevel::Trace => Colour::Fixed(8), // grey
    }
}

impl Log for VLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.log_level
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let level = if atty::is(atty::Stream::Stdout) && atty::is(atty::Stream::Stderr) {
                format!("{}",
                        level_style(record.level()).paint(record.location().module_path()))
            } else {
                format!("{}", record.location().module_path())
            };

            if record.level() <= LogLevel::Warn {
                let _ = writeln!(&mut io::stderr(), "{}: {}", level, record.args());
            } else {
                println!("{}: {}", level, record.args());
            }
        }
    }
}

/// Initialize loggerv with a maximal log level.
///
/// See the main loggerv documentation page for an example.
pub fn init_with_level(log_level: LogLevel) -> Result<(), SetLoggerError> {
    log::set_logger(|max_log_level| {
        max_log_level.set(log_level.to_log_level_filter());
        Box::new(VLogger { log_level: log_level })
    })
}

/// Initialize loggerv with a verbosity level.
///
/// Intended to be used with an arg parser counting the amount of -v flags.
/// See the main loggerv documentation page for an example.
pub fn init_with_verbosity(verbosity: u64) -> Result<(), SetLoggerError> {
    init_with_level(match verbosity {
        0 => LogLevel::Warn,  // default
        1 => LogLevel::Info,  // -v
        2 => LogLevel::Debug, // -vv
        _ => LogLevel::Trace, // -vvv and above
    })
}

/// Initializes loggerv with only warnings and errors.
///
/// See the main loggerv documentation page for an example.
pub fn init_quiet() -> Result<(), SetLoggerError> {
    init_with_level(LogLevel::Warn)
}

#[cfg(test)]
mod tests {
    use init_with_verbosity;

    #[test]
    fn init_and_macros() {
        let l = init_with_verbosity(3);
        assert_eq!(l.is_ok(), true);
        error!("error log");
        warn!("warn log");
        info!("info log");
        debug!("debug log");
        trace!("trace log");
    }
}
<commit_msg>use to_string over format!{}<commit_after>//! A simple `io::stdout` and `io::stderr` writing `Logger` implementation from the
//! `log` crate, using the `ansi_term` crate for colors and configured at runtime,
//! or at compile time with simple function calls. Designed for simple CLIs.
//!
//! This library only comes with 3 public ways to initialize the global logger.
//! Ensure you call one of these exactly once early in your rust program as shown
//! in one of the examples below.
//!
//! ## Example
//! The standard example with `clap` as the arg parser.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate clap;
//! extern crate loggerv;
//!
//! use clap::{Arg, App};
//!
//! fn main() {
//!     let args = App::new("app")
//!                    .arg(Arg::with_name("v")
//!                             .short("v")
//!                             .multiple(true)
//!                             .help("Sets the level of verbosity"))
//!                    .get_matches();
//!
//!     loggerv::init_with_verbosity(args.occurrences_of("v")).unwrap();
//!
//!     error!("this is always printed");
//!     warn!("this too, and it's printed to stderr");
//!     info!("this is optional");  // for ./app -v or higher
//!     debug!("this is optional"); // for ./app -vv or higher
//!     trace!("this is optional"); // for ./app -vvv
//! }
//! ```
//!
//! But obviously use whatever argument parsing methods you prefer.
//!
//! ## Example
//! For a compile time switch, all you really need is `log` (for the macros)
//! and `loggerv` for how to print what's being sent to the macros.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! use log::LogLevel;
//!
//! fn main() {
//!     loggerv::init_with_level(LogLevel::Info).unwrap();
//!     debug!("this is a debug {}", "message");
//!     error!("this is printed by default");
//! }
//! ```
//!
//! # Example
//! If you don't really care at all you could just use the plain `init_quiet` function
//! to only show warnings and errors:
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! fn main() {
//!     loggerv::init_quiet().unwrap();
//!     info!("hidden");
//!     error!("this is printed by default");
//! }
//! ```
//!
//!
//! See the documentation for the log crate for more information about its API.
//!

#[cfg(test)]
#[macro_use]
extern crate log;

#[cfg(not(test))]
extern crate log;

extern crate atty;
extern crate ansi_term;

use log::{Log, LogLevel, LogMetadata, LogRecord, SetLoggerError};
use std::io::{self, Write};
use ansi_term::Colour;

struct VLogger {
    log_level: LogLevel,
}

fn level_style(l: LogLevel) -> Colour {
    match l {
        LogLevel::Error => Colour::Fixed(9), // bright red
        LogLevel::Warn => Colour::Fixed(11), // bright yellow
        LogLevel::Info => Colour::Fixed(10), // bright green
        LogLevel::Debug => Colour::Fixed(7), // light grey
        LogLevel::Trace => Colour::Fixed(8), // grey
    }
}

impl Log for VLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.log_level
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let level = if atty::is(atty::Stream::Stdout) && atty::is(atty::Stream::Stderr) {
                level_style(record.level()).paint(record.location().module_path()).to_string()
            } else {
                record.location().module_path().to_string()
            };

            if record.level() <= LogLevel::Warn {
                let _ = writeln!(&mut io::stderr(), "{}: {}", level, record.args());
            } else {
                println!("{}: {}", level, record.args());
            }
        }
    }
}

/// Initialize loggerv with a maximal log level.
///
/// See the main loggerv documentation page for an example.
pub fn init_with_level(log_level: LogLevel) -> Result<(), SetLoggerError> {
    log::set_logger(|max_log_level| {
        max_log_level.set(log_level.to_log_level_filter());
        Box::new(VLogger { log_level: log_level })
    })
}

/// Initialize loggerv with a verbosity level.
///
/// Intended to be used with an arg parser counting the amount of -v flags.
/// See the main loggerv documentation page for an example.
pub fn init_with_verbosity(verbosity: u64) -> Result<(), SetLoggerError> {
    init_with_level(match verbosity {
        0 => LogLevel::Warn,  // default
        1 => LogLevel::Info,  // -v
        2 => LogLevel::Debug, // -vv
        _ => LogLevel::Trace, // -vvv and above
    })
}

/// Initializes loggerv with only warnings and errors.
///
/// See the main loggerv documentation page for an example.
pub fn init_quiet() -> Result<(), SetLoggerError> {
    init_with_level(LogLevel::Warn)
}

#[cfg(test)]
mod tests {
    use init_with_verbosity;

    #[test]
    fn init_and_macros() {
        let l = init_with_verbosity(3);
        assert_eq!(l.is_ok(), true);
        error!("error log");
        warn!("warn log");
        info!("info log");
        debug!("debug log");
        trace!("trace log");
    }
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate rayon;
// extern crate crossbeam;

use self::rand::{thread_rng, Rng};
use std::sync::{Arc, Mutex, RwLock};
use rayon::prelude::*;

#[derive(Clone, PartialEq, Eq)]
pub struct GameCell {
	x: usize,
	y: usize,
	pub alive: bool,
}

impl GameCell {
	fn count_neighbors(&self, board: &Vec<GameCell>, size: usize) -> u8 {
		let mut count: u8 = 0;

		// UL
		if let Some(&GameCell {alive: true, ..}) = board.get((self.y - 1) * size + self.x - 1) { count += 1; }

		// UU
		if let Some(&GameCell {alive: true, ..}) = board.get((self.y - 1) * size + self.x + 0) { count += 1; }

		// UR
		if let Some(&GameCell {alive: true, ..}) = board.get((self.y - 1) * size + self.x + 1) { count += 1; }

		// L
		if let Some(&GameCell {alive: true, ..}) = board.get(self.y * size + self.x - 1)       { count += 1; }

		// R
		if let Some(&GameCell {alive: true, ..}) = board.get(self.y * size + self.x + 1)       { count += 1; }

		// DL
		if let Some(&GameCell {alive: true, ..}) = board.get((self.y + 1) * size + self.x - 1) { count += 1; }

		// DD
		if let Some(&GameCell {alive: true, ..}) = board.get((self.y + 1) * size + self.x + 0) { count += 1; }

		// DR
		if let Some(&GameCell {alive: true, ..}) = board.get((self.y + 1) * size + self.x + 1) { count += 1; }

		count
	}
}

// struct Board( Vec<GameCell> );

// impl Index<usize> for Board {
// 	type Output = State;

// 	fn index(&self, index: usize) -> &State {
// 		self.0[index].state;
// 	}
// }

#[derive(Clone)]
pub struct Game {
	pub size: usize,
	current: Arc<RwLock< Vec<GameCell> >>,
	next: Arc<Mutex< Vec<GameCell> >>,
}

// impl From<Vec<State>> for Game {
// 	fn from(preset_game: Vec<State>) -> Self {
// 		let size: usize = (preset_game.len() as f64).sqrt() as usize;
// 		assert!(size >= 3);

// 		Game {
// 			size: size,
// 			current: Arc::new(RwLock::new(preset_game.clone())),
// 			next: Arc::new(Mutex::new(preset_game.clone()))
// 		}
// 	}
// }

impl Game {
	pub fn new(size: usize, percent_chance_for_cell_to_be_alive: f64) -> Game {
		assert!(size >= 3);
		assert!(percent_chance_for_cell_to_be_alive < 1.0);
		assert!(percent_chance_for_cell_to_be_alive >= 0.0);

		let mut board = vec![GameCell {x: 0, y: 0, alive: false}; size*size];

		for y in 0..size {
			for x in 0..size {
				let index = y * size + x;
				board[index].x = x;
				board[index].y = y;
				board[index].alive = match thread_rng().next_f64() {
					i if i < percent_chance_for_cell_to_be_alive => true,
					_ => false,
				};
			}
		}

		Game {
			size: size,
			current: Arc::new(RwLock::new(board)),
			next: Arc::new(Mutex::new(Vec::with_capacity(size))),
		}
	}

	pub fn get_current_read_lock(&self) -> std::sync::RwLockReadGuard< Vec<GameCell> > {
		self.current.read().unwrap()
	}

	fn get_next_cell_from_current_cell_and_neighbors(game_cell: &GameCell, number_of_neighbors: u8) -> GameCell {
		match game_cell.alive {
			false => {
				if number_of_neighbors != 3 {
					GameCell {x: game_cell.x, y: game_cell.y, alive: false}
				} else {
					GameCell {x: game_cell.x, y: game_cell.y, alive: true}
				}
			},
			true => {
				if number_of_neighbors < 2 || number_of_neighbors > 3 {
					GameCell {x: game_cell.x, y: game_cell.y, alive: false}
				} else {
					GameCell {x: game_cell.x, y: game_cell.y, alive: true}
				}
			},
		}
	}

	pub fn advance(&self) {
		let mut next_guard = self.next.lock().unwrap();
		let current_guard = self.current.read().unwrap();

		current_guard.par_iter()
			.map(|game_cell| {
				let neighbor_count = game_cell.count_neighbors(&*current_guard, self.size);
				Game::get_next_cell_from_current_cell_and_neighbors(game_cell, neighbor_count)
			})
			.collect_into(&mut *next_guard);

		// Exchange read lock for write lock
		drop(current_guard);
		let mut current_guard = self.current.write().unwrap();

		*current_guard = next_guard.clone();
	}

	// pub fn advance_toroidally(&self) {
	// 	// Get read lock for 'current' and mutex lock for 'next'
	// 	// N.B. By locking 'next' first, this ensures that if another thread tries
	// 	// 		to call 'advance', that thread will block until this is done.
	// 	let mut next = self.next.lock().unwrap();
	// 	let current = self.current.read().unwrap();

	// 	for y in 0..self.size {
	// 		for x in 0..self.size {
	// 			let ul = if y >= 1 {
	// 				if x != 0 { current[(y - 1) * self.size + x - 1] } // normal case
	// 				else { current[y * self.size - 1] } // left edge
	// 			} else {
	// 				if x != 0 { current[(self.size - 1) * self.size + x - 1] } // top edge
	// 				else { current[self.size * self.size - 1] } // top-left corner
	// 			};

	// 			let uu = if y >= 1 {
	// 				current[(y - 1) * self.size + x + 0] // normal case
	// 			} else {
	// 				current[(self.size - 1) * self.size + x + 0] // top edge
	// 			};

	// 			let ur = if y >= 1 {
	// 				if x != self.size - 1 { current[(y - 1) * self.size + x + 1] } // normal case
	// 				else { current[(y - 1) * self.size + 0] } // right edge
	// 			} else {
	// 				if x != self.size - 1 { current[(self.size - 1) * self.size + x + 1] } // top edge
	// 				else { current[(self.size - 1) * self.size + 0] } // top-right corner
	// 			};

	// 			let l = if x != 0 {
	// 				current[y * self.size + x - 1] // normal case
	// 			} else {
	// 				current[(y + 1) * self.size - 1] // left edge
	// 			};

	// 			let r = if x != self.size - 1 {
	// 				current[y * self.size + x + 1] // normal case
	// 			} else {
	// 				current[y * self.size + 0] // right edge
	// 			};

	// 			let dl = if y != self.size - 1 {
	// 				if x != 0 { current[(y + 1) * self.size + x - 1] } // normal case
	// 				else { current[(y + 2) * self.size - 1] } // left edge
	// 			} else {
	// 				if x != 0 { current[x - 1] } // bottom edge
	// 				else { current[self.size - 1] } // bottom-left corner
	// 			};

	// 			let dd = if y != self.size - 1 {
	// 				current[(y + 1) * self.size + x + 0] // normal case
	// 			} else {
	// 				current[x + 0] // bottom edge
	// 			};

	// 			let dr = if y != self.size - 1 {
	// 				if x != self.size - 1 { current[(y + 1) * self.size + x + 1] } // normal case
	// 				else { current[(y + 1) * self.size] } // right edge
	// 			} else {
	// 				if x != self.size - 1 { current[x + 1] } // bottom edge
	// 				else { current[0] } // bottom-right corner
	// 			};

	// 			let mut neighbors: usize = 0;
	// 			if ul == State::Alive { neighbors += 1; }
	// 			if uu == State::Alive { neighbors += 1; }
	// 			if ur == State::Alive { neighbors += 1; }
	// 			if l == State::Alive { neighbors += 1; }
	// 			if r == State::Alive { neighbors += 1; }
	// 			if dl == State::Alive { neighbors += 1; }
	// 			if dd == State::Alive { neighbors += 1; }
	// 			if dr == State::Alive { neighbors += 1; }

	// 			next[y * self.size + x] = Game::get_next_cell_from_current_cell_and_neighbors(current[y * self.size + x], neighbors);
	// 		}
	// 	}

	// 	// Exchange read lock for write lock
	// 	drop(current);
	// 	let mut current = self.current.write().unwrap();

	// 	*current = next.clone();
	// }
}
<commit_msg>Revert to original neighbor counting code<commit_after>extern crate rand;
extern crate rayon;
// extern crate crossbeam;

use self::rand::{thread_rng, Rng};
use std::sync::{Arc, Mutex, RwLock};
use rayon::prelude::*;

#[derive(Clone, PartialEq, Eq)]
pub struct GameCell {
	x: usize,
	y: usize,
	pub alive: bool,
}

impl GameCell {
	fn count_neighbors(&self, board: &Vec<GameCell>, size: usize) -> u8 {
		let ul = if self.y >= 1 && self.x != 0 { board[(self.y - 1) * size + self.x - 1].alive } else {false};
		let uu = if self.y >= 1 {board[(self.y - 1) * size + self.x + 0].alive } else {false};
		let ur = if self.y >= 1 && self.x != size - 1 { board[(self.y - 1) * size + self.x + 1].alive } else {false};
		let l  = if self.x != 0 {board[self.y * size + self.x - 1].alive } else {false};
		let r  = if self.x != size - 1 {board[self.y * size + self.x + 1].alive } else {false};
		let dl = if self.y != size - 1 && self.x != 0 {board[(self.y + 1) * size + self.x - 1].alive } else {false};
		let dd = if self.y != size - 1 {board[(self.y + 1) * size + self.x + 0].alive } else {false};
		let dr = if self.y != size - 1 && self.x != size - 1 {board[(self.y + 1) * size + self.x + 1].alive } else {false};

		let mut neighbors: u8 = 0;
		if ul == true { neighbors += 1; }
		if uu == true { neighbors += 1; }
		if ur == true { neighbors += 1; }
		if l  == true { neighbors += 1; }
		if r  == true { neighbors += 1; }
		if dl == true { neighbors += 1; }
		if dd == true { neighbors += 1; }
		if dr == true { neighbors += 1; }

		neighbors
	}
}

// struct Board( Vec<GameCell> );

// impl Index<usize> for Board {
// 	type Output = State;

// 	fn index(&self, index: usize) -> &State {
// 		self.0[index].state;
// 	}
// }

#[derive(Clone)]
pub struct Game {
	pub size: usize,
	current: Arc<RwLock< Vec<GameCell> >>,
	next: Arc<Mutex< Vec<GameCell> >>,
}

// impl From<Vec<State>> for Game {
// 	fn from(preset_game: Vec<State>) -> Self {
// 		let size: usize = (preset_game.len() as f64).sqrt() as usize;
// 		assert!(size >= 3);

// 		Game {
// 			size: size,
// 			current: Arc::new(RwLock::new(preset_game.clone())),
// 			next: Arc::new(Mutex::new(preset_game.clone()))
// 		}
// 	}
// }

impl Game {
	pub fn new(size: usize, percent_chance_for_cell_to_be_alive: f64) -> Game {
		assert!(size >= 3);
		assert!(percent_chance_for_cell_to_be_alive < 1.0);
		assert!(percent_chance_for_cell_to_be_alive >= 0.0);

		let mut board = vec![GameCell {x: 0, y: 0, alive: false}; size*size];

		for y in 0..size {
			for x in 0..size {
				let index = y * size + x;
				board[index].x = x;
				board[index].y = y;
				board[index].alive = match thread_rng().next_f64() {
					i if i < percent_chance_for_cell_to_be_alive => true,
					_ => false,
				};
			}
		}

		Game {
			size: size,
			current: Arc::new(RwLock::new(board)),
			next: Arc::new(Mutex::new(Vec::with_capacity(size))),
		}
	}

	pub fn get_current_read_lock(&self) -> std::sync::RwLockReadGuard< Vec<GameCell> > {
		self.current.read().unwrap()
	}

	fn get_next_cell_from_current_cell_and_neighbors(game_cell: &GameCell, number_of_neighbors: u8) -> GameCell {
		match game_cell.alive {
			false => {
				if number_of_neighbors != 3 {
					GameCell {x: game_cell.x, y: game_cell.y, alive: false}
				} else {
					GameCell {x: game_cell.x, y: game_cell.y, alive: true}
				}
			},
			true => {
				if number_of_neighbors < 2 || number_of_neighbors > 3 {
					GameCell {x: game_cell.x, y: game_cell.y, alive: false}
				} else {
					GameCell {x: game_cell.x, y: game_cell.y, alive: true}
				}
			},
		}
	}

	pub fn advance(&self) {
		let mut next_guard = self.next.lock().unwrap();
		let current_guard = self.current.read().unwrap();

		current_guard.par_iter()
			.map(|game_cell| {
				let neighbor_count = game_cell.count_neighbors(&*current_guard, self.size);
				Game::get_next_cell_from_current_cell_and_neighbors(game_cell, neighbor_count)
			})
			.collect_into(&mut *next_guard);

		// Exchange read lock for write lock
		drop(current_guard);
		let mut current_guard = self.current.write().unwrap();

		*current_guard = next_guard.clone();
	}

	// pub fn advance_toroidally(&self) {
	// 	// Get read lock for 'current' and mutex lock for 'next'
	// 	// N.B. By locking 'next' first, this ensures that if another thread tries
	// 	// 		to call 'advance', that thread will block until this is done.
	// 	let mut next = self.next.lock().unwrap();
	// 	let current = self.current.read().unwrap();

	// 	for y in 0..self.size {
	// 		for x in 0..self.size {
	// 			let ul = if y >= 1 {
	// 				if x != 0 { current[(y - 1) * self.size + x - 1] } // normal case
	// 				else { current[y * self.size - 1] } // left edge
	// 			} else {
	// 				if x != 0 { current[(self.size - 1) * self.size + x - 1] } // top edge
	// 				else { current[self.size * self.size - 1] } // top-left corner
	// 			};

	// 			let uu = if y >= 1 {
	// 				current[(y - 1) * self.size + x + 0] // normal case
	// 			} else {
	// 				current[(self.size - 1) * self.size + x + 0] // top edge
	// 			};

	// 			let ur = if y >= 1 {
	// 				if x != self.size - 1 { current[(y - 1) * self.size + x + 1] } // normal case
	// 				else { current[(y - 1) * self.size + 0] } // right edge
	// 			} else {
	// 				if x != self.size - 1 { current[(self.size - 1) * self.size + x + 1] } // top edge
	// 				else { current[(self.size - 1) * self.size + 0] } // top-right corner
	// 			};

	// 			let l = if x != 0 {
	// 				current[y * self.size + x - 1] // normal case
	// 			} else {
	// 				current[(y + 1) * self.size - 1] // left edge
	// 			};

	// 			let r = if x != self.size - 1 {
	// 				current[y * self.size + x + 1] // normal case
	// 			} else {
	// 				current[y * self.size + 0] // right edge
	// 			};

	// 			let dl = if y != self.size - 1 {
	// 				if x != 0 { current[(y + 1) * self.size + x - 1] } // normal case
	// 				else { current[(y + 2) * self.size - 1] } // left edge
	// 			} else {
	// 				if x != 0 { current[x - 1] } // bottom edge
	// 				else { current[self.size - 1] } // bottom-left corner
	// 			};

	// 			let dd = if y != self.size - 1 {
	// 				current[(y + 1) * self.size + x + 0] // normal case
	// 			} else {
	// 				current[x + 0] // bottom edge
	// 			};

	// 			let dr = if y != self.size - 1 {
	// 				if x != self.size - 1 { current[(y + 1) * self.size + x + 1] } // normal case
	// 				else { current[(y + 1) * self.size] } // right edge
	// 			} else {
	// 				if x != self.size - 1 { current[x + 1] } // bottom edge
	// 				else { current[0] } // bottom-right corner
	// 			};

	// 			let mut neighbors: usize = 0;
	// 			if ul == State::Alive { neighbors += 1; }
	// 			if uu == State::Alive { neighbors += 1; }
	// 			if ur == State::Alive { neighbors += 1; }
	// 			if l == State::Alive { neighbors += 1; }
	// 			if r == State::Alive { neighbors += 1; }
	// 			if dl == State::Alive { neighbors += 1; }
	// 			if dd == State::Alive { neighbors += 1; }
	// 			if dr == State::Alive { neighbors += 1; }

	// 			next[y * self.size + x] = Game::get_next_cell_from_current_cell_and_neighbors(current[y * self.size + x], neighbors);
	// 		}
	// 	}

	// 	// Exchange read lock for write lock
	// 	drop(current);
	// 	let mut current = self.current.write().unwrap();

	// 	*current = next.clone();
	// }
}
<|endoftext|>


<commit_before>//! File locking via POSIX advisory record locks.
//!
//! This crate provides the facility to lock and unlock a file following the
//! advisory record lock scheme as specified by UNIX IEEE Std 1003.1-2001
//! (POSIX.1) via `fcntl()`.
//!
//! # Examples
//!
//! ```
//! extern crate file_lock;
//!
//! use file_lock::*;
//! use file_lock::Error::*;
//!
//! fn main() {
//!     let l = lock("/tmp/file-lock-test");
//!
//!     match l {
//!         Ok(_)  => println!("Got lock"),
//!         Err(e) => match e {
//!             InvalidFilename => println!("Invalid filename"),
//!             Errno(i)        => println!("Got filesystem error {}", i),
//!         }
//!     }
//! }
//! ```

extern crate libc;

use std::ffi::CString;

/// Represents a lock on a file.
pub struct Lock {
  _fd: i32,
}

/// Represents the error that occured while trying to lock or unlock a file.
pub enum Error {
  /// caused when the filename is invalid as it contains a nul byte.
  InvalidFilename,
  /// caused when the error occurred at the filesystem layer (see
  /// [errno](https://crates.io/crates/errno)).
  Errno(i32),
}

#[repr(C)]
struct c_result {
  _fd:    i32,
  _errno: i32,
}

macro_rules! _create_lock_type {
  ($lock_type:ident, $c_lock_type:ident) => {
    extern {
      fn $c_lock_type(filename: *const libc::c_char) -> c_result;
    }

    /// Locks the specified file.
    ///
    /// The `lock()` and `lock_wait()` functions try to perform a lock on the
    /// specified file. The difference between the two is what they do when
    /// another process has a lock on the same file:
    ///
    /// * lock() - immediately return with an `Errno` error.
    /// * lock_wait() - waits (i.e. blocks the running thread) for the current
    /// owner of the lock to relinquish the lock.
    ///
    /// # Example
    ///
    /// ```
    /// extern crate file_lock;
    ///
    /// use file_lock::*;
    /// use file_lock::Error::*;
    ///
    /// fn main() {
    ///     let l = lock("/tmp/file-lock-test");
    ///
    ///     match l {
    ///         Ok(_)  => println!("Got lock"),
    ///         Err(e) => match e {
    ///             InvalidFilename => println!("Invalid filename"),
    ///             Errno(i)        => println!("Got filesystem error {}", i),
    ///         }
    ///     }
    /// }
    /// ```
    pub fn $lock_type(filename: &str) -> Result<Lock, Error> {
      let raw_filename = CString::new(filename);

      if raw_filename.is_err() {
        return Err(Error::InvalidFilename);
      }

      unsafe {
        let my_result = $c_lock_type(raw_filename.unwrap().as_ptr());

        return match my_result._fd {
          -1 => Err(Error::Errno(my_result._errno)),
           _ => Ok(Lock{_fd: my_result._fd}),
        }
      }
    }
  };
}

_create_lock_type!(lock, c_lock);
_create_lock_type!(lock_wait, c_lock_wait);

extern {
  fn c_unlock(_fd: i32) -> c_result;
}

/// Unlocks the file held by `Lock`.
///
/// In reality, you shouldn't need to call `unlock()`. As `Lock` implements
/// the `Drop` trait, once the `Lock` reference goes out of scope, `unlock()`
/// will be called automatically.
///
/// # Example
///
/// ```
/// extern crate file_lock;
///
/// use file_lock::*;
///
/// fn main() {
///     let l = lock("/tmp/file-lock-test").ok().unwrap();
///
///     if unlock(&l).is_ok() {
///         println!("Unlocked!");
///     }
/// }
/// ```
pub fn unlock(lock: &Lock) -> Result<bool, Error> {
  unsafe {
    let my_result = c_unlock(lock._fd);

    return match my_result._fd {
      -1 => Err(Error::Errno(my_result._errno)),
       _ => Ok(true),
    }
  }
}

#[allow(unused_must_use)]
impl Drop for Lock {
  fn drop(&mut self) {
    unlock(self);
  }
}

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

    //
    // unfortunately we can't abstract this out for lock() and lock_wait()
    // into a macro because string concat doesn't exist
    //

    // lock_wait() tests

    #[test]
    fn lock_invalid_filename() {
        assert_eq!(_lock("null\0inside"), "invalid");
    }

    #[test]
    fn lock_errno() {
        assert_eq!(_lock(""), "errno");
    }

    #[test]
    fn lock_ok() {
        assert_eq!(_lock("/tmp/file-lock-test"), "ok");
    }

    fn _lock(filename: &str) -> &str {
        let l = lock(filename);

        match l {
            Ok(_)  => "ok",
            Err(e) => match e {
                InvalidFilename => "invalid",
                Errno(_)        => "errno",
            }
        }
    }

    // lock_wait() tests

    #[test]
    fn lock_wait_invalid_filename() {
        assert_eq!(_lock_wait("null\0inside"), "invalid");
    }

    #[test]
    fn lock_wait_errno() {
        assert_eq!(_lock_wait(""), "errno");
    }

    #[test]
    fn lock_wait_ok() {
        assert_eq!(_lock_wait("/tmp/file-lock-test"), "ok");
    }

    fn _lock_wait(filename: &str) -> &str {
        let l = lock_wait(filename);

        match l {
            Ok(_)  => "ok",
            Err(e) => match e {
                InvalidFilename => "invalid",
                Errno(_)        => "errno",
            }
        }
    }

    // unlock()

    //
    // fcntl() will only allow us to hold a single lock on a file at a time
    // so this test can't work :(
    //
    // #[test]
    // fn unlock_error() {
    //     let l1 = lock("/tmp/file-lock-test");
    //     let l2 = lock("/tmp/file-lock-test");
    //
    //     assert!(l1.is_ok());
    //     assert!(l2.is_err());
    // }
    //

    #[test]
    fn unlock_ok() {
        let l        = lock_wait("/tmp/file-lock-test");
        let unlocked = l.ok().unwrap();

        assert!(unlock(&unlocked).is_ok(), true);
    }
}
<commit_msg>refactor(lib): made code more idiomatic<commit_after>//! File locking via POSIX advisory record locks.
//!
//! This crate provides the facility to lock and unlock a file following the
//! advisory record lock scheme as specified by UNIX IEEE Std 1003.1-2001
//! (POSIX.1) via `fcntl()`.
//!
//! # Examples
//!
//! ```
//! extern crate file_lock;
//!
//! use file_lock::*;
//! use file_lock::Error::*;
//!
//! fn main() {
//!     let l = lock("/tmp/file-lock-test");
//!
//!     match l {
//!         Ok(_)  => println!("Got lock"),
//!         Err(e) => match e {
//!             InvalidFilename => println!("Invalid filename"),
//!             Errno(i)        => println!("Got filesystem error {}", i),
//!         }
//!     }
//! }
//! ```

extern crate libc;

use std::ffi::CString;

/// Represents a lock on a file.
#[derive(Debug, Eq, PartialEq)]
pub struct Lock {
  _fd: i32,
}

/// Represents the error that occurred while trying to lock or unlock a file.
#[derive(Debug, Eq, PartialEq)]
pub enum Error {
  /// caused when the filename is invalid as it contains a null byte.
  InvalidFilename,
  /// caused when the error occurred at the filesystem layer (see
  /// [errno](https://crates.io/crates/errno)).
  Errno(i32),
}

#[repr(C)]
struct c_result {
  _fd:    i32,
  _errno: i32,
}

macro_rules! _create_lock_type {
  ($lock_type:ident, $c_lock_type:ident) => {
    extern {
      fn $c_lock_type(filename: *const libc::c_char) -> c_result;
    }

    /// Locks the specified file.
    ///
    /// The `lock()` and `lock_wait()` functions try to perform a lock on the
    /// specified file. The difference between the two is what they do when
    /// another process has a lock on the same file:
    ///
    /// * lock() - immediately return with an `Errno` error.
    /// * lock_wait() - waits (i.e. blocks the running thread) for the current
    /// owner of the lock to relinquish the lock.
    ///
    /// # Example
    ///
    /// ```
    /// extern crate file_lock;
    ///
    /// use file_lock::*;
    /// use file_lock::Error::*;
    ///
    /// fn main() {
    ///     let l = lock("/tmp/file-lock-test");
    ///
    ///     match l {
    ///         Ok(_)  => println!("Got lock"),
    ///         Err(e) => match e {
    ///             InvalidFilename => println!("Invalid filename"),
    ///             Errno(i)        => println!("Got filesystem error {}", i),
    ///         }
    ///     }
    /// }
    /// ```
    pub fn $lock_type(filename: &str) -> Result<Lock, Error> {
      let raw_filename = CString::new(filename);

      if raw_filename.is_err() {
        return Err(Error::InvalidFilename);
      }

      unsafe {
        let my_result = $c_lock_type(raw_filename.unwrap().as_ptr());

        return match my_result._fd {
          -1 => Err(Error::Errno(my_result._errno)),
           _ => Ok(Lock{_fd: my_result._fd}),
        }
      }
    }
  };
}

_create_lock_type!(lock, c_lock);
_create_lock_type!(lock_wait, c_lock_wait);

extern {
  fn c_unlock(_fd: i32) -> c_result;
}

/// Unlocks the file held by `Lock`.
///
/// In reality, you shouldn't need to call `unlock()`. As `Lock` implements
/// the `Drop` trait, once the `Lock` reference goes out of scope, `unlock()`
/// will be called automatically.
///
/// # Example
///
/// ```
/// extern crate file_lock;
///
/// use file_lock::*;
///
/// fn main() {
///     let l = lock("/tmp/file-lock-test").unwrap();
///
///     if unlock(&l).is_ok() {
///         println!("Unlocked!");
///     }
/// }
/// ```
pub fn unlock(lock: &Lock) -> Result<bool, Error> {
  unsafe {
    let my_result = c_unlock(lock._fd);

    return match my_result._fd {
      -1 => Err(Error::Errno(my_result._errno)),
       _ => Ok(true),
    }
  }
}

#[allow(unused_must_use)]
impl Drop for Lock {
  fn drop(&mut self) {
    unlock(self);
  }
}

#[cfg(test)]
mod test {
    use libc;

    use super::*;
    use super::Error::*;

    //
    // unfortunately we can't abstract this out for lock() and lock_wait()
    // into a macro because string concat doesn't exist
    //

    // lock_wait() tests

    #[test]
    fn lock_invalid_filename() {
        assert_eq!(lock("null\0inside"), Err(Error::InvalidFilename));
    }

    #[test]
    fn lock_errno() {
        assert_eq!(lock(""), Err(Error::Errno(libc::consts::os::posix88::ENOENT)));
    }

    #[test]
    fn lock_ok() {
        assert!(lock("/tmp/file-lock-test").is_ok());
    }

    // lock_wait() tests

    #[test]
    fn lock_wait_invalid_filename() {
        assert_eq!(lock_wait("null\0inside"), Err(Error::InvalidFilename));
    }

    #[test]
    fn lock_wait_errno() {
        assert_eq!(lock_wait(""), Err(Error::Errno(libc::consts::os::posix88::ENOENT)));
    }

    #[test]
    fn lock_wait_ok() {
        assert!(lock_wait("/tmp/file-lock-test").is_ok());
    }

    // unlock()

    // fcntl() will only allow us to hold a single lock on a file at a time
    // so this test can't work :(

    #[test]
    #[should_panic]
    fn unlock_error() {
        let l1 = lock("/tmp/file-lock-test");
        let l2 = lock("/tmp/file-lock-test");

        assert!(l1.is_ok());
        assert!(l2.is_err());
    }

    #[test]
    fn unlock_ok() {
        let l        = lock_wait("/tmp/file-lock-test");
        let unlocked = l.unwrap();

        assert!(unlock(&unlocked).is_ok(), true);
    }
}
<|endoftext|>


<commit_before>extern crate glob;
extern crate nix;
extern crate reqwest;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate toml;

#[macro_use]
extern crate lazy_static;

use std::ffi::CStr;
use std::io::{BufRead, Write};
extern crate libc;

mod structs;
use structs::Config;
mod buffer;
mod ghclient;
use buffer::Buffer;
mod cstructs;
use cstructs::{Group, Passwd, Spwd};
mod runfiles;
mod statics;
use statics::{CLIENT, CONFIG};

#[allow(dead_code)]
enum NssStatus {
    TryAgain,
    Unavail,
    NotFound,
    Success,
}

impl From<NssStatus> for libc::c_int {
    fn from(status: NssStatus) -> libc::c_int {
        match status {
            NssStatus::TryAgain => -2,
            NssStatus::Unavail => -1,
            NssStatus::NotFound => 0,
            NssStatus::Success => 1,
        }
    }
}

fn string_from(cstrptr: *const libc::c_char) -> String {
    let cstr: &CStr = unsafe { CStr::from_ptr(cstrptr) };
    String::from(cstr.to_str().unwrap_or(""))
}

macro_rules! succeed {
    () => {{
        return libc::c_int::from(NssStatus::Success);
    }};
    ($finalize:expr) => {{
        $finalize;
        return libc::c_int::from(NssStatus::Success);
    }};
}

macro_rules! fail {
    ($err_no_p:ident, $err_no:expr, $return_val:expr) => {{
        unsafe { *$err_no_p = $err_no as libc::c_int };
        return libc::c_int::from($return_val);
    }};
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getpwnam_r(cnameptr: *const libc::c_char, pwptr: *mut Passwd, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let name = string_from(cnameptr);
    match CLIENT.get_sectors() {
        Ok(sectors) => {
            for sector in sectors {
                if let Some(member) = sector.members.get(&name) {
                    match unsafe {
                              (*pwptr).pack_args(&mut buffer, &member.login, member.id, sector.get_gid(), &CONFIG)
                          } {
                        Ok(_) => succeed!(),
                        Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
                    }
                }
            }
        }
        Err(_) => fail!(errnop, nix::Errno::EAGAIN, NssStatus::TryAgain),
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getpwuid_r(uid: libc::uid_t, pwptr: *mut Passwd, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    match CLIENT.get_sectors() {
        Ok(sectors) => {
            for sector in sectors {
                for member in sector.members.values() {
                    if uid == member.id as libc::uid_t {
                        match unsafe {
                                  (*pwptr).pack_args(&mut buffer, &member.login, member.id, sector.get_gid(), &CONFIG)
                              } {
                            Ok(_) => succeed!(),
                            Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
                        }
                    }
                }
            }
        }
        Err(_) => fail!(errnop, nix::Errno::EAGAIN, NssStatus::TryAgain),
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_setpwent() -> libc::c_int {
    let mut list_file = match runfiles::create() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    match CLIENT.get_sectors() {
        Ok(sectors) => {
            for sector in sectors {
                for member in sector.members.values() {
                    list_file.write(format!("{}\t{}\t{}\n", member.login, member.id, sector.get_gid()).as_bytes())
                             .unwrap();
                }
            }
        }
        Err(_) => return libc::c_int::from(NssStatus::TryAgain),
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getpwent_r(pwptr: *mut Passwd, buf: *mut libc::c_char, buflen: libc::size_t,
                                          errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let (idx, idx_file, list) = match runfiles::open() {
        Ok(ret) => ret,
        Err(_) => fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound),
    };
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let words: Vec<&str> = line.split("\t").collect();
        let id = words[1].parse::<u64>().unwrap();
        let gid = words[2].parse::<u64>().unwrap();
        match unsafe { (*pwptr).pack_args(&mut buffer, words[0], id, gid, &CONFIG) } {
            Ok(_) => succeed!(runfiles::increment(idx, idx_file)),
            Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
        }
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_endpwent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getspnam_r(cnameptr: *const libc::c_char, spptr: *mut Spwd, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let name = string_from(cnameptr);
    match CLIENT.get_sectors() {
        Ok(sectors) => {
            for sector in sectors {
                if let Some(member) = sector.members.get(&name) {
                    match unsafe { (*spptr).pack_args(&mut buffer, &member.login, &CONFIG) } {
                        Ok(_) => succeed!(),
                        Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
                    }
                }
            }
        }

        Err(_) => fail!(errnop, nix::Errno::EAGAIN, NssStatus::TryAgain),
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_setspent() -> libc::c_int {
    let mut list_file = match runfiles::create() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    match CLIENT.get_sectors() {
        Ok(sectors) => {
            for sector in sectors {
                for member in sector.members.values() {
                    list_file.write(format!("{}\t{}\n", member.login, member.id).as_bytes())
                             .unwrap();
                }
            }
        }
        Err(_) => return libc::c_int::from(NssStatus::TryAgain),
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getspent_r(spptr: *mut Spwd, buf: *mut libc::c_char, buflen: libc::size_t,
                                          errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let (idx, idx_file, list) = match runfiles::open() {
        Ok(ret) => ret,
        Err(_) => fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound),
    };
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let words: Vec<&str> = line.split("\t").collect();
        match unsafe { (*spptr).pack_args(&mut buffer, words[0], &CONFIG) } {
            Ok(_) => succeed!(runfiles::increment(idx, idx_file)),
            Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
        }
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_endspent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getgrgid_r(gid: libc::gid_t, grptr: *mut Group, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    match CLIENT.get_sectors() {
        Ok(sectors) => {
            for sector in sectors {
                let members: Vec<&str> = sector.members.values().map(|m| m.login.as_str()).collect();
                if gid as u64 == sector.get_gid() {
                    match unsafe { (*grptr).pack_args(&mut buffer, &sector.get_group(), gid as u64, &members) } {
                        Ok(_) => succeed!(),
                        Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
                    }
                }
            }
        }

        Err(_) => fail!(errnop, nix::Errno::EAGAIN, NssStatus::TryAgain),
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getgrnam_r(cnameptr: *const libc::c_char, grptr: *mut Group, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let name = string_from(cnameptr);
    match CLIENT.get_sectors() {
        Ok(sectors) => {
            for sector in sectors {
                let members: Vec<&str> = sector.members.values().map(|m| m.login.as_str()).collect();
                if name == sector.get_group() {
                    match unsafe { (*grptr).pack_args(&mut buffer, &sector.get_group(), sector.get_gid(), &members) } {
                        Ok(_) => succeed!(),
                        Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
                    }
                }
            }
        }
        Err(_) => fail!(errnop, nix::Errno::EAGAIN, NssStatus::TryAgain),
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_setgrent() -> libc::c_int {
    let mut list_file = match runfiles::create() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };

    match CLIENT.get_sectors() {
        Ok(sectors) => {
            for sector in sectors {
                let member_names = sector.members
                                         .values()
                                         .map(|x| x.login.as_str())
                                         .collect::<Vec<&str>>()
                                         .join(" ");
                list_file.write(format!("{}\t{}\t{}\n", sector.get_group(), sector.get_gid(), member_names).as_bytes())
                         .unwrap();
            }
        }

        Err(_) => return libc::c_int::from(NssStatus::TryAgain),
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getgrent_r(grptr: *mut Group, buf: *mut libc::c_char, buflen: libc::size_t,
                                          errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let (idx, idx_file, list) = match runfiles::open() {
        Ok(ret) => ret,
        Err(_) => fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound),
    };
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let words: Vec<&str> = line.split("\t").collect();
        let member_names: Vec<&str> = words[2].split(" ").collect();
        let gid = words[1].parse::<u64>().unwrap();
        match unsafe { (*grptr).pack_args(&mut buffer, words[0], gid, &member_names) } {
            Ok(_) => succeed!(runfiles::increment(idx, idx_file)),
            Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
        }
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_endgrent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}
<commit_msg>Change to return the error code when file creation fails<commit_after>extern crate glob;
extern crate nix;
extern crate reqwest;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate toml;

#[macro_use]
extern crate lazy_static;

use std::ffi::CStr;
use std::io::{BufRead, Write};
extern crate libc;

mod structs;
use structs::Config;
mod buffer;
mod ghclient;
use buffer::Buffer;
mod cstructs;
use cstructs::{Group, Passwd, Spwd};
mod runfiles;
mod statics;
use statics::{CLIENT, CONFIG};

#[allow(dead_code)]
enum NssStatus {
    TryAgain,
    Unavail,
    NotFound,
    Success,
}

impl From<NssStatus> for libc::c_int {
    fn from(status: NssStatus) -> libc::c_int {
        match status {
            NssStatus::TryAgain => -2,
            NssStatus::Unavail => -1,
            NssStatus::NotFound => 0,
            NssStatus::Success => 1,
        }
    }
}

fn string_from(cstrptr: *const libc::c_char) -> String {
    let cstr: &CStr = unsafe { CStr::from_ptr(cstrptr) };
    String::from(cstr.to_str().unwrap_or(""))
}

macro_rules! succeed {
    () => {{
        return libc::c_int::from(NssStatus::Success);
    }};
    ($finalize:expr) => {{
        $finalize;
        return libc::c_int::from(NssStatus::Success);
    }};
}

macro_rules! fail {
    ($err_no_p:ident, $err_no:expr, $return_val:expr) => {{
        unsafe { *$err_no_p = $err_no as libc::c_int };
        return libc::c_int::from($return_val);
    }};
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getpwnam_r(cnameptr: *const libc::c_char, pwptr: *mut Passwd, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let name = string_from(cnameptr);
    match CLIENT.get_sectors() {
        Ok(sectors) => {
            for sector in sectors {
                if let Some(member) = sector.members.get(&name) {
                    match unsafe {
                              (*pwptr).pack_args(&mut buffer, &member.login, member.id, sector.get_gid(), &CONFIG)
                          } {
                        Ok(_) => succeed!(),
                        Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
                    }
                }
            }
        }
        Err(_) => fail!(errnop, nix::Errno::EAGAIN, NssStatus::TryAgain),
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getpwuid_r(uid: libc::uid_t, pwptr: *mut Passwd, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    match CLIENT.get_sectors() {
        Ok(sectors) => {
            for sector in sectors {
                for member in sector.members.values() {
                    if uid == member.id as libc::uid_t {
                        match unsafe {
                                  (*pwptr).pack_args(&mut buffer, &member.login, member.id, sector.get_gid(), &CONFIG)
                              } {
                            Ok(_) => succeed!(),
                            Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
                        }
                    }
                }
            }
        }
        Err(_) => fail!(errnop, nix::Errno::EAGAIN, NssStatus::TryAgain),
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_setpwent() -> libc::c_int {
    let mut list_file = match runfiles::create() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::TryAgain),
    };
    match CLIENT.get_sectors() {
        Ok(sectors) => {
            for sector in sectors {
                for member in sector.members.values() {
                    list_file.write(format!("{}\t{}\t{}\n", member.login, member.id, sector.get_gid()).as_bytes())
                             .unwrap();
                }
            }
        }
        Err(_) => return libc::c_int::from(NssStatus::TryAgain),
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getpwent_r(pwptr: *mut Passwd, buf: *mut libc::c_char, buflen: libc::size_t,
                                          errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let (idx, idx_file, list) = match runfiles::open() {
        Ok(ret) => ret,
        Err(_) => fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound),
    };
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let words: Vec<&str> = line.split("\t").collect();
        let id = words[1].parse::<u64>().unwrap();
        let gid = words[2].parse::<u64>().unwrap();
        match unsafe { (*pwptr).pack_args(&mut buffer, words[0], id, gid, &CONFIG) } {
            Ok(_) => succeed!(runfiles::increment(idx, idx_file)),
            Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
        }
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_endpwent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getspnam_r(cnameptr: *const libc::c_char, spptr: *mut Spwd, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let name = string_from(cnameptr);
    match CLIENT.get_sectors() {
        Ok(sectors) => {
            for sector in sectors {
                if let Some(member) = sector.members.get(&name) {
                    match unsafe { (*spptr).pack_args(&mut buffer, &member.login, &CONFIG) } {
                        Ok(_) => succeed!(),
                        Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
                    }
                }
            }
        }

        Err(_) => fail!(errnop, nix::Errno::EAGAIN, NssStatus::TryAgain),
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_setspent() -> libc::c_int {
    let mut list_file = match runfiles::create() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::TryAgain),
    };
    match CLIENT.get_sectors() {
        Ok(sectors) => {
            for sector in sectors {
                for member in sector.members.values() {
                    list_file.write(format!("{}\t{}\n", member.login, member.id).as_bytes())
                             .unwrap();
                }
            }
        }
        Err(_) => return libc::c_int::from(NssStatus::TryAgain),
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getspent_r(spptr: *mut Spwd, buf: *mut libc::c_char, buflen: libc::size_t,
                                          errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let (idx, idx_file, list) = match runfiles::open() {
        Ok(ret) => ret,
        Err(_) => fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound),
    };
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let words: Vec<&str> = line.split("\t").collect();
        match unsafe { (*spptr).pack_args(&mut buffer, words[0], &CONFIG) } {
            Ok(_) => succeed!(runfiles::increment(idx, idx_file)),
            Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
        }
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_endspent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getgrgid_r(gid: libc::gid_t, grptr: *mut Group, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    match CLIENT.get_sectors() {
        Ok(sectors) => {
            for sector in sectors {
                let members: Vec<&str> = sector.members.values().map(|m| m.login.as_str()).collect();
                if gid as u64 == sector.get_gid() {
                    match unsafe { (*grptr).pack_args(&mut buffer, &sector.get_group(), gid as u64, &members) } {
                        Ok(_) => succeed!(),
                        Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
                    }
                }
            }
        }

        Err(_) => fail!(errnop, nix::Errno::EAGAIN, NssStatus::TryAgain),
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getgrnam_r(cnameptr: *const libc::c_char, grptr: *mut Group, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let name = string_from(cnameptr);
    match CLIENT.get_sectors() {
        Ok(sectors) => {
            for sector in sectors {
                let members: Vec<&str> = sector.members.values().map(|m| m.login.as_str()).collect();
                if name == sector.get_group() {
                    match unsafe { (*grptr).pack_args(&mut buffer, &sector.get_group(), sector.get_gid(), &members) } {
                        Ok(_) => succeed!(),
                        Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
                    }
                }
            }
        }
        Err(_) => fail!(errnop, nix::Errno::EAGAIN, NssStatus::TryAgain),
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_setgrent() -> libc::c_int {
    let mut list_file = match runfiles::create() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::TryAgain),
    };

    match CLIENT.get_sectors() {
        Ok(sectors) => {
            for sector in sectors {
                let member_names = sector.members
                                         .values()
                                         .map(|x| x.login.as_str())
                                         .collect::<Vec<&str>>()
                                         .join(" ");
                list_file.write(format!("{}\t{}\t{}\n", sector.get_group(), sector.get_gid(), member_names).as_bytes())
                         .unwrap();
            }
        }

        Err(_) => return libc::c_int::from(NssStatus::TryAgain),
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getgrent_r(grptr: *mut Group, buf: *mut libc::c_char, buflen: libc::size_t,
                                          errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let (idx, idx_file, list) = match runfiles::open() {
        Ok(ret) => ret,
        Err(_) => fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound),
    };
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let words: Vec<&str> = line.split("\t").collect();
        let member_names: Vec<&str> = words[2].split(" ").collect();
        let gid = words[1].parse::<u64>().unwrap();
        match unsafe { (*grptr).pack_args(&mut buffer, words[0], gid, &member_names) } {
            Ok(_) => succeed!(runfiles::increment(idx, idx_file)),
            Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
        }
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_endgrent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}
<|endoftext|>


<commit_before>use std::error::FromError;

use std::str::Utf8Error;
use std::string::FromUtf8Error;

use std::io::{Reader, BufReader, IoError};
use std::io::net::ip::IpAddr;

#[derive(Show)]
pub enum Error {
    Io(IoError),
    FormatError(FormatError)
}

#[derive(Show, Copy)]
pub enum FormatError {
    UnknownBlock(u32),
    UnknownOption(u16),
    Utf8Error(Utf8Error)
}

impl FromError<IoError> for Error {
    fn from_error(err: IoError) -> Error {
        Error::Io(err)
    }
}

impl FromError<FromUtf8Error> for Error {
    fn from_error(err: FromUtf8Error) -> Error {
        Error::FormatError(FormatError::Utf8Error(err.utf8_error()))
    }
}

impl FromError<FormatError> for Error {
    fn from_error(err: FormatError) -> Error {
        Error::FormatError(err)
    }
}

#[derive(Show)]
pub enum Block {
    SectionHeader(SectionHeaderBlock),
    InterfaceDescription(InterfaceDescriptionBlock),
    InterfaceStatistics(InterfaceStatisticsBlock),
    EnhancedPacket(EnhancedPacketBlock)
}

#[derive(Show)]
pub struct SectionHeaderBlock {
    /// Magic number equal to 0x1A2B3C4D. This field can be used to detect
    /// sections saved on systems with different endianness.
    pub magic: u32,

    pub major_version: u16,
    pub minor_version: u16,

    /// Length in bytes of the following section excluding this block.
    ///
    /// This block can be used to skip the section for faster navigation in
    /// large files. Length of -1u64 means that the length is unspecified.
    pub section_length: u64,
    pub options: Vec<SectionHeaderOption>
}

#[derive(Show)]
pub enum SectionHeaderOption {
    /// Comment associated with the current block
    Comment(String),

    /// Description of the hardware used to create this section
    Hardware(String),

    /// Name of the operating system used to create this section
    OS(String),

    /// Name of the application used to create this section
    UserApplication(String)
}

/// Block type 1
#[derive(Show)]
pub struct InterfaceDescriptionBlock {
    /// Link layer type of the interface
    pub link_type: u16,

    /// Maximum number of bytes stored from each packet
    pub snap_len: u32,

    pub options: Vec<InterfaceDescriptionOption>
}

#[derive(Show)]
pub enum InterfaceDescriptionOption {
    /// Comment associated with the current block
    Comment(String),

    /// Name of the device used to capture data
    Name(String),

    /// Description of the device used to capture data
    Description(String),

    /// IPv4 interface address and netmask
    Ipv4Addr(u32, u32),

    /// IPv6 interface address and prefix length
    Ipv6Addr(IpAddr, u8),

    /// Hardware MAC address (48 bits)
    MacAddr(u64),

    /// Hardware EUI address
    EuiAddr(u64),

    /// Interface speed in bps
    Speed(u64),

    /// Resolution of timestamps.
    ///
    /// If the MSB is equal to zero, the remaining bits indicate the resolution
    /// as a negative power of 10 (e.g. 6 means microsecond resolution,
    /// timestamps are teh number of microseconds since 1/1/1970).
    ///
    /// If the MSB is equal to one, the remaining bits indicate the resolution
    /// as a negative power of 2 (e.g. 10 means 1/1024 of a second).
    ///
    /// If this options is not present, microsecond resolution is assumed.
    TsResolution(u8),

    /// Timezone for GMT support (?)
    Timezone(u32),

    /// The filter used to capture traffic. The first byte specifies the type
    /// of filter used (e.g. libpcap string, BPF bytecode, etc)
    Filter(u8, Vec<u8>),

    /// Operating system of the machine in which this interface is installed.
    /// This can be different from the Section Header Block if the capture
    /// was done remotely.
    OS(String),

    /// Length of Frame Check Sequence in bits for this interface. For link
    /// layers whose FCS length can change during time, the Packet Block
    /// flags be used.
    FcsLen(u8),

    /// Offset pf the timestamp in seconds
    TsOffset(u64)
}

/// Block type 5
#[derive(Show)]
pub struct InterfaceStatisticsBlock {
    pub interface_id: u32,
    pub timestamp: u64,

    pub options: Vec<InterfaceStatisticsOption>
}

#[derive(Show)]
pub enum InterfaceStatisticsOption {
    /// Comment associated with the current block
    Comment(String),

    /// Time when capture started
    StartTime(u64),

    /// Time when capture ended
    EndTime(u64),

    /// Number of packets received from the physical interface
    Received(u64),

    /// Number of packets dropped by the interface due to the lack of resources
    Dropped(u64),

    /// Number of packets accepted by the filter
    FilterAccepted(u64),

    /// Number of packets dropped by the operating system
    OSDropped(u64),

    /// Number of packets delivered to the user starting. The value in this
    /// field can be different from 'Accepted - Dropped' because some packets
    /// could still be in the OS buffers when the capture ended.
    Delivered(u64)
}

#[derive(Show)]
pub struct EnhancedPacketBlock {
    pub interface_id: u32,
    pub timestamp: u64,

    /// Actual length of the packet when it was transmitted on the network
    pub len: u32,

    pub data: Vec<u8>,
    pub options: Vec<EnhancedPacketBlockOption>
}

#[derive(Show)]
pub enum EnhancedPacketBlockOption {
    Comment(String),
    Flags(u32),
    Hash,

    /// Number of packets lost between the last packet
    DropCount(u64)
}

#[inline(always)]
fn dword_aligned(n: usize) -> usize {
    (n + 3) & !3
}

pub fn read_raw_block(r: &mut Reader) -> Result<(u32, Vec<u8>), IoError> {
    let block_type = try!(r.read_le_u32());

    let total_len = try!(r.read_le_u32()) as usize;
    let data_len = total_len - 12; // 12 = type + 2*length

    let mut data = try!(r.read_exact(dword_aligned(data_len)));
    data.truncate(data_len);

    assert!(total_len == try!(r.read_le_u32()) as usize);

    Ok((block_type, data))
}

fn read_option(r: &mut Reader) -> Result<(u16, Vec<u8>), IoError> {
    let code = try!(r.read_le_u16());
    let len = try!(r.read_le_u16()) as usize;

    let mut data = try!(r.read_exact(dword_aligned(len)));
    data.truncate(len);

    Ok((code, data))
}

pub fn read_block(r: &mut Reader) -> Result<Block, Error> {
    use Block::*;

    let (block_type, data) = try!(read_raw_block(r));
    let mut r = BufReader::new(&*data);

    let r = match block_type {
        0x0A0D0D0A => SectionHeader(try!(SectionHeaderBlock::read(&mut r))),
        1 => InterfaceDescription(try!(InterfaceDescriptionBlock::read(&mut r))),
        5 => InterfaceStatistics(try!(InterfaceStatisticsBlock::read(&mut r))),
        6 => EnhancedPacket(try!(EnhancedPacketBlock::read(&mut r))),
        _ => return Err(FromError::from_error(FormatError::UnknownBlock(block_type)))
    };

    Ok(r)
}

pub struct BlockIter<'a> {
    r: &'a mut (Reader + 'a)
}

pub struct PacketIter<'a> {
    r: &'a mut SimpleReader<'a>
}

pub struct SimpleReader<'a> {
    r: &'a mut (Reader + 'a),

    interfaces: Vec<InterfaceDescriptionBlock>,
    if_offset: usize
}

impl<'a> Iterator for BlockIter<'a> {
    type Item = Block;

    fn next(&mut self) -> Option<Block> {
        match read_block(self.r) {
            Ok(block) => Some(block),
            Err(_) => None
        }
    }
}

type IterPacket<'a> = (&'a InterfaceDescriptionBlock, EnhancedPacketBlock);

impl<'a> Iterator for PacketIter<'a> {
    type Item = IterPacket<'a>;

    fn next(&mut self) -> Option<IterPacket<'a>> {
        while let Ok(block) = read_block(self.r.r) {
            match block {
                Block::SectionHeader(_) => {
                    // Each section is independent from another,
                    // however we might still have live references
                    // to the old interface descriptions so we
                    // can't just clear the vector
                    self.r.if_offset = self.r.interfaces.len()
                },

                Block::InterfaceDescription(id) => self.r.interfaces.push(id),

                Block::EnhancedPacket(ep) => {
                    let iface = &self.r.interfaces[self.r.if_offset + ep.interface_id as usize];
                    unsafe {
                        // The interface description should live as long as
                        // SimpleReader, so this should be safe.
                        let iface = std::mem::transmute(iface);

                        return Some((iface, ep))
                    }
                },
                _ => {}
            }
        }

        None
    }
}

impl<'a> SimpleReader<'a> {
    pub fn new(r: &mut Reader) -> SimpleReader {
        SimpleReader { r: r, interfaces: Vec::new(), if_offset: 0}
    }

    pub fn blocks(&mut self) -> BlockIter {
        BlockIter { r: self.r }
    }

    pub fn packets(&'a mut self) -> PacketIter<'a> {
        PacketIter { r: self }
    }
}

impl SectionHeaderBlock {
    pub fn read(r: &mut BufReader) -> Result<SectionHeaderBlock, Error> {
        let magic = try!(r.read_le_u32());

        assert!(magic == 0x1A2B3C4D, "unsupported endianness");

        let major_version = try!(r.read_le_u16());
        let minor_version = try!(r.read_le_u16());
        let section_length = try!(r.read_le_u64());

        let mut options = Vec::new();

        if !r.eof() {
            loop {
                use SectionHeaderOption::*;

                let (code, data) = try!(read_option(r));

                let opt = match code {
                    0 => break,

                    1...4 => {
                        let s = try!(String::from_utf8(data));

                        match code {
                            1 => Comment(s),
                            2 => Hardware(s),
                            3 => OS(s),
                            4 => UserApplication(s),
                            _ => unreachable!()
                        }
                    }

                    _ => return Err(FromError::from_error(FormatError::UnknownOption(code)))
                };

                options.push(opt);
            }
        }

        Ok(SectionHeaderBlock {
            magic: magic,
            major_version: major_version,
            minor_version: minor_version,
            section_length: section_length,

            options: options
        })
    }
}

impl InterfaceDescriptionBlock {
    pub fn read(r: &mut BufReader) -> Result<InterfaceDescriptionBlock, Error> {
        let link_type = try!(r.read_le_u16());
        try!(r.read_le_u16()); // reserved
        let snap_len = try!(r.read_le_u32());

        let mut options = Vec::new();

        if !r.eof() {
            loop {
                use InterfaceDescriptionOption::*;
                let (code, data) = try!(read_option(r));

                let mut d = &*data;

                let opt = match code {
                    0 => break,
                    1...3 | 12 => {
                        let s = try!(String::from_utf8(data.clone()));

                        match code {
                            1 => Comment(s),
                            2 => Name(s),
                            3 => Description(s),
                            12 => OS(s),
                            _ => unreachable!()
                        }
                    }

                    4 => {
                        let ip = try!(d.read_le_u32());
                        let mask = try!(d.read_le_u32());

                        Ipv4Addr(ip, mask)
                    }

                    6 => MacAddr(try!(d.read_le_uint_n(6))),
                    9 => TsResolution(try!(d.read_byte())),

                    _ => return Err(FromError::from_error(FormatError::UnknownOption(code)))
                };

                options.push(opt);
            }
        }

        Ok(InterfaceDescriptionBlock {
            link_type: link_type,
            snap_len: snap_len,
            options: options
        })
    }
}

impl EnhancedPacketBlock {
    pub fn read(r: &mut BufReader) -> Result<EnhancedPacketBlock, Error> {
        let interface_id = try!(r.read_le_u32());
        let ts = try!(r.read_le_u64());
        let cap_len = try!(r.read_le_u32()) as usize;
        let len = try!(r.read_le_u32());

        let aligned_len = dword_aligned(cap_len);

        let mut packet_data = try!(r.read_exact(aligned_len));
        packet_data.truncate(cap_len);

        let mut options = Vec::new();

        if !r.eof() {
            loop {
                use EnhancedPacketBlockOption::*;
                let (code, data) = try!(read_option(r));

                let opt = match code {
                    0 => break,
                    1 => {
                        match String::from_utf8(data.clone()) {
                            Ok(r) => Comment(r),
                            Err(err) => return Err(FromError::from_error(err))
                        }
                    }

                    // TODO: rest of the options
                    _ => return Err(FromError::from_error(FormatError::UnknownOption(code)))
                };

                options.push(opt);
            }
        }

        Ok(EnhancedPacketBlock {
            interface_id: interface_id,
            timestamp: ts,
            len: len,
            data: packet_data,
            options: options
        })
    }
}

impl InterfaceStatisticsBlock {
    pub fn read(r: &mut BufReader) -> Result<InterfaceStatisticsBlock, Error> {
        let interface_id = try!(r.read_le_u32());
        let ts = try!(r.read_le_u64());

        let mut options = Vec::new();

        if !r.eof() {
            loop {
                use InterfaceStatisticsOption::*;
                let (code, data) = try!(read_option(r));

                let opt = match code {
                    0 => break,
                    1 => {
                        match String::from_utf8(data.clone()) {
                            Ok(r) => Comment(r),
                            Err(err) => return Err(FromError::from_error(err))
                        }
                    }

                    2...8 => {
                        let data = try!((&*data).read_le_u64());

                        match code {
                            2 => StartTime(data),
                            3 => EndTime(data),
                            4 => Received(data),
                            5 => Dropped(data),
                            6 => FilterAccepted(data),
                            7 => OSDropped(data),
                            8 => Delivered(data),
                            _ => unreachable!()
                        }
                    }

                    _ => return Err(FromError::from_error(FormatError::UnknownOption(code)))
                };

                options.push(opt);
            }
        }

        Ok(InterfaceStatisticsBlock {
            interface_id: interface_id,
            timestamp: ts,
            options: options
        })
    }
}
<commit_msg>Update to Rust master<commit_after>#![feature(io)]

use std::error::FromError;

use std::str::Utf8Error;
use std::string::FromUtf8Error;

use std::old_io::{Reader, BufReader, IoError};
use std::old_io::net::ip::IpAddr;

#[derive(Debug)]
pub enum Error {
    Io(IoError),
    FormatError(FormatError)
}

#[derive(Debug, Copy)]
pub enum FormatError {
    UnknownBlock(u32),
    UnknownOption(u16),
    Utf8Error(Utf8Error)
}

impl FromError<IoError> for Error {
    fn from_error(err: IoError) -> Error {
        Error::Io(err)
    }
}

impl FromError<FromUtf8Error> for Error {
    fn from_error(err: FromUtf8Error) -> Error {
        Error::FormatError(FormatError::Utf8Error(err.utf8_error()))
    }
}

impl FromError<FormatError> for Error {
    fn from_error(err: FormatError) -> Error {
        Error::FormatError(err)
    }
}

#[derive(Debug)]
pub enum Block {
    SectionHeader(SectionHeaderBlock),
    InterfaceDescription(InterfaceDescriptionBlock),
    InterfaceStatistics(InterfaceStatisticsBlock),
    EnhancedPacket(EnhancedPacketBlock)
}

#[derive(Debug)]
pub struct SectionHeaderBlock {
    /// Magic number equal to 0x1A2B3C4D. This field can be used to detect
    /// sections saved on systems with different endianness.
    pub magic: u32,

    pub major_version: u16,
    pub minor_version: u16,

    /// Length in bytes of the following section excluding this block.
    ///
    /// This block can be used to skip the section for faster navigation in
    /// large files. Length of -1u64 means that the length is unspecified.
    pub section_length: u64,
    pub options: Vec<SectionHeaderOption>
}

#[derive(Debug)]
pub enum SectionHeaderOption {
    /// Comment associated with the current block
    Comment(String),

    /// Description of the hardware used to create this section
    Hardware(String),

    /// Name of the operating system used to create this section
    OS(String),

    /// Name of the application used to create this section
    UserApplication(String)
}

/// Block type 1
#[derive(Debug)]
pub struct InterfaceDescriptionBlock {
    /// Link layer type of the interface
    pub link_type: u16,

    /// Maximum number of bytes stored from each packet
    pub snap_len: u32,

    pub options: Vec<InterfaceDescriptionOption>
}

#[derive(Debug)]
pub enum InterfaceDescriptionOption {
    /// Comment associated with the current block
    Comment(String),

    /// Name of the device used to capture data
    Name(String),

    /// Description of the device used to capture data
    Description(String),

    /// IPv4 interface address and netmask
    Ipv4Addr(u32, u32),

    /// IPv6 interface address and prefix length
    Ipv6Addr(IpAddr, u8),

    /// Hardware MAC address (48 bits)
    MacAddr(u64),

    /// Hardware EUI address
    EuiAddr(u64),

    /// Interface speed in bps
    Speed(u64),

    /// Resolution of timestamps.
    ///
    /// If the MSB is equal to zero, the remaining bits indicate the resolution
    /// as a negative power of 10 (e.g. 6 means microsecond resolution,
    /// timestamps are teh number of microseconds since 1/1/1970).
    ///
    /// If the MSB is equal to one, the remaining bits indicate the resolution
    /// as a negative power of 2 (e.g. 10 means 1/1024 of a second).
    ///
    /// If this options is not present, microsecond resolution is assumed.
    TsResolution(u8),

    /// Timezone for GMT support (?)
    Timezone(u32),

    /// The filter used to capture traffic. The first byte specifies the type
    /// of filter used (e.g. libpcap string, BPF bytecode, etc)
    Filter(u8, Vec<u8>),

    /// Operating system of the machine in which this interface is installed.
    /// This can be different from the Section Header Block if the capture
    /// was done remotely.
    OS(String),

    /// Length of Frame Check Sequence in bits for this interface. For link
    /// layers whose FCS length can change during time, the Packet Block
    /// flags be used.
    FcsLen(u8),

    /// Offset pf the timestamp in seconds
    TsOffset(u64)
}

/// Block type 5
#[derive(Debug)]
pub struct InterfaceStatisticsBlock {
    pub interface_id: u32,
    pub timestamp: u64,

    pub options: Vec<InterfaceStatisticsOption>
}

#[derive(Debug)]
pub enum InterfaceStatisticsOption {
    /// Comment associated with the current block
    Comment(String),

    /// Time when capture started
    StartTime(u64),

    /// Time when capture ended
    EndTime(u64),

    /// Number of packets received from the physical interface
    Received(u64),

    /// Number of packets dropped by the interface due to the lack of resources
    Dropped(u64),

    /// Number of packets accepted by the filter
    FilterAccepted(u64),

    /// Number of packets dropped by the operating system
    OSDropped(u64),

    /// Number of packets delivered to the user starting. The value in this
    /// field can be different from 'Accepted - Dropped' because some packets
    /// could still be in the OS buffers when the capture ended.
    Delivered(u64)
}

#[derive(Debug)]
pub struct EnhancedPacketBlock {
    pub interface_id: u32,
    pub timestamp: u64,

    /// Actual length of the packet when it was transmitted on the network
    pub len: u32,

    pub data: Vec<u8>,
    pub options: Vec<EnhancedPacketBlockOption>
}

#[derive(Debug)]
pub enum EnhancedPacketBlockOption {
    Comment(String),
    Flags(u32),
    Hash,

    /// Number of packets lost between the last packet
    DropCount(u64)
}

#[inline(always)]
fn dword_aligned(n: usize) -> usize {
    (n + 3) & !3
}

pub fn read_raw_block(r: &mut Reader) -> Result<(u32, Vec<u8>), IoError> {
    let block_type = try!(r.read_le_u32());

    let total_len = try!(r.read_le_u32()) as usize;
    let data_len = total_len - 12; // 12 = type + 2*length

    let mut data = try!(r.read_exact(dword_aligned(data_len)));
    data.truncate(data_len);

    assert!(total_len == try!(r.read_le_u32()) as usize);

    Ok((block_type, data))
}

fn read_option(r: &mut Reader) -> Result<(u16, Vec<u8>), IoError> {
    let code = try!(r.read_le_u16());
    let len = try!(r.read_le_u16()) as usize;

    let mut data = try!(r.read_exact(dword_aligned(len)));
    data.truncate(len);

    Ok((code, data))
}

pub fn read_block(r: &mut Reader) -> Result<Block, Error> {
    use Block::*;

    let (block_type, data) = try!(read_raw_block(r));
    let mut r = BufReader::new(&*data);

    let r = match block_type {
        0x0A0D0D0A => SectionHeader(try!(SectionHeaderBlock::read(&mut r))),
        1 => InterfaceDescription(try!(InterfaceDescriptionBlock::read(&mut r))),
        5 => InterfaceStatistics(try!(InterfaceStatisticsBlock::read(&mut r))),
        6 => EnhancedPacket(try!(EnhancedPacketBlock::read(&mut r))),
        _ => return Err(FromError::from_error(FormatError::UnknownBlock(block_type)))
    };

    Ok(r)
}

pub struct BlockIter<'a> {
    r: &'a mut (Reader + 'a)
}

pub struct PacketIter<'a> {
    r: &'a mut SimpleReader<'a>
}

pub struct SimpleReader<'a> {
    r: &'a mut (Reader + 'a),

    interfaces: Vec<InterfaceDescriptionBlock>,
    if_offset: usize
}

impl<'a> Iterator for BlockIter<'a> {
    type Item = Block;

    fn next(&mut self) -> Option<Block> {
        match read_block(self.r) {
            Ok(block) => Some(block),
            Err(_) => None
        }
    }
}

type IterPacket<'a> = (&'a InterfaceDescriptionBlock, EnhancedPacketBlock);

impl<'a> Iterator for PacketIter<'a> {
    type Item = IterPacket<'a>;

    fn next(&mut self) -> Option<IterPacket<'a>> {
        while let Ok(block) = read_block(self.r.r) {
            match block {
                Block::SectionHeader(_) => {
                    // Each section is independent from another,
                    // however we might still have live references
                    // to the old interface descriptions so we
                    // can't just clear the vector
                    self.r.if_offset = self.r.interfaces.len()
                },

                Block::InterfaceDescription(id) => self.r.interfaces.push(id),

                Block::EnhancedPacket(ep) => {
                    let iface = &self.r.interfaces[self.r.if_offset + ep.interface_id as usize];
                    unsafe {
                        // The interface description should live as long as
                        // SimpleReader, so this should be safe.
                        let iface = std::mem::transmute(iface);

                        return Some((iface, ep))
                    }
                },
                _ => {}
            }
        }

        None
    }
}

impl<'a> SimpleReader<'a> {
    pub fn new(r: &mut Reader) -> SimpleReader {
        SimpleReader { r: r, interfaces: Vec::new(), if_offset: 0}
    }

    pub fn blocks(&mut self) -> BlockIter {
        BlockIter { r: self.r }
    }

    pub fn packets(&'a mut self) -> PacketIter<'a> {
        PacketIter { r: self }
    }
}

impl SectionHeaderBlock {
    pub fn read(r: &mut BufReader) -> Result<SectionHeaderBlock, Error> {
        let magic = try!(r.read_le_u32());

        assert!(magic == 0x1A2B3C4D, "unsupported endianness");

        let major_version = try!(r.read_le_u16());
        let minor_version = try!(r.read_le_u16());
        let section_length = try!(r.read_le_u64());

        let mut options = Vec::new();

        if !r.eof() {
            loop {
                use SectionHeaderOption::*;

                let (code, data) = try!(read_option(r));

                let opt = match code {
                    0 => break,

                    1...4 => {
                        let s = try!(String::from_utf8(data));

                        match code {
                            1 => Comment(s),
                            2 => Hardware(s),
                            3 => OS(s),
                            4 => UserApplication(s),
                            _ => unreachable!()
                        }
                    }

                    _ => return Err(FromError::from_error(FormatError::UnknownOption(code)))
                };

                options.push(opt);
            }
        }

        Ok(SectionHeaderBlock {
            magic: magic,
            major_version: major_version,
            minor_version: minor_version,
            section_length: section_length,

            options: options
        })
    }
}

impl InterfaceDescriptionBlock {
    pub fn read(r: &mut BufReader) -> Result<InterfaceDescriptionBlock, Error> {
        let link_type = try!(r.read_le_u16());
        try!(r.read_le_u16()); // reserved
        let snap_len = try!(r.read_le_u32());

        let mut options = Vec::new();

        if !r.eof() {
            loop {
                use InterfaceDescriptionOption::*;
                let (code, data) = try!(read_option(r));

                let mut d = &*data;

                let opt = match code {
                    0 => break,
                    1...3 | 12 => {
                        let s = try!(String::from_utf8(data.clone()));

                        match code {
                            1 => Comment(s),
                            2 => Name(s),
                            3 => Description(s),
                            12 => OS(s),
                            _ => unreachable!()
                        }
                    }

                    4 => {
                        let ip = try!(d.read_le_u32());
                        let mask = try!(d.read_le_u32());

                        Ipv4Addr(ip, mask)
                    }

                    6 => MacAddr(try!(d.read_le_uint_n(6))),
                    9 => TsResolution(try!(d.read_byte())),

                    _ => return Err(FromError::from_error(FormatError::UnknownOption(code)))
                };

                options.push(opt);
            }
        }

        Ok(InterfaceDescriptionBlock {
            link_type: link_type,
            snap_len: snap_len,
            options: options
        })
    }
}

impl EnhancedPacketBlock {
    pub fn read(r: &mut BufReader) -> Result<EnhancedPacketBlock, Error> {
        let interface_id = try!(r.read_le_u32());
        let ts = try!(r.read_le_u64());
        let cap_len = try!(r.read_le_u32()) as usize;
        let len = try!(r.read_le_u32());

        let aligned_len = dword_aligned(cap_len);

        let mut packet_data = try!(r.read_exact(aligned_len));
        packet_data.truncate(cap_len);

        let mut options = Vec::new();

        if !r.eof() {
            loop {
                use EnhancedPacketBlockOption::*;
                let (code, data) = try!(read_option(r));

                let opt = match code {
                    0 => break,
                    1 => {
                        match String::from_utf8(data.clone()) {
                            Ok(r) => Comment(r),
                            Err(err) => return Err(FromError::from_error(err))
                        }
                    }

                    // TODO: rest of the options
                    _ => return Err(FromError::from_error(FormatError::UnknownOption(code)))
                };

                options.push(opt);
            }
        }

        Ok(EnhancedPacketBlock {
            interface_id: interface_id,
            timestamp: ts,
            len: len,
            data: packet_data,
            options: options
        })
    }
}

impl InterfaceStatisticsBlock {
    pub fn read(r: &mut BufReader) -> Result<InterfaceStatisticsBlock, Error> {
        let interface_id = try!(r.read_le_u32());
        let ts = try!(r.read_le_u64());

        let mut options = Vec::new();

        if !r.eof() {
            loop {
                use InterfaceStatisticsOption::*;
                let (code, data) = try!(read_option(r));

                let opt = match code {
                    0 => break,
                    1 => {
                        match String::from_utf8(data.clone()) {
                            Ok(r) => Comment(r),
                            Err(err) => return Err(FromError::from_error(err))
                        }
                    }

                    2...8 => {
                        let data = try!((&*data).read_le_u64());

                        match code {
                            2 => StartTime(data),
                            3 => EndTime(data),
                            4 => Received(data),
                            5 => Dropped(data),
                            6 => FilterAccepted(data),
                            7 => OSDropped(data),
                            8 => Delivered(data),
                            _ => unreachable!()
                        }
                    }

                    _ => return Err(FromError::from_error(FormatError::UnknownOption(code)))
                };

                options.push(opt);
            }
        }

        Ok(InterfaceStatisticsBlock {
            interface_id: interface_id,
            timestamp: ts,
            options: options
        })
    }
}
<|endoftext|>