<commit_before>use combine::{Parser, Stream, ParseError, ParseResult};
use combine::{between, choice, many, many1, optional, parser, satisfy, satisfy_map, sep_by, try};
use combine::char::{alpha_num, digit, char, letter, spaces, string};

use token::{Literal, Token};

pub fn lex<'a>(line: &'a str) -> Result<(Vec<Token>, &'a str), ParseError<&'a str>> {
    spaces()
        .with(parser(token_stream))
        .parse(line)
}

fn literal<I>(input: I) -> ParseResult<Literal, I>
    where I: Stream<Item = char>
{
    let digits = many1::<String, _>(digit());
    let integer = optional(char('-'))
        .and(digits.clone())
        .map(|(sign, s)| {
            let magnitude = s.parse::<i64>().unwrap();
            if sign.is_some() {
                -magnitude
            } else {
                magnitude
            }
        })
        .map(Literal::from);

    let float = optional(char('-'))
        .and((digits.clone(), char('.'), digits.clone())
            .map(|(prefix, _, suffix)| format!("{}.{}", prefix, suffix)))
        .map(|(sign, s)| {
            let magnitude = s.parse::<f64>().unwrap();
            if sign.is_some() {
                -magnitude
            } else {
                magnitude
            }
        })
        .map(Literal::from);

    let num = try(float).or(try(integer));

    let boolean = char('#')
        .with(satisfy_map(|c| {
            match c {
                't' => Some(true),
                'f' => Some(false),
                _ => None,
            }
        }))
        .map(Literal::from);

    let escaped = char('\\')
        .with(satisfy_map(|c| {
            match c {
                '\"' => Some('\"'),
                '\\' => Some('\\'),
                'n' => Some('\n'),
                'r' => Some('\r'),
                't' => Some('\t'),
                _ => None,
            }
        }));

    let non_quote = try(escaped).or(satisfy(|c| c != '"'));

    let string = between(char('"'), char('"'), many::<String, _>(non_quote)).map(Literal::from);

    boolean.or(string)
        .or(num)
        .parse_stream(input)
}

fn symbol<I>(input: I) -> ParseResult<Token, I>
    where I: Stream<Item = char>
{
    let first = letter().or(char('_'));
    let rest = many::<String, _>(alpha_num().or(char('_')));
    first.and(rest)
        .map(|(f, mut r)| {
            r.insert(0, f);
            r
        })
        .map(Token::Symbol)
        .parse_stream(input)
}

fn punctuation<I>(input: I) -> ParseResult<Token, I>
    where I: Stream<Item = char>
{
    let single_char_tokens = satisfy_map(|c| {
        match c {
            '(' => Some(Token::LParen),
            ')' => Some(Token::RParen),
            '[' => Some(Token::LBracket),
            ']' => Some(Token::RBracket),
            '+' => Some(Token::Plus),
            '-' => Some(Token::Minus),
            '*' => Some(Token::Star),
            '/' => Some(Token::Slash),
            '=' => Some(Token::Equal),
            '<' => Some(Token::Less),
            '>' => Some(Token::Greater),
            _ => None,
        }
    });

    let two_char_tokens = choice([string("<="), string(">=")]).map(|s| match s {
        "<=" => Token::LessEq,
        ">=" => Token::GreaterEq,
        _ => unreachable!(),
    });

    // Maximal munch: attempt parsing two-char tokens before one-char tokens
    two_char_tokens.or(single_char_tokens).parse_stream(input)
}

fn token<I>(input: I) -> ParseResult<Token, I>
    where I: Stream<Item = char>
{
    parser(symbol)
        .or(parser(literal).map(Token::Literal))
        .or(parser(symbol))
        .or(parser(punctuation))
        .parse_stream(input)
}

fn token_stream<I>(input: I) -> ParseResult<Vec<Token>, I>
    where I: Stream<Item = char>
{
    sep_by(parser(token), spaces()).parse_stream(input)
}

#[cfg(test)]
mod test {
    use float_cmp::ApproxEqUlps;
    use quickcheck::TestResult;
    use super::*;

    #[test]
    fn parse_bool_literal() {
        assert_eq!(Ok((Literal::Bool(true), "")), parser(literal).parse("#t"));
        assert_eq!(Ok((Literal::Bool(false), "")), parser(literal).parse("#f"));
    }

    #[test]
    fn parse_zero_literal() {
        // Integer case
        assert_eq!(Ok((Literal::Int(0i64), "")), parser(literal).parse("0"));

        // Float case
        match parser(literal).parse("0.0") {
            Ok((Literal::Flt(flt), _)) => assert!(flt.approx_eq_ulps(&0.0f64, 4)),
            Ok(x) => assert!(false, format!("0.0 parsed as {}", x.0)),
            Err(e) => assert!(false, format!("0.0 parsed as {}", e)),
        };
    }

    #[test]
    fn parse_empty() {
        assert_eq!(Ok((Vec::new(), "")), parser(token_stream).parse(""));
    }

    quickcheck!{
        fn parse_int_literal(x: i64) -> bool {
            match parser(literal).parse(&*x.to_string()) {
                Ok((Literal::Int(y), _)) => x == y,
                _ => false,
            }
        }

        fn parse_float_literal(x: f64) -> bool {
            let mut string = x.to_string();
            if x.trunc() == x {
                string.push_str(".0");
            }

            if let Ok((Literal::Flt(y), _)) = parser(literal).parse(&*string) {
                x.approx_eq_ulps(&y, 4)
            } else {
                false
            }
        }

        fn parse_str_literal(x: String) -> TestResult {
            let string = format!("\"{}\"", x);
            if x.contains('\"') {
                return TestResult::discard()
            }
            match parser(literal).parse(&*string) {
                Ok((Literal::Str(result), _)) => TestResult::from_bool(result == x),
                _ => TestResult::failed(),
            }
        }

        fn parse_symbol(x: String) -> TestResult {
            if x.is_empty() {
                return TestResult::discard()
            }

            if !x.chars().next().unwrap().is_alphabetic() {
                return TestResult::discard()
            }

            // Test only valid symbols
            for c in x.chars() {
                if !(c.is_alphanumeric() || c == '_') {
                    return TestResult::discard()
                }
            }

            match parser(symbol).parse(&*x) {
                Ok((Token::Symbol(result), _)) => TestResult::from_bool(result == x),
                _ => TestResult::failed(),
            }
        }
    }
}
<commit_msg>Fix escape literal tests<commit_after>use combine::{Parser, Stream, ParseError, ParseResult};
use combine::{between, choice, many, many1, optional, parser, satisfy, satisfy_map, sep_by, try};
use combine::char::{alpha_num, digit, char, letter, spaces, string};

use token::{Literal, Token};

pub fn lex<'a>(line: &'a str) -> Result<(Vec<Token>, &'a str), ParseError<&'a str>> {
    spaces()
        .with(parser(token_stream))
        .parse(line)
}

fn literal<I>(input: I) -> ParseResult<Literal, I>
    where I: Stream<Item = char>
{
    let digits = many1::<String, _>(digit());
    let integer = optional(char('-'))
        .and(digits.clone())
        .map(|(sign, s)| {
            let magnitude = s.parse::<i64>().unwrap();
            if sign.is_some() {
                -magnitude
            } else {
                magnitude
            }
        })
        .map(Literal::from);

    let float = optional(char('-'))
        .and((digits.clone(), char('.'), digits.clone())
            .map(|(prefix, _, suffix)| format!("{}.{}", prefix, suffix)))
        .map(|(sign, s)| {
            let magnitude = s.parse::<f64>().unwrap();
            if sign.is_some() {
                -magnitude
            } else {
                magnitude
            }
        })
        .map(Literal::from);

    let num = try(float).or(try(integer));

    let boolean = char('#')
        .with(satisfy_map(|c| {
            match c {
                't' => Some(true),
                'f' => Some(false),
                _ => None,
            }
        }))
        .map(Literal::from);

    let escaped = char('\\')
        .with(satisfy_map(|c| {
            match c {
                '\"' => Some('\"'),
                '\\' => Some('\\'),
                'n' => Some('\n'),
                'r' => Some('\r'),
                't' => Some('\t'),
                _ => None,
            }
        }));

    let non_quote = try(escaped).or(satisfy(|c| c != '"'));

    let string = between(char('"'), char('"'), many::<String, _>(non_quote)).map(Literal::from);

    boolean.or(string)
        .or(num)
        .parse_stream(input)
}

fn symbol<I>(input: I) -> ParseResult<Token, I>
    where I: Stream<Item = char>
{
    let first = letter().or(char('_'));
    let rest = many::<String, _>(alpha_num().or(char('_')));
    first.and(rest)
        .map(|(f, mut r)| {
            r.insert(0, f);
            r
        })
        .map(Token::Symbol)
        .parse_stream(input)
}

fn punctuation<I>(input: I) -> ParseResult<Token, I>
    where I: Stream<Item = char>
{
    let single_char_tokens = satisfy_map(|c| {
        match c {
            '(' => Some(Token::LParen),
            ')' => Some(Token::RParen),
            '[' => Some(Token::LBracket),
            ']' => Some(Token::RBracket),
            '+' => Some(Token::Plus),
            '-' => Some(Token::Minus),
            '*' => Some(Token::Star),
            '/' => Some(Token::Slash),
            '=' => Some(Token::Equal),
            '<' => Some(Token::Less),
            '>' => Some(Token::Greater),
            _ => None,
        }
    });

    let two_char_tokens = choice([string("<="), string(">=")]).map(|s| match s {
        "<=" => Token::LessEq,
        ">=" => Token::GreaterEq,
        _ => unreachable!(),
    });

    // Maximal munch: attempt parsing two-char tokens before one-char tokens
    two_char_tokens.or(single_char_tokens).parse_stream(input)
}

fn token<I>(input: I) -> ParseResult<Token, I>
    where I: Stream<Item = char>
{
    parser(symbol)
        .or(parser(literal).map(Token::Literal))
        .or(parser(symbol))
        .or(parser(punctuation))
        .parse_stream(input)
}

fn token_stream<I>(input: I) -> ParseResult<Vec<Token>, I>
    where I: Stream<Item = char>
{
    sep_by(parser(token), spaces()).parse_stream(input)
}

#[cfg(test)]
mod test {
    use float_cmp::ApproxEqUlps;
    use quickcheck::TestResult;
    use super::*;

    #[test]
    fn parse_bool_literal() {
        assert_eq!(Ok((Literal::Bool(true), "")), parser(literal).parse("#t"));
        assert_eq!(Ok((Literal::Bool(false), "")), parser(literal).parse("#f"));
    }

    #[test]
    fn parse_zero_literal() {
        // Integer case
        assert_eq!(Ok((Literal::Int(0i64), "")), parser(literal).parse("0"));

        // Float case
        match parser(literal).parse("0.0") {
            Ok((Literal::Flt(flt), _)) => assert!(flt.approx_eq_ulps(&0.0f64, 4)),
            Ok(x) => assert!(false, format!("0.0 parsed as {}", x.0)),
            Err(e) => assert!(false, format!("0.0 parsed as {}", e)),
        };
    }

    #[test]
    fn parse_escape_chars() {
        assert_eq!(Ok((Literal::Str("\"".into()), "")), parser(literal).parse(r#""\"""#));
        assert_eq!(Ok((Literal::Str("\\".into()), "")), parser(literal).parse(r#""\\""#));
        assert_eq!(Ok((Literal::Str("\n".into()), "")), parser(literal).parse(r#""\n""#));
        assert_eq!(Ok((Literal::Str("\r".into()), "")), parser(literal).parse(r#""\r""#));
        assert_eq!(Ok((Literal::Str("\t".into()), "")), parser(literal).parse(r#""\t""#));
    }

    #[test]
    fn parse_empty() {
        assert_eq!(Ok((Vec::new(), "")), parser(token_stream).parse(""));
    }

    quickcheck!{
        fn parse_int_literal(x: i64) -> bool {
            match parser(literal).parse(&*x.to_string()) {
                Ok((Literal::Int(y), _)) => x == y,
                _ => false,
            }
        }

        fn parse_float_literal(x: f64) -> bool {
            let mut string = x.to_string();
            if x.trunc() == x {
                string.push_str(".0");
            }

            if let Ok((Literal::Flt(y), _)) = parser(literal).parse(&*string) {
                x.approx_eq_ulps(&y, 4)
            } else {
                false
            }
        }

        fn parse_str_literal(x: String) -> () {
            let has_escape_chars = x.contains('\\') || x.contains('\"');
            let string = if has_escape_chars {
                x.chars()
                    .map(char::escape_default)
                    .map(|x| x.to_string())
                    .inspect(|x| println!("{}", x))
                    .collect()
            } else {
                format!("\"{}\"", x)
            };
            match parser(literal).parse(&*string) {
                Ok((Literal::Str(result), _)) => assert_eq!(result, x),
                _ => (),
            }
        }

        fn parse_symbol(x: String) -> TestResult {
            if x.is_empty() {
                return TestResult::discard()
            }

            if !x.chars().next().unwrap().is_alphabetic() {
                return TestResult::discard()
            }

            // Test only valid symbols
            for c in x.chars() {
                if !(c.is_alphanumeric() || c == '_') {
                    return TestResult::discard()
                }
            }

            match parser(symbol).parse(&*x) {
                Ok((Token::Symbol(result), _)) => TestResult::from_bool(result == x),
                _ => TestResult::failed(),
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::str::FromStr;

pub struct VM {
	stack: Vec<Operator>,
}

impl VM {
	pub fn pop <'a> (&'a mut self) -> Operator {
		return self.stack.pop().expect("gg reinstall");
	}

	pub fn push <'a> (&'a mut self, op: Operator) {
		self.stack.push(op);
	}

	pub fn eval <'a> (&'a mut self, op: Operator) {

	}

	pub fn add <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => i+j,
				_ => panic!("can only add ints"),
			},
			_ => panic!("can only add ints"),
		};
		self.push(Operator::Value(z));
	}

	pub fn subtract <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => i-j,
				_ => panic!("can only subtract ints"),
			},
			_ => panic!("can only subtract ints"),
		};
		self.push(Operator::Value(z));
	}

	pub fn multiply <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => i*j,
				_ => panic!("can only multiply ints"),
			},
			_ => panic!("can only multiply ints"),
		};
		self.push(Operator::Value(z));
	}

	pub fn divide <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => i/j,
				_ => panic!("can only divide ints"),
			},
			_ => panic!("can only divide ints"),
		};
		self.push(Operator::Value(z));
	}

	pub fn modulus <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => i % j,
				_ => panic!("can only mod ints"),
			},
			_ => panic!("can only mod ints"),
		};
		self.push(Operator::Value(z));
	}

	pub fn and <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => i & j,
				_ => panic!("can only and ints"),
			},
			_ => panic!("can only and ints"),
		};
		self.push(Operator::Value(z));
	}

	pub fn or <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => i | j,
				_ => panic!("can only or ints"),
			},
			_ => panic!("can only or ints"),
		};
		self.push(Operator::Value(z));
	}

	pub fn xor <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => i ^ j,
				_ => panic!("can only xor ints"),
			},
			_ => panic!("can only xor ints"),
		};
		self.push(Operator::Value(z));
	}

	pub fn lshift <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => i << j,
				_ => panic!("can only lshift ints"),
			},
			_ => panic!("can only lshift ints"),
		};
		self.push(Operator::Value(z));
	}

	pub fn rshift <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => i >> j,
				_ => panic!("can only rshift ints"),
			},
			_ => panic!("can only rshift ints"),
		};
		self.push(Operator::Value(z));
	}

	pub fn abs <'a> (&'a mut self) {
		let x = self.pop();
		let z = match x{
			Operator::Value(i) => if i < 0{-i} else {i},
			_ => panic!("can only abs an int"),
		};
		self.push(Operator::Value(z));
	}

	pub fn max <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => if j > i {j} else{i},
				_ => panic!("can only max ints"),
			},
			_ => panic!("can only max ints"),
		};
		self.push(Operator::Value(z));
	}

	pub fn min <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => if j < i {j} else {i},
				_ => panic!("can only min ints"),
			},
			_ => panic!("can only min ints"),
		};
		self.push(Operator::Value(z));
	}

	pub fn invert <'a> (&'a mut self) {
		let x = self.pop();
		let z = match x{
			Operator::Value(i) => !i,
			_ => panic!("can only invert an int"),
		};
		self.push(Operator::Value(z));
	}

	pub fn negate <'a> (&'a mut self) {
		let x = self.pop();
		let z = match x{
			Operator::Value(i) => -i,
			_ => panic!("can only negate an int"),
		};
		self.push(Operator::Value(z));
	}
}

