<commit_before>use std::io;
use std::io::Write;

#[derive(Debug, PartialEq, Clone)]
pub enum Token {
    Unknown(String), // Invalid test (basically non-ascii)
    Literal(String), // Numeric literal number
    Func(Function), // Pre-defined function (like cos() )
    Const(Constant), // Constant like pi or e
    Var(String), // str arbitrary single char variable name
    Op(Operator), // Any of the 4 operators (+-*/)
    Open(u8), // Open parens '('
    Close(u8), // Closing parens ')'
    Set(Vec<Token>), // [ (, tokens..., ) ]
}

#[derive(Debug, PartialEq, Clone)]
pub enum Function {
    Sqrt(Vec<Token>),
    Ln(Vec<Token>),
    Log(f64, Vec<Token>),
    Sin(Vec<Token>),
    Cos(Vec<Token>),
    Tan(Vec<Token>),
    Asin(Vec<Token>),
    Acos(Vec<Token>),
    Atan(Vec<Token>),
    Sinh(Vec<Token>),
    Cosh(Vec<Token>),
    Tanh(Vec<Token>),
    Asinh(Vec<Token>),
    Acosh(Vec<Token>),
    Atanh(Vec<Token>),
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Constant {
	Pi,
	E,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Operator {
    Add,
    Sub,
    Div,
    Mul,
    Pow,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u32)]
pub enum Assoc {
    Left,
    Right,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u32)]
pub enum Order {
    AddSub = 1,
    MulDiv = 2,
    IMul = 3, // Implicit multiplication
    Pow = 4,
    Paren = 5,
}

#[derive(Debug, PartialEq, Clone)]
struct Expression {
    tokens: Vec<Token>,
    constant: f64,
}

struct ExpressionIter<'a> {
	expr: &'a Expression,
	count: usize,
}

impl<'a> Iterator for ExpressionIter<'a> {
	type Item = &'a Token;
    fn next(&mut self) -> Option<&'a Token> {
    	let token = self.expr.get_tokens().get(self.count);
    	self.count += 1;
    	token
    }
}

#[allow(dead_code)]
impl Expression {
	fn new(tokens: Vec<Token>, constant: f64) -> Self {
		Expression {tokens: tokens, constant: constant}
	}

	fn push(&mut self, token: Token) {
		self.tokens.push(token);
	}

	fn update_constant(&mut self, constant: &f64) {
		self.constant += *constant;
	}

	fn get_constant(&self) -> f64 {
		self.constant
	}

	fn get_tokens(&self) -> &[Token] {
		self.tokens.as_slice()
	}

	fn get_mut_tokens(&mut self) -> &mut [Token] {
		self.tokens.as_mut_slice()
	}

	fn replace_token(&mut self, index: usize, new_token: Token) {
		self.tokens.remove(index);
		self.tokens.insert(index, new_token);
	}

	fn replace_all_tokens(&mut self, new_token: Vec<Token>) {
		self.tokens = new_token
	}

	fn find_first(&self, token: &Token) -> Option<usize> {
		for i in 0..self.tokens.len() {
			//if self.tokens.get(i).unwrap() == Token::Set {
				println!("HERE {:?}", self.tokens.get(i).unwrap().0);
			//}
			if self.tokens.get(i).unwrap() == token {
				return Some(i);
			}
		}
		None
	}

	fn find_last(&self, token: &Token) -> Option<usize> {
		for i in (0..self.tokens.len()).rev() {
			if self.tokens.get(i).unwrap() == token {
				return Some(i);
			}
		}
		None
	}

	fn split_at(&self, index: usize) -> (&[Token], &[Token]) {
		self.tokens.split_at(index)
	}

	fn len(&self) -> usize {
		self.tokens.len()
	}

	fn iter(&self) -> ExpressionIter {
		ExpressionIter {expr: &self, count: 0}
	}
}

fn main() {
    println!("Welcome to Rust-Calculus!");
    println!("To evaluate an expression, simply type one in and hit RETURN.");
    println!("To set a variable, simply type VAR_NAME=EXPRESSION and hit RETURN.");
    println!("Valid commands are: sym_int, int, sym_def, and def.");
    println!("Type 'quit' to exit.");
    let mut input = String::new();
    let stdin = io::stdin();
    let mut stdout = io::stdout();
    loop {
    	input.clear();
    	print!(">>>> ");
    	stdout.flush().ok();
        if let Err(x) = stdin.read_line(&mut input) {
        	println!("There was a problem reading stdin: {:?}", x);
        	print!("Exiting...");;
        	break;
        }
        input = strip_white_space(&input).to_lowercase();
        if input == "quit" {
        	print!("Exiting...");
        	break;
        }
        let expr = match parse_input(&input) {
        		Ok(x) => x,
        		Err(x) => {println!("Encountered an error while parsing: {:?}", x); print!("Exiting..."); break;},
        	};
        println!("{:?}", &expr);
    }
}

fn strip_white_space(input: &String) -> String {
	input.split_whitespace().collect::<Vec<&str>>().join("")
}

fn parse_input(input: &String) -> Result<Expression, String> {
	let mut expr: Expression = Expression::new(Vec::new(), 0.0);
	let mut depth: u8 = 0;
	let mut lastParens = ' ';
	let mut maxDepth: u8 = 0;
	for c in input.chars() {
		match c {
			'-' => {
				expr.push(Token::Op(Operator::Sub));
			},
			'+' => {
				expr.push(Token::Op(Operator::Add));
			},
			'/' => {
				expr.push(Token::Op(Operator::Div));
			},
			'*' => {
				expr.push(Token::Op(Operator::Mul));
			},
			'^' => {
				expr.push(Token::Op(Operator::Pow));
			},
			'(' => {
				if lastParens == '(' {
					depth += 1;
					if maxDepth < depth {maxDepth = depth}
				}
				expr.push(Token::Open(depth));
				lastParens = '(';
			},
			')' => {
				if lastParens == ')' {
					depth -= 1;
				}
				expr.push(Token::Close(depth));
				lastParens = ')';

			},
			_ => continue,
		}
	}
	assert!(depth == 0); // Depth should always end at 0
	println!("ORIG EXPR {:?}", &expr);
	loop {
		let mut index: Option<usize> = None;
		depth = 0;
		while depth <= maxDepth {
			if let Some(x) = expr.find_first(&Token::Open(depth)) {
				index = Some(x);
				break;
			}
			depth += 1;
		}
		if index == None {break;}
		let index = index.unwrap(); // If we reach here, we know index is not None
		let mut end_set: usize = expr.find_first(&Token::Close(depth)).unwrap();
		let mut lhs: Vec<Token> = Vec::new();
		{
			let (temp_lhs, temp_rhs) = expr.split_at(index); // [0, where set should be placed)
			lhs = temp_lhs.to_vec();
			let mut rhs = temp_rhs.to_vec(); // [where set should be placed, len)
			rhs.remove(0);
			end_set = end_set - (index + 1); // Compensate for part of vec split off and the removal of one element
			let (left_rhs, right_rhs) = rhs.split_at(end_set);
			let (left_rhs, mut right_rhs) = (left_rhs.to_vec(), right_rhs.to_vec());
			right_rhs.remove(0);
			lhs.push(Token::Set(left_rhs));
			lhs.append(&mut right_rhs);
		}

		expr.replace_all_tokens(lhs);
		println!("NEW EXPR {:?}", &expr);
		depth += 1;
		if depth > maxDepth {break;}
	}
	Ok(expr)
}