pub enum Operator {
	//stack
	Dup,
	Drop,
	Swap,
	Over,
	Rot,

	//debug
	Print,

	//math
	Add,
	Subtract,
	Multiply,
	Divide,
	Modulus,
	And,
	Or,
	Xor,
	Lshift,
	Rshift,
	Abs,
	Max,
	Min,
	Invert,
	Negate,

	//custom
	Define,

	//values and custom calls
	Value(i32),
	Other,
}

fn parse(s: &str) -> Operator {
	match s {
		//stack operations:
		"dup" => Operator::Dup,
		"drop" => Operator::Drop,
		"swap" => Operator::Swap,
		"over" => Operator::Over,
		"rot" => Operator::Rot,

		//debug operations:
		"." => Operator::Print,

		//math operations:
		"+" => Operator::Add,
		"-" => Operator::Subtract,
		"*" => Operator::Multiply,
		"/" => Operator::Divide,
		"mod" => Operator::Modulus,
		"and" => Operator::And,
		"or" => Operator::Or,
		"xor" => Operator::Xor,
		"lshift" => Operator::Lshift,
		"<<" => Operator::Lshift,
		"rshift" => Operator::Rshift,
		">>" => Operator::Rshift,
		"abs" => Operator::Abs,
		"max" => Operator::Max,
		"min" => Operator::Min,
		"invert" => Operator::Invert,
		"negate" => Operator::Negate,

		//custom definitions
		":" => Operator::Define,

		//value or custom operator
		x => {
			let y: Option<i32> = FromStr::from_str(x).ok();
			match y{
				Some(i) => Operator::Value(i),
				None => Operator::Other,
			}
		},
	}
}

fn main() {
	let mut x = io::stdin();
	let mut vm = VM {stack: vec![Operator::Print]};

	loop{
		let mut line: String = "".to_string();
		let _ = x.read_line(&mut line);

		for o in line.split(" "){
			println!("evaling: {}", o.trim());
			let b = parse(o.trim());
			vm.eval(b);
		}
	}
}
<commit_msg>stack and debug functions<commit_after>use std::io;
use std::str::FromStr;

pub struct VM {
	stack: Vec<Operator>,
}

impl VM {
	pub fn pop <'a> (&'a mut self) -> Operator {
		return self.stack.pop().expect("gg reinstall");
	}

	pub fn push <'a> (&'a mut self, op: Operator) {
		self.stack.push(op);
	}

	pub fn eval <'a> (&'a mut self, op: Operator) {

	}

	// Math Functions
	pub fn add <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => i+j,
				_ => panic!("can only add ints"),
			},
			_ => panic!("can only add ints"),
		};
		self.push(Operator::Value(z));
	}

	pub fn subtract <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => i-j,
				_ => panic!("can only subtract ints"),
			},
			_ => panic!("can only subtract ints"),
		};
		self.push(Operator::Value(z));
	}

	pub fn multiply <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => i*j,
				_ => panic!("can only multiply ints"),
			},
			_ => panic!("can only multiply ints"),
		};
		self.push(Operator::Value(z));
	}

	pub fn divide <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => i/j,
				_ => panic!("can only divide ints"),
			},
			_ => panic!("can only divide ints"),
		};
		self.push(Operator::Value(z));
	}

	pub fn modulus <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => i % j,
				_ => panic!("can only mod ints"),
			},
			_ => panic!("can only mod ints"),
		};
		self.push(Operator::Value(z));
	}

	pub fn and <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => i & j,
				_ => panic!("can only and ints"),
			},
			_ => panic!("can only and ints"),
		};
		self.push(Operator::Value(z));
	}

	pub fn or <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => i | j,
				_ => panic!("can only or ints"),
			},
			_ => panic!("can only or ints"),
		};
		self.push(Operator::Value(z));
	}

	pub fn xor <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => i ^ j,
				_ => panic!("can only xor ints"),
			},
			_ => panic!("can only xor ints"),
		};
		self.push(Operator::Value(z));
	}

	pub fn lshift <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => i << j,
				_ => panic!("can only lshift ints"),
			},
			_ => panic!("can only lshift ints"),
		};
		self.push(Operator::Value(z));
	}

	pub fn rshift <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => i >> j,
				_ => panic!("can only rshift ints"),
			},
			_ => panic!("can only rshift ints"),
		};
		self.push(Operator::Value(z));
	}

	pub fn abs <'a> (&'a mut self) {
		let x = self.pop();
		let z = match x{
			Operator::Value(i) => if i < 0{-i} else {i},
			_ => panic!("can only abs an int"),
		};
		self.push(Operator::Value(z));
	}

	pub fn max <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => if j > i {j} else{i},
				_ => panic!("can only max ints"),
			},
			_ => panic!("can only max ints"),
		};
		self.push(Operator::Value(z));
	}

	pub fn min <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => if j < i {j} else {i},
				_ => panic!("can only min ints"),
			},
			_ => panic!("can only min ints"),
		};
		self.push(Operator::Value(z));
	}

	pub fn invert <'a> (&'a mut self) {
		let x = self.pop();
		let z = match x{
			Operator::Value(i) => !i,
			_ => panic!("can only invert an int"),
		};
		self.push(Operator::Value(z));
	}

	pub fn negate <'a> (&'a mut self) {
		let x = self.pop();
		let z = match x{
			Operator::Value(i) => -i,
			_ => panic!("can only negate an int"),
		};
		self.push(Operator::Value(z));
	}

	//Stack Functions
	pub fn dup <'a> (&'a mut self) {
		let x = self.pop();
		let y = x.clone();
		self.push(x);
		self.push(y);
	}

	pub fn drop <'a> (&'a mut self) {
		self.pop();
	}

	pub fn swap <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		self.push(x);
		self.push(y);
	}

	pub fn over <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = x.clone();
		self.push(x);
		self.push(y);
		self.push(z);
	}

	pub fn rot <'a> (&'a mut self) {
		let x = self.pop();
		let y = self.pop();
		let z = self.pop();
		self.push(x);
		self.push(z);
		self.push(y);
	}

	//Debug Functions
	pub fn print <'a> (&'a mut self) {
		let x = self.pop();
		println!("{}",match x{
			Operator::Value(i) => i,
			_ => panic!("tried to print something other than a value"),
		});
	}

}

#[derive(Clone)]
pub enum Operator {
	//stack
	Dup,
	Drop,
	Swap,
	Over,
	Rot,

	//debug
	Print,

	//math
	Add,
	Subtract,
	Multiply,
	Divide,
	Modulus,
	And,
	Or,
	Xor,
	Lshift,
	Rshift,
	Abs,
	Max,
	Min,
	Invert,
	Negate,

	//custom
	Define,

	//values and custom calls
	Value(i32),
	Other,
}

fn parse(s: &str) -> Operator {
	match s {
		//stack operations:
		"dup" => Operator::Dup,
		"drop" => Operator::Drop,
		"swap" => Operator::Swap,
		"over" => Operator::Over,
		"rot" => Operator::Rot,

		//debug operations:
		"." => Operator::Print,

		//math operations:
		"+" => Operator::Add,
		"-" => Operator::Subtract,
		"*" => Operator::Multiply,
		"/" => Operator::Divide,
		"mod" => Operator::Modulus,
		"and" => Operator::And,
		"or" => Operator::Or,
		"xor" => Operator::Xor,
		"lshift" => Operator::Lshift,
		"<<" => Operator::Lshift,
		"rshift" => Operator::Rshift,
		">>" => Operator::Rshift,
		"abs" => Operator::Abs,
		"max" => Operator::Max,
		"min" => Operator::Min,
		"invert" => Operator::Invert,
		"negate" => Operator::Negate,

		//custom definitions
		":" => Operator::Define,

		//value or custom operator
		x => {
			let y: Option<i32> = FromStr::from_str(x).ok();
			match y{
				Some(i) => Operator::Value(i),
				None => Operator::Other,
			}
		},
	}
}

fn main() {
	let mut x = io::stdin();
	let mut vm = VM {stack: vec![Operator::Print]};

	loop{
		let mut line: String = "".to_string();
		let _ = x.read_line(&mut line);

		for o in line.split(" "){
			println!("evaling: {}", o.trim());
			let b = parse(o.trim());
			vm.eval(b);
		}

		if vm.stack.len() == 0{break;}
	}
}
<|endoftext|>


<commit_before>// Copyright 2021 Google LLC
//
// 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
//
//     https://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.

use crate::fetcher::{Fetcher, NULL_FETCHER};
use crate::headers::Headers;
use crate::http::{HttpRequest, HttpResponse, Method};
use crate::http_cache::{HttpCache, NullCache};
use crate::utils::{get_sha, signed_headers_and_payload};
use anyhow::{anyhow, Error, Result};
use async_trait::async_trait;
use once_cell::sync::Lazy;
use std::collections::BTreeSet;
use url::Url;

#[async_trait(?Send)]
pub trait HeaderIntegrityFetcher {
    async fn fetch(&mut self, url: &str) -> Result<String>;
}

pub fn new_fetcher<'a, F: Fetcher, C: HttpCache>(
    subresource_fetcher: F,
    header_integrity_cache: &'a mut C,
    strip_response_headers: &'a BTreeSet<String>,
) -> HeaderIntegrityFetcherImpl<'a, F, C> {
    HeaderIntegrityFetcherImpl {
        subresource_fetcher,
        header_integrity_cache,
        strip_response_headers,
    }
}

pub struct HeaderIntegrityFetcherImpl<'a, F: Fetcher, C: HttpCache> {
    subresource_fetcher: F,
    header_integrity_cache: &'a mut C,
    strip_response_headers: &'a BTreeSet<String>,
}

// A synthesized error response that can be cached, to prevent overloading the
// origin for non-SXG subresources that it preloads.
static ERROR_RESPONSE: Lazy<HttpResponse> = Lazy::new(|| HttpResponse {
    body: vec![],
    headers: vec![("cache-control".into(), "max-age=3600".into())],
    status: 406,
});

#[async_trait(?Send)]
impl<'a, F: Fetcher, C: HttpCache> HeaderIntegrityFetcher for HeaderIntegrityFetcherImpl<'a, F, C> {
    async fn fetch(&mut self, url: &str) -> Result<String> {
        let integrity_response = match self.header_integrity_cache.get(url).await {
            // Use cached header-integrity.
            Ok(response @ HttpResponse { status: 200, .. }) => response,
            // Respect the cached error status; don't fetch from origin.
            Ok(response @ HttpResponse { status: 406, .. }) => {
                console_log(&format!(
                    "Cached header-integrity error for {}; not refetching for up to an hour: {}",
                    url,
                    String::from_utf8_lossy(&response.body),
                ));
                response
            }
            // Cache miss or error fetching from cache; fall back to origin.
            _ => {
                console_log(&format!(
                    "{} not found in header-integrity cache. Fetching.",
                    url
                ));
                let response = match self.fetch_subresource(url).await {
                    Ok(response) => {
                        match self.compute_integrity(url, &response).await {
                            Ok(integrity) => {
                                // Keep original cache-control headers, so the integrity is
                                // up-to-date with the subresource.
                                HttpResponse {
                                    body: integrity,
                                    ..response
                                }
                            }
                            Err(err) => Self::error_response(&format!(
                                "Error computing header-integrity for {}: {:#}",
                                url, err
                            )),
                        }
                    }
                    Err(err) => Self::error_response(&format!(
                        "Error fetching subresource at {}: {:#}",
                        url, err
                    )),
                };
                let _ = self.header_integrity_cache.put(url, &response).await;
                response
            }
        };
        Self::extract_integrity(integrity_response)
    }
}

impl<'a, F: Fetcher, C: HttpCache> HeaderIntegrityFetcherImpl<'a, F, C> {
    async fn fetch_subresource(&self, url: &str) -> Result<HttpResponse> {
        // A generic SXG-preferring Accept header, for use in populating the
        // subresource integrity cache. This will be cached and reused for
        // other clients, so there is no need to proxy the client's accept
        // header.
        const ACCEPT: &str = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3";
        let request = HttpRequest {
            body: vec![],
            headers: vec![("Accept".into(), ACCEPT.into())],
            method: Method::Get,
            url: url.into(),
        };
        self.subresource_fetcher.fetch(request).await
    }
    // Computes header-integrity of the given unsigned response, per the definition at
    // https://github.com/WICG/webpackage/blob/main/explainers/signed-exchange-subresource-substitution.md#identifying-exactly-one-version-of-a-signed-exchange
    // and the serialization at
    // https://w3c.github.io/webappsec-csp/#grammardef-hash-source. Though it is
    // not specified, the base64 encoding must use the non-websafe alphabet with
    // padding, per this usage:
    // https://source.chromium.org/chromium/chromium/src/+/main:content/browser/web_package/prefetched_signed_exchange_cache.cc;l=616;drc=d6962609965d2b9f804e66792486506de801f46c
    async fn compute_integrity(&self, url: &str, response: &HttpResponse) -> Result<Vec<u8>> {
        let fallback_base =
            Url::parse(url).map_err(|e| Error::new(e).context("parsing fallback URL"))?;
        // TODO: Figure out how to reduce the amount of data cloned.
        let payload_headers = Headers::new(response.headers.clone(), self.strip_response_headers);
        let (signed_headers, _) = signed_headers_and_payload(
            &fallback_base,
            response.status,
            &payload_headers,
            &response.body,
            NULL_FETCHER,
            &mut NullCache {},
            self.strip_response_headers,
        )
        .await?;
        Ok([
            b"sha256-",
            base64::encode(get_sha(&signed_headers)).as_bytes(),
        ]
        .concat())
    }
    fn error_response(msg: &str) -> HttpResponse {
        console_log(&msg.clone());
        HttpResponse {
            body: msg.as_bytes().into(),
            ..ERROR_RESPONSE.clone()
        }
    }
    fn extract_integrity(response: HttpResponse) -> Result<String> {
        if response.status == 200 && response.body.is_ascii() {
            String::from_utf8(response.body)
                .map_err(|e| Error::new(e).context("parsing header-integrity as utf8"))
        } else {
            Err(anyhow!("{}", String::from_utf8_lossy(&response.body)))
        }
    }
}

#[cfg(target_family = "wasm")]
fn console_log(msg: &str) {
    web_sys::console::log_1(&msg.into());
}

#[cfg(not(target_family = "wasm"))]
fn console_log(msg: &str) {
    println!("{}", msg);
}

#[cfg(test)]
pub mod tests {
    use super::*;
    use crate::fetcher::{NullFetcher, NULL_FETCHER};
    use crate::http_cache::NullCache;
    use anyhow::{anyhow, Result};
    use std::collections::HashMap;

    static EMPTY_SET: Lazy<BTreeSet<String>> = Lazy::new(|| BTreeSet::new());
    static mut NULL_CACHE: NullCache = NullCache {};