#[test]
fn test_parse() {
	let input: String = String::from("+");
	assert_eq!(Expression::new(vec![Token::Op(Operator::Add)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("-");
	assert_eq!(Expression::new(vec![Token::Op(Operator::Sub)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("/");
	assert_eq!(Expression::new(vec![Token::Op(Operator::Div)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("*");
	assert_eq!(Expression::new(vec![Token::Op(Operator::Mul)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("^");
	assert_eq!(Expression::new(vec![Token::Op(Operator::Pow)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("()");
	assert_eq!(Expression::new(vec![Token::Set(Vec::new())], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("(+)");
	assert_eq!(Expression::new(vec![Token::Set(vec![Token::Op(Operator::Add)])], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("(-)");
	assert_eq!(Expression::new(vec![Token::Set(vec![Token::Op(Operator::Sub)])], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("(*)");
	assert_eq!(Expression::new(vec![Token::Set(vec![Token::Op(Operator::Mul)])], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("(/)");
	assert_eq!(Expression::new(vec![Token::Set(vec![Token::Op(Operator::Div)])], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("(^)");
	assert_eq!(Expression::new(vec![Token::Set(vec![Token::Op(Operator::Pow)])], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("(())");
	assert_eq!(Expression::new(vec![Token::Set(vec![Token::Set(Vec::new())])], 0.0), parse_input(&input).unwrap());
}<commit_msg>Updated testing for a no-set implementation<commit_after>use std::io;
use std::io::Write;

#[derive(Debug, PartialEq, Clone)]
pub enum Token {
    Unknown(String), // Invalid test (basically non-ascii)
    Literal(String), // Numeric literal number
    Func(Function), // Pre-defined function (like cos() )
    Const(Constant), // Constant like pi or e
    Var(String), // str arbitrary single char variable name
    Op(Operator), // Any of the 4 operators (+-*/)
    Open(u8), // Open parens '('
    Close(u8), // Closing parens ')'
    //Set(Vec<Token>), // [ (, tokens..., ) ]
}

#[derive(Debug, PartialEq, Clone)]
pub enum Function {
    Sqrt(Vec<Token>),
    Ln(Vec<Token>),
    Log(f64, Vec<Token>),
    Sin(Vec<Token>),
    Cos(Vec<Token>),
    Tan(Vec<Token>),
    Asin(Vec<Token>),
    Acos(Vec<Token>),
    Atan(Vec<Token>),
    Sinh(Vec<Token>),
    Cosh(Vec<Token>),
    Tanh(Vec<Token>),
    Asinh(Vec<Token>),
    Acosh(Vec<Token>),
    Atanh(Vec<Token>),
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Constant {
	Pi,
	E,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Operator {
    Add,
    Sub,
    Div,
    Mul,
    Pow,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u32)]
pub enum Assoc {
    Left,
    Right,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u32)]
pub enum Order {
    AddSub = 1,
    MulDiv = 2,
    IMul = 3, // Implicit multiplication
    Pow = 4,
    Paren = 5,
}

#[derive(Debug, PartialEq, Clone)]
struct Expression {
    tokens: Vec<Token>,
    constant: f64,
}

struct ExpressionIter<'a> {
	expr: &'a Expression,
	count: usize,
}

impl<'a> Iterator for ExpressionIter<'a> {
	type Item = &'a Token;
    fn next(&mut self) -> Option<&'a Token> {
    	let token = self.expr.get_tokens().get(self.count);
    	self.count += 1;
    	token
    }
}

#[allow(dead_code)]
impl Expression {
	fn new(tokens: Vec<Token>, constant: f64) -> Self {
		Expression {tokens: tokens, constant: constant}
	}

	fn push(&mut self, token: Token) {
		self.tokens.push(token);
	}

	fn update_constant(&mut self, constant: &f64) {
		self.constant += *constant;
	}

	fn get_constant(&self) -> f64 {
		self.constant
	}

	fn get_tokens(&self) -> &[Token] {
		self.tokens.as_slice()
	}

	fn get_mut_tokens(&mut self) -> &mut [Token] {
		self.tokens.as_mut_slice()
	}

	fn replace_token(&mut self, index: usize, new_token: Token) {
		self.tokens.remove(index);
		self.tokens.insert(index, new_token);
	}

	fn replace_all_tokens(&mut self, new_token: Vec<Token>) {
		self.tokens = new_token
	}

	fn find_first(&self, token: &Token) -> Option<usize> {
		for i in 0..self.tokens.len() {
			if self.tokens.get(i).unwrap() == token {
				return Some(i);
			}
		}
		None
	}

	fn find_last(&self, token: &Token) -> Option<usize> {
		for i in (0..self.tokens.len()).rev() {
			if self.tokens.get(i).unwrap() == token {
				return Some(i);
			}
		}
		None
	}

	fn split_at(&self, index: usize) -> (&[Token], &[Token]) {
		self.tokens.split_at(index)
	}

	fn len(&self) -> usize {
		self.tokens.len()
	}

	fn iter(&self) -> ExpressionIter {
		ExpressionIter {expr: &self, count: 0}
	}
}

fn main() {
    println!("Welcome to Rust-Calculus!");
    println!("To evaluate an expression, simply type one in and hit RETURN.");
    println!("To set a variable, simply type VAR_NAME=EXPRESSION and hit RETURN.");
    println!("Valid commands are: sym_int, int, sym_def, and def.");
    println!("Type 'quit' to exit.");
    let mut input = String::new();
    let stdin = io::stdin();
    let mut stdout = io::stdout();
    loop {
    	input.clear();
    	print!(">>>> ");
    	stdout.flush().ok();
        if let Err(x) = stdin.read_line(&mut input) {
        	println!("There was a problem reading stdin: {:?}", x);
        	print!("Exiting...");;
        	break;
        }
        input = strip_white_space(&input).to_lowercase();
        if input == "quit" {
        	print!("Exiting...");
        	break;
        }
        let expr = match parse_input(&input) {
        		Ok(x) => x,
        		Err(x) => {println!("Encountered an error while parsing: {:?}", x); print!("Exiting..."); break;},
        	};
        println!("{:?}", &expr);
    }
}

fn strip_white_space(input: &String) -> String {
	input.split_whitespace().collect::<Vec<&str>>().join("")
}

fn parse_input(input: &String) -> Result<Expression, String> {
	let mut expr: Expression = Expression::new(Vec::new(), 0.0);
	let mut depth: u8 = 0;
	let mut last_parens = ' ';
	for c in input.chars() {
		match c {
			'-' => {
				expr.push(Token::Op(Operator::Sub));
			},
			'+' => {
				expr.push(Token::Op(Operator::Add));
			},
			'/' => {
				expr.push(Token::Op(Operator::Div));
			},
			'*' => {
				expr.push(Token::Op(Operator::Mul));
			},
			'^' => {
				expr.push(Token::Op(Operator::Pow));
			},
			'(' => {
				if last_parens == '(' {
					depth += 1;
				}
				expr.push(Token::Open(depth));
				last_parens = '(';
			},
			')' => {
				if last_parens == ')' {
					depth -= 1;
				}
				expr.push(Token::Close(depth));
				last_parens = ')';

			},
			_ => continue,
		}
	}
	Ok(expr)
}

#[test]
fn test_parse() {
	let input: String = String::from("+");
	assert_eq!(Expression::new(vec![Token::Op(Operator::Add)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("-");
	assert_eq!(Expression::new(vec![Token::Op(Operator::Sub)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("/");
	assert_eq!(Expression::new(vec![Token::Op(Operator::Div)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("*");
	assert_eq!(Expression::new(vec![Token::Op(Operator::Mul)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("^");
	assert_eq!(Expression::new(vec![Token::Op(Operator::Pow)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("()");
	assert_eq!(Expression::new(vec![Token::Open(0), Token::Close(0)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("(+)");
	assert_eq!(Expression::new(vec![Token::Open(0), Token::Op(Operator::Add), Token::Close(0)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("(-)");
	assert_eq!(Expression::new(vec![Token::Open(0), Token::Op(Operator::Sub), Token::Close(0)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("(*)");
	assert_eq!(Expression::new(vec![Token::Open(0), Token::Op(Operator::Mul), Token::Close(0)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("(/)");
	assert_eq!(Expression::new(vec![Token::Open(0), Token::Op(Operator::Div), Token::Close(0)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("(^)");
	assert_eq!(Expression::new(vec![Token::Open(0), Token::Op(Operator::Pow), Token::Close(0)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("(())");
	assert_eq!(Expression::new(vec![Token::Open(0), Token::Open(1), Token::Close(1), Token::Close(0)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("+(+(-)*(+))+(/)^");
	assert_eq!(Expression::new(vec![Token::Op(Operator::Add), Token::Open(0), Token::Op(Operator::Add), Token::Open(1), Token::Op(Operator::Sub),
									Token::Close(1), Token::Op(Operator::Mul), Token::Open(1), Token::Op(Operator::Add), Token::Close(1), Token::Close(0),
									Token::Op(Operator::Add), Token::Open(0), Token::Op(Operator::Div), Token::Close(0), Token::Op(Operator::Pow)], 0.0), parse_input(&input).unwrap());
}<|endoftext|>


<commit_before>use std::ops::{Add, Sub, Mul, Div};

fn do_operation<F, V>(f: F, v1: V, v2: V) -> V
    where
        F: Fn(V, V) -> V,
        V: Add + Sub + Mul + Div {
    f(v1, v2)
}

pub fn rpn(raw: &str) -> f64 {
    let mut stack = Vec::new();

    for c in raw.split(' ') {
        if let Some(i) = c.parse::<f64>().ok() {
            stack.push(i);
            continue;
        }

        let msg = "Invalid equation. No numbers left in stack for the left side of the operation";
        let r = stack.pop().expect(msg);
        let l = stack.pop().expect(msg);

        let result = match c {
            "+" => do_operation(|l, r| l + r, l, r),
            "-" => do_operation(|l, r| l - r, l, r),
            "*" => do_operation(|l, r| l * r, l, r),
            "/" =>
            {
                if r == 0.0
                {
                    panic!("Division by zero not allowed");
                }

                do_operation(|l, r| l / r, l, r)
            },
            _ => panic!("Unknown character {:?}", c),
        };

        stack.push(result);
    }

    if stack.len() != 1
    {
        panic!("Invalid equation. Wrong number of elements left in stack. Expected left: 1, actual: {:?}", stack.len());
    }

    stack.pop().unwrap()
}

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

    #[test]
    fn basic_integer() {
        assert_eq!(0.25, rpn("14 4 6 8 + * /"));
        assert_eq!(14.0, rpn("5 1 2 + 4 * + 3 -"));
        assert_eq!(0.5, rpn("5 4 6 + /"));
        assert_eq!(2.0, rpn("2 5 * 4 + 3 2 * 1 + /"));
    }

    #[test]
    fn basic_floating_point() {
        assert_eq!(20.04, rpn("5.5 1.3 2.3 + 4.9 * + 3.1 -"));
        assert_eq!(11.25, rpn("1.5 3.0 4.5 + *"));
    }

    #[test]
    fn negative() {
        assert_eq!(-2503.0, rpn("-4 -9 -33 -76 * + -"));
        assert_eq!(2653660.0, rpn("-56 -34 + -54 * 43 23 54 + * -800 * -"));
    }

    #[test]
    #[should_panic]
    fn divide_by_zero() {
        assert_eq!(-2503.0, rpn("2 0 /"));
    }

    #[test]
    #[should_panic]
    fn invalid_input_1() {
        rpn("");
    }

    #[test]
    #[should_panic]
    fn invalid_input_2() {
        rpn("14 4 6 8 + . /");
    }

    #[test]
    #[should_panic]
    fn invalid_input_3() {
        rpn("POTATO");
    }

    #[test]
    #[should_panic]
    fn invalid_input_4() {
        rpn("54 4 6 O + \\ /");
    }

    #[test]
    fn long_equation() {
        let mut eq = "2 ".to_string();
        for _ in 0..2000000 {
            eq.push_str("2 + ");
        }

        eq.push_str("1 +");

        assert_eq!(4000003.0, rpn(&eq));
    }
}<commit_msg>Fix error message<commit_after>use std::ops::{Add, Sub, Mul, Div};

fn do_operation<F, V>(f: F, v1: V, v2: V) -> V
    where
        F: Fn(V, V) -> V,
        V: Add + Sub + Mul + Div {
    f(v1, v2)
}

pub fn rpn(raw: &str) -> f64 {
    let mut stack = Vec::new();

    for c in raw.split(' ') {
        if let Some(i) = c.parse::<f64>().ok() {
            stack.push(i);
            continue;
        }

        let r = stack.pop().expect("Invalid equation. No numbers left in stack for the right side of the operation");
        let l = stack.pop().expect("Invalid equation. No numbers left in stack for the left side of the operation");

        let result = match c {
            "+" => do_operation(|l, r| l + r, l, r),
            "-" => do_operation(|l, r| l - r, l, r),
            "*" => do_operation(|l, r| l * r, l, r),
            "/" =>
            {
                if r == 0.0
                {
                    panic!("Division by zero not allowed");
                }

                do_operation(|l, r| l / r, l, r)
            },
            _ => panic!("Unknown character {:?}", c),
        };

        stack.push(result);
    }

    if stack.len() != 1
    {
        panic!("Invalid equation. Wrong number of elements left in stack. Expected left: 1, actual: {:?}", stack.len());
    }

    stack.pop().unwrap()
}

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

    #[test]
    fn basic_integer() {
        assert_eq!(0.25, rpn("14 4 6 8 + * /"));
        assert_eq!(14.0, rpn("5 1 2 + 4 * + 3 -"));
        assert_eq!(0.5, rpn("5 4 6 + /"));
        assert_eq!(2.0, rpn("2 5 * 4 + 3 2 * 1 + /"));
    }

    #[test]
    fn basic_floating_point() {
        assert_eq!(20.04, rpn("5.5 1.3 2.3 + 4.9 * + 3.1 -"));
        assert_eq!(11.25, rpn("1.5 3.0 4.5 + *"));
    }

    #[test]
    fn negative() {
        assert_eq!(-2503.0, rpn("-4 -9 -33 -76 * + -"));
        assert_eq!(2653660.0, rpn("-56 -34 + -54 * 43 23 54 + * -800 * -"));
    }

    #[test]
    #[should_panic]
    fn divide_by_zero() {
        assert_eq!(-2503.0, rpn("2 0 /"));
    }

    #[test]
    #[should_panic]
    fn invalid_input_1() {
        rpn("");
    }

    #[test]
    #[should_panic]
    fn invalid_input_2() {
        rpn("14 4 6 8 + . /");
    }

    #[test]
    #[should_panic]
    fn invalid_input_3() {
        rpn("POTATO");
    }

    #[test]
    #[should_panic]
    fn invalid_input_4() {
        rpn("54 4 6 O + \\ /");
    }

    #[test]
    fn long_equation() {
        let mut eq = "2 ".to_string();
        for _ in 0..2000000 {
            eq.push_str("2 + ");
        }

        eq.push_str("1 +");

        assert_eq!(4000003.0, rpn(&eq));
    }
}<|endoftext|>


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

#[macro_use]
extern crate clap;
extern crate hyper;
extern crate hyper_rustls;
extern crate pulldown_cmark;
extern crate rayon;
extern crate url;
extern crate walkdir;

mod document;
mod error;

use clap::{Arg, App};
use document::{Document, Error, Event};
use error::{DocumentError, DocumentLocation, LinkError, LocatedDocumentError};
use hyper::client::Client;
use hyper::header::UserAgent;
use hyper::net::HttpsConnector;
use hyper::status::StatusCode;
use hyper_rustls::TlsClient;
use rayon::prelude::*;
use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs::File;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use std::process::exit;
use std::sync::Arc;
use url::{ParseError, Url};
use walkdir::WalkDir;

macro_rules! fail {
    ($($print:expr),+) => {
        {
            let _ = writeln!(&mut std::io::stderr(), $($print),+);
            exit(1);
        }
    };
}

macro_rules! printerror {
    ($error:expr, $flag:expr) => {
        {
            println!("{}", $error);
            $flag = true;
        }
    };
}

struct LinkContext {
    target: String,
    text: String,
    line: usize,
    file: PathBuf,
}

impl LinkContext {
    fn new_error(self, error: LinkError) -> LocatedDocumentError {
        LocatedDocumentError {
            location: DocumentLocation {
                path: self.file,
                line: self.line,
            },
            error: DocumentError::Link {
                text: self.text,
                target: self.target,
                error: error,
            },
        }
    }
}

fn main() {
    let matches = App::new("Marker")
        .version(crate_version!())
        .arg(
            Arg::with_name("root")
                .short("r")
                .long("root")
                .help("The path to the root of the documentation to be checked")
                .takes_value(true),
        )
        .arg(Arg::with_name("skip-http").long("skip-http").help(
            "Skip validation of HTTP[S] URLs",
        ))
        .get_matches();

    let skip_http = matches.is_present("skip-http");
    let root = Path::new(matches.value_of("root").unwrap_or("."));
    let mut links = Vec::new();
    let mut found_error = false;

    for entry in WalkDir::new(root).into_iter().filter_map(|entry| {
        let entry = entry.unwrap_or_else(|error| {
            fail!("Failed to walk directory: {}", error);
        });
        if entry.file_type().is_file() && entry.path().extension() == Some(OsStr::new("md")) {
            Some(entry)
        } else {
            None
        }
    })
    {
        let contents = {
            let mut file = File::open(entry.path()).unwrap_or_else(|error| {
                fail!(
                    "Failed to open file ({}): {}",
                    entry.path().display(),
                    error
                );
            });
            let mut text = String::new();
            if let Err(error) = file.read_to_string(&mut text) {
                fail!(
                    "Failed to read file ({}): {}",
                    entry.path().display(),
                    error
                );
            };
            text
        };

        for event in Document::new(&contents) {
            match event.event {
                Event::Link { target, text } => {
                    links.push(LinkContext {
                        target: target,
                        text: text,
                        line: event.line,
                        file: entry.path().to_path_buf(),
                    })
                }
                Event::Error(Error::ReferenceBroken { target, text }) => {
                    printerror!(
                        LinkContext {
                            target: target,
                            text: text,
                            line: event.line,
                            file: entry.path().to_path_buf(),
                        }.new_error(LinkError::ReferenceBroken),
                        found_error
                    )
                }
            }
        }
    }

    let mut urls = HashMap::new();
    for link in links {
        match Url::parse(&link.target) {
            Ok(_) if skip_http => {}
            Ok(mut url) => {
                url.set_fragment(None);
                urls.entry(url).or_insert(Vec::new()).push(link)
            }
            Err(ParseError::RelativeUrlWithoutBase) => {
                if let Err(error) = check_path(&link.target, &link.file) {
                    printerror!(link.new_error(error), found_error)
                }
            }
            Err(error) => printerror!(link.new_error(LinkError::UrlMalformed(error)), found_error),
        }
    }

    for (result, links) in urls.into_par_iter()
        .map(|(url, links)| (check_url(url), links))
        .collect::<Vec<_>>()
    {
        if let Err(error) = result {
            for link in links {
                printerror!(link.new_error(error.clone()), found_error)
            }
        }
    }

    if found_error {
        exit(1)
    }
}

fn check_url(url: Url) -> Result<(), LinkError> {
    if url.scheme() != "http" && url.scheme() != "https" {
        return Ok(());
    }

    let client = Client::with_connector(HttpsConnector::new(TlsClient::new()));
    let agent = UserAgent(format!("marker/{}", crate_version!()));

    let res = client
        .head(url.clone())
        .header(agent.clone())
        .send()
        .and_then(|resp| if resp.status == StatusCode::MethodNotAllowed {
            client.get(url.clone()).header(agent.clone()).send()
        } else {
            Ok(resp)
        });
    match res {
        Ok(resp) => {
            match resp.status {
                StatusCode::Ok => Ok(()),
                status => Err(LinkError::HttpStatus(status)),
            }
        }
        Err(error) => return Err(LinkError::HttpError(Arc::new(error))),
    }
}

fn check_path(target: &str, file: &Path) -> Result<(), LinkError> {
    let path = Path::new(OsStr::new(target.split('#').next().expect("string")));
    if path.is_absolute() {
        Err(LinkError::PathAbsolute)
    } else if !file.parent()
               .expect("non-root file path")
               .join(path)
               .exists()
    {
        Err(LinkError::PathNonExistant)
    } else {
        Ok(())
    }
}
<commit_msg>main: use eprintln<commit_after>// Copyright 2016 Alex Crawford
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[macro_use]
extern crate clap;
extern crate hyper;
extern crate hyper_rustls;
extern crate pulldown_cmark;
extern crate rayon;
extern crate url;
extern crate walkdir;

mod document;
mod error;

use clap::{Arg, App};
use document::{Document, Error, Event};
use error::{DocumentError, DocumentLocation, LinkError, LocatedDocumentError};
use hyper::client::Client;
use hyper::header::UserAgent;
use hyper::net::HttpsConnector;
use hyper::status::StatusCode;
use hyper_rustls::TlsClient;
use rayon::prelude::*;
use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::process::exit;
use std::sync::Arc;
use url::{ParseError, Url};
use walkdir::WalkDir;

macro_rules! fail {
    ($($print:expr),+) => {
        {
            eprintln!($($print),+);
            exit(1);
        }
    };
}

macro_rules! printerror {
    ($error:expr, $flag:expr) => {
        {
            println!("{}", $error);
            $flag = true;
        }
    };
}

struct LinkContext {
    target: String,
    text: String,
    line: usize,
    file: PathBuf,
}

impl LinkContext {
    fn new_error(self, error: LinkError) -> LocatedDocumentError {
        LocatedDocumentError {
            location: DocumentLocation {
                path: self.file,
                line: self.line,
            },
            error: DocumentError::Link {
                text: self.text,
                target: self.target,
                error: error,
            },
        }
    }
}

fn main() {
    let matches = App::new("Marker")
        .version(crate_version!())
        .arg(
            Arg::with_name("root")
                .short("r")
                .long("root")
                .help("The path to the root of the documentation to be checked")
                .takes_value(true),
        )
        .arg(Arg::with_name("skip-http").long("skip-http").help(
            "Skip validation of HTTP[S] URLs",
        ))
        .get_matches();

    let skip_http = matches.is_present("skip-http");
    let root = Path::new(matches.value_of("root").unwrap_or("."));
    let mut links = Vec::new();
    let mut found_error = false;

    for entry in WalkDir::new(root).into_iter().filter_map(|entry| {
        let entry = entry.unwrap_or_else(|error| {
            fail!("Failed to walk directory: {}", error);
        });
        if entry.file_type().is_file() && entry.path().extension() == Some(OsStr::new("md")) {
            Some(entry)
        } else {
            None
        }
    })
    {
        let contents = {
            let mut file = File::open(entry.path()).unwrap_or_else(|error| {
                fail!(
                    "Failed to open file ({}): {}",
                    entry.path().display(),
                    error
                );
            });
            let mut text = String::new();
            if let Err(error) = file.read_to_string(&mut text) {
                fail!(
                    "Failed to read file ({}): {}",
                    entry.path().display(),
                    error
                );
            };
            text
        };

        for event in Document::new(&contents) {
            match event.event {
                Event::Link { target, text } => {
                    links.push(LinkContext {
                        target: target,
                        text: text,
                        line: event.line,
                        file: entry.path().to_path_buf(),
                    })
                }
                Event::Error(Error::ReferenceBroken { target, text }) => {
                    printerror!(
                        LinkContext {
                            target: target,
                            text: text,
                            line: event.line,
                            file: entry.path().to_path_buf(),
                        }.new_error(LinkError::ReferenceBroken),
                        found_error
                    )
                }
            }
        }
    }

    let mut urls = HashMap::new();
    for link in links {
        match Url::parse(&link.target) {
            Ok(_) if skip_http => {}
            Ok(mut url) => {
                url.set_fragment(None);
                urls.entry(url).or_insert(Vec::new()).push(link)
            }
            Err(ParseError::RelativeUrlWithoutBase) => {
                if let Err(error) = check_path(&link.target, &link.file) {
                    printerror!(link.new_error(error), found_error)
                }
            }
            Err(error) => printerror!(link.new_error(LinkError::UrlMalformed(error)), found_error),
        }
    }

    for (result, links) in urls.into_par_iter()
        .map(|(url, links)| (check_url(url), links))
        .collect::<Vec<_>>()
    {
        if let Err(error) = result {
            for link in links {
                printerror!(link.new_error(error.clone()), found_error)
            }
        }
    }

    if found_error {
        exit(1)
    }
}

fn check_url(url: Url) -> Result<(), LinkError> {
    if url.scheme() != "http" && url.scheme() != "https" {
        return Ok(());
    }

    let client = Client::with_connector(HttpsConnector::new(TlsClient::new()));
    let agent = UserAgent(format!("marker/{}", crate_version!()));

    let res = client
        .head(url.clone())
        .header(agent.clone())
        .send()
        .and_then(|resp| if resp.status == StatusCode::MethodNotAllowed {
            client.get(url.clone()).header(agent.clone()).send()
        } else {
            Ok(resp)
        });
    match res {
        Ok(resp) => {
            match resp.status {
                StatusCode::Ok => Ok(()),
                status => Err(LinkError::HttpStatus(status)),
            }
        }
        Err(error) => return Err(LinkError::HttpError(Arc::new(error))),
    }
}

fn check_path(target: &str, file: &Path) -> Result<(), LinkError> {
    let path = Path::new(OsStr::new(target.split('#').next().expect("string")));
    if path.is_absolute() {
        Err(LinkError::PathAbsolute)
    } else if !file.parent()
               .expect("non-root file path")
               .join(path)
               .exists()
    {
        Err(LinkError::PathNonExistant)
    } else {
        Ok(())
    }
}
<|endoftext|>


<commit_before>extern crate ar;
extern crate clap;
extern crate libflate;
extern crate tar;
extern crate tempfile;
extern crate time as crates_time;
extern crate xz2;
extern crate zip;

use std::fs;
use std::io;
use std::time;

use std::rc::Rc;
use std::vec::Vec;

use clap::{Arg, App};

use libflate::gzip;
use tempfile::tempfile;

// magic:
use std::io::Seek;

#[derive(Debug)]
struct Node<T> {
    next: Option<Rc<Node<T>>>,
    value: T,
}

impl<T> Node<T> {
    fn head(obj: T) -> Rc<Node<T>> {
        Rc::new(Node {
            next: None,
            value: obj,
        })
    }

    fn plus(what: &Rc<Node<T>>, obj: T) -> Rc<Node<T>> {
        Rc::new(Node {
            next: Some(what.clone()),
            value: obj
        })
    }
}

struct OutputTo {
    path: Rc<Node<String>>,
    size: u64,
    atime: u64,
    mtime: u64,
    ctime: u64,
    btime: u64,
}

impl OutputTo {
    fn warn(&self, msg: String) {
        println!("TODO: {}", msg);
    }

    fn raw<F: io::Read>(&self, file: F) -> io::Result<()> {
        unimplemented!();
    }
}

impl OutputTo {
    fn from_file(path: &str, fd: &fs::File) -> io::Result<OutputTo> {
        let meta = fd.metadata()?;
        Ok(OutputTo {
            path: Node::head(path.to_string()),
            size: meta.len(),
            atime: meta.accessed().map(simple_time_sys)?,
            mtime: meta.modified().map(simple_time_sys)?,
            ctime: simple_time_ctime(&meta),
            btime: meta.created().map(simple_time_sys)?,
        })
    }

    fn with_path(&self, path: String) -> OutputTo {
        OutputTo {
            path: Node::plus(&self.path, path),
            size: 0,
            atime: 0,
            mtime: 0,
            ctime: 0,
            btime: 0,
        }
    }
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum FileType {
    GZip,
    Zip,
    Tar,
    Ar,
    BZip2,
    Xz,
    Other,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum Status {
    Done,
    Rewind,
}

fn read_octal(bytes: &[u8]) -> Option<u32> {
    let mut start = 0;
    while start < bytes.len() && b' ' == bytes[start] {
        start += 1;
    }

    let mut end = bytes.len() - 1;
    while end > start && (b' ' == bytes[end] || 0 == bytes[end]) {
        end -= 1;
    }

    if let Ok(string) = std::str::from_utf8(&bytes[start..(end+1)]) {
        if let Ok(val) = u32::from_str_radix(string, 8) {
            return Some(val);
        }
    }
    None
}

fn simple_time(dur: time::Duration) -> u64 {
    dur.as_secs().checked_mul(1_000_000_000)
        .map_or(0, |nanos| nanos + dur.subsec_nanos() as u64)
}

fn simple_time_sys(val: time::SystemTime) -> u64 {
    val.duration_since(time::UNIX_EPOCH).map(simple_time).unwrap_or(0)
}

fn simple_time_tm(val: crates_time::Tm) -> u64 {
    let timespec = val.to_timespec();
    simple_time(time::Duration::new(timespec.sec as u64, timespec.nsec as u32))
}

// TODO: I really feel this should be exposed by Rust, without cfg.
fn simple_time_ctime(val: &fs::Metadata) -> u64 {
    #[cfg(linux)] {
        use std::os::linux::fs::MetadataExt;
        let ctime: i64 = val.st_ctime();
        if ctime <= 0 {
            0
        } else {
            ctime as u64
        }
    }

    #[cfg(not(linux))] {
        0
    }
}

fn is_probably_tar(header: &[u8]) -> bool {
    if header.len() < 512 {
        return false;
    }

    if let Some(checksum) = read_octal(&header[148..156]) {
        let mut sum: u32 = (b' ' as u32) * 8;
        for i in 0..148 {
            sum += header[i] as u32;
        }
        for i in 156..512 {
            sum += header[i] as u32;
        }

        if checksum == sum {
            return true;
        }
    }

    return false;
}

fn identify<'a>(fd: &mut Box<io::BufRead + 'a>) -> io::Result<FileType> {
    let header = fd.fill_buf()?;
    if header.len() >= 20
        && 0x1f == header[0] && 0x8b == header[1] {
        Ok(FileType::GZip)
   } else if header.len() >= 152
        && b'P' == header[0] && b'K' == header[1]
        && 0x03 == header[2] && 0x04 == header[3] {
        Ok(FileType::Zip)
    } else if header.len() > 257 + 10
        && b'u' == header[257] && b's' == header[258]
        && b't' == header[259] && b'a' == header[260]
        && b'r' == header[261]
        && (
            (0 == header[262] && b'0' == header[263] && b'0' == header[264]) ||
            (b' ' == header[262] && b' ' == header[263] && 0 == header[264])
        ) {
        Ok(FileType::Tar)
    } else if header.len() > 8
        && b'!' == header[0] && b'<' == header[1]
        && b'a' == header[2] && b'r' == header[3]
        && b'c' == header[4] && b'h' == header[5]
        && b'>' == header[6] && b'\n' == header[7] {
        Ok(FileType::Ar)
    } else if header.len() > 40
        && b'B' == header[0] && b'Z' == header[1]
        && b'h' == header[2] && 0x31 == header[3]
        && 0x41 == header[4] && 0x59 == header[5]
        && 0x26 == header[6] {
        Ok(FileType::BZip2)
    } else if header.len() > 6
        && 0xfd == header[0] && b'7' == header[1]
        && b'z' == header[2] && b'X' == header[3]
        && b'Z' == header[4] && 0 == header[5] {
        Ok(FileType::Xz)
    } else if is_probably_tar(header) {
        Ok(FileType::Tar)
    } else {
        Ok(FileType::Other)
    }
}

struct BoxReader<'a> {
    fd: Box<io::BufRead + 'a>
}

impl<'a> io::Read for BoxReader<'a> {
    fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
        self.fd.read(&mut buf)
    }
}

fn count_bytes<'a, R: io::Read>(mut fd: &mut R) -> io::Result<u64> {
    let mut block = [0u8; 4096];
    let mut count = 0u64;
    loop {
        let found = fd.read(&mut block[..])?;
        if 0 == found {
            break;
        }
        count += found as u64;
    }
    Ok(count)
}

fn unpack_or_raw<'a, F>(
    fd: Box<io::BufRead + 'a>,
    output: &OutputTo,
    fun: F) -> io::Result<Status>
where F: FnOnce(Box<io::BufRead + 'a>) -> io::Result<Box<io::BufRead + 'a>>
{
    match fun(fd) {
        Ok(inner) => unpack(inner, output),
        Err(e) => {
            output.warn(format!(
                    "thought we could unpack '{:?}' but we couldn't: {}",
                    output.path, e));
            Ok(Status::Rewind)
        }
    }
}

fn unpack<'a>(mut fd: Box<io::BufRead + 'a>, output: &OutputTo) -> io::Result<Status> {
    match identify(&mut fd)? {
        FileType::GZip => {
            unpack_or_raw(fd, output,
                |fd| gzip::Decoder::new(fd).map(
                    |dec| Box::new(io::BufReader::new(dec)) as Box<io::BufRead>))
        },
        FileType::Xz => {
            unpack_or_raw(fd, output,
                |fd| Ok(Box::new(io::BufReader::new(xz2::bufread::XzDecoder::new(fd)))))
        },
        FileType::Ar if output.path.value.ends_with(".deb") => {
            let mut decoder = ar::Archive::new(fd);
            while let Some(entry) = decoder.next_entry() {
                let entry = entry?;
                let new_output = output.with_path(entry.header().identifier().to_string());
                unpack(Box::new(io::BufReader::new(entry)), &new_output)?;
            }
            Ok(Status::Done)
        },
        FileType::Tar => {
            let mut decoder = tar::Archive::new(fd);
            for entry in decoder.entries()? {
                let entry = entry?;
                let new_output = output.with_path(entry.path()?.to_str().expect("valid utf-8").to_string());
                unpack(Box::new(io::BufReader::new(entry)), &new_output)?;
            }
            Ok(Status::Done)
        },
        FileType::Zip => {
            let mut temp = tempfile()?;
            io::copy(&mut BoxReader { fd }, &mut temp)?;
            let mut zip = zip::ZipArchive::new(temp)?;

            for i in 0..zip.len() {
                let file_result = {
                    let entry = zip.by_index(i)?;
                    let mut new_output = output.with_path((entry.name()).to_string());
                    new_output.size = entry.size();
                    new_output.mtime = simple_time_tm(entry.last_modified());
                    let reader = Box::new(io::BufReader::new(entry));
                    unpack(reader, &new_output)?
                };
                match file_result {
                    Status::Done => (),
                    Status::Rewind => {
                        // TODO: update output? ? handling? ???
                        output.raw(zip.by_index(i)?)?
                    },
                };
            }

            Ok(Status::Done)
        },
        other => {
            println!("{:?}: {:?} {}", output.path, other, count_bytes(&mut BoxReader { fd })?);
            Ok(Status::Done)
        },
    }
}

fn main() {
    let matches = App::new("contentin")
                    .arg(Arg::with_name("to-tar")
                         .long("to-tar")
                         .help("emit a tar file")
                         .required(true))
                    .arg(Arg::with_name("INPUT")
                         .required(true)
                         .multiple(true))
                    .get_matches();
    for path in matches.values_of("INPUT").unwrap() {
        let file = fs::File::open(path).unwrap();
        let output = OutputTo::from_file(
            path,
            &file
        ).expect("input file metadata");
        let read = io::BufReader::new(file);
        assert_eq!(Status::Done, unpack(Box::new(read), &output).unwrap());
    }
}

<commit_msg>mask badly hidden btimes<commit_after>extern crate ar;
extern crate clap;
extern crate libflate;
extern crate tar;
extern crate tempfile;
extern crate time as crates_time;
extern crate xz2;
extern crate zip;

use std::fs;
use std::io;
use std::time;

use std::rc::Rc;
use std::vec::Vec;

use clap::{Arg, App};

use libflate::gzip;
use tempfile::tempfile;

// magic:
use std::io::Seek;

#[derive(Debug)]
struct Node<T> {
    next: Option<Rc<Node<T>>>,
    value: T,
}

impl<T> Node<T> {
    fn head(obj: T) -> Rc<Node<T>> {
        Rc::new(Node {
            next: None,
            value: obj,
        })
    }

    fn plus(what: &Rc<Node<T>>, obj: T) -> Rc<Node<T>> {
        Rc::new(Node {
            next: Some(what.clone()),
            value: obj
        })
    }
}

struct OutputTo {
    path: Rc<Node<String>>,
    size: u64,
    atime: u64,
    mtime: u64,
    ctime: u64,
    btime: u64,
}

impl OutputTo {
    fn warn(&self, msg: String) {
        println!("TODO: {}", msg);
    }

    fn raw<F: io::Read>(&self, file: F) -> io::Result<()> {
        unimplemented!();
    }
}

impl OutputTo {
    fn from_file(path: &str, fd: &fs::File) -> io::Result<OutputTo> {
        let meta = fd.metadata()?;
        Ok(OutputTo {
            path: Node::head(path.to_string()),
            size: meta.len(),
            atime: meta.accessed().map(simple_time_sys)?,
            mtime: meta.modified().map(simple_time_sys)?,
            ctime: simple_time_ctime(&meta),
            btime: simple_time_btime(&meta)?,
        })
    }

    fn with_path(&self, path: String) -> OutputTo {
        OutputTo {
            path: Node::plus(&self.path, path),
            size: 0,
            atime: 0,
            mtime: 0,
            ctime: 0,
            btime: 0,
        }
    }
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum FileType {
    GZip,
    Zip,
    Tar,
    Ar,
    BZip2,
    Xz,
    Other,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum Status {
    Done,
    Rewind,
}

fn read_octal(bytes: &[u8]) -> Option<u32> {
    let mut start = 0;
    while start < bytes.len() && b' ' == bytes[start] {
        start += 1;
    }

    let mut end = bytes.len() - 1;
    while end > start && (b' ' == bytes[end] || 0 == bytes[end]) {
        end -= 1;
    }

    if let Ok(string) = std::str::from_utf8(&bytes[start..(end+1)]) {
        if let Ok(val) = u32::from_str_radix(string, 8) {
            return Some(val);
        }
    }
    None
}

fn simple_time(dur: time::Duration) -> u64 {
    dur.as_secs().checked_mul(1_000_000_000)
        .map_or(0, |nanos| nanos + dur.subsec_nanos() as u64)
}

fn simple_time_sys(val: time::SystemTime) -> u64 {
    val.duration_since(time::UNIX_EPOCH).map(simple_time).unwrap_or(0)
}

fn simple_time_tm(val: crates_time::Tm) -> u64 {
    let timespec = val.to_timespec();
    simple_time(time::Duration::new(timespec.sec as u64, timespec.nsec as u32))
}

fn simple_time_btime(val: &fs::Metadata) -> io::Result<u64> {
    match val.created() {
        Ok(time) => Ok(simple_time_sys(time)),
        // "Other" is how "unsupported" is represented here; ew.
        Err(ref e) if e.kind() == io::ErrorKind::Other => Ok(0),
        Err(other) => Err(other),
    }
}

// TODO: I really feel this should be exposed by Rust, without cfg.
fn simple_time_ctime(val: &fs::Metadata) -> u64 {
    #[cfg(linux)] {
        use std::os::linux::fs::MetadataExt;
        let ctime: i64 = val.st_ctime();
        if ctime <= 0 {
            0
        } else {
            ctime as u64
        }
    }

    #[cfg(not(linux))] {
        0
    }
}

fn is_probably_tar(header: &[u8]) -> bool {
    if header.len() < 512 {
        return false;
    }

    if let Some(checksum) = read_octal(&header[148..156]) {
        let mut sum: u32 = (b' ' as u32) * 8;
        for i in 0..148 {
            sum += header[i] as u32;
        }
        for i in 156..512 {
            sum += header[i] as u32;
        }

        if checksum == sum {
            return true;
        }
    }

    return false;
}

fn identify<'a>(fd: &mut Box<io::BufRead + 'a>) -> io::Result<FileType> {
    let header = fd.fill_buf()?;
    if header.len() >= 20
        && 0x1f == header[0] && 0x8b == header[1] {
        Ok(FileType::GZip)
   } else if header.len() >= 152
        && b'P' == header[0] && b'K' == header[1]
        && 0x03 == header[2] && 0x04 == header[3] {
        Ok(FileType::Zip)
    } else if header.len() > 257 + 10
        && b'u' == header[257] && b's' == header[258]
        && b't' == header[259] && b'a' == header[260]
        && b'r' == header[261]
        && (
            (0 == header[262] && b'0' == header[263] && b'0' == header[264]) ||
            (b' ' == header[262] && b' ' == header[263] && 0 == header[264])
        ) {
        Ok(FileType::Tar)
    } else if header.len() > 8
        && b'!' == header[0] && b'<' == header[1]
        && b'a' == header[2] && b'r' == header[3]
        && b'c' == header[4] && b'h' == header[5]
        && b'>' == header[6] && b'\n' == header[7] {
        Ok(FileType::Ar)
    } else if header.len() > 40
        && b'B' == header[0] && b'Z' == header[1]
        && b'h' == header[2] && 0x31 == header[3]
        && 0x41 == header[4] && 0x59 == header[5]
        && 0x26 == header[6] {
        Ok(FileType::BZip2)
    } else if header.len() > 6
        && 0xfd == header[0] && b'7' == header[1]
        && b'z' == header[2] && b'X' == header[3]
        && b'Z' == header[4] && 0 == header[5] {
        Ok(FileType::Xz)
    } else if is_probably_tar(header) {
        Ok(FileType::Tar)
    } else {
        Ok(FileType::Other)
    }
}

struct BoxReader<'a> {
    fd: Box<io::BufRead + 'a>
}

impl<'a> io::Read for BoxReader<'a> {
    fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
        self.fd.read(&mut buf)
    }
}

fn count_bytes<'a, R: io::Read>(mut fd: &mut R) -> io::Result<u64> {
    let mut block = [0u8; 4096];
    let mut count = 0u64;
    loop {
        let found = fd.read(&mut block[..])?;
        if 0 == found {
            break;
        }
        count += found as u64;
    }
    Ok(count)
}

fn unpack_or_raw<'a, F>(
    fd: Box<io::BufRead + 'a>,
    output: &OutputTo,
    fun: F) -> io::Result<Status>
where F: FnOnce(Box<io::BufRead + 'a>) -> io::Result<Box<io::BufRead + 'a>>
{
    match fun(fd) {
        Ok(inner) => unpack(inner, output),
        Err(e) => {
            output.warn(format!(
                    "thought we could unpack '{:?}' but we couldn't: {}",
                    output.path, e));
            Ok(Status::Rewind)
        }
    }
}

fn unpack<'a>(mut fd: Box<io::BufRead + 'a>, output: &OutputTo) -> io::Result<Status> {
    match identify(&mut fd)? {
        FileType::GZip => {
            unpack_or_raw(fd, output,
                |fd| gzip::Decoder::new(fd).map(
                    |dec| Box::new(io::BufReader::new(dec)) as Box<io::BufRead>))
        },
        FileType::Xz => {
            unpack_or_raw(fd, output,
                |fd| Ok(Box::new(io::BufReader::new(xz2::bufread::XzDecoder::new(fd)))))
        },
        FileType::Ar if output.path.value.ends_with(".deb") => {
            let mut decoder = ar::Archive::new(fd);
            while let Some(entry) = decoder.next_entry() {
                let entry = entry?;
                let new_output = output.with_path(entry.header().identifier().to_string());
                unpack(Box::new(io::BufReader::new(entry)), &new_output)?;
            }
            Ok(Status::Done)
        },
        FileType::Tar => {
            let mut decoder = tar::Archive::new(fd);
            for entry in decoder.entries()? {
                let entry = entry?;
                let new_output = output.with_path(entry.path()?.to_str().expect("valid utf-8").to_string());
                unpack(Box::new(io::BufReader::new(entry)), &new_output)?;
            }
            Ok(Status::Done)
        },
        FileType::Zip => {
            let mut temp = tempfile()?;
            io::copy(&mut BoxReader { fd }, &mut temp)?;
            let mut zip = zip::ZipArchive::new(temp)?;

            for i in 0..zip.len() {
                let file_result = {
                    let entry = zip.by_index(i)?;
                    let mut new_output = output.with_path((entry.name()).to_string());
                    new_output.size = entry.size();
                    new_output.mtime = simple_time_tm(entry.last_modified());
                    let reader = Box::new(io::BufReader::new(entry));
                    unpack(reader, &new_output)?
                };
                match file_result {
                    Status::Done => (),
                    Status::Rewind => {
                        // TODO: update output? ? handling? ???
                        output.raw(zip.by_index(i)?)?
                    },
                };
            }

            Ok(Status::Done)
        },
        other => {
            println!("{:?}: {:?} {}", output.path, other, count_bytes(&mut BoxReader { fd })?);
            Ok(Status::Done)
        },
    }
}

fn main() {
    let matches = App::new("contentin")
                    .arg(Arg::with_name("to-tar")
                         .long("to-tar")
                         .help("emit a tar file")
                         .required(true))
                    .arg(Arg::with_name("INPUT")
                         .required(true)
                         .multiple(true))
                    .get_matches();
    for path in matches.values_of("INPUT").unwrap() {
        let file = fs::File::open(path).unwrap();
        let output = OutputTo::from_file(
            path,
            &file
        ).expect("input file metadata");
        let read = io::BufReader::new(file);
        assert_eq!(Status::Done, unpack(Box::new(read), &output).unwrap());
    }
}

<|endoftext|>


<commit_before>#![allow(dead_code)]

extern crate genmesh;
extern crate obj;

use std::thread;
use std::time::{Duration, Instant};
use glium::{self, Display};
use glium::vertex::VertexBufferAny;

pub mod camera;

pub enum Action {
    Stop,
    Continue,
}

pub fn start_loop<F>(mut callback: F) where F: FnMut() -> Action {
    let mut accumulator = 0;
    let mut previous_clock = Instant::now();

    loop {
        match callback() {
            Action::Stop => break,
            Action::Continue => ()
        };

        let now = Instant::now();
        accumulator += now - previous_clock;
        previous_clock = now;

        let fixed_time_stamp = Duration::new(0, 16666667);
        while accumulator >= fixed_time_stamp {
            accumulator -= fixed_time_stamp;

            // if you have a game, update the state here
        }

        thread::sleep(fixed_time_stamp - accumulator);
    }
}

/// Returns a vertex buffer that should be rendered as `TrianglesList`.
pub fn load_wavefront(display: &Display, data: &[u8]) -> VertexBufferAny {
    #[derive(Copy, Clone)]
    struct Vertex {
        position: [f32; 3],
        normal: [f32; 3],
        texture: [f32; 2],
    }

    implement_vertex!(Vertex, position, normal, texture);

    let mut data = ::std::io::BufReader::new(data);
    let data = obj::Obj::load(&mut data);

    let mut vertex_data = Vec::new();

    for object in data.object_iter() {
        for shape in object.group_iter().flat_map(|g| g.indices().iter()) {
            match shape {
                &genmesh::Polygon::PolyTri(genmesh::Triangle { x: v1, y: v2, z: v3 }) => {
                    for v in [v1, v2, v3].iter() {
                        let position = data.position()[v.0];
                        let texture = v.1.map(|index| data.texture()[index]);
                        let normal = v.2.map(|index| data.normal()[index]);

                        let texture = texture.unwrap_or([0.0, 0.0]);
                        let normal = normal.unwrap_or([0.0, 0.0, 0.0]);

                        vertex_data.push(Vertex {
                            position: position,
                            normal: normal,
                            texture: texture,
                        })
                    }
                },
                _ => unimplemented!()
            }
        }
    }

    glium::vertex::VertexBuffer::new(display, &vertex_data).unwrap().into_vertex_buffer_any()
}
<commit_msg>Fix accumulator in examples/support/mod.rs<commit_after>#![allow(dead_code)]

extern crate genmesh;
extern crate obj;

use std::thread;
use std::time::{Duration, Instant};
use glium::{self, Display};
use glium::vertex::VertexBufferAny;

pub mod camera;

pub enum Action {
    Stop,
    Continue,
}

pub fn start_loop<F>(mut callback: F) where F: FnMut() -> Action {
    let mut accumulator = Duration::new(0, 0);
    let mut previous_clock = Instant::now();

    loop {
        match callback() {
            Action::Stop => break,
            Action::Continue => ()
        };

        let now = Instant::now();
        accumulator += now - previous_clock;
        previous_clock = now;

        let fixed_time_stamp = Duration::new(0, 16666667);
        while accumulator >= fixed_time_stamp {
            accumulator -= fixed_time_stamp;

            // if you have a game, update the state here
        }

        thread::sleep(fixed_time_stamp - accumulator);
    }
}

/// Returns a vertex buffer that should be rendered as `TrianglesList`.
pub fn load_wavefront(display: &Display, data: &[u8]) -> VertexBufferAny {
    #[derive(Copy, Clone)]
    struct Vertex {
        position: [f32; 3],
        normal: [f32; 3],
        texture: [f32; 2],
    }

    implement_vertex!(Vertex, position, normal, texture);

    let mut data = ::std::io::BufReader::new(data);
    let data = obj::Obj::load(&mut data);

    let mut vertex_data = Vec::new();

    for object in data.object_iter() {
        for shape in object.group_iter().flat_map(|g| g.indices().iter()) {
            match shape {
                &genmesh::Polygon::PolyTri(genmesh::Triangle { x: v1, y: v2, z: v3 }) => {
                    for v in [v1, v2, v3].iter() {
                        let position = data.position()[v.0];
                        let texture = v.1.map(|index| data.texture()[index]);
                        let normal = v.2.map(|index| data.normal()[index]);

                        let texture = texture.unwrap_or([0.0, 0.0]);
                        let normal = normal.unwrap_or([0.0, 0.0, 0.0]);

                        vertex_data.push(Vertex {
                            position: position,
                            normal: normal,
                            texture: texture,
                        })
                    }
                },
                _ => unimplemented!()
            }
        }
    }

    glium::vertex::VertexBuffer::new(display, &vertex_data).unwrap().into_vertex_buffer_any()
}
<|endoftext|>


<commit_before>use crate::prelude::*;

use syntax::source_map::FileName;

use cranelift::codegen::binemit::CodeOffset;

use gimli::write::{
    Address, AttributeValue, FileId, LineProgram, LineString, LineStringTable, UnitEntryId,
};

fn line_program_add_file(
    line_program: &mut LineProgram,
    line_strings: &mut LineStringTable,
    file: &FileName,
) -> FileId {
    match file {
        FileName::Real(path) => {
            let dir_name = path.parent().unwrap().to_str().unwrap().as_bytes();
            let dir_id = if !dir_name.is_empty() {
                let dir_name = LineString::new(dir_name, line_program.encoding(), line_strings);
                line_program.add_directory(dir_name)
            } else {
                line_program.default_directory()
            };
            let file_name = LineString::new(
                path.file_name().unwrap().to_str().unwrap().as_bytes(),
                line_program.encoding(),
                line_strings,
            );
            line_program.add_file(file_name, dir_id, None)
        }
        // FIXME give more appropriate file names
        _ => {
            let dir_id = line_program.default_directory();
            let dummy_file_name = LineString::new(
                file.to_string().into_bytes(),
                line_program.encoding(),
                line_strings,
            );
            line_program.add_file(dummy_file_name, dir_id, None)
        }
    }
}

impl<'tcx> DebugContext<'tcx> {
    pub(super) fn emit_location(&mut self, entry_id: UnitEntryId, span: Span) {
        let loc = self.tcx.sess.source_map().lookup_char_pos(span.lo());

        let file_id = line_program_add_file(
            &mut self.dwarf.unit.line_program,
            &mut self.dwarf.line_strings,
            &loc.file.name,
        );

        let entry = self.dwarf.unit.get_mut(entry_id);

        entry.set(
            gimli::DW_AT_decl_file,
            AttributeValue::FileIndex(Some(file_id)),
        );
        entry.set(
            gimli::DW_AT_decl_line,
            AttributeValue::Udata(loc.line as u64),
        );
        // FIXME: probably omit this
        entry.set(
            gimli::DW_AT_decl_column,
            AttributeValue::Udata(loc.col.to_usize() as u64),
        );
    }
}

impl<'a, 'tcx> FunctionDebugContext<'a, 'tcx> {
    pub(crate) fn create_debug_lines(
        &mut self,
        context: &Context,
        isa: &dyn cranelift::codegen::isa::TargetIsa,
        source_info_set: &indexmap::IndexSet<(Span, mir::SourceScope)>,
    ) -> CodeOffset {
        let tcx = self.debug_context.tcx;

        let line_program = &mut self.debug_context.dwarf.unit.line_program;

        line_program.begin_sequence(Some(Address::Symbol {
            symbol: self.symbol,
            addend: 0,
        }));

        let encinfo = isa.encoding_info();
        let func = &context.func;
        let mut ebbs = func.layout.ebbs().collect::<Vec<_>>();
        ebbs.sort_by_key(|ebb| func.offsets[*ebb]); // Ensure inst offsets always increase

        let line_strings = &mut self.debug_context.dwarf.line_strings;
        let mut create_row_for_span = |line_program: &mut LineProgram, span: Span| {
            let loc = tcx.sess.source_map().lookup_char_pos(span.lo());
            let file_id = line_program_add_file(line_program, line_strings, &loc.file.name);

            /*println!(
                "srcloc {:>04X} {}:{}:{}",
                line_program.row().address_offset,
                file.display(),
                loc.line,
                loc.col.to_u32()
            );*/

            line_program.row().file = file_id;
            line_program.row().line = loc.line as u64;
            line_program.row().column = loc.col.to_u32() as u64 + 1;
            line_program.generate_row();
        };

        let mut end = 0;
        for ebb in ebbs {
            for (offset, inst, size) in func.inst_offsets(ebb, &encinfo) {
                let srcloc = func.srclocs[inst];
                line_program.row().address_offset = offset as u64;
                if !srcloc.is_default() {
                    let source_info = *source_info_set.get_index(srcloc.bits() as usize).unwrap();
                    create_row_for_span(line_program, source_info.0);
                } else {
                    create_row_for_span(line_program, self.mir.span);
                }
                end = offset + size;
            }
        }

        line_program.end_sequence(end as u64);

        let entry = self.debug_context.dwarf.unit.get_mut(self.entry_id);
        entry.set(
            gimli::DW_AT_low_pc,
            AttributeValue::Address(Address::Symbol {
                symbol: self.symbol,
                addend: 0,
            }),
        );
        entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(end as u64));

        self.debug_context
            .emit_location(self.entry_id, self.mir.span);

        end
    }
}
<commit_msg>Optimize line_program_add_file<commit_after>use std::ffi::OsStr;
use std::path::{Component, Path};

use crate::prelude::*;

use syntax::source_map::FileName;

use cranelift::codegen::binemit::CodeOffset;

use gimli::write::{
    Address, AttributeValue, FileId, LineProgram, LineString, LineStringTable, UnitEntryId,
};

// OPTIMIZATION: It is cheaper to do this in one pass than using `.parent()` and `.file_name()`.
fn split_path_dir_and_file(path: &Path) -> (&Path, &OsStr) {
    let mut iter = path.components();
    let file_name = match iter.next_back() {
        Some(Component::Normal(p)) => p,
        component => {
            panic!("Path component {:?} of path {} is an invalid filename", component, path.display());
        }
    };
    let parent = iter.as_path();
    (parent, file_name)
}

// OPTIMIZATION: Avoid UTF-8 validation on UNIX.
fn osstr_as_utf8_bytes(path: &OsStr) -> &[u8] {
    #[cfg(unix)] {
        use std::os::unix::ffi::OsStrExt;
        return path.as_bytes();
    }
    #[cfg(not(unix))] {
        return path.to_str().unwrap().as_bytes();
    }
}

fn line_program_add_file(
    line_program: &mut LineProgram,
    line_strings: &mut LineStringTable,
    file: &FileName,
) -> FileId {
    match file {
        FileName::Real(path) => {
            let (dir_path, file_name) = split_path_dir_and_file(path);
            let dir_name = osstr_as_utf8_bytes(dir_path.as_os_str());
            let file_name = osstr_as_utf8_bytes(file_name);

            let dir_id = if !dir_name.is_empty() {
                let dir_name = LineString::new(dir_name, line_program.encoding(), line_strings);
                line_program.add_directory(dir_name)
            } else {
                line_program.default_directory()
            };
            let file_name = LineString::new(
                file_name,
                line_program.encoding(),
                line_strings,
            );
            line_program.add_file(file_name, dir_id, None)
        }
        // FIXME give more appropriate file names
        _ => {
            let dir_id = line_program.default_directory();
            let dummy_file_name = LineString::new(
                file.to_string().into_bytes(),
                line_program.encoding(),
                line_strings,
            );
            line_program.add_file(dummy_file_name, dir_id, None)
        }
    }
}

impl<'tcx> DebugContext<'tcx> {
    pub(super) fn emit_location(&mut self, entry_id: UnitEntryId, span: Span) {
        let loc = self.tcx.sess.source_map().lookup_char_pos(span.lo());

        let file_id = line_program_add_file(
            &mut self.dwarf.unit.line_program,
            &mut self.dwarf.line_strings,
            &loc.file.name,
        );

        let entry = self.dwarf.unit.get_mut(entry_id);

        entry.set(
            gimli::DW_AT_decl_file,
            AttributeValue::FileIndex(Some(file_id)),
        );
        entry.set(
            gimli::DW_AT_decl_line,
            AttributeValue::Udata(loc.line as u64),
        );
        // FIXME: probably omit this
        entry.set(
            gimli::DW_AT_decl_column,
            AttributeValue::Udata(loc.col.to_usize() as u64),
        );
    }
}

impl<'a, 'tcx> FunctionDebugContext<'a, 'tcx> {
    pub(crate) fn create_debug_lines(
        &mut self,
        context: &Context,
        isa: &dyn cranelift::codegen::isa::TargetIsa,
        source_info_set: &indexmap::IndexSet<(Span, mir::SourceScope)>,
    ) -> CodeOffset {
        let tcx = self.debug_context.tcx;

        let line_program = &mut self.debug_context.dwarf.unit.line_program;

        line_program.begin_sequence(Some(Address::Symbol {
            symbol: self.symbol,
            addend: 0,
        }));

        let encinfo = isa.encoding_info();
        let func = &context.func;
        let mut ebbs = func.layout.ebbs().collect::<Vec<_>>();
        ebbs.sort_by_key(|ebb| func.offsets[*ebb]); // Ensure inst offsets always increase

        let line_strings = &mut self.debug_context.dwarf.line_strings;
        let mut create_row_for_span = |line_program: &mut LineProgram, span: Span| {
            let loc = tcx.sess.source_map().lookup_char_pos(span.lo());
            let file_id = line_program_add_file(line_program, line_strings, &loc.file.name);

            /*println!(
                "srcloc {:>04X} {}:{}:{}",
                line_program.row().address_offset,
                file.display(),
                loc.line,
                loc.col.to_u32()
            );*/

            line_program.row().file = file_id;
            line_program.row().line = loc.line as u64;
            line_program.row().column = loc.col.to_u32() as u64 + 1;
            line_program.generate_row();
        };

        let mut end = 0;
        for ebb in ebbs {
            for (offset, inst, size) in func.inst_offsets(ebb, &encinfo) {
                let srcloc = func.srclocs[inst];
                line_program.row().address_offset = offset as u64;
                if !srcloc.is_default() {
                    let source_info = *source_info_set.get_index(srcloc.bits() as usize).unwrap();
                    create_row_for_span(line_program, source_info.0);
                } else {
                    create_row_for_span(line_program, self.mir.span);
                }
                end = offset + size;
            }
        }

        line_program.end_sequence(end as u64);

        let entry = self.debug_context.dwarf.unit.get_mut(self.entry_id);
        entry.set(
            gimli::DW_AT_low_pc,
            AttributeValue::Address(Address::Symbol {
                symbol: self.symbol,
                addend: 0,
            }),
        );
        entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(end as u64));

        self.debug_context
            .emit_location(self.entry_id, self.mir.span);

        end
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Miscellaneous utilities for low level networking

extern crate libc;

use packet::PrimitiveValues;
use packet::ip::IpNextHeaderProtocol;
use datalink::NetworkInterface;
use pnet_macros_support::types::u16be;

use std::fmt;
use std::str::FromStr;
use std::u8;
use std::net::{IpAddr, Ipv4Addr};
use std::mem;
use std::slice;

use internal;
use sockets;

/// A MAC address
#[derive(PartialEq, Eq, Clone, Copy, Hash)]
pub struct MacAddr(pub u8, pub u8, pub u8, pub u8, pub u8, pub u8);

impl MacAddr {
    /// Construct a new MacAddr
    pub fn new(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8) -> MacAddr {
        MacAddr(a, b, c, d, e, f)
    }
}

impl PrimitiveValues for MacAddr {
    type T = (u8, u8, u8, u8, u8, u8);
    fn to_primitive_values(&self) -> (u8, u8, u8, u8, u8, u8) {
        (self.0, self.1, self.2, self.3, self.4, self.5)
    }
}

impl fmt::Display for MacAddr {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt,
               "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
               self.0,
               self.1,
               self.2,
               self.3,
               self.4,
               self.5)
    }
}

impl fmt::Debug for MacAddr {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, fmt)
    }
}

// FIXME Is this the right way to do this? Which occurs is an implementation
//       issue rather than actually defined - is it useful to provide these
//       errors, or would it be better to just give ()?
/// Represents an error which occurred whilst parsing a MAC address
#[derive(Copy, Debug, PartialEq, Eq, Clone)]
pub enum ParseMacAddrErr {
    /// The MAC address has too many components, eg. 00:11:22:33:44:55:66
    TooManyComponents,
    /// The MAC address has too few components, eg. 00:11
    TooFewComponents,
    /// One of the components contains an invalid value, eg. 00:GG:22:33:44:55
    InvalidComponent,
}

impl FromStr for MacAddr {
    type Err = ParseMacAddrErr;
    fn from_str(s: &str) -> Result<MacAddr, ParseMacAddrErr> {
        let mut parts = [0u8; 6];
        let splits = s.split(':');
        let mut i = 0;
        for split in splits {
            if i == 6 {
                return Err(ParseMacAddrErr::TooManyComponents);
            }
            match u8::from_str_radix(split, 16) {
                Ok(b) if split.len() != 0 => parts[i] = b,
                _ => return Err(ParseMacAddrErr::InvalidComponent),
            }
            i += 1;
        }

        if i == 6 {
            Ok(MacAddr(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5]))
        } else {
            Err(ParseMacAddrErr::TooFewComponents)
        }
    }
}

#[test]
fn mac_addr_from_str() {
    assert_eq!("00:00:00:00:00:00".parse(), Ok(MacAddr(0, 0, 0, 0, 0, 0)));
    assert_eq!("ff:ff:ff:ff:ff:ff".parse(),
               Ok(MacAddr(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF)));
    assert_eq!("12:34:56:78:90:ab".parse(),
               Ok(MacAddr(0x12, 0x34, 0x56, 0x78, 0x90, 0xAB)));
    assert_eq!("::::::".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("0::::::".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("::::0::".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("12:34:56:78".parse::<MacAddr>(),
               Err(ParseMacAddrErr::TooFewComponents));
    assert_eq!("12:34:56:78:".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("12:34:56:78:90".parse::<MacAddr>(),
               Err(ParseMacAddrErr::TooFewComponents));
    assert_eq!("12:34:56:78:90:".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("12:34:56:78:90:00:00".parse::<MacAddr>(),
               Err(ParseMacAddrErr::TooManyComponents));
    assert_eq!("xx:xx:xx:xx:xx:xx".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
}

#[cfg(target_os = "linux")]
fn sockaddr_to_network_addr(sa: *const sockets::SockAddr) -> (Option<MacAddr>, Option<IpAddr>) {
    use std::net::SocketAddr;

    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == libc::AF_PACKET {
            let sll: *const libc::sockaddr_ll = mem::transmute(sa);
            let mac = MacAddr((*sll).sll_addr[0],
                              (*sll).sll_addr[1],
                              (*sll).sll_addr[2],
                              (*sll).sll_addr[3],
                              (*sll).sll_addr[4],
                              (*sll).sll_addr[5]);

            (Some(mac), None)
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                                  mem::size_of::<sockets::SockAddrStorage>());

            match addr {
                Ok(SocketAddr::V4(sa)) => (None, Some(IpAddr::V4(*sa.ip()))),
                Ok(SocketAddr::V6(sa)) => (None, Some(IpAddr::V6(*sa.ip()))),
                Err(_) => (None, None),
            }
        }
    }
}

#[cfg(any(target_os = "freebsd", target_os = "macos"))]
fn sockaddr_to_network_addr(sa: *const sockets::SockAddr) -> (Option<MacAddr>, Option<IpAddr>) {
    use bindings::bpf;
    use std::net::SocketAddr;

    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == bpf::AF_LINK {
            let sdl: *const bpf::sockaddr_dl = mem::transmute(sa);
            let nlen = (*sdl).sdl_nlen as usize;
            let mac = MacAddr((*sdl).sdl_data[nlen] as u8,
                              (*sdl).sdl_data[nlen + 1] as u8,
                              (*sdl).sdl_data[nlen + 2] as u8,
                              (*sdl).sdl_data[nlen + 3] as u8,
                              (*sdl).sdl_data[nlen + 4] as u8,
                              (*sdl).sdl_data[nlen + 5] as u8);

            (Some(mac), None)
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                                  mem::size_of::<sockets::SockAddrStorage>());

            match addr {
                Ok(SocketAddr::V4(sa)) => (None, Some(IpAddr::V4(*sa.ip()))),
                Ok(SocketAddr::V6(sa)) => (None, Some(IpAddr::V6(*sa.ip()))),
                Err(_) => (None, None),
            }
        }
    }
}

/// Get a list of available network interfaces for the current machine.
/// Deprecated. Instead use the implementation available for your backend.
/// The default one is at `pnet::datalink::interfaces`.
#[deprecated(note="Moved to datalink::interfaces()")]
#[inline]
pub fn get_network_interfaces() -> Vec<NetworkInterface> {
    ::datalink::interfaces()
}

/// Convert value to byte array
pub trait Octets {
    /// Output type - bytes array
    type Output;

    /// Return value as bytes (big-endian order)
    fn octets(&self) -> Self::Output;
}

impl Octets for u64 {
    type Output = [u8; 8];

    fn octets(&self) -> Self::Output {
        [(*self >> 56) as u8, (*self >> 48) as u8, (*self >> 40) as u8, (*self >> 32) as u8,
         (*self >> 24) as u8, (*self >> 16) as u8, (*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u32 {
    type Output = [u8; 4];

    fn octets(&self) -> Self::Output {
        [(*self >> 24) as u8, (*self >> 16) as u8 , (*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u16 {
    type Output = [u8; 2];

    fn octets(&self) -> Self::Output {
        [(*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u8 {
    type Output = [u8; 1];

    fn octets(&self) -> Self::Output {
        [*self]
    }
}

/// Calculates a checksum. Used by ipv4 and icmp. The two bytes starting at `skipword * 2` will be
/// ignored. Supposed to be the checksum field, which is regarded as zero during calculation.
/// To not skip any word, set `skipword` to `data.len()`.
pub fn checksum(data: &[u8], skipword: Option<usize>) -> u16be {
    let mut sum = sum_be_words(data, skipword);
    while sum >> 16 != 0 {
        sum = (sum >> 16) + (sum & 0xFFFF);
    }
    !sum as u16
}

/// Calculate the checksum for a packet built on IPv4
pub fn ipv4_checksum(data: &[u8],
                     ipv4_source: Ipv4Addr,
                     ipv4_destination: Ipv4Addr,
                     next_level_protocol: IpNextHeaderProtocol)
    -> u16be {
    let mut sum = 0u32;

    // Checksum pseudo-header
    // IPv4 source
    let octets = ipv4_source.octets();
    sum += (octets[0] as u32) << 8 | octets[1] as u32;
    sum += (octets[2] as u32) << 8 | octets[3] as u32;

    // IPv4 destination
    let octets = ipv4_destination.octets();
    sum += (octets[0] as u32) << 8 | octets[1] as u32;
    sum += (octets[2] as u32) << 8 | octets[3] as u32;

    // IPv4 Next level protocol
    let IpNextHeaderProtocol(next_level_protocol) = next_level_protocol;
    sum += next_level_protocol as u32;

    // Length
    sum += data.len() as u32;

    // Checksum packet header and data
    sum += sum_be_words(data, None);

    while sum >> 16 != 0 {
        sum = (sum >> 16) + (sum & 0xFFFF);
    }

    !sum as u16
}

/// Sum all words (16 bit chunks) in the given data. The word at word offset `skipword` will be
/// ignored if passed. Each word is treated as big endian.
fn sum_be_words(data: &[u8], skipword: Option<usize>) -> u32 {
    let len = data.len();
    let wdata: &[u16] = unsafe { slice::from_raw_parts(data.as_ptr() as *const u16, len / 2) };

    let mut sum = 0u32;
    let mut i = 0;
    if let Some(skipword) = skipword {
        assert!(skipword <= wdata.len());
        while i < skipword {
            sum += u16::from_be(unsafe { *wdata.get_unchecked(i) }) as u32;
            i += 1;
        }
        i += 1;
    }
    while i < wdata.len() {
        sum += u16::from_be(unsafe { *wdata.get_unchecked(i) }) as u32;
        i += 1;
    }
    // If the length is odd, make sure to checksum the final byte
    if len & 1 != 0 {
        sum += (data[len - 1] as u32) << 8;
    }

    sum
}

#[cfg(all(test, feature = "benchmark"))]
mod checksum_benchmarks {
    use super::checksum;
    use test::{Bencher, black_box};

    #[bench]
    fn bench_checksum_small(b: &mut Bencher) {
        let data = vec![99u8; 20];
        b.iter(|| checksum(black_box(&data), Some(5)));
    }

    #[bench]
    fn bench_checksum_large(b: &mut Bencher) {
        let data = vec![123u8; 1024];
        b.iter(|| checksum(black_box(&data), Some(5)));
    }
}
<commit_msg>Extract Ipv4Addr checksum to function<commit_after>// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Miscellaneous utilities for low level networking

extern crate libc;

use packet::PrimitiveValues;
use packet::ip::IpNextHeaderProtocol;
use datalink::NetworkInterface;
use pnet_macros_support::types::u16be;

use std::fmt;
use std::str::FromStr;
use std::u8;
use std::net::{IpAddr, Ipv4Addr};
use std::mem;
use std::slice;

use internal;
use sockets;

/// A MAC address
#[derive(PartialEq, Eq, Clone, Copy, Hash)]
pub struct MacAddr(pub u8, pub u8, pub u8, pub u8, pub u8, pub u8);

impl MacAddr {
    /// Construct a new MacAddr
    pub fn new(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8) -> MacAddr {
        MacAddr(a, b, c, d, e, f)
    }
}

impl PrimitiveValues for MacAddr {
    type T = (u8, u8, u8, u8, u8, u8);
    fn to_primitive_values(&self) -> (u8, u8, u8, u8, u8, u8) {
        (self.0, self.1, self.2, self.3, self.4, self.5)
    }
}

impl fmt::Display for MacAddr {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt,
               "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
               self.0,
               self.1,
               self.2,
               self.3,
               self.4,
               self.5)
    }
}

impl fmt::Debug for MacAddr {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, fmt)
    }
}

// FIXME Is this the right way to do this? Which occurs is an implementation
//       issue rather than actually defined - is it useful to provide these
//       errors, or would it be better to just give ()?
/// Represents an error which occurred whilst parsing a MAC address
#[derive(Copy, Debug, PartialEq, Eq, Clone)]
pub enum ParseMacAddrErr {
    /// The MAC address has too many components, eg. 00:11:22:33:44:55:66
    TooManyComponents,
    /// The MAC address has too few components, eg. 00:11
    TooFewComponents,
    /// One of the components contains an invalid value, eg. 00:GG:22:33:44:55
    InvalidComponent,
}

impl FromStr for MacAddr {
    type Err = ParseMacAddrErr;
    fn from_str(s: &str) -> Result<MacAddr, ParseMacAddrErr> {
        let mut parts = [0u8; 6];
        let splits = s.split(':');
        let mut i = 0;
        for split in splits {
            if i == 6 {
                return Err(ParseMacAddrErr::TooManyComponents);
            }
            match u8::from_str_radix(split, 16) {
                Ok(b) if split.len() != 0 => parts[i] = b,
                _ => return Err(ParseMacAddrErr::InvalidComponent),
            }
            i += 1;
        }

        if i == 6 {
            Ok(MacAddr(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5]))
        } else {
            Err(ParseMacAddrErr::TooFewComponents)
        }
    }
}

#[test]
fn mac_addr_from_str() {
    assert_eq!("00:00:00:00:00:00".parse(), Ok(MacAddr(0, 0, 0, 0, 0, 0)));
    assert_eq!("ff:ff:ff:ff:ff:ff".parse(),
               Ok(MacAddr(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF)));
    assert_eq!("12:34:56:78:90:ab".parse(),
               Ok(MacAddr(0x12, 0x34, 0x56, 0x78, 0x90, 0xAB)));
    assert_eq!("::::::".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("0::::::".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("::::0::".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("12:34:56:78".parse::<MacAddr>(),
               Err(ParseMacAddrErr::TooFewComponents));
    assert_eq!("12:34:56:78:".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("12:34:56:78:90".parse::<MacAddr>(),
               Err(ParseMacAddrErr::TooFewComponents));
    assert_eq!("12:34:56:78:90:".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("12:34:56:78:90:00:00".parse::<MacAddr>(),
               Err(ParseMacAddrErr::TooManyComponents));
    assert_eq!("xx:xx:xx:xx:xx:xx".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
}

#[cfg(target_os = "linux")]
fn sockaddr_to_network_addr(sa: *const sockets::SockAddr) -> (Option<MacAddr>, Option<IpAddr>) {
    use std::net::SocketAddr;

    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == libc::AF_PACKET {
            let sll: *const libc::sockaddr_ll = mem::transmute(sa);
            let mac = MacAddr((*sll).sll_addr[0],
                              (*sll).sll_addr[1],
                              (*sll).sll_addr[2],
                              (*sll).sll_addr[3],
                              (*sll).sll_addr[4],
                              (*sll).sll_addr[5]);

            (Some(mac), None)
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                                  mem::size_of::<sockets::SockAddrStorage>());

            match addr {
                Ok(SocketAddr::V4(sa)) => (None, Some(IpAddr::V4(*sa.ip()))),
                Ok(SocketAddr::V6(sa)) => (None, Some(IpAddr::V6(*sa.ip()))),
                Err(_) => (None, None),
            }
        }
    }
}

#[cfg(any(target_os = "freebsd", target_os = "macos"))]
fn sockaddr_to_network_addr(sa: *const sockets::SockAddr) -> (Option<MacAddr>, Option<IpAddr>) {
    use bindings::bpf;
    use std::net::SocketAddr;

    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == bpf::AF_LINK {
            let sdl: *const bpf::sockaddr_dl = mem::transmute(sa);
            let nlen = (*sdl).sdl_nlen as usize;
            let mac = MacAddr((*sdl).sdl_data[nlen] as u8,
                              (*sdl).sdl_data[nlen + 1] as u8,
                              (*sdl).sdl_data[nlen + 2] as u8,
                              (*sdl).sdl_data[nlen + 3] as u8,
                              (*sdl).sdl_data[nlen + 4] as u8,
                              (*sdl).sdl_data[nlen + 5] as u8);

            (Some(mac), None)
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                                  mem::size_of::<sockets::SockAddrStorage>());

            match addr {
                Ok(SocketAddr::V4(sa)) => (None, Some(IpAddr::V4(*sa.ip()))),
                Ok(SocketAddr::V6(sa)) => (None, Some(IpAddr::V6(*sa.ip()))),
                Err(_) => (None, None),
            }
        }
    }
}

/// Get a list of available network interfaces for the current machine.
/// Deprecated. Instead use the implementation available for your backend.
/// The default one is at `pnet::datalink::interfaces`.
#[deprecated(note="Moved to datalink::interfaces()")]
#[inline]
pub fn get_network_interfaces() -> Vec<NetworkInterface> {
    ::datalink::interfaces()
}

/// Convert value to byte array
pub trait Octets {
    /// Output type - bytes array
    type Output;

    /// Return value as bytes (big-endian order)
    fn octets(&self) -> Self::Output;
}

impl Octets for u64 {
    type Output = [u8; 8];

    fn octets(&self) -> Self::Output {
        [(*self >> 56) as u8, (*self >> 48) as u8, (*self >> 40) as u8, (*self >> 32) as u8,
         (*self >> 24) as u8, (*self >> 16) as u8, (*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u32 {
    type Output = [u8; 4];

    fn octets(&self) -> Self::Output {
        [(*self >> 24) as u8, (*self >> 16) as u8 , (*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u16 {
    type Output = [u8; 2];

    fn octets(&self) -> Self::Output {
        [(*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u8 {
    type Output = [u8; 1];

    fn octets(&self) -> Self::Output {
        [*self]
    }
}

/// Calculates a checksum. Used by ipv4 and icmp. The two bytes starting at `skipword * 2` will be
/// ignored. Supposed to be the checksum field, which is regarded as zero during calculation.
/// To not skip any word, set `skipword` to `data.len()`.
pub fn checksum(data: &[u8], skipword: Option<usize>) -> u16be {
    let mut sum = sum_be_words(data, skipword);
    while sum >> 16 != 0 {
        sum = (sum >> 16) + (sum & 0xFFFF);
    }
    !sum as u16
}

/// Calculate the checksum for a packet built on IPv4
pub fn ipv4_checksum(data: &[u8],
                     ipv4_source: Ipv4Addr,
                     ipv4_destination: Ipv4Addr,
                     next_level_protocol: IpNextHeaderProtocol)
    -> u16be {
    let mut sum = 0u32;

    // Checksum pseudo-header
    sum += ipv4_word_sum(ipv4_source);
    sum += ipv4_word_sum(ipv4_destination);

    let IpNextHeaderProtocol(next_level_protocol) = next_level_protocol;
    sum += next_level_protocol as u32;

    sum += data.len() as u32;

    // Checksum packet header and data
    sum += sum_be_words(data, None);

    while sum >> 16 != 0 {
        sum = (sum >> 16) + (sum & 0xFFFF);
    }

    !sum as u16
}

fn ipv4_word_sum(ip: Ipv4Addr) -> u32 {
    let octets = ip.octets();
    ((octets[0] as u32) << 8 | octets[1] as u32) + ((octets[2] as u32) << 8 | octets[3] as u32)
}

/// Sum all words (16 bit chunks) in the given data. The word at word offset `skipword` will be
/// ignored if passed. Each word is treated as big endian.
fn sum_be_words(data: &[u8], skipword: Option<usize>) -> u32 {
    let len = data.len();
    let wdata: &[u16] = unsafe { slice::from_raw_parts(data.as_ptr() as *const u16, len / 2) };

    let mut sum = 0u32;
    let mut i = 0;
    if let Some(skipword) = skipword {
        assert!(skipword <= wdata.len());
        while i < skipword {
            sum += u16::from_be(unsafe { *wdata.get_unchecked(i) }) as u32;
            i += 1;
        }
        i += 1;
    }
    while i < wdata.len() {
        sum += u16::from_be(unsafe { *wdata.get_unchecked(i) }) as u32;
        i += 1;
    }
    // If the length is odd, make sure to checksum the final byte
    if len & 1 != 0 {
        sum += (data[len - 1] as u32) << 8;
    }

    sum
}

#[cfg(all(test, feature = "benchmark"))]
mod checksum_benchmarks {
    use super::checksum;
    use test::{Bencher, black_box};

    #[bench]
    fn bench_checksum_small(b: &mut Bencher) {
        let data = vec![99u8; 20];
        b.iter(|| checksum(black_box(&data), Some(5)));
    }

    #[bench]
    fn bench_checksum_large(b: &mut Bencher) {
        let data = vec![123u8; 1024];
        b.iter(|| checksum(black_box(&data), Some(5)));
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The implementations of the `Uniform` distribution for other built-in types.

use core::char;

use {Rng};
use distributions::{Distribution, Uniform};

impl Distribution<char> for Uniform {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
        // a char is 21 bits
        const CHAR_MASK: u32 = 0x001f_ffff;
        loop {
            // Rejection sampling. About 0.2% of numbers with at most
            // 21-bits are invalid codepoints (surrogates), so this
            // will succeed first go almost every time.
            match char::from_u32(rng.next_u32() & CHAR_MASK) {
                Some(c) => return c,
                None => {}
            }
        }
    }
}

impl Distribution<bool> for Uniform {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> bool {
        rng.gen::<u8>() & 1 == 1
    }
}

macro_rules! tuple_impl {
    // use variables to indicate the arity of the tuple
    ($($tyvar:ident),* ) => {
        // the trailing commas are for the 1 tuple
        impl< $( $tyvar ),* >
            Distribution<( $( $tyvar ),* , )>
            for Uniform
            where $( Uniform: Distribution<$tyvar> ),*
        {
            #[inline]
            fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> ( $( $tyvar ),* , ) {
                (
                    // use the $tyvar's to get the appropriate number of
                    // repeats (they're not actually needed)
                    $(
                        _rng.gen::<$tyvar>()
                    ),*
                    ,
                )
            }
        }
    }
}

impl Distribution<()> for Uniform {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, _: &mut R) -> () { () }
}
tuple_impl!{A}
tuple_impl!{A, B}
tuple_impl!{A, B, C}
tuple_impl!{A, B, C, D}
tuple_impl!{A, B, C, D, E}
tuple_impl!{A, B, C, D, E, F}
tuple_impl!{A, B, C, D, E, F, G}
tuple_impl!{A, B, C, D, E, F, G, H}
tuple_impl!{A, B, C, D, E, F, G, H, I}
tuple_impl!{A, B, C, D, E, F, G, H, I, J}
tuple_impl!{A, B, C, D, E, F, G, H, I, J, K}
tuple_impl!{A, B, C, D, E, F, G, H, I, J, K, L}

macro_rules! array_impl {
    // recursive, given at least one type parameter:
    {$n:expr, $t:ident, $($ts:ident,)*} => {
        array_impl!{($n - 1), $($ts,)*}

        impl<T> Distribution<[T; $n]> for Uniform where Uniform: Distribution<T> {
            #[inline]
            fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; $n] {
                [_rng.gen::<$t>(), $(_rng.gen::<$ts>()),*]
            }
        }
    };
    // empty case:
    {$n:expr,} => {
        impl<T> Distribution<[T; $n]> for Uniform {
            fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; $n] { [] }
        }
    };
}

array_impl!{32, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,}

impl<T> Distribution<Option<T>> for Uniform where Uniform: Distribution<T> {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Option<T> {
        // UFCS is needed here: https://github.com/rust-lang/rust/issues/24066
        if rng.gen::<bool>() {
            Some(rng.gen())
        } else {
            None
        }
    }
}

#[cfg(test)]
mod tests {
    use {Rng, RngCore, Uniform};

    #[test]
    fn test_misc() {
        let mut rng: &mut RngCore = &mut ::test::rng(820);

        rng.sample::<char, _>(Uniform);
        rng.sample::<bool, _>(Uniform);
    }
}
<commit_msg>Use `Range` in `Distribution<char>`<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The implementations of the `Uniform` distribution for other built-in types.

use core::char;

use {Rng};
use distributions::{Distribution, Uniform, Range};

impl Distribution<char> for Uniform {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
        let range = Range::new(0u32, 0x11_0000);
        loop {
            match char::from_u32(range.sample(rng)) {
                Some(c) => return c,
                // About 0.2% of numbers in the range 0..0x110000 are invalid
                // codepoints (surrogates).
                None => {}
            }
        }
    }
}

impl Distribution<bool> for Uniform {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> bool {
        rng.gen::<u8>() & 1 == 1
    }
}

macro_rules! tuple_impl {
    // use variables to indicate the arity of the tuple
    ($($tyvar:ident),* ) => {
        // the trailing commas are for the 1 tuple
        impl< $( $tyvar ),* >
            Distribution<( $( $tyvar ),* , )>
            for Uniform
            where $( Uniform: Distribution<$tyvar> ),*
        {
            #[inline]
            fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> ( $( $tyvar ),* , ) {
                (
                    // use the $tyvar's to get the appropriate number of
                    // repeats (they're not actually needed)
                    $(
                        _rng.gen::<$tyvar>()
                    ),*
                    ,
                )
            }
        }
    }
}

impl Distribution<()> for Uniform {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, _: &mut R) -> () { () }
}
tuple_impl!{A}
tuple_impl!{A, B}
tuple_impl!{A, B, C}
tuple_impl!{A, B, C, D}
tuple_impl!{A, B, C, D, E}
tuple_impl!{A, B, C, D, E, F}
tuple_impl!{A, B, C, D, E, F, G}
tuple_impl!{A, B, C, D, E, F, G, H}
tuple_impl!{A, B, C, D, E, F, G, H, I}
tuple_impl!{A, B, C, D, E, F, G, H, I, J}
tuple_impl!{A, B, C, D, E, F, G, H, I, J, K}
tuple_impl!{A, B, C, D, E, F, G, H, I, J, K, L}

macro_rules! array_impl {
    // recursive, given at least one type parameter:
    {$n:expr, $t:ident, $($ts:ident,)*} => {
        array_impl!{($n - 1), $($ts,)*}

        impl<T> Distribution<[T; $n]> for Uniform where Uniform: Distribution<T> {
            #[inline]
            fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; $n] {
                [_rng.gen::<$t>(), $(_rng.gen::<$ts>()),*]
            }
        }
    };
    // empty case:
    {$n:expr,} => {
        impl<T> Distribution<[T; $n]> for Uniform {
            fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; $n] { [] }
        }
    };
}

array_impl!{32, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,}

impl<T> Distribution<Option<T>> for Uniform where Uniform: Distribution<T> {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Option<T> {
        // UFCS is needed here: https://github.com/rust-lang/rust/issues/24066
        if rng.gen::<bool>() {
            Some(rng.gen())
        } else {
            None
        }
    }
}

#[cfg(test)]
mod tests {
    use {Rng, RngCore, Uniform};

    #[test]
    fn test_misc() {
        let mut rng: &mut RngCore = &mut ::test::rng(820);

        rng.sample::<char, _>(Uniform);
        rng.sample::<bool, _>(Uniform);
    }
}
<|endoftext|>