    // For use in other modules' tests.
    pub fn null_integrity_fetcher() -> HeaderIntegrityFetcherImpl<'static, NullFetcher, NullCache> {
        // The unsafe should be OK since there's no data in NULL_CACHE to race.
        new_fetcher(NULL_FETCHER, unsafe { &mut NULL_CACHE }, &*EMPTY_SET)
    }

    const TEST_URL: &str = "https://signed-exchange-testing.dev/sxgs/image.jpg";
    static TEST_RESPONSE: Lazy<HttpResponse> = Lazy::new(|| HttpResponse {
        // The result of `curl $TEST_URL`.
        body: include_bytes!("static/image.jpg").to_vec(),
        // The headers from `dump-signedexchange -payload=false -uri $TEST_URL`.
        headers: vec![("content-type".into(), "image/jpeg".into())],
        status: 200,
    });
    // The result of `dump-signedexchange -headerIntegrity -uri $TEST_URL`.
    const EXPECTED_HEADER_INTEGRITY: &str = "sha256-ypu/jZuGukVK2EEGlEkiN92qQDg3Zw6Fb0kCtees1bo=";

    struct FakeFetcher<'a>(&'a HttpResponse);

    #[async_trait(?Send)]
    impl<'a> Fetcher for FakeFetcher<'a> {
        async fn fetch(&self, _request: HttpRequest) -> Result<HttpResponse> {
            Ok(self.0.clone())
        }
    }

    #[async_std::test]
    async fn computes_integrity() {
        let strip_response_headers = BTreeSet::new();
        let mut cache = NullCache {};
        let mut fetcher = new_fetcher(
            FakeFetcher(&TEST_RESPONSE),
            &mut cache,
            &strip_response_headers,
        );
        assert_eq!(
            fetcher.fetch(TEST_URL).await.unwrap(),
            EXPECTED_HEADER_INTEGRITY
        );
    }

    struct InMemoryCache(HashMap<String, HttpResponse>);

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

    #[async_trait(?Send)]
    impl HttpCache for InMemoryCache {
        async fn get(&mut self, url: &str) -> Result<HttpResponse> {
            self.0
                .get(url)
                .map(|r| r.clone())
                .ok_or(anyhow!("not found"))
        }
        async fn put(&mut self, url: &str, response: &HttpResponse) -> Result<()> {
            self.0.insert(url.into(), response.clone());
            Ok(())
        }
    }

    #[async_std::test]
    async fn gets_header_integrity_from_cache() {
        let mut cache = InMemoryCache::new();
        let response = HttpResponse {
            body: b"sha256-blah".to_vec(),
            headers: vec![],
            status: 200,
        };
        let _ = cache.put(TEST_URL, &response).await;

        let strip_response_headers = BTreeSet::new();
        let mut fetcher = new_fetcher(
            FakeFetcher(&TEST_RESPONSE),
            &mut cache,
            &strip_response_headers,
        );

        assert_eq!(fetcher.fetch(TEST_URL).await.unwrap(), "sha256-blah",);
    }
    #[async_std::test]
    async fn gets_error_from_cache() {
        let mut cache = InMemoryCache::new();
        let response = HttpResponse {
            body: b"something went wrong".to_vec(),
            headers: vec![],
            status: 406,
        };
        let _ = cache.put(TEST_URL, &response).await;

        let strip_response_headers = BTreeSet::new();
        let mut fetcher = new_fetcher(
            FakeFetcher(&TEST_RESPONSE),
            &mut cache,
            &strip_response_headers,
        );

        assert_eq!(
            fetcher.fetch(TEST_URL).await.unwrap_err().to_string(),
            "something went wrong",
        )
    }
    #[async_std::test]
    async fn puts_into_cache() {
        let mut cache = InMemoryCache::new();

        let strip_response_headers = BTreeSet::new();
        let mut fetcher = new_fetcher(
            FakeFetcher(&TEST_RESPONSE),
            &mut cache,
            &strip_response_headers,
        );

        let _ = fetcher.fetch(TEST_URL).await;
        assert_eq!(
            cache.get(TEST_URL).await.unwrap().body,
            EXPECTED_HEADER_INTEGRITY.as_bytes(),
        );
    }
}
<commit_msg>Gate console_log on feature="wasm" also. (#58)<commit_after>// Copyright 2021 Google LLC
//
// 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
//
//     https://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.

use crate::fetcher::{Fetcher, NULL_FETCHER};
use crate::headers::Headers;
use crate::http::{HttpRequest, HttpResponse, Method};
use crate::http_cache::{HttpCache, NullCache};
use crate::utils::{get_sha, signed_headers_and_payload};
use anyhow::{anyhow, Error, Result};
use async_trait::async_trait;
use once_cell::sync::Lazy;
use std::collections::BTreeSet;
use url::Url;

#[async_trait(?Send)]
pub trait HeaderIntegrityFetcher {
    async fn fetch(&mut self, url: &str) -> Result<String>;
}

pub fn new_fetcher<'a, F: Fetcher, C: HttpCache>(
    subresource_fetcher: F,
    header_integrity_cache: &'a mut C,
    strip_response_headers: &'a BTreeSet<String>,
) -> HeaderIntegrityFetcherImpl<'a, F, C> {
    HeaderIntegrityFetcherImpl {
        subresource_fetcher,
        header_integrity_cache,
        strip_response_headers,
    }
}

pub struct HeaderIntegrityFetcherImpl<'a, F: Fetcher, C: HttpCache> {
    subresource_fetcher: F,
    header_integrity_cache: &'a mut C,
    strip_response_headers: &'a BTreeSet<String>,
}

// A synthesized error response that can be cached, to prevent overloading the
// origin for non-SXG subresources that it preloads.
static ERROR_RESPONSE: Lazy<HttpResponse> = Lazy::new(|| HttpResponse {
    body: vec![],
    headers: vec![("cache-control".into(), "max-age=3600".into())],
    status: 406,
});

#[async_trait(?Send)]
impl<'a, F: Fetcher, C: HttpCache> HeaderIntegrityFetcher for HeaderIntegrityFetcherImpl<'a, F, C> {
    async fn fetch(&mut self, url: &str) -> Result<String> {
        let integrity_response = match self.header_integrity_cache.get(url).await {
            // Use cached header-integrity.
            Ok(response @ HttpResponse { status: 200, .. }) => response,
            // Respect the cached error status; don't fetch from origin.
            Ok(response @ HttpResponse { status: 406, .. }) => {
                console_log(&format!(
                    "Cached header-integrity error for {}; not refetching for up to an hour: {}",
                    url,
                    String::from_utf8_lossy(&response.body),
                ));
                response
            }
            // Cache miss or error fetching from cache; fall back to origin.
            _ => {
                console_log(&format!(
                    "{} not found in header-integrity cache. Fetching.",
                    url
                ));
                let response = match self.fetch_subresource(url).await {
                    Ok(response) => {
                        match self.compute_integrity(url, &response).await {
                            Ok(integrity) => {
                                // Keep original cache-control headers, so the integrity is
                                // up-to-date with the subresource.
                                HttpResponse {
                                    body: integrity,
                                    ..response
                                }
                            }
                            Err(err) => Self::error_response(&format!(
                                "Error computing header-integrity for {}: {:#}",
                                url, err
                            )),
                        }
                    }
                    Err(err) => Self::error_response(&format!(
                        "Error fetching subresource at {}: {:#}",
                        url, err
                    )),
                };
                let _ = self.header_integrity_cache.put(url, &response).await;
                response
            }
        };
        Self::extract_integrity(integrity_response)
    }
}

impl<'a, F: Fetcher, C: HttpCache> HeaderIntegrityFetcherImpl<'a, F, C> {
    async fn fetch_subresource(&self, url: &str) -> Result<HttpResponse> {
        // A generic SXG-preferring Accept header, for use in populating the
        // subresource integrity cache. This will be cached and reused for
        // other clients, so there is no need to proxy the client's accept
        // header.
        const ACCEPT: &str = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3";
        let request = HttpRequest {
            body: vec![],
            headers: vec![("Accept".into(), ACCEPT.into())],
            method: Method::Get,
            url: url.into(),
        };
        self.subresource_fetcher.fetch(request).await
    }
    // Computes header-integrity of the given unsigned response, per the definition at
    // https://github.com/WICG/webpackage/blob/main/explainers/signed-exchange-subresource-substitution.md#identifying-exactly-one-version-of-a-signed-exchange
    // and the serialization at
    // https://w3c.github.io/webappsec-csp/#grammardef-hash-source. Though it is
    // not specified, the base64 encoding must use the non-websafe alphabet with
    // padding, per this usage:
    // https://source.chromium.org/chromium/chromium/src/+/main:content/browser/web_package/prefetched_signed_exchange_cache.cc;l=616;drc=d6962609965d2b9f804e66792486506de801f46c
    async fn compute_integrity(&self, url: &str, response: &HttpResponse) -> Result<Vec<u8>> {
        let fallback_base =
            Url::parse(url).map_err(|e| Error::new(e).context("parsing fallback URL"))?;
        // TODO: Figure out how to reduce the amount of data cloned.
        let payload_headers = Headers::new(response.headers.clone(), self.strip_response_headers);
        let (signed_headers, _) = signed_headers_and_payload(
            &fallback_base,
            response.status,
            &payload_headers,
            &response.body,
            NULL_FETCHER,
            &mut NullCache {},
            self.strip_response_headers,
        )
        .await?;
        Ok([
            b"sha256-",
            base64::encode(get_sha(&signed_headers)).as_bytes(),
        ]
        .concat())
    }
    fn error_response(msg: &str) -> HttpResponse {
        console_log(&msg.clone());
        HttpResponse {
            body: msg.as_bytes().into(),
            ..ERROR_RESPONSE.clone()
        }
    }
    fn extract_integrity(response: HttpResponse) -> Result<String> {
        if response.status == 200 && response.body.is_ascii() {
            String::from_utf8(response.body)
                .map_err(|e| Error::new(e).context("parsing header-integrity as utf8"))
        } else {
            Err(anyhow!("{}", String::from_utf8_lossy(&response.body)))
        }
    }
}

#[cfg(all(target_family = "wasm", feature = "wasm"))]
fn console_log(msg: &str) {
    web_sys::console::log_1(&msg.into());
}

#[cfg(not(all(target_family = "wasm", feature = "wasm")))]
fn console_log(msg: &str) {
    println!("{}", msg);
}

#[cfg(test)]
pub mod tests {
    use super::*;
    use crate::fetcher::{NullFetcher, NULL_FETCHER};
    use crate::http_cache::NullCache;
    use anyhow::{anyhow, Result};
    use std::collections::HashMap;

    static EMPTY_SET: Lazy<BTreeSet<String>> = Lazy::new(|| BTreeSet::new());
    static mut NULL_CACHE: NullCache = NullCache {};

    // For use in other modules' tests.
    pub fn null_integrity_fetcher() -> HeaderIntegrityFetcherImpl<'static, NullFetcher, NullCache> {
        // The unsafe should be OK since there's no data in NULL_CACHE to race.
        new_fetcher(NULL_FETCHER, unsafe { &mut NULL_CACHE }, &*EMPTY_SET)
    }

    const TEST_URL: &str = "https://signed-exchange-testing.dev/sxgs/image.jpg";
    static TEST_RESPONSE: Lazy<HttpResponse> = Lazy::new(|| HttpResponse {
        // The result of `curl $TEST_URL`.
        body: include_bytes!("static/image.jpg").to_vec(),
        // The headers from `dump-signedexchange -payload=false -uri $TEST_URL`.
        headers: vec![("content-type".into(), "image/jpeg".into())],
        status: 200,
    });
    // The result of `dump-signedexchange -headerIntegrity -uri $TEST_URL`.
    const EXPECTED_HEADER_INTEGRITY: &str = "sha256-ypu/jZuGukVK2EEGlEkiN92qQDg3Zw6Fb0kCtees1bo=";

    struct FakeFetcher<'a>(&'a HttpResponse);

    #[async_trait(?Send)]
    impl<'a> Fetcher for FakeFetcher<'a> {
        async fn fetch(&self, _request: HttpRequest) -> Result<HttpResponse> {
            Ok(self.0.clone())
        }
    }

    #[async_std::test]
    async fn computes_integrity() {
        let strip_response_headers = BTreeSet::new();
        let mut cache = NullCache {};
        let mut fetcher = new_fetcher(
            FakeFetcher(&TEST_RESPONSE),
            &mut cache,
            &strip_response_headers,
        );
        assert_eq!(
            fetcher.fetch(TEST_URL).await.unwrap(),
            EXPECTED_HEADER_INTEGRITY
        );
    }

    struct InMemoryCache(HashMap<String, HttpResponse>);

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

    #[async_trait(?Send)]
    impl HttpCache for InMemoryCache {
        async fn get(&mut self, url: &str) -> Result<HttpResponse> {
            self.0
                .get(url)
                .map(|r| r.clone())
                .ok_or(anyhow!("not found"))
        }
        async fn put(&mut self, url: &str, response: &HttpResponse) -> Result<()> {
            self.0.insert(url.into(), response.clone());
            Ok(())
        }
    }

    #[async_std::test]
    async fn gets_header_integrity_from_cache() {
        let mut cache = InMemoryCache::new();
        let response = HttpResponse {
            body: b"sha256-blah".to_vec(),
            headers: vec![],
            status: 200,
        };
        let _ = cache.put(TEST_URL, &response).await;

        let strip_response_headers = BTreeSet::new();
        let mut fetcher = new_fetcher(
            FakeFetcher(&TEST_RESPONSE),
            &mut cache,
            &strip_response_headers,
        );

        assert_eq!(fetcher.fetch(TEST_URL).await.unwrap(), "sha256-blah",);
    }
    #[async_std::test]
    async fn gets_error_from_cache() {
        let mut cache = InMemoryCache::new();
        let response = HttpResponse {
            body: b"something went wrong".to_vec(),
            headers: vec![],
            status: 406,
        };
        let _ = cache.put(TEST_URL, &response).await;

        let strip_response_headers = BTreeSet::new();
        let mut fetcher = new_fetcher(
            FakeFetcher(&TEST_RESPONSE),
            &mut cache,
            &strip_response_headers,
        );

        assert_eq!(
            fetcher.fetch(TEST_URL).await.unwrap_err().to_string(),
            "something went wrong",
        )
    }
    #[async_std::test]
    async fn puts_into_cache() {
        let mut cache = InMemoryCache::new();

        let strip_response_headers = BTreeSet::new();
        let mut fetcher = new_fetcher(
            FakeFetcher(&TEST_RESPONSE),
            &mut cache,
            &strip_response_headers,
        );

        let _ = fetcher.fetch(TEST_URL).await;
        assert_eq!(
            cache.get(TEST_URL).await.unwrap().body,
            EXPECTED_HEADER_INTEGRITY.as_bytes(),
        );
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

pub struct Model {
    pub board: Board,
    pub turn: Color,
    pub white_pieces: u32,
    pub white_hexes: u32,
    pub black_pieces: u32,
    pub black_hexes: u32,
    pub selected_piece: Option<FieldCoord>,
    pub last_move: Option<(FieldCoord, FieldCoord)>,
    pub available_moves: Option<Vec<FieldCoord>>,
}

impl Model {
    pub fn new() -> Model {
        Model {
            board: Board::new(),
            turn: Color::White,
            white_pieces: 18,
            white_hexes: 0,
            black_pieces: 18,
            black_hexes: 0,
            selected_piece: None,
            last_move: None,
            available_moves: None,
        }
    }
    pub fn switch_turns(&mut self) {
        self.turn = match self.turn {
            Color::White => Color::Black,
            Color::Black => Color::White,
        }
    }
}

#[derive(PartialEq)]
pub enum Color {
    White,
    Black,
}

pub struct Board {
    /*
                ____
               /    \
          ____/  +y  \____
         /    \      /    \
        /      \____/  +x  \
        \      /    \      /
         \____/      \____/
         /    \      /    \
        /  -x  \____/      \
        \      /    \      /
         \____/  -y  \____/
              \      /
               \____/

        The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
        up to the right, and the y-axis goes up and down. The board is stored as a dense 2D array,
        because a ragged array won't work (since each row would have to be a different type).

        See http://www.redblobgames.com/grids/hexagons/#coordinates-axial for more info.
    */
    board: [[Option<Hex>; 5]; 5],
}

// Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
type Hex = [Field; 6];

// There's no need to store the color of the piece on this field, since only white pieces can be on
// white fields, and vice versa.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Field {
    Piece,
    Empty,
}

impl Board {
    #[cfg_attr(rustfmt, rustfmt_skip)]
    /// Create a new board with the "Laurentius" starting position.
    pub fn new() -> Board {
        let mut board = Board {
            board: [[None; 5]; 5]
        };

        // (0, 0) is the only empty hex.
        board.set_hex(&HexCoord::new(0, 0), Some([Field::Empty; 6]));

        // All other hexes have exactly two pieces on them in the starting position.
        let piece_locations = [
            (-2,  2, 0, 4),
            (-2,  1, 0, 3),
            (-2,  0, 3, 5),
            (-1,  2, 1, 4),
            (-1,  1, 0, 4),
            (-1,  0, 3, 5),
            (-1, -1, 2, 5),
            ( 0,  2, 1, 5),
            ( 0,  1, 1, 5),
            ( 0, -1, 2, 4),
            ( 0, -2, 2, 4),
            ( 1,  1, 2, 5),
            ( 1,  0, 0, 2),
            ( 1, -1, 1, 3),
            ( 1, -2, 1, 4),
            ( 2,  0, 0, 2),
            ( 2, -1, 0, 3),
            ( 2, -2, 1, 3),
        ];

        for &(x, y, f1, f2) in &piece_locations {
            let mut hex = [Field::Empty; 6];
            hex[f1] = Field::Piece;
            hex[f2] = Field::Piece;
            board.set_hex(&HexCoord::new(x, y), Some(hex));
        }

        board
    }

    fn get_field(&self, coord: &FieldCoord) -> &Field {
        match *self.get_hex(&coord.to_hex()) {
            Some(ref hex) => &hex[coord.f as usize],
            None => panic!(
                "Cannot get field {} on removed hex at {:?}",
                coord.f,
                coord.to_hex()
            ),
        }
    }
    fn set_field(&mut self, coord: &FieldCoord, field: Field) {
        match *self.get_hex(&coord.to_hex()) {
            Some(mut hex) => {
                hex[coord.f as usize] = field;
                self.set_hex(&coord.to_hex(), Some(hex));
            }
            None => panic!(
                "Cannot set field {} on removed hex at {:?}",
                coord.f,
                coord.to_hex()
            ),
        }
    }
    pub fn is_piece_on_field(&self, coord: &FieldCoord) -> bool {
        self.get_field(coord) == &Field::Piece
    }
    /// Return fields that share an edge with the given field. These fields are always the opposite
    /// color of the given field. If all of a piece's edge neighbors are occupied, that piece might
    /// be capturable.
    pub fn get_field_edge_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![
            // There are always two edge neighbors on the same hex as the given field
            FieldCoord::new(coord.x, coord.y, (coord.f + 1) % 6),
            FieldCoord::new(coord.x, coord.y, (coord.f + 5) % 6),
        ];

        if let Some(hex) = self.get_hex_neighbor(&coord.to_hex(), coord.f) {
            neighbors.push(hex.to_field((coord.f + 3) % 6));
        }

        neighbors
    }
    /// Return fields that share a vertex with the given field and have the same color as the given
    /// field. Pieces can move to fields that are vertex neighbors of the field they are on.
    pub fn get_field_vertex_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        // A field's vertex neighbors can be defined as the edge neighbors of its edge neighbors
        let mut neighbors = vec![];
        for field in self.get_field_edge_neighbors(coord) {
            neighbors.append(&mut self.get_field_edge_neighbors(&field));
        }
        // A field is not its own neighbor
        neighbors.into_iter().filter(|n| n != coord).collect()
    }
    pub fn get_available_moves(&self, field: &FieldCoord) -> Vec<FieldCoord> {
        if self.is_piece_on_field(field) {
            self.get_field_vertex_neighbors(field)
                .into_iter()
                .filter(|c| !self.is_piece_on_field(c))
                .collect()
        } else {
            vec![]
        }
    }
    pub fn can_move_piece(&self, from: &FieldCoord, to: &FieldCoord) -> bool {
        self.is_piece_on_field(from) && !self.is_piece_on_field(to) &&
            self.get_field_vertex_neighbors(from).contains(to)
    }
    pub fn move_piece(&mut self, from: &FieldCoord, to: &FieldCoord) {
        assert!(
            self.can_move_piece(from, to),
            "Can't move {:?} at {:?} to {:?} at {:?}. These fields {} vertex neighbors.",
            self.get_field(from),
            from,
            self.get_field(to),
            to,
            if self.get_field_vertex_neighbors(from).contains(to) {
                "ARE"
            } else {
                "ARE NOT"
            },
        );

        self.set_field(from, Field::Empty);
        self.set_field(to, Field::Piece);
    }
    pub fn remove_piece(&mut self, coord: &FieldCoord) {
        assert!(
            self.is_piece_on_field(coord),
            "There is no piece at {:?} to remove",
            coord
        );
        self.set_field(coord, Field::Empty);
    }
    fn get_hex(&self, coord: &HexCoord) -> &Option<Hex> {
        &self.board[(coord.x + 2) as usize][(coord.y + 2) as usize]
    }
    fn set_hex(&mut self, coord: &HexCoord, hex: Option<Hex>) {
        self.board[(coord.x + 2) as usize][(coord.y + 2) as usize] = hex;
    }
    fn try_hex(&self, x: i32, y: i32) -> Option<HexCoord> {
        if let Some(coord) = HexCoord::try_new(x, y) {
            if self.is_hex_extant(&coord) {
                return Some(coord);
            }
        }
        None
    }
    pub fn get_hex_neighbor(&self, coord: &HexCoord, direction: u32) -> Option<HexCoord> {
        assert!(direction < 6);

        let neighbors = [
            (coord.x, coord.y + 1),
            (coord.x + 1, coord.y),
            (coord.x + 1, coord.y - 1),
            (coord.x, coord.y - 1),
            (coord.x - 1, coord.y),
            (coord.x - 1, coord.y + 1),
        ];

        let (x, y) = neighbors[direction as usize];
        self.try_hex(x, y)
    }
    /// A hex is removable (and must be removed) if it is empty and is "attached to the board by 3
    /// or less adjacent sides."
    pub fn is_hex_removable(&self, coord: &HexCoord) -> bool {
        match *self.get_hex(coord) {
            Some(hex) => if hex != [Field::Empty; 6] {
                return false;
            },
            None => return false,
        }

        let neighbor_indexes: Vec<u32> = vec![0, 1, 2, 3, 4, 5]
            .into_iter()
            .filter(|&f| self.get_hex_neighbor(coord, f).is_some())
            .collect();
        let neighbor_indexes = neighbor_indexes.as_slice();

        match neighbor_indexes.len() {
            0 => panic!("A hex at {:?} is empty and has no neighbors", coord),
            1 => true,
            2 => {
                let valid_idx_combos = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [0, 5]];
                valid_idx_combos.iter().any(|c| c == neighbor_indexes)
            }
            3 => {
                let valid_idx_combos = [
                    [0, 1, 2],
                    [1, 2, 3],
                    [2, 3, 4],
                    [3, 4, 5],
                    [0, 4, 5],
                    [0, 1, 5],
                ];
                valid_idx_combos.iter().any(|c| c == neighbor_indexes)
            }
            _ => false,
        }
    }
    pub fn remove_hex(&mut self, coord: &HexCoord) {
        assert!(
            self.is_hex_removable(coord),
            "Cannot remove the hex at {:?} which is {:?} and has {} neighbors",
            coord,
            self.get_hex(coord),
            [0, 1, 2, 3, 4, 5]
                .into_iter()
                .filter(|&&f| self.get_hex_neighbor(coord, f).is_some())
                .collect::<Vec<_>>()
                .len(),
        );
        self.set_hex(coord, None);
    }
    /// > extant (adj.): Still in existence; not destroyed, lost, or extinct (The Free Dictionary)
    ///
    /// Return true if the passed hex has not been removed yet.
    pub fn is_hex_extant(&self, coord: &HexCoord) -> bool {
        self.get_hex(coord).is_some()
    }
    /// > extant (adj.): Still in existence; not destroyed, lost, or extinct (The Free Dictionary)
    ///
    /// Return the coordinates of the hexes that have not been removed yet.
    pub fn extant_hexes(&self) -> Vec<HexCoord> {
        let mut coords = vec![];

        for x in -2..3 {
            for y in -2..3 {
                if let Some(hex) = self.try_hex(x, y) {
                    coords.push(hex);
                }
            }
        }
        coords
    }
}

#[derive(Debug, PartialEq)]
pub struct FieldCoord {
    x: i32,
    y: i32,
    f: u32,
}

#[derive(Clone, Copy, Debug)]
pub struct HexCoord {
    x: i32,
    y: i32,
}

impl FieldCoord {
    pub fn new(x: i32, y: i32, f: u32) -> FieldCoord {
        assert!(Self::is_valid_coord(x, y, f));
        FieldCoord { x, y, f }
    }
    pub fn f(&self) -> u32 {
        self.f
    }
    pub fn to_hex(&self) -> HexCoord {
        HexCoord::new(self.x, self.y)
    }
    fn is_valid_coord(x: i32, y: i32, f: u32) -> bool {
        (x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2 && f < 6
    }
    pub fn color(&self) -> Color {
        if self.f % 2 == 0 {
            Color::Black
        } else {
            Color::White
        }
    }
}

impl HexCoord {
    pub fn new(x: i32, y: i32) -> HexCoord {
        assert!(Self::is_valid_coord(x, y));
        HexCoord { x, y }
    }
    pub fn try_new(x: i32, y: i32) -> Option<HexCoord> {
        if Self::is_valid_coord(x, y) {
            Some(HexCoord { x, y })
        } else {
            None
        }
    }
    pub fn x(&self) -> i32 {
        self.x
    }
    pub fn y(&self) -> i32 {
        self.y
    }
    pub fn to_field(&self, f: u32) -> FieldCoord {
        FieldCoord::new(self.x, self.y, f)
    }
    fn is_valid_coord(x: i32, y: i32) -> bool {
        (x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2
    }
}
<commit_msg>Shuffle Board methods<commit_after>/*
 * Copyright (C) 2017 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

pub struct Model {
    pub board: Board,
    pub turn: Color,
    pub white_pieces: u32,
    pub white_hexes: u32,
    pub black_pieces: u32,
    pub black_hexes: u32,
    pub selected_piece: Option<FieldCoord>,
    pub last_move: Option<(FieldCoord, FieldCoord)>,
    pub available_moves: Option<Vec<FieldCoord>>,
}

impl Model {
    pub fn new() -> Model {
        Model {
            board: Board::new(),
            turn: Color::White,
            white_pieces: 18,
            white_hexes: 0,
            black_pieces: 18,
            black_hexes: 0,
            selected_piece: None,
            last_move: None,
            available_moves: None,
        }
    }
    pub fn switch_turns(&mut self) {
        self.turn = match self.turn {
            Color::White => Color::Black,
            Color::Black => Color::White,
        }
    }
}

#[derive(PartialEq)]
pub enum Color {
    White,
    Black,
}

pub struct Board {
    /*
                ____
               /    \
          ____/  +y  \____
         /    \      /    \
        /      \____/  +x  \
        \      /    \      /
         \____/      \____/
         /    \      /    \
        /  -x  \____/      \
        \      /    \      /
         \____/  -y  \____/
              \      /
               \____/

        The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
        up to the right, and the y-axis goes up and down. The board is stored as a dense 2D array,
        because a ragged array won't work (since each row would have to be a different type).

        See http://www.redblobgames.com/grids/hexagons/#coordinates-axial for more info.
    */
    board: [[Option<Hex>; 5]; 5],
}

// Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
type Hex = [Field; 6];

// There's no need to store the color of the piece on this field, since only white pieces can be on
// white fields, and vice versa.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Field {
    Piece,
    Empty,
}

impl Board {
    #[cfg_attr(rustfmt, rustfmt_skip)]
    /// Create a new board with the "Laurentius" starting position.
    pub fn new() -> Board {
        let mut board = Board {
            board: [[None; 5]; 5]
        };

        // (0, 0) is the only empty hex.
        board.set_hex(&HexCoord::new(0, 0), Some([Field::Empty; 6]));

        // All other hexes have exactly two pieces on them in the starting position.
        let piece_locations = [
            (-2,  2, 0, 4),
            (-2,  1, 0, 3),
            (-2,  0, 3, 5),
            (-1,  2, 1, 4),
            (-1,  1, 0, 4),
            (-1,  0, 3, 5),
            (-1, -1, 2, 5),
            ( 0,  2, 1, 5),
            ( 0,  1, 1, 5),
            ( 0, -1, 2, 4),
            ( 0, -2, 2, 4),
            ( 1,  1, 2, 5),
            ( 1,  0, 0, 2),
            ( 1, -1, 1, 3),
            ( 1, -2, 1, 4),
            ( 2,  0, 0, 2),
            ( 2, -1, 0, 3),
            ( 2, -2, 1, 3),
        ];

        for &(x, y, f1, f2) in &piece_locations {
            let mut hex = [Field::Empty; 6];
            hex[f1] = Field::Piece;
            hex[f2] = Field::Piece;
            board.set_hex(&HexCoord::new(x, y), Some(hex));
        }

        board
    }

    fn get_field(&self, coord: &FieldCoord) -> &Field {
        match *self.get_hex(&coord.to_hex()) {
            Some(ref hex) => &hex[coord.f as usize],
            None => panic!(
                "Cannot get field {} on removed hex at {:?}",
                coord.f,
                coord.to_hex()
            ),
        }
    }
    fn set_field(&mut self, coord: &FieldCoord, field: Field) {
        match *self.get_hex(&coord.to_hex()) {
            Some(mut hex) => {
                hex[coord.f as usize] = field;
                self.set_hex(&coord.to_hex(), Some(hex));
            }
            None => panic!(
                "Cannot set field {} on removed hex at {:?}",
                coord.f,
                coord.to_hex()
            ),
        }
    }
    /// Return fields that share an edge with the given field. These fields are always the opposite
    /// color of the given field. If all of a piece's edge neighbors are occupied, that piece might
    /// be capturable.
    pub fn get_field_edge_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![
            // There are always two edge neighbors on the same hex as the given field
            FieldCoord::new(coord.x, coord.y, (coord.f + 1) % 6),
            FieldCoord::new(coord.x, coord.y, (coord.f + 5) % 6),
        ];

        if let Some(hex) = self.get_hex_neighbor(&coord.to_hex(), coord.f) {
            neighbors.push(hex.to_field((coord.f + 3) % 6));
        }

        neighbors
    }
    /// Return fields that share a vertex with the given field and have the same color as the given
    /// field. Pieces can move to fields that are vertex neighbors of the field they are on.
    pub fn get_field_vertex_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        // A field's vertex neighbors can be defined as the edge neighbors of its edge neighbors
        let mut neighbors = vec![];
        for field in self.get_field_edge_neighbors(coord) {
            neighbors.append(&mut self.get_field_edge_neighbors(&field));
        }
        // A field is not its own neighbor
        neighbors.into_iter().filter(|n| n != coord).collect()
    }
    pub fn is_piece_on_field(&self, coord: &FieldCoord) -> bool {
        self.get_field(coord) == &Field::Piece
    }
    pub fn get_available_moves(&self, field: &FieldCoord) -> Vec<FieldCoord> {
        if self.is_piece_on_field(field) {
            self.get_field_vertex_neighbors(field)
                .into_iter()
                .filter(|c| !self.is_piece_on_field(c))
                .collect()
        } else {
            vec![]
        }
    }
    pub fn can_move_piece(&self, from: &FieldCoord, to: &FieldCoord) -> bool {
        self.is_piece_on_field(from) && !self.is_piece_on_field(to) &&
            self.get_field_vertex_neighbors(from).contains(to)
    }
    pub fn move_piece(&mut self, from: &FieldCoord, to: &FieldCoord) {
        assert!(
            self.can_move_piece(from, to),
            "Can't move {:?} at {:?} to {:?} at {:?}. These fields {} vertex neighbors.",
            self.get_field(from),
            from,
            self.get_field(to),
            to,
            if self.get_field_vertex_neighbors(from).contains(to) {
                "ARE"
            } else {
                "ARE NOT"
            },
        );

        self.set_field(from, Field::Empty);
        self.set_field(to, Field::Piece);
    }
    pub fn remove_piece(&mut self, coord: &FieldCoord) {
        assert!(
            self.is_piece_on_field(coord),
            "There is no piece at {:?} to remove",
            coord
        );
        self.set_field(coord, Field::Empty);
    }
    fn get_hex(&self, coord: &HexCoord) -> &Option<Hex> {
        &self.board[(coord.x + 2) as usize][(coord.y + 2) as usize]
    }
    fn set_hex(&mut self, coord: &HexCoord, hex: Option<Hex>) {
        self.board[(coord.x + 2) as usize][(coord.y + 2) as usize] = hex;
    }
    pub fn get_hex_neighbor(&self, coord: &HexCoord, direction: u32) -> Option<HexCoord> {
        assert!(direction < 6);

        let neighbors = [
            (coord.x, coord.y + 1),
            (coord.x + 1, coord.y),
            (coord.x + 1, coord.y - 1),
            (coord.x, coord.y - 1),
            (coord.x - 1, coord.y),
            (coord.x - 1, coord.y + 1),
        ];

        let (x, y) = neighbors[direction as usize];
        self.try_hex(x, y)
    }
    /// A hex is removable (and must be removed) if it is empty and is "attached to the board by 3
    /// or less adjacent sides."
    pub fn is_hex_removable(&self, coord: &HexCoord) -> bool {
        match *self.get_hex(coord) {
            Some(hex) => if hex != [Field::Empty; 6] {
                return false;
            },
            None => return false,
        }

        let neighbor_indexes: Vec<u32> = vec![0, 1, 2, 3, 4, 5]
            .into_iter()
            .filter(|&f| self.get_hex_neighbor(coord, f).is_some())
            .collect();
        let neighbor_indexes = neighbor_indexes.as_slice();

        match neighbor_indexes.len() {
            0 => panic!("A hex at {:?} is empty and has no neighbors", coord),
            1 => true,
            2 => {
                let valid_idx_combos = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [0, 5]];
                valid_idx_combos.iter().any(|c| c == neighbor_indexes)
            }
            3 => {
                let valid_idx_combos = [
                    [0, 1, 2],
                    [1, 2, 3],
                    [2, 3, 4],
                    [3, 4, 5],
                    [0, 4, 5],
                    [0, 1, 5],
                ];
                valid_idx_combos.iter().any(|c| c == neighbor_indexes)
            }
            _ => false,
        }
    }
    pub fn remove_hex(&mut self, coord: &HexCoord) {
        assert!(
            self.is_hex_removable(coord),
            "Cannot remove the hex at {:?} which is {:?} and has {} neighbors",
            coord,
            self.get_hex(coord),
            [0, 1, 2, 3, 4, 5]
                .into_iter()
                .filter(|&&f| self.get_hex_neighbor(coord, f).is_some())
                .collect::<Vec<_>>()
                .len(),
        );
        self.set_hex(coord, None);
    }
    fn try_hex(&self, x: i32, y: i32) -> Option<HexCoord> {
        if let Some(coord) = HexCoord::try_new(x, y) {
            if self.is_hex_extant(&coord) {
                return Some(coord);
            }
        }
        None
    }
    /// > extant (adj.): Still in existence; not destroyed, lost, or extinct (The Free Dictionary)
    ///
    /// Return true if the passed hex has not been removed yet.
    pub fn is_hex_extant(&self, coord: &HexCoord) -> bool {
        self.get_hex(coord).is_some()
    }
    /// > extant (adj.): Still in existence; not destroyed, lost, or extinct (The Free Dictionary)
    ///
    /// Return the coordinates of the hexes that have not been removed yet.
    pub fn extant_hexes(&self) -> Vec<HexCoord> {
        let mut coords = vec![];

        for x in -2..3 {
            for y in -2..3 {
                if let Some(hex) = self.try_hex(x, y) {
                    coords.push(hex);
                }
            }
        }
        coords
    }
}

#[derive(Debug, PartialEq)]
pub struct FieldCoord {
    x: i32,
    y: i32,
    f: u32,
}

#[derive(Clone, Copy, Debug)]
pub struct HexCoord {
    x: i32,
    y: i32,
}

impl FieldCoord {
    pub fn new(x: i32, y: i32, f: u32) -> FieldCoord {
        assert!(Self::is_valid_coord(x, y, f));
        FieldCoord { x, y, f }
    }
    pub fn f(&self) -> u32 {
        self.f
    }
    pub fn to_hex(&self) -> HexCoord {
        HexCoord::new(self.x, self.y)
    }
    fn is_valid_coord(x: i32, y: i32, f: u32) -> bool {
        (x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2 && f < 6
    }
    pub fn color(&self) -> Color {
        if self.f % 2 == 0 {
            Color::Black
        } else {
            Color::White
        }
    }
}

impl HexCoord {
    pub fn new(x: i32, y: i32) -> HexCoord {
        assert!(Self::is_valid_coord(x, y));
        HexCoord { x, y }
    }
    pub fn try_new(x: i32, y: i32) -> Option<HexCoord> {
        if Self::is_valid_coord(x, y) {
            Some(HexCoord { x, y })
        } else {
            None
        }
    }
    pub fn x(&self) -> i32 {
        self.x
    }
    pub fn y(&self) -> i32 {
        self.y
    }
    pub fn to_field(&self, f: u32) -> FieldCoord {
        FieldCoord::new(self.x, self.y, f)
    }
    fn is_valid_coord(x: i32, y: i32) -> bool {
        (x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2
    }
}
<|endoftext|>


<commit_before>use luminance::tessellation;
use luminance_gl::gl33::Tessellation;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::Read;
use std::iter::IntoIterator;
use std::path::{Path, PathBuf};
use std::vec;
use wavefront_obj::{self, obj};

// FIXME: implement materials
pub type Material = ();

pub type Vertex = (VertexPos, VertexNor, VertexTexCoord);
pub type VertexPos = [f32; 3];
pub type VertexNor = [f32; 3];
pub type VertexTexCoord = [f32; 2];

pub struct Model<'a> {
  parts: Vec<Part<'a>>
}

impl<'a> Model<'a> {
  pub fn from_parts(parts: Vec<Part<'a>>) -> Self {
    Model {
      parts: parts
    }
  }
}

impl<'a> IntoIterator for Model<'a> {
  type Item = Part<'a>;
  type IntoIter = vec::IntoIter<Part<'a>>;

  fn into_iter(self) -> Self::IntoIter {
    self.parts.into_iter()
  }
}

pub struct Part<'a> {
  tess: Tessellation,
  mat: Option<&'a Material>
}

impl<'a> Part<'a> {
  pub fn new(tess: Tessellation, mat: Option<&'a Material>) -> Self {
    Part {
      tess: tess,
      mat: mat
    }
  }

  pub fn tessellation(&self) -> &Tessellation {
    &self.tess
  }

  pub fn material(&self) -> Option<&Material> {
    self.mat.clone()
  }
}

pub fn load<'a, P>(path: P) -> Result<Model<'a>, ModelError> where P: AsRef<Path> {
  let path = path.as_ref();

  info!("loading model: \x1b[35m{:?}", path);

  let mut input = String::new();

  // load the data directly into memory; no buffering nor streaming
  {
    let mut file = try!(File::open(path).map_err(|e| ModelError::FileNotFound(path.to_path_buf(), format!("{:?}", e))));
    let _ = file.read_to_string(&mut input);
  }

  // parse the obj file and convert it
  let obj_set = try!(obj::parse(input).map_err(ModelError::ParseFailed));

  convert_obj(obj_set)
}

// Turn a wavefront obj object into a `Model`
fn convert_obj<'a>(obj_set: obj::ObjSet) -> Result<Model<'a>, ModelError> {
  if obj_set.objects.len() != 1 {
    return Err(ModelError::MultiObjects);
  }

  let obj = &obj_set.objects[0];
  info!("  converting object \x1b[35m{}", obj.name);

  // convert all the geometries
  let mut parts = Vec::with_capacity(obj.geometry.len());

  for geometry in &obj.geometry {
    let (vertices, indices, mode) = try!(convert_geometry(geometry, &obj.vertices, &obj.normals, &obj.tex_vertices));
    let part = Part::new(Tessellation::new(mode, &vertices, Some(&indices)), None); // FIXME: material
    parts.push(part);
  }

  Ok(Model::from_parts(parts))
}

// Convert wavefront_obj’s Geometry into a pair of vertices and indices.
//
// This function will regenerate the indices on the fly based on which are used in the shapes in the
// geometry. It’s used to create independent tessellation.
fn convert_geometry(geo: &obj::Geometry, positions: &[obj::Vertex], normals: &[obj::Normal], tvertices: &[obj::TVertex]) -> Result<(Vec<Vertex>, Vec<u32>, tessellation::Mode), ModelError> {
  if geo.shapes.is_empty() {
    return Err(ModelError::NoShape);
  }

  let mut vertices = Vec::new(); // FIXME: better allocation scheme?
  let mut indices = Vec::new();
  let mut index_map = BTreeMap::new();

  info!("    converting geometry");

  let mode = guess_mode(geo.shapes[0].primitive);

  for prim in geo.shapes.iter().map(|s| s.primitive) {
    let keys = try!(create_keys_from_primitive(prim));

    for key in keys {
      match index_map.get(&key).map(|&i| i) {
        Some(index) => {
          // that triplet already exists; just append the index in the indices buffer
          indices.push(index);
        },
        None => {
          // this is a new, not yet discovered triplet; create the corresponding vertex and add it
          // to the vertices buffer, and map the triplet to the index in the indices buffer
          let vertex = interleave_vertex(&positions[key.0], &normals[key.1], &tvertices[key.2]);
          let index = vertices.len() as u32;

          vertices.push(vertex);
          indices.push(index);
          index_map.insert(key, index);
        }
      }
    }
  }

  Ok((vertices, indices, mode))
}

// Create triplet keys from wavefront_obj primitives. If any primitive doesn’t have all the triplet
// information (position, normal, tex), a ModelError::UnsupportedVertex error is returned instead.
fn create_keys_from_primitive(prim: obj::Primitive) -> Result<Vec<(usize, usize, usize)>, ModelError> {
  match prim {
    obj::Primitive::Point(i) => {
      let a = try!(vtnindex_to_key(i));
      Ok(vec![a])
    },
    obj::Primitive::Line(i, j) => {
      let a = try!(vtnindex_to_key(i));
      let b = try!(vtnindex_to_key(j));
      Ok(vec![a, b])
    },
    obj::Primitive::Triangle(i, j, k) => {
      let a = try!(vtnindex_to_key(i));
      let b = try!(vtnindex_to_key(j));
      let c = try!(vtnindex_to_key(k));
      Ok(vec![a, b, c])
    }
  }
}

// Convert from a wavefront_obj VTNIndex into our triplet, raising error if not possible.
fn vtnindex_to_key(i: obj::VTNIndex) -> Result<(usize, usize, usize), ModelError> {
  match i {
    (pi, Some(ti), Some(ni)) => Ok((pi, ni, ti)),
    _ => Err(ModelError::UnsupportedVertex)
  }
}

fn interleave_vertex(p: &obj::Vertex, n: &obj::Normal, t: &obj::TVertex) -> Vertex {
  (convert_vertex(p), convert_nor(n), convert_tvertex(t))
}

fn convert_vertex(v: &obj::Vertex) -> VertexPos {
  [v.x as f32, v.y as f32, v.z as f32]
}

fn convert_nor(n: &obj::Normal) -> VertexNor {
  convert_vertex(n)
}

fn convert_tvertex(t: &obj::TVertex) -> VertexTexCoord {
  [t.x as f32, t.y as f32]
}

fn guess_mode(prim: obj::Primitive) -> tessellation::Mode {
  match prim {
    obj::Primitive::Point(_) => tessellation::Mode::Point,
    obj::Primitive::Line(_, _) => tessellation::Mode::Line,
    obj::Primitive::Triangle(_, _, _) => tessellation::Mode::Triangle
  }
}

////mod hot {
////  use super::{TessellationError, Vertex};
////
////  use luminance::tessellation;
////  use luminance_gl::gl33;
////  use resource::ResourceManager;
////  use std::ops::Deref;
////  use std::path::{Path, PathBuf};
////
////  pub struct Tessellation {
////    path: PathBuf,
////    mode: tessellation::Mode,
////    tess: gl33::Tessellation
////  }
////
////  impl Tessellation {
////    fn load<P>(manager: &mut ResourceManager, path: P, mode: tessellation::Mode) -> Result<Self, TessellationError> where P: AsRef<Path> {
////      Err(TessellationError::Error)
////    }
////  }
////
////  impl Deref for Tessellation {
////    type Target = gl33::Tessellation;
////
////    fn deref(&self) -> &Self::Target {
////      &self.tess
////    }
////  }
////}

#[derive(Debug)]
pub enum ModelError {
  FileNotFound(PathBuf, String),
  ParseFailed(wavefront_obj::ParseError),
  MultiObjects,
  UnsupportedVertex,
  NoShape
}
<commit_msg>Made some fields of model::* pub. (#9).<commit_after>use luminance::tessellation;
use luminance_gl::gl33::Tessellation;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::Read;
use std::iter::IntoIterator;
use std::path::{Path, PathBuf};
use std::vec;
use wavefront_obj::{self, obj};

// FIXME: implement materials
pub type Material = ();

pub type Vertex = (VertexPos, VertexNor, VertexTexCoord);
pub type VertexPos = [f32; 3];
pub type VertexNor = [f32; 3];
pub type VertexTexCoord = [f32; 2];

pub struct Model<'a> {
  pub parts: Vec<Part<'a>>
}

impl<'a> Model<'a> {
  pub fn from_parts(parts: Vec<Part<'a>>) -> Self {
    Model {
      parts: parts
    }
  }
}

impl<'a> IntoIterator for Model<'a> {
  type Item = Part<'a>;
  type IntoIter = vec::IntoIter<Part<'a>>;

  fn into_iter(self) -> Self::IntoIter {
    self.parts.into_iter()
  }
}

pub struct Part<'a> {
  pub tess: Tessellation,
  pub mat: Option<&'a Material>
}

impl<'a> Part<'a> {
  pub fn new(tess: Tessellation, mat: Option<&'a Material>) -> Self {
    Part {
      tess: tess,
      mat: mat
    }
  }
}

pub fn load<'a, P>(path: P) -> Result<Model<'a>, ModelError> where P: AsRef<Path> {
  let path = path.as_ref();

  info!("loading model: \x1b[35m{:?}", path);

  let mut input = String::new();

  // load the data directly into memory; no buffering nor streaming
  {
    let mut file = try!(File::open(path).map_err(|e| ModelError::FileNotFound(path.to_path_buf(), format!("{:?}", e))));
    let _ = file.read_to_string(&mut input);
  }

  // parse the obj file and convert it
  let obj_set = try!(obj::parse(input).map_err(ModelError::ParseFailed));

  convert_obj(obj_set)
}

// Turn a wavefront obj object into a `Model`
fn convert_obj<'a>(obj_set: obj::ObjSet) -> Result<Model<'a>, ModelError> {
  if obj_set.objects.len() != 1 {
    return Err(ModelError::MultiObjects);
  }

  let obj = &obj_set.objects[0];
  info!("  converting object \x1b[35m{}", obj.name);

  // convert all the geometries
  let mut parts = Vec::with_capacity(obj.geometry.len());

  for geometry in &obj.geometry {
    let (vertices, indices, mode) = try!(convert_geometry(geometry, &obj.vertices, &obj.normals, &obj.tex_vertices));
    let part = Part::new(Tessellation::new(mode, &vertices, Some(&indices)), None); // FIXME: material
    parts.push(part);
  }

  Ok(Model::from_parts(parts))
}

// Convert wavefront_obj’s Geometry into a pair of vertices and indices.
//
// This function will regenerate the indices on the fly based on which are used in the shapes in the
// geometry. It’s used to create independent tessellation.
fn convert_geometry(geo: &obj::Geometry, positions: &[obj::Vertex], normals: &[obj::Normal], tvertices: &[obj::TVertex]) -> Result<(Vec<Vertex>, Vec<u32>, tessellation::Mode), ModelError> {
  if geo.shapes.is_empty() {
    return Err(ModelError::NoShape);
  }

  let mut vertices = Vec::new(); // FIXME: better allocation scheme?
  let mut indices = Vec::new();
  let mut index_map = BTreeMap::new();

  info!("    converting geometry");

  let mode = guess_mode(geo.shapes[0].primitive);

  for prim in geo.shapes.iter().map(|s| s.primitive) {
    let keys = try!(create_keys_from_primitive(prim));

    for key in keys {
      match index_map.get(&key).map(|&i| i) {
        Some(index) => {
          // that triplet already exists; just append the index in the indices buffer
          indices.push(index);
        },
        None => {
          // this is a new, not yet discovered triplet; create the corresponding vertex and add it
          // to the vertices buffer, and map the triplet to the index in the indices buffer
          let vertex = interleave_vertex(&positions[key.0], &normals[key.1], &tvertices[key.2]);
          let index = vertices.len() as u32;

          vertices.push(vertex);
          indices.push(index);
          index_map.insert(key, index);
        }
      }
    }
  }

  Ok((vertices, indices, mode))
}

// Create triplet keys from wavefront_obj primitives. If any primitive doesn’t have all the triplet
// information (position, normal, tex), a ModelError::UnsupportedVertex error is returned instead.
fn create_keys_from_primitive(prim: obj::Primitive) -> Result<Vec<(usize, usize, usize)>, ModelError> {
  match prim {
    obj::Primitive::Point(i) => {
      let a = try!(vtnindex_to_key(i));
      Ok(vec![a])
    },
    obj::Primitive::Line(i, j) => {
      let a = try!(vtnindex_to_key(i));
      let b = try!(vtnindex_to_key(j));
      Ok(vec![a, b])
    },
    obj::Primitive::Triangle(i, j, k) => {
      let a = try!(vtnindex_to_key(i));
      let b = try!(vtnindex_to_key(j));
      let c = try!(vtnindex_to_key(k));
      Ok(vec![a, b, c])
    }
  }
}

// Convert from a wavefront_obj VTNIndex into our triplet, raising error if not possible.
fn vtnindex_to_key(i: obj::VTNIndex) -> Result<(usize, usize, usize), ModelError> {
  match i {
    (pi, Some(ti), Some(ni)) => Ok((pi, ni, ti)),
    _ => Err(ModelError::UnsupportedVertex)
  }
}

fn interleave_vertex(p: &obj::Vertex, n: &obj::Normal, t: &obj::TVertex) -> Vertex {
  (convert_vertex(p), convert_nor(n), convert_tvertex(t))
}

fn convert_vertex(v: &obj::Vertex) -> VertexPos {
  [v.x as f32, v.y as f32, v.z as f32]
}

fn convert_nor(n: &obj::Normal) -> VertexNor {
  convert_vertex(n)
}

fn convert_tvertex(t: &obj::TVertex) -> VertexTexCoord {
  [t.x as f32, t.y as f32]
}

fn guess_mode(prim: obj::Primitive) -> tessellation::Mode {
  match prim {
    obj::Primitive::Point(_) => tessellation::Mode::Point,
    obj::Primitive::Line(_, _) => tessellation::Mode::Line,
    obj::Primitive::Triangle(_, _, _) => tessellation::Mode::Triangle
  }
}

////mod hot {
////  use super::{TessellationError, Vertex};
////
////  use luminance::tessellation;
////  use luminance_gl::gl33;
////  use resource::ResourceManager;
////  use std::ops::Deref;
////  use std::path::{Path, PathBuf};
////
////  pub struct Tessellation {
////    path: PathBuf,
////    mode: tessellation::Mode,
////    tess: gl33::Tessellation
////  }
////
////  impl Tessellation {
////    fn load<P>(manager: &mut ResourceManager, path: P, mode: tessellation::Mode) -> Result<Self, TessellationError> where P: AsRef<Path> {
////      Err(TessellationError::Error)
////    }
////  }
////
////  impl Deref for Tessellation {
////    type Target = gl33::Tessellation;
////
////    fn deref(&self) -> &Self::Target {
////      &self.tess
////    }
////  }
////}

#[derive(Debug)]
pub enum ModelError {
  FileNotFound(PathBuf, String),
  ParseFailed(wavefront_obj::ParseError),
  MultiObjects,
  UnsupportedVertex,
  NoShape
}
<|endoftext|>


<commit_before>mod testdata;
use testdata::{
    newton,
    generate_data,
    NEWTON_ITER,
    SETLEN
};

use std::time::SystemTime;
use std::thread;
use std::thread::JoinHandle;
use std::iter::Map;
use std::slice::Chunks;
use std::sync::Arc;
use std::boxed::Box;
use std::sync::Mutex;

const THREADS: usize = 4;

fn main() {
    let data = generate_data(SETLEN);
    println!("generiere {} testdaten", SETLEN);
    let earlier = SystemTime::now();
    let _ = map_data(data);
    let dur = match SystemTime::now().duration_since(earlier) {
        Ok(v) => v,
        Err(e) => {
            println!("messfehler: {}", e);
            return;
        }
    };
    println!("duration: {}.{} secs", dur.as_secs(), dur.subsec_nanos());
}

fn map_data(data: Vec<f64>) -> Vec<f64> {
    let mut handles:Vec<JoinHandle<Vec<f64>>> = Vec::new();
    let mut data = data.chunks(data.len()/THREADS + 1).
                                        map(|x| Arc::new(x.to_owned()));
    for d in data {
        handles.push(thread::spawn(move || d.iter().map(|x| newton(*x, NEWTON_ITER)).collect()));
    }
    handles.into_iter().flat_map(|x| x.join().unwrap()).collect()
}
<commit_msg>Format pmap2<commit_after>mod testdata;
use testdata::{
    newton,
    generate_data,
    NEWTON_ITER,
    SETLEN
};

use std::time::SystemTime;
use std::thread;
use std::thread::JoinHandle;
use std::sync::Arc;

const THREADS: usize = 4;

fn main() {
    let data = generate_data(SETLEN);
    println!("generiere {} testdaten", SETLEN);
    let earlier = SystemTime::now();
    let _ = map_data(data);
    let dur = match SystemTime::now().duration_since(earlier) {
        Ok(v) => v,
        Err(e) => {
            println!("messfehler: {}", e);
            return;
        }
    };
    println!("duration: {}.{} secs", dur.as_secs(), dur.subsec_nanos());
}

fn map_data(data: Vec<f64>) -> Vec<f64> {
    let mut handles: Vec<JoinHandle<Vec<f64>>> = Vec::new();
    let chunk_len = data.len()/THREADS + 1;
    let chunks = data.chunks(chunk_len).map(|x| Arc::new(x.to_owned()));
    for chunk in chunks {
        handles.push(thread::spawn(move || chunk.iter().map(|x| newton(*x, NEWTON_ITER)).collect()));
    }
    handles.into_iter().flat_map(|x| x.join().unwrap()).collect()
}
<|endoftext|>