<commit_before>use std::collections::HashMap;
use std::str::FromStr;
use core::{Instruction, Program};
use core::Instruction::*;

/// An error which can be returned when parsing a TIS-100 program.
#[derive(Debug, PartialEq)]
pub enum ParseProgramError<'a> {
    InvalidSyntax(&'a str),
    UndefinedLabel(&'a str),
    DuplicateLabel(&'a str),
    InvalidOpcode(&'a str),
    InvalidExpression(&'a str),
    InvalidInstruction(&'a str, &'a str, &'a str),
}

use self::ParseProgramError::*;

/// The list of errors encountered while parsing the program source code.
pub type ErrorList<'a> = Vec<ParseProgramError<'a>>;

type ParseResult<'a, T> = Result<T, ParseProgramError<'a>>;

/// Parse the program source code into a list of instructions. If one or more errors are
/// encountered during parsing, then the list of errors will be returned instead.
///
/// Example:
///
/// ```
/// use tis_100::core::*;
/// use tis_100::core::Instruction::*;
/// use tis_100::core::Source::*;
/// use tis_100::core::Register::*;
/// use tis_100::core::IoRegister::*;
/// use tis_100::core::Port::*;
/// use tis_100::parse::parse_program;
///
/// let src = "MOV UP ACC\n
///            ADD 1\n
///            MOV ACC DOWN\n";
/// let prog = parse_program(src).unwrap();
/// assert_eq!(prog[0], Mov(Reg(Io(Dir(Up))), Acc));
/// assert_eq!(prog[1], Add(Val(1)));
/// assert_eq!(prog[2], Mov(Reg(Acc), Io(Dir(Down))));
/// ```
pub fn parse_program<'a>(source: &'a str) -> Result<Program, ErrorList<'a>> {
    // The basic parsing strategy is:
    // 1. Tokenize the input using a regex.
    // 2. Store the location of each label.
    // 3. Parse each instruction and resolve labels.

    let re = regex!(r"^,* *(?:(\w+):)?,* *(?:(\w+))?,* *(?:(\w+))?,* *(?:(\w+))?,* *(?:#.*)?$");

    let mut line_captures = Vec::new();
    let mut errors = Vec::new();
    let mut labels = HashMap::new();
    let mut instructions = Vec::new();

    // Label pass
    let mut next_idx = 0;
    for line in source.lines() {
        if let Some(captures) = re.captures(line) {
            if let Some(label) = captures.at(1) {
                if let None = labels.get(label) {
                    labels.insert(label, next_idx);
                } else {
                    errors.push(DuplicateLabel(label));
                }
            }

            // If we find an opcode, then increment the next index that the next label should
            // refer to.
            if let Some(_) = captures.at(2) {
                next_idx += 1;
            }

            line_captures.push(captures);
        } else {
            errors.push(InvalidSyntax(line));
        }
    }

    // Instruction pass
    for captures in line_captures.iter() {
        if let Some(opcode) = captures.at(2) {
            let operand1 = captures.at(3).unwrap_or("");
            let operand2 = captures.at(4).unwrap_or("");

            match parse_instruction(opcode, operand1, operand2, &labels) {
                Ok(instruction) => instructions.push(instruction),
                Err(error) => errors.push(error),
            };
        }
    }

    if errors.len() > 0 {
        Err(errors)
    } else {
        Ok(instructions)
    }
}

/// Attempt to parse an instruction given an opcode, two operands, and a map of labels.
fn parse_instruction<'a>(opcode: &'a str, operand1: &'a str, operand2: &'a str, labels: &HashMap<&'a str, usize>) -> ParseResult<'a, Instruction> {
    let num_ops = count_operands(operand1, operand2);
    match str::parse::<Opcode>(opcode) {
        Ok(code) => {
            match code {
                Opcode::Nop if num_ops == 0 => Ok(Nop),
                Opcode::Mov if num_ops == 2 => parse_two_operands(operand1, operand2).and_then(|(op1, op2)| { Ok(Mov(op1, op2)) }),
                Opcode::Swp if num_ops == 0 => Ok(Swp),
                Opcode::Sav if num_ops == 0 => Ok(Sav),
                Opcode::Add if num_ops == 1 => parse_one_operand(operand1).and_then(|op| { Ok(Add(op)) }),
                Opcode::Sub if num_ops == 1 => parse_one_operand(operand1).and_then(|op| { Ok(Sub(op)) }),
                Opcode::Neg if num_ops == 0 => Ok(Neg),
                Opcode::Jmp if num_ops == 1 => resolve_jump_label(operand1, labels, Jmp),
                Opcode::Jez if num_ops == 1 => resolve_jump_label(operand1, labels, Jez),
                Opcode::Jnz if num_ops == 1 => resolve_jump_label(operand1, labels, Jnz),
                Opcode::Jgz if num_ops == 1 => resolve_jump_label(operand1, labels, Jgz),
                Opcode::Jlz if num_ops == 1 => resolve_jump_label(operand1, labels, Jlz),
                Opcode::Jro if num_ops == 1 => parse_one_operand(operand1).and_then(|op| { Ok(Jro(op)) }),
                _ => Err(InvalidInstruction(opcode, operand1, operand2)),
            }
        },
        Err(_) => Err(InvalidOpcode(opcode)),
    }
}

/// A helper function to count the number of operands.
fn count_operands(op1: &str, op2: &str) -> usize {
    let mut num_ops = 0;

    if op1.len() > 0 {
        num_ops += 1;
    }

    if op2.len() > 0 {
        num_ops += 1;
    }

    return num_ops;
}

/// Look up the index for a label and create a jump instruction if the label is found.
fn resolve_jump_label<'a, F: Fn(usize) -> Instruction>(label: &'a str, labels: &HashMap<&str, usize>, f: F) -> ParseResult<'a, Instruction> {
    labels.get(label)
        .ok_or(UndefinedLabel(label))
        .map(|&i| { f(i) })
}

/// Attempt to parse an operand from a string.
fn parse_one_operand<'a, T: FromStr>(operand: &'a str) -> ParseResult<'a, T> {
    match str::parse::<T>(operand) {
        Ok(op) => Ok(op),
        Err(_) => Err(InvalidExpression(operand)),
    }
}

/// Attempt to parse two operands from a string.
fn parse_two_operands<'a, T: FromStr, U: FromStr>(operand1: &'a str, operand2: &'a str) -> ParseResult<'a, (T, U)> {
    match str::parse::<T>(operand1) {
        Ok(op1) => {
            match str::parse::<U>(operand2) {
                Ok(op2) => Ok((op1, op2)),
                Err(_) => Err(InvalidExpression(operand2)),
            }
        },
        Err(_) => Err(InvalidExpression(operand1)),
    }
}

/// The opcode component of a TIS-100 instruction.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Opcode {
    Nop,
    Mov,
    Swp,
    Sav,
    Add,
    Sub,
    Neg,
    Jmp,
    Jez,
    Jnz,
    Jgz,
    Jlz,
    Jro,
}

/// An error which can be returned when parsing an opcode.
#[derive(Debug, PartialEq)]
pub struct ParseOpcodeError;

impl FromStr for Opcode {
    type Err = ParseOpcodeError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_uppercase().as_str() {
            "NOP" => Ok(Opcode::Nop),
            "MOV" => Ok(Opcode::Mov),
            "SWP" => Ok(Opcode::Swp),
            "SAV" => Ok(Opcode::Sav),
            "ADD" => Ok(Opcode::Add),
            "SUB" => Ok(Opcode::Sub),
            "NEG" => Ok(Opcode::Neg),
            "JMP" => Ok(Opcode::Jmp),
            "JEZ" => Ok(Opcode::Jez),
            "JNZ" => Ok(Opcode::Jnz),
            "JGZ" => Ok(Opcode::Jgz),
            "JLZ" => Ok(Opcode::Jlz),
            "JRO" => Ok(Opcode::Jro),
            _ => Err(ParseOpcodeError),
        }
    }
}

#[test]
fn test_parse_opcode() {
    assert_eq!(str::parse::<Opcode>("NOP"), Ok(Opcode::Nop));
    assert_eq!(str::parse::<Opcode>("nop"), Ok(Opcode::Nop));
    assert_eq!(str::parse::<Opcode>("MOV"), Ok(Opcode::Mov));
    assert_eq!(str::parse::<Opcode>("SWP"), Ok(Opcode::Swp));
    assert_eq!(str::parse::<Opcode>("SAV"), Ok(Opcode::Sav));
    assert_eq!(str::parse::<Opcode>("ADD"), Ok(Opcode::Add));
    assert_eq!(str::parse::<Opcode>("SUB"), Ok(Opcode::Sub));
    assert_eq!(str::parse::<Opcode>("NEG"), Ok(Opcode::Neg));
    assert_eq!(str::parse::<Opcode>("JMP"), Ok(Opcode::Jmp));
    assert_eq!(str::parse::<Opcode>("JEZ"), Ok(Opcode::Jez));
    assert_eq!(str::parse::<Opcode>("JNZ"), Ok(Opcode::Jnz));
    assert_eq!(str::parse::<Opcode>("JGZ"), Ok(Opcode::Jgz));
    assert_eq!(str::parse::<Opcode>("JLZ"), Ok(Opcode::Jlz));
    assert_eq!(str::parse::<Opcode>("JRO"), Ok(Opcode::Jro));
    assert_eq!(str::parse::<Opcode>("bad"), Err(ParseOpcodeError));
}

#[test]
fn test_parse_one_operand() {
    use core::{Register, Source};

    assert_eq!(parse_one_operand("ACC"), Ok(Source::Reg(Register::Acc)));
    assert_eq!(parse_one_operand::<Source>("bad"), Err(InvalidExpression("bad")));
}

#[test]
fn test_parse_two_operands() {
    use core::{Register, Source};

    assert_eq!(parse_two_operands("1", "ACC"), Ok((Source::Val(1), Source::Reg(Register::Acc))));
    assert_eq!(parse_two_operands::<Source, Register>("1", "bad"), Err(InvalidExpression("bad")));
    assert_eq!(parse_two_operands::<Source, Register>("bad", "bad"), Err(InvalidExpression("bad")));
}

#[test]
fn test_resolve_jump_label() {
    let mut labels = HashMap::new();
    labels.insert("good", 1);

    assert_eq!(resolve_jump_label("good", &labels, Jmp), Ok(Jmp(1)));
    assert_eq!(resolve_jump_label("bad", &labels, Jmp), Err(UndefinedLabel("bad")));
}

#[test]
fn test_count_operands() {
    assert_eq!(count_operands("", ""), 0);
    assert_eq!(count_operands("ACC", ""), 1);
    assert_eq!(count_operands("ACC", "BAK"), 2);
}

#[test]
fn test_parse_instruction() {
    use core::Source::*;
    use core::Register::*;

    let mut labels = HashMap::new();
    labels.insert("TEST", 0);

    assert_eq!(parse_instruction("BAD", "", "", &labels), Err(InvalidOpcode("BAD")));

    assert_eq!(parse_instruction("NOP", "", "", &labels), Ok(Nop));
    assert_eq!(parse_instruction("NOP", "bad", "", &labels), Err(InvalidInstruction("NOP", "bad", "")));

    assert_eq!(parse_instruction("MOV", "1", "ACC", &labels), Ok(Mov(Val(1), Acc)));
    assert_eq!(parse_instruction("MOV", "", "", &labels), Err(InvalidInstruction("MOV", "", "")));

    assert_eq!(parse_instruction("SWP", "", "", &labels), Ok(Swp));
    assert_eq!(parse_instruction("SWP", "bad", "", &labels), Err(InvalidInstruction("SWP", "bad", "")));

    assert_eq!(parse_instruction("SAV", "", "", &labels), Ok(Sav));
    assert_eq!(parse_instruction("SAV", "bad", "", &labels), Err(InvalidInstruction("SAV", "bad", "")));

    assert_eq!(parse_instruction("ADD", "1", "", &labels), Ok(Add(Val(1))));
    assert_eq!(parse_instruction("ADD", "", "", &labels), Err(InvalidInstruction("ADD", "", "")));

    assert_eq!(parse_instruction("SUB", "1", "", &labels), Ok(Sub(Val(1))));
    assert_eq!(parse_instruction("SUB", "", "", &labels), Err(InvalidInstruction("SUB", "", "")));

    assert_eq!(parse_instruction("NEG", "", "", &labels), Ok(Neg));
    assert_eq!(parse_instruction("NEG", "bad", "", &labels), Err(InvalidInstruction("NEG", "bad", "")));

    assert_eq!(parse_instruction("JMP", "TEST", "", &labels), Ok(Jmp(0)));
    assert_eq!(parse_instruction("JMP", "", "", &labels), Err(InvalidInstruction("JMP", "", "")));
    assert_eq!(parse_instruction("JMP", "BAD", "", &labels), Err(UndefinedLabel("BAD")));

    assert_eq!(parse_instruction("JEZ", "TEST", "", &labels), Ok(Jez(0)));
    assert_eq!(parse_instruction("JEZ", "", "", &labels), Err(InvalidInstruction("JEZ", "", "")));
    assert_eq!(parse_instruction("JEZ", "BAD", "", &labels), Err(UndefinedLabel("BAD")));

    assert_eq!(parse_instruction("JNZ", "TEST", "", &labels), Ok(Jnz(0)));
    assert_eq!(parse_instruction("JNZ", "", "", &labels), Err(InvalidInstruction("JNZ", "", "")));
    assert_eq!(parse_instruction("JNZ", "BAD", "", &labels), Err(UndefinedLabel("BAD")));

    assert_eq!(parse_instruction("JGZ", "TEST", "", &labels), Ok(Jgz(0)));
    assert_eq!(parse_instruction("JGZ", "", "", &labels), Err(InvalidInstruction("JGZ", "", "")));
    assert_eq!(parse_instruction("JGZ", "BAD", "", &labels), Err(UndefinedLabel("BAD")));

    assert_eq!(parse_instruction("JLZ", "TEST", "", &labels), Ok(Jlz(0)));
    assert_eq!(parse_instruction("JLZ", "", "", &labels), Err(InvalidInstruction("JLZ", "", "")));
    assert_eq!(parse_instruction("JLZ", "BAD", "", &labels), Err(UndefinedLabel("BAD")));

    assert_eq!(parse_instruction("JRO", "-1", "", &labels), Ok(Jro(Val(-1))));
    assert_eq!(parse_instruction("JRO", "ACC", "", &labels), Ok(Jro(Reg(Acc))));
    assert_eq!(parse_instruction("JRO", "", "", &labels), Err(InvalidInstruction("JRO", "", "")));
}
<commit_msg>Clean up doc test<commit_after>use std::collections::HashMap;
use std::str::FromStr;
use core::{Instruction, Program};
use core::Instruction::*;

/// An error which can be returned when parsing a TIS-100 program.
#[derive(Debug, PartialEq)]
pub enum ParseProgramError<'a> {
    InvalidSyntax(&'a str),
    UndefinedLabel(&'a str),
    DuplicateLabel(&'a str),
    InvalidOpcode(&'a str),
    InvalidExpression(&'a str),
    InvalidInstruction(&'a str, &'a str, &'a str),
}

use self::ParseProgramError::*;

/// The list of errors encountered while parsing the program source code.
pub type ErrorList<'a> = Vec<ParseProgramError<'a>>;

type ParseResult<'a, T> = Result<T, ParseProgramError<'a>>;

/// Parse the program source code into a list of instructions. If one or more errors are
/// encountered during parsing, then the list of errors will be returned instead.
///
/// Example:
///
/// ```
/// use tis_100::core::Instruction::*;
/// use tis_100::core::Source::*;
/// use tis_100::core::Register::*;
/// use tis_100::core::IoRegister::*;
/// use tis_100::core::Port::*;
/// use tis_100::parse::parse_program;
///
/// let src = "MOV UP ACC\n
///            ADD 1\n
///            MOV ACC DOWN\n";
/// let prog = parse_program(src).unwrap();
/// assert_eq!(prog[0], Mov(Reg(Io(Dir(Up))), Acc));
/// assert_eq!(prog[1], Add(Val(1)));
/// assert_eq!(prog[2], Mov(Reg(Acc), Io(Dir(Down))));
/// ```
pub fn parse_program<'a>(source: &'a str) -> Result<Program, ErrorList<'a>> {
    // The basic parsing strategy is:
    // 1. Tokenize the input using a regex.
    // 2. Store the location of each label.
    // 3. Parse each instruction and resolve labels.

    let re = regex!(r"^,* *(?:(\w+):)?,* *(?:(\w+))?,* *(?:(\w+))?,* *(?:(\w+))?,* *(?:#.*)?$");

    let mut line_captures = Vec::new();
    let mut errors = Vec::new();
    let mut labels = HashMap::new();
    let mut instructions = Vec::new();

    // Label pass
    let mut next_idx = 0;
    for line in source.lines() {
        if let Some(captures) = re.captures(line) {
            if let Some(label) = captures.at(1) {
                if let None = labels.get(label) {
                    labels.insert(label, next_idx);
                } else {
                    errors.push(DuplicateLabel(label));
                }
            }

            // If we find an opcode, then increment the next index that the next label should
            // refer to.
            if let Some(_) = captures.at(2) {
                next_idx += 1;
            }

            line_captures.push(captures);
        } else {
            errors.push(InvalidSyntax(line));
        }
    }

    // Instruction pass
    for captures in line_captures.iter() {
        if let Some(opcode) = captures.at(2) {
            let operand1 = captures.at(3).unwrap_or("");
            let operand2 = captures.at(4).unwrap_or("");

            match parse_instruction(opcode, operand1, operand2, &labels) {
                Ok(instruction) => instructions.push(instruction),
                Err(error) => errors.push(error),
            };
        }
    }

    if errors.len() > 0 {
        Err(errors)
    } else {
        Ok(instructions)
    }
}

/// Attempt to parse an instruction given an opcode, two operands, and a map of labels.
fn parse_instruction<'a>(opcode: &'a str, operand1: &'a str, operand2: &'a str, labels: &HashMap<&'a str, usize>) -> ParseResult<'a, Instruction> {
    let num_ops = count_operands(operand1, operand2);
    match str::parse::<Opcode>(opcode) {
        Ok(code) => {
            match code {
                Opcode::Nop if num_ops == 0 => Ok(Nop),
                Opcode::Mov if num_ops == 2 => parse_two_operands(operand1, operand2).and_then(|(op1, op2)| { Ok(Mov(op1, op2)) }),
                Opcode::Swp if num_ops == 0 => Ok(Swp),
                Opcode::Sav if num_ops == 0 => Ok(Sav),
                Opcode::Add if num_ops == 1 => parse_one_operand(operand1).and_then(|op| { Ok(Add(op)) }),
                Opcode::Sub if num_ops == 1 => parse_one_operand(operand1).and_then(|op| { Ok(Sub(op)) }),
                Opcode::Neg if num_ops == 0 => Ok(Neg),
                Opcode::Jmp if num_ops == 1 => resolve_jump_label(operand1, labels, Jmp),
                Opcode::Jez if num_ops == 1 => resolve_jump_label(operand1, labels, Jez),
                Opcode::Jnz if num_ops == 1 => resolve_jump_label(operand1, labels, Jnz),
                Opcode::Jgz if num_ops == 1 => resolve_jump_label(operand1, labels, Jgz),
                Opcode::Jlz if num_ops == 1 => resolve_jump_label(operand1, labels, Jlz),
                Opcode::Jro if num_ops == 1 => parse_one_operand(operand1).and_then(|op| { Ok(Jro(op)) }),
                _ => Err(InvalidInstruction(opcode, operand1, operand2)),
            }
        },
        Err(_) => Err(InvalidOpcode(opcode)),
    }
}

/// A helper function to count the number of operands.
fn count_operands(op1: &str, op2: &str) -> usize {
    let mut num_ops = 0;

    if op1.len() > 0 {
        num_ops += 1;
    }

    if op2.len() > 0 {
        num_ops += 1;
    }

    return num_ops;
}

/// Look up the index for a label and create a jump instruction if the label is found.
fn resolve_jump_label<'a, F: Fn(usize) -> Instruction>(label: &'a str, labels: &HashMap<&str, usize>, f: F) -> ParseResult<'a, Instruction> {
    labels.get(label)
        .ok_or(UndefinedLabel(label))
        .map(|&i| { f(i) })
}

/// Attempt to parse an operand from a string.
fn parse_one_operand<'a, T: FromStr>(operand: &'a str) -> ParseResult<'a, T> {
    match str::parse::<T>(operand) {
        Ok(op) => Ok(op),
        Err(_) => Err(InvalidExpression(operand)),
    }
}

/// Attempt to parse two operands from a string.
fn parse_two_operands<'a, T: FromStr, U: FromStr>(operand1: &'a str, operand2: &'a str) -> ParseResult<'a, (T, U)> {
    match str::parse::<T>(operand1) {
        Ok(op1) => {
            match str::parse::<U>(operand2) {
                Ok(op2) => Ok((op1, op2)),
                Err(_) => Err(InvalidExpression(operand2)),
            }
        },
        Err(_) => Err(InvalidExpression(operand1)),
    }
}

/// The opcode component of a TIS-100 instruction.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Opcode {
    Nop,
    Mov,
    Swp,
    Sav,
    Add,
    Sub,
    Neg,
    Jmp,
    Jez,
    Jnz,
    Jgz,
    Jlz,
    Jro,
}

/// An error which can be returned when parsing an opcode.
#[derive(Debug, PartialEq)]
pub struct ParseOpcodeError;

impl FromStr for Opcode {
    type Err = ParseOpcodeError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_uppercase().as_str() {
            "NOP" => Ok(Opcode::Nop),
            "MOV" => Ok(Opcode::Mov),
            "SWP" => Ok(Opcode::Swp),
            "SAV" => Ok(Opcode::Sav),
            "ADD" => Ok(Opcode::Add),
            "SUB" => Ok(Opcode::Sub),
            "NEG" => Ok(Opcode::Neg),
            "JMP" => Ok(Opcode::Jmp),
            "JEZ" => Ok(Opcode::Jez),
            "JNZ" => Ok(Opcode::Jnz),
            "JGZ" => Ok(Opcode::Jgz),
            "JLZ" => Ok(Opcode::Jlz),
            "JRO" => Ok(Opcode::Jro),
            _ => Err(ParseOpcodeError),
        }
    }
}

#[test]
fn test_parse_opcode() {
    assert_eq!(str::parse::<Opcode>("NOP"), Ok(Opcode::Nop));
    assert_eq!(str::parse::<Opcode>("nop"), Ok(Opcode::Nop));
    assert_eq!(str::parse::<Opcode>("MOV"), Ok(Opcode::Mov));
    assert_eq!(str::parse::<Opcode>("SWP"), Ok(Opcode::Swp));
    assert_eq!(str::parse::<Opcode>("SAV"), Ok(Opcode::Sav));
    assert_eq!(str::parse::<Opcode>("ADD"), Ok(Opcode::Add));
    assert_eq!(str::parse::<Opcode>("SUB"), Ok(Opcode::Sub));
    assert_eq!(str::parse::<Opcode>("NEG"), Ok(Opcode::Neg));
    assert_eq!(str::parse::<Opcode>("JMP"), Ok(Opcode::Jmp));
    assert_eq!(str::parse::<Opcode>("JEZ"), Ok(Opcode::Jez));
    assert_eq!(str::parse::<Opcode>("JNZ"), Ok(Opcode::Jnz));
    assert_eq!(str::parse::<Opcode>("JGZ"), Ok(Opcode::Jgz));
    assert_eq!(str::parse::<Opcode>("JLZ"), Ok(Opcode::Jlz));
    assert_eq!(str::parse::<Opcode>("JRO"), Ok(Opcode::Jro));
    assert_eq!(str::parse::<Opcode>("bad"), Err(ParseOpcodeError));
}

#[test]
fn test_parse_one_operand() {
    use core::{Register, Source};

    assert_eq!(parse_one_operand("ACC"), Ok(Source::Reg(Register::Acc)));
    assert_eq!(parse_one_operand::<Source>("bad"), Err(InvalidExpression("bad")));
}

#[test]
fn test_parse_two_operands() {
    use core::{Register, Source};

    assert_eq!(parse_two_operands("1", "ACC"), Ok((Source::Val(1), Source::Reg(Register::Acc))));
    assert_eq!(parse_two_operands::<Source, Register>("1", "bad"), Err(InvalidExpression("bad")));
    assert_eq!(parse_two_operands::<Source, Register>("bad", "bad"), Err(InvalidExpression("bad")));
}

#[test]
fn test_resolve_jump_label() {
    let mut labels = HashMap::new();
    labels.insert("good", 1);

    assert_eq!(resolve_jump_label("good", &labels, Jmp), Ok(Jmp(1)));
    assert_eq!(resolve_jump_label("bad", &labels, Jmp), Err(UndefinedLabel("bad")));
}

#[test]
fn test_count_operands() {
    assert_eq!(count_operands("", ""), 0);
    assert_eq!(count_operands("ACC", ""), 1);
    assert_eq!(count_operands("ACC", "BAK"), 2);
}

#[test]
fn test_parse_instruction() {
    use core::Source::*;
    use core::Register::*;

    let mut labels = HashMap::new();
    labels.insert("TEST", 0);

    assert_eq!(parse_instruction("BAD", "", "", &labels), Err(InvalidOpcode("BAD")));

    assert_eq!(parse_instruction("NOP", "", "", &labels), Ok(Nop));
    assert_eq!(parse_instruction("NOP", "bad", "", &labels), Err(InvalidInstruction("NOP", "bad", "")));

    assert_eq!(parse_instruction("MOV", "1", "ACC", &labels), Ok(Mov(Val(1), Acc)));
    assert_eq!(parse_instruction("MOV", "", "", &labels), Err(InvalidInstruction("MOV", "", "")));

    assert_eq!(parse_instruction("SWP", "", "", &labels), Ok(Swp));
    assert_eq!(parse_instruction("SWP", "bad", "", &labels), Err(InvalidInstruction("SWP", "bad", "")));

    assert_eq!(parse_instruction("SAV", "", "", &labels), Ok(Sav));
    assert_eq!(parse_instruction("SAV", "bad", "", &labels), Err(InvalidInstruction("SAV", "bad", "")));

    assert_eq!(parse_instruction("ADD", "1", "", &labels), Ok(Add(Val(1))));
    assert_eq!(parse_instruction("ADD", "", "", &labels), Err(InvalidInstruction("ADD", "", "")));

    assert_eq!(parse_instruction("SUB", "1", "", &labels), Ok(Sub(Val(1))));
    assert_eq!(parse_instruction("SUB", "", "", &labels), Err(InvalidInstruction("SUB", "", "")));

    assert_eq!(parse_instruction("NEG", "", "", &labels), Ok(Neg));
    assert_eq!(parse_instruction("NEG", "bad", "", &labels), Err(InvalidInstruction("NEG", "bad", "")));

    assert_eq!(parse_instruction("JMP", "TEST", "", &labels), Ok(Jmp(0)));
    assert_eq!(parse_instruction("JMP", "", "", &labels), Err(InvalidInstruction("JMP", "", "")));
    assert_eq!(parse_instruction("JMP", "BAD", "", &labels), Err(UndefinedLabel("BAD")));

    assert_eq!(parse_instruction("JEZ", "TEST", "", &labels), Ok(Jez(0)));
    assert_eq!(parse_instruction("JEZ", "", "", &labels), Err(InvalidInstruction("JEZ", "", "")));
    assert_eq!(parse_instruction("JEZ", "BAD", "", &labels), Err(UndefinedLabel("BAD")));

    assert_eq!(parse_instruction("JNZ", "TEST", "", &labels), Ok(Jnz(0)));
    assert_eq!(parse_instruction("JNZ", "", "", &labels), Err(InvalidInstruction("JNZ", "", "")));
    assert_eq!(parse_instruction("JNZ", "BAD", "", &labels), Err(UndefinedLabel("BAD")));

    assert_eq!(parse_instruction("JGZ", "TEST", "", &labels), Ok(Jgz(0)));
    assert_eq!(parse_instruction("JGZ", "", "", &labels), Err(InvalidInstruction("JGZ", "", "")));
    assert_eq!(parse_instruction("JGZ", "BAD", "", &labels), Err(UndefinedLabel("BAD")));

    assert_eq!(parse_instruction("JLZ", "TEST", "", &labels), Ok(Jlz(0)));
    assert_eq!(parse_instruction("JLZ", "", "", &labels), Err(InvalidInstruction("JLZ", "", "")));
    assert_eq!(parse_instruction("JLZ", "BAD", "", &labels), Err(UndefinedLabel("BAD")));

    assert_eq!(parse_instruction("JRO", "-1", "", &labels), Ok(Jro(Val(-1))));
    assert_eq!(parse_instruction("JRO", "ACC", "", &labels), Ok(Jro(Reg(Acc))));
    assert_eq!(parse_instruction("JRO", "", "", &labels), Err(InvalidInstruction("JRO", "", "")));
}
<|endoftext|>


<commit_before>use syntax::{ast, codemap};
use syntax::ext::base;
use syntax::parse::token;

use syntax::ptr::P;
use syntax::parse::parser::Parser;

use test::Test;
use bench::Bench;
use describe::{DescribeState, SubBlock};

/// Trait that means something can be parsed with a configuration.
pub trait Parse<Cfg> {
    /// Parse Self from a Parser and a configuration object.
    fn parse(&mut Parser, Cfg) -> Self;
}

impl Parse<bool> for Test {
    fn parse(parser: &mut Parser, failing: bool) -> Test {
        // Description of this test.
        let (description, _) = parser.parse_str().ok().unwrap();

        Test {
            // Get as a String
            description: description.to_string(),

            // The associated block
            block: parser.parse_block().ok().unwrap(),

            failing: failing
        }
    }
}

impl Parse<()> for Bench {
    fn parse(parser: &mut Parser, _: ()) -> Bench {
        // Description of this benchmark
        let (description, _) = parser.parse_str().ok().unwrap();

        let name = match (parser.bump_and_get().ok().unwrap(), parser.parse_ident().ok().unwrap(), parser.bump_and_get().ok().unwrap()) {
            (token::OpenDelim(token::Paren), ident, token::CloseDelim(token::Paren)) => { ident },

            (one, two, three) => {
                panic!("{}", parser.fatal(&format!("Expected `($ident)`, found {:?}{:?}{:?}", one, two, three)));
            }
        };

        Bench {
            description: description.to_string(),
            block: parser.parse_block().ok().unwrap(),
            bench: P(name)
        }
    }
}

const BEFORE_EACH: &'static str = "before_each";
const GIVEN:       &'static str = "given";
const AFTER_EACH:  &'static str = "after_each";
const THEN:        &'static str = "then";
const BEFORE:      &'static str = "before";
const AFTER:       &'static str = "after";
const IT:          &'static str = "it";
const WHEN:        &'static str = "when";
const DESCRIBE:    &'static str = "describe";
const FAILING:     &'static str = "failing";
const BENCH:       &'static str = "bench";

impl<'a, 'b> Parse<(codemap::Span, &'a mut base::ExtCtxt<'b>, Option<ast::Ident>)> for DescribeState {
    fn parse(parser: &mut Parser,
             (sp, cx, name): (codemap::Span, &'a mut base::ExtCtxt, Option<ast::Ident>)) -> DescribeState {
        let mut state = DescribeState {
            name: None, before: None, after: None,
            before_each: None, after_each: None, subblocks: vec![]
        };

        state.name = match name {
            // Top-level describe block.
            Some(name) => Some(name),
            // Nested describe block.
            None => {
                // Get the name of this describe block
                let name = parser.parse_ident().ok().unwrap();
                // Move past the opening {
                try(parser, token::OpenDelim(token::Brace), "{ after the name of a describe! block");
                Some(name)
            }
        };

        // Now parse all tests and subsections:
        while parser.token != token::CloseDelim(token::Brace) && parser.token != token::Eof {
            // Get the name of this block, must be either:
            //     - before_each
            //     - after_each
            //     - before
            //     - after
            //     - it
            //     - failing
            //     - bench
            //     - describe!
            //
            // Any other top-level idents are not allowed.
            let block_name = parser.parse_ident().ok().unwrap().name;

            match &*block_name.as_str() {
                BEFORE_EACH | GIVEN => {
                    if state.before_each.is_some() {
                        panic!("{}", parser.fatal("Only one `before_each` block is allowed per `describe!` block."));
                    }
                    state.before_each = Some(parser.parse_block().ok().unwrap());
                },

                AFTER_EACH | THEN => {
                    if state.after_each.is_some() {
                        panic!("{}", parser.fatal("Only one `after_each` block is allowed per `describe!` block."));
                    }
                    state.after_each = Some(parser.parse_block().ok().unwrap());
                },

                BEFORE => {
                    if state.before.is_some() {
                        panic!("{}", parser.fatal("Only one `before` block is allowed per `describe!` block."));
                    }
                    state.before = Some(parser.parse_block().ok().unwrap());
                },

                AFTER => {
                    if state.after.is_some() {
                        panic!("{}", parser.fatal("Only one `after` block is allowed per `describe!` block."));
                    }
                    state.after = Some(parser.parse_block().ok().unwrap());
                },

                // Regular `#[test]`.
                IT | WHEN => { state.subblocks.push(SubBlock::Test(Parse::parse(parser, false))) },

                // `#[should_panic]` test.
                FAILING => { state.subblocks.push(SubBlock::Test(Parse::parse(parser, true))) },

                // #[bench] benchmark.
                BENCH => { state.subblocks.push(SubBlock::Bench(Parse::parse(parser, ()))) }

                // Nested `describe!` block.
                DESCRIBE => {
                    // Skip over the ! in describe!
                    try(parser, token::Not, "!");

                    // Parse this subblock, generate new item.
                    state.subblocks.push(SubBlock::Describe(Parse::parse(parser, (sp, &mut*cx, None))));

                    // Move past closing bracket and paren.
                    //
                    // This has to go in here because it is EOF on the highest-level invocation.
                    try(parser, token::CloseDelim(token::Brace), "}} to close `describe!`")
                }

                otherwise => { illegal(parser, otherwise) }
            }
        }

        state
    }
}

fn try(parser: &mut Parser, token: token::Token, err: &str) {
    let real = parser.bump_and_get().ok().unwrap();
    if real != token {
        panic!("{}", parser.fatal(&format!("Expected {}, but found `{:?}`", err, real)));
    }
}

fn illegal(parser: &mut Parser, banned: &str) {
    // Illegal block name.
    let span = parser.span;
    panic!("{}", parser.span_fatal(span, &format!("Expected one of: `{}`, but found: `{}`",
        format!("{}, {}, {}, {}, {}, {}, {}, {}",
                BEFORE_EACH, AFTER_EACH, BEFORE, AFTER,
                IT, BENCH, FAILING, DESCRIBE),
        banned)));
}
<commit_msg>Using fmt::Debug instead of fmt::Display<commit_after>use syntax::{ast, codemap};
use syntax::ext::base;
use syntax::parse::token;

use syntax::ptr::P;
use syntax::parse::parser::Parser;

use test::Test;
use bench::Bench;
use describe::{DescribeState, SubBlock};

/// Trait that means something can be parsed with a configuration.
pub trait Parse<Cfg> {
    /// Parse Self from a Parser and a configuration object.
    fn parse(&mut Parser, Cfg) -> Self;
}

impl Parse<bool> for Test {
    fn parse(parser: &mut Parser, failing: bool) -> Test {
        // Description of this test.
        let (description, _) = parser.parse_str().ok().unwrap();

        Test {
            // Get as a String
            description: description.to_string(),

            // The associated block
            block: parser.parse_block().ok().unwrap(),

            failing: failing
        }
    }
}

impl Parse<()> for Bench {
    fn parse(parser: &mut Parser, _: ()) -> Bench {
        // Description of this benchmark
        let (description, _) = parser.parse_str().ok().unwrap();

        let name = match (parser.bump_and_get().ok().unwrap(), parser.parse_ident().ok().unwrap(), parser.bump_and_get().ok().unwrap()) {
            (token::OpenDelim(token::Paren), ident, token::CloseDelim(token::Paren)) => { ident },

            (one, two, three) => {
                panic!("{:?}", parser.fatal(&format!("Expected `($ident)`, found {:?}{:?}{:?}", one, two, three)));
            }
        };

        Bench {
            description: description.to_string(),
            block: parser.parse_block().ok().unwrap(),
            bench: P(name)
        }
    }
}

const BEFORE_EACH: &'static str = "before_each";
const GIVEN:       &'static str = "given";
const AFTER_EACH:  &'static str = "after_each";
const THEN:        &'static str = "then";
const BEFORE:      &'static str = "before";
const AFTER:       &'static str = "after";
const IT:          &'static str = "it";
const WHEN:        &'static str = "when";
const DESCRIBE:    &'static str = "describe";
const FAILING:     &'static str = "failing";
const BENCH:       &'static str = "bench";

impl<'a, 'b> Parse<(codemap::Span, &'a mut base::ExtCtxt<'b>, Option<ast::Ident>)> for DescribeState {
    fn parse(parser: &mut Parser,
             (sp, cx, name): (codemap::Span, &'a mut base::ExtCtxt, Option<ast::Ident>)) -> DescribeState {
        let mut state = DescribeState {
            name: None, before: None, after: None,
            before_each: None, after_each: None, subblocks: vec![]
        };

        state.name = match name {
            // Top-level describe block.
            Some(name) => Some(name),
            // Nested describe block.
            None => {
                // Get the name of this describe block
                let name = parser.parse_ident().ok().unwrap();
                // Move past the opening {
                try(parser, token::OpenDelim(token::Brace), "{ after the name of a describe! block");
                Some(name)
            }
        };

        // Now parse all tests and subsections:
        while parser.token != token::CloseDelim(token::Brace) && parser.token != token::Eof {
            // Get the name of this block, must be either:
            //     - before_each
            //     - after_each
            //     - before
            //     - after
            //     - it
            //     - failing
            //     - bench
            //     - describe!
            //
            // Any other top-level idents are not allowed.
            let block_name = parser.parse_ident().ok().unwrap().name;

            match &*block_name.as_str() {
                BEFORE_EACH | GIVEN => {
                    if state.before_each.is_some() {
                        panic!("{:?}", parser.fatal("Only one `before_each` block is allowed per `describe!` block."));
                    }
                    state.before_each = Some(parser.parse_block().ok().unwrap());
                },

                AFTER_EACH | THEN => {
                    if state.after_each.is_some() {
                        panic!("{:?}", parser.fatal("Only one `after_each` block is allowed per `describe!` block."));
                    }
                    state.after_each = Some(parser.parse_block().ok().unwrap());
                },

                BEFORE => {
                    if state.before.is_some() {
                        panic!("{:?}", parser.fatal("Only one `before` block is allowed per `describe!` block."));
                    }
                    state.before = Some(parser.parse_block().ok().unwrap());
                },

                AFTER => {
                    if state.after.is_some() {
                        panic!("{:?}", parser.fatal("Only one `after` block is allowed per `describe!` block."));
                    }
                    state.after = Some(parser.parse_block().ok().unwrap());
                },

                // Regular `#[test]`.
                IT | WHEN => { state.subblocks.push(SubBlock::Test(Parse::parse(parser, false))) },

                // `#[should_panic]` test.
                FAILING => { state.subblocks.push(SubBlock::Test(Parse::parse(parser, true))) },

                // #[bench] benchmark.
                BENCH => { state.subblocks.push(SubBlock::Bench(Parse::parse(parser, ()))) }

                // Nested `describe!` block.
                DESCRIBE => {
                    // Skip over the ! in describe!
                    try(parser, token::Not, "!");

                    // Parse this subblock, generate new item.
                    state.subblocks.push(SubBlock::Describe(Parse::parse(parser, (sp, &mut*cx, None))));

                    // Move past closing bracket and paren.
                    //
                    // This has to go in here because it is EOF on the highest-level invocation.
                    try(parser, token::CloseDelim(token::Brace), "}} to close `describe!`")
                }

                otherwise => { illegal(parser, otherwise) }
            }
        }

        state
    }
}

fn try(parser: &mut Parser, token: token::Token, err: &str) {
    let real = parser.bump_and_get().ok().unwrap();
    if real != token {
        panic!("{:?}", parser.fatal(&format!("Expected {}, but found `{:?}`", err, real)));
    }
}

fn illegal(parser: &mut Parser, banned: &str) {
    // Illegal block name.
    let span = parser.span;
    panic!("{:?}", parser.span_fatal(span, &format!("Expected one of: `{}`, but found: `{}`",
        format!("{}, {}, {}, {}, {}, {}, {}, {}",
                BEFORE_EACH, AFTER_EACH, BEFORE, AFTER,
                IT, BENCH, FAILING, DESCRIBE),
        banned)));
}
<|endoftext|>


<commit_before>//! `Scene` and `SyncGuard` structures.

use node;
use color::Color;
use hub::{Hub, HubPtr, SubNode};
use object::{Base, DowncastObject, Group, Object};
use texture::{CubeMap, Texture};

use std::mem;
use std::marker::PhantomData;
use std::sync::MutexGuard;

/// Background type.
#[derive(Clone, Debug, PartialEq)]
pub enum Background {
    /// Basic solid color background.
    Color(Color),
    /// Texture background, covers the whole screen.
    // TODO: different wrap modes?
    Texture(Texture<[f32; 4]>),
    /// Skybox
    Skybox(CubeMap<[f32; 4]>),
}

/// The root node of a tree of game objects that may be rendered by a [`Camera`].
///
/// [`Camera`]: ../camera/struct.Camera.html
pub struct Scene {
    pub(crate) hub: HubPtr,
    pub(crate) first_child: Option<node::NodePointer>,
    /// See [`Background`](struct.Background.html).
    pub background: Background,
}

impl Scene {
    /// Add new [`Base`](struct.Base.html) to the scene.
    pub fn add<P>(
        &mut self,
        child_base: P,
    ) where
        P: AsRef<Base>,
    {
        let mut hub = self.hub.lock().unwrap();
        let node_ptr = child_base.as_ref().node.clone();
        let child = &mut hub[child_base];

        if child.next_sibling.is_some() {
            error!("Element {:?} is added to a scene while still having old parent - {}",
                child.sub_node, "discarding siblings");
        }

        child.next_sibling = mem::replace(&mut self.first_child, Some(node_ptr));
    }

    /// Remove a previously added [`Base`](struct.Base.html) from the scene.
    pub fn remove<P>(
        &mut self,
        child_base: P,
    ) where
        P: AsRef<Base>,
    {
        let target_maybe = Some(child_base.as_ref().node.clone());
        let mut hub = self.hub.lock().unwrap();
        let next_sibling = hub[child_base].next_sibling.clone();

        if self.first_child == target_maybe {
            self.first_child = next_sibling;
            return;
        }

        let mut cur_ptr = self.first_child.clone();
        while let Some(ptr) = cur_ptr.take() {
            let node = &mut hub.nodes[&ptr];
            if node.next_sibling == target_maybe {
                node.next_sibling = next_sibling;
                return;
            }
            cur_ptr = node.next_sibling.clone(); //TODO: avoid clone
        }

        error!("Unable to find child for removal");
    }
}

/// `SyncGuard` is used to obtain information about scene nodes in the most effective way.
///
/// # Examples
///
/// Imagine that you have your own helper type `Enemy`:
///
/// ```rust
/// # extern crate three;
/// struct Enemy {
///     mesh: three::Mesh,
///     is_visible: bool,
/// }
/// # fn main() {}
/// ```
///
/// You need this wrapper around `three::Mesh` to cache some information - in our case, visibility.
///
/// In your game you contain all your enemy objects in `Vec<Enemy>`. In the main loop you need
/// to iterate over all the enemies and make them visible or not, basing on current position.
/// The most obvious way is to use [`object::Base::sync`], but it's not the best idea from the side of
/// performance. Instead, you can create `SyncGuard` and use its `resolve` method to effectively
/// walk through every enemy in your game:
///
/// ```rust,no_run
/// # extern crate three;
/// # #[derive(Clone)]
/// # struct Enemy {
/// #     mesh: three::Mesh,
/// #     is_visible: bool,
/// # }
/// #
/// # impl three::Object for Enemy {}
/// #
/// # impl AsRef<three::object::Base> for Enemy {
/// #     fn as_ref(&self) -> &three::object::Base {
/// #         self.mesh.as_ref()
/// #     }
/// # }
/// #
/// # fn main() {
/// # use three::Object;
/// # let mut win = three::Window::new("SyncGuard example");
/// # let geometry = three::Geometry::default();
/// # let material = three::material::Basic { color: three::color::RED, map: None };
/// # let mesh = win.factory.mesh(geometry, material);
/// # let enemy = Enemy { mesh, is_visible: true };
/// # win.scene.add(&enemy);
/// # let mut enemies = vec![enemy];
/// # loop {
/// let mut sync = win.scene.sync_guard();
/// for mut enemy in &mut enemies {
///     let node = sync.resolve(enemy);
///     let position = node.transform.position;
///     if position.x > 10.0 {
///         enemy.is_visible = false;
///         enemy.set_visible(false);
///     } else {
///         enemy.is_visible = true;
///         enemy.set_visible(true);
///     }
/// }
/// # }}
/// ```
///
/// [`object::Base::sync`]: ../object/struct.Base.html#method.sync
pub struct SyncGuard<'a> {
    pub(crate) scene: &'a Scene,
    pub(crate) hub: MutexGuard<'a, Hub>,
}

impl<'a> SyncGuard<'a> {
    /// Obtains `objects`'s local space [`Node`] in an effective way.
    ///
    /// # Panics
    /// Panics if `scene` doesn't have this `object::Base`.
    ///
    /// [`Node`]: ../node/struct.Node.html
    pub fn resolve<T: 'a + Object>(
        &self,
        object: &T,
    ) -> node::Node<node::Local> {
        self.hub[object].to_node()
    }

    /// Obtains `objects`'s world [`Node`] by traversing the scene graph.
    /// *Note*: this can be slow.
    ///
    /// # Panics
    /// Panics if the doesn't have this `object::Base`.
    ///
    /// [`Node`]: ../node/struct.Node.html
    pub fn resolve_world<T: 'a + Object>(
        &self,
        object: &T,
    ) -> node::Node<node::World> {
        let internal = &self.hub[object] as *const _;
        let wn = self.hub
            .walk_all(&self.scene.first_child)
            .find(|wn| wn.node as *const _ == internal)
            .expect("Unable to find objects for world resolve!");
        node::Node {
            visible: wn.world_visible,
            name: wn.node.name.clone(),
            transform: wn.world_transform.into(),
            material: match wn.node.sub_node {
                SubNode::Visual(ref mat, _, _) => Some(mat.clone()),
                _ => None,
            },
            _space: PhantomData,
        }
    }

    /// Obtains internal state data for `object`.
    ///
    /// Three-rs objects normally expose a write-only interface, making it possible to change
    /// an object's internal values but not possible to read those values. `SyncGuard` allows
    /// for that data to be read in a controlled way.
    ///
    /// Each object type has its own internal data, and not all object types can provide access
    /// to meaningful data. The following types provide specific data you can use:
    ///
    /// * [`Base`]: Returns an [`ObjectType`], which provides access to the concrete object type
    ///   for `object`.
    /// * [`Group`]: Returns a list of the group's direct children.
    /// * [`Camera`]: Returns the [`Projection`] for the camera.
    /// * [`Ambient`]: Returns the [`LightData`] for the light.
    /// * [`Point`]: Returns the [`LightData`] for the light.
    /// * [`Directional`]: Returns the [`LightData`] for the light.
    /// * [`Hemisphere`]: Returns the [`HemisphereLightData`] for the light.
    ///
    /// The other object types do not have a user-facing way to represent their internal data,
    /// and so return `()`.
    ///
    /// [`Base`]: ../object/struct.Base.html
    /// [`ObjectType`]: ../object/enum.ObjectType.html
    /// [`Group`]: ../struct.Group.html
    /// [`Camera`]: ../camera/struct.Camera.html
    /// [`Projection`]: ../camera/enum.Projection.html
    /// [`LightData`]: ../light/struct.LightData.html
    /// [`Ambient`]: ../light/struct.Ambient.html
    /// [`Point`]: ../light/struct.Point.html
    /// [`Directional`]: ../light/struct.Directional.html
    /// [`Hemisphere`]: ../light/struct.Hemisphere.html
    /// [`HemisphereLightData`]: ../light/struct.HemisphereLightData.html
    pub fn resolve_data<T: 'a + Object>(
        &self,
        object: &T,
    ) -> T::Data {
        object.resolve_data(self)
    }

    /// Returns an iterator that walks all the objects in `root`'s hierarchy.
    ///
    /// Walks the children of `root`, recursively walking the children of any [`Group`] objects
    /// found until all objects in the hierarchy have been visited. The hierarchy is walked
    /// depth-first, and objects are yielded in the order they are visited.
    ///
    /// [`Group`]: ../struct.Group.html
    pub fn walk_hierarchy(&'a self, root: &Group) -> impl Iterator<Item = Base> + 'a {
        let root = root.as_ref().node.clone();
        let guard = &*self;
        self
            .hub
            .walk_all(&Some(root))
            .map(move |walked| guard.hub.upgrade_ptr(walked.node_ptr.clone()))
    }

    /// Finds a node in a group, or any of its children, by name.
    ///
    /// Performs a depth-first search starting with `root` looking for an object with `name`.
    /// Returns the [`Base`] for the first object found with a matching name, otherwise returns
    /// `None` if no such object is found. Note that if more than one such object exists in the
    /// hierarchy, then only the first one discovered will be returned. Note, also, that if
    /// `root` matches `name`, it will be returned.
    ///
    /// [`Base`]: ../object/struct.Base.html
    pub fn find_child_by_name(&self, root: &Group, name: &str) -> Option<Base> {
        let root = root.as_ref().node.clone();
        self
            .hub
            .walk_all(&Some(root))
            .find(|walked| walked.node.name.as_ref().map(|node_name| node_name == name).unwrap_or(false))
            .map(|walked| self.hub.upgrade_ptr(walked.node_ptr.clone()))
    }

    /// Returns an iterator of all objects under `root` with the specified name.
    ///
    /// Performs a depth-first search starting with `root`, yielding each object in the hierarchy
    /// matching `name`. Note that if `root` matches `name`, then it will be the first object
    /// yielded by the iterator.
    pub fn find_children_by_name(
        &'a self,
        root: &Group,
        name: &'a str,
    ) -> impl Iterator<Item = Base> + 'a {
        let root = root.as_ref().node.clone();
        let guard = &*self;
        self
            .hub
            .walk_all(&Some(root))
            .filter(move |walked| {
                walked
                    .node
                    .name
                    .as_ref()
                    .map(|node_name| node_name == name)
                    .unwrap_or(false)
            })
            .map(move |walked| guard.hub.upgrade_ptr(walked.node_ptr.clone()))
    }

    /// Finds the first object in a group, or any of its children, of type `T`.
    ///
    /// Performs a depth-first search starting with `root`, recusively descending into any
    /// [`Group`] objects found. Returns the first object of type `T` encountered in the
    /// hierarchy. Note that if `T` is `Group`, then `root` will be returned.
    pub fn find_child_of_type<T: DowncastObject>(&'a self, root: &Group) -> Option<T> {
        self.find_children_of_type::<T>(root).next()
    }

    /// Returns an iterator yielding all children of `root` of type `T`.
    pub fn find_children_of_type<T: DowncastObject>(&'a self, root: &Group) -> impl Iterator<Item = T> + 'a {
        let root = root.as_ref().node.clone();
        let guard = &*self;
        self
            .hub
            .walk_all(&Some(root))
            .map(move |walked| guard.hub.upgrade_ptr(walked.node_ptr.clone()))
            .filter_map(move |base| guard.downcast(&base))
    }

    /// Attempts to find an object of type `T` in the group or any of its children.
    ///
    /// Performs a depth-first search starting with `root`, recursively searching [`Group`]
    /// objects, until an object of type `T` that matches `name` is found. Note that if `T` is
    /// [`Group`] and `root` matches `name`, then it will be returned.
    ///
    /// [`Group`]: ../struct.Group.html
    pub fn find_child_of_type_by_name<T: DowncastObject>(
        &'a self,
        root: &Group,
        name: &'a str,
    ) -> Option<T> {
        self.find_children_of_type_by_name(root, name).next()
    }

    /// Returns an iterator yielding all children of `root` of type `T` named `name`.
    ///
    /// Performs a depth-first search starting with `root`, recursively searching [`Group`]
    /// objects, yielding any objects of `T` that match `name`. Note that if `T` is [`Group`]
    /// and `root` matches `name`, then it will be the first object yielded by the iterator.
    pub fn find_children_of_type_by_name<T: DowncastObject>(
        &'a self,
        root: &Group,
        name: &'a str,
    ) -> impl Iterator<Item = T> + 'a {
        let guard = &*self;
        self
            .find_children_by_name(root, name)
            .filter_map(move |base| guard.downcast(&base))
    }

    /// Attempts to downcast a [`Base`] to its concrete object type.
    ///
    /// If the downcast succeeds, the concrete object is returned. Returns `None` if the
    /// downcast fails.
    pub fn downcast<T: DowncastObject>(&self, base: &Base) -> Option<T> {
        let object_type = self.resolve_data(base);
        T::downcast(object_type)
    }
}

impl Scene {
    /// Create new [`SyncGuard`](struct.SyncGuard.html).
    ///
    /// This is performance-costly operation, you should not use it many times per frame.
    pub fn sync_guard(&mut self) -> SyncGuard {
        let mut hub = self.hub.lock().unwrap();
        hub.process_messages();
        SyncGuard { scene: self, hub }
    }
}
<commit_msg>Update more docs for SyncGuard<commit_after>//! `Scene` and `SyncGuard` structures.

use node;
use color::Color;
use hub::{Hub, HubPtr, SubNode};
use object::{Base, DowncastObject, Group, Object};
use texture::{CubeMap, Texture};

use std::mem;
use std::marker::PhantomData;
use std::sync::MutexGuard;

/// Background type.
#[derive(Clone, Debug, PartialEq)]
pub enum Background {
    /// Basic solid color background.
    Color(Color),
    /// Texture background, covers the whole screen.
    // TODO: different wrap modes?
    Texture(Texture<[f32; 4]>),
    /// Skybox
    Skybox(CubeMap<[f32; 4]>),
}

/// The root node of a tree of game objects that may be rendered by a [`Camera`].
///
/// [`Camera`]: ../camera/struct.Camera.html
pub struct Scene {
    pub(crate) hub: HubPtr,
    pub(crate) first_child: Option<node::NodePointer>,
    /// See [`Background`](struct.Background.html).
    pub background: Background,
}

impl Scene {
    /// Add new [`Base`](struct.Base.html) to the scene.
    pub fn add<P>(
        &mut self,
        child_base: P,
    ) where
        P: AsRef<Base>,
    {
        let mut hub = self.hub.lock().unwrap();
        let node_ptr = child_base.as_ref().node.clone();
        let child = &mut hub[child_base];

        if child.next_sibling.is_some() {
            error!("Element {:?} is added to a scene while still having old parent - {}",
                child.sub_node, "discarding siblings");
        }

        child.next_sibling = mem::replace(&mut self.first_child, Some(node_ptr));
    }

    /// Remove a previously added [`Base`](struct.Base.html) from the scene.
    pub fn remove<P>(
        &mut self,
        child_base: P,
    ) where
        P: AsRef<Base>,
    {
        let target_maybe = Some(child_base.as_ref().node.clone());
        let mut hub = self.hub.lock().unwrap();
        let next_sibling = hub[child_base].next_sibling.clone();

        if self.first_child == target_maybe {
            self.first_child = next_sibling;
            return;
        }

        let mut cur_ptr = self.first_child.clone();
        while let Some(ptr) = cur_ptr.take() {
            let node = &mut hub.nodes[&ptr];
            if node.next_sibling == target_maybe {
                node.next_sibling = next_sibling;
                return;
            }
            cur_ptr = node.next_sibling.clone(); //TODO: avoid clone
        }

        error!("Unable to find child for removal");
    }
}

/// `SyncGuard` is used to obtain information about scene nodes in the most effective way.
///
/// # Examples
///
/// Imagine that you have your own helper type `Enemy`:
///
/// ```rust
/// # extern crate three;
/// struct Enemy {
///     mesh: three::Mesh,
///     is_visible: bool,
/// }
/// # fn main() {}
/// ```
///
/// You need this wrapper around `three::Mesh` to cache some information - in our case, visibility.
///
/// In your game you contain all your enemy objects in `Vec<Enemy>`. In the main loop you need
/// to iterate over all the enemies and make them visible or not, basing on current position.
/// The most obvious way is to use [`object::Base::sync`], but it's not the best idea from the side of
/// performance. Instead, you can create `SyncGuard` and use its `resolve` method to effectively
/// walk through every enemy in your game:
///
/// ```rust,no_run
/// # extern crate three;
/// # #[derive(Clone)]
/// # struct Enemy {
/// #     mesh: three::Mesh,
/// #     is_visible: bool,
/// # }
/// #
/// # impl three::Object for Enemy {}
/// #
/// # impl AsRef<three::object::Base> for Enemy {
/// #     fn as_ref(&self) -> &three::object::Base {
/// #         self.mesh.as_ref()
/// #     }
/// # }
/// #
/// # fn main() {
/// # use three::Object;
/// # let mut win = three::Window::new("SyncGuard example");
/// # let geometry = three::Geometry::default();
/// # let material = three::material::Basic { color: three::color::RED, map: None };
/// # let mesh = win.factory.mesh(geometry, material);
/// # let enemy = Enemy { mesh, is_visible: true };
/// # win.scene.add(&enemy);
/// # let mut enemies = vec![enemy];
/// # loop {
/// let mut sync = win.scene.sync_guard();
/// for mut enemy in &mut enemies {
///     let node = sync.resolve(enemy);
///     let position = node.transform.position;
///     if position.x > 10.0 {
///         enemy.is_visible = false;
///         enemy.set_visible(false);
///     } else {
///         enemy.is_visible = true;
///         enemy.set_visible(true);
///     }
/// }
/// # }}
/// ```
///
/// [`object::Base::sync`]: ../object/struct.Base.html#method.sync
pub struct SyncGuard<'a> {
    pub(crate) scene: &'a Scene,
    pub(crate) hub: MutexGuard<'a, Hub>,
}

impl<'a> SyncGuard<'a> {
    /// Obtains `objects`'s local space [`Node`] in an effective way.
    ///
    /// # Panics
    /// Panics if `scene` doesn't have this `object::Base`.
    ///
    /// [`Node`]: ../node/struct.Node.html
    pub fn resolve<T: 'a + Object>(
        &self,
        object: &T,
    ) -> node::Node<node::Local> {
        self.hub[object].to_node()
    }

    /// Obtains `objects`'s world [`Node`] by traversing the scene graph.
    /// *Note*: this can be slow.
    ///
    /// # Panics
    /// Panics if the scene doesn't have this `object::Base`.
    ///
    /// [`Node`]: ../node/struct.Node.html
    pub fn resolve_world<T: 'a + Object>(
        &self,
        object: &T,
    ) -> node::Node<node::World> {
        let internal = &self.hub[object] as *const _;
        let wn = self.hub
            .walk_all(&self.scene.first_child)
            .find(|wn| wn.node as *const _ == internal)
            .expect("Unable to find objects for world resolve!");
        node::Node {
            visible: wn.world_visible,
            name: wn.node.name.clone(),
            transform: wn.world_transform.into(),
            material: match wn.node.sub_node {
                SubNode::Visual(ref mat, _, _) => Some(mat.clone()),
                _ => None,
            },
            _space: PhantomData,
        }
    }

    /// Obtains internal state data for `object`.
    ///
    /// Three-rs objects normally expose a write-only interface, making it possible to change
    /// an object's internal values but not possible to read those values. `SyncGuard` allows
    /// for that data to be read in a controlled way.
    ///
    /// Each object type has its own internal data, and not all object types can provide access
    /// to meaningful data. The following types provide specific data you can use:
    ///
    /// * [`Base`]: Returns an [`ObjectType`], which provides access to the concrete object type
    ///   for `object`.
    /// * [`Group`]: Returns a list of the group's direct children.
    /// * [`Camera`]: Returns the [`Projection`] for the camera.
    /// * [`Ambient`]: Returns the [`LightData`] for the light.
    /// * [`Point`]: Returns the [`LightData`] for the light.
    /// * [`Directional`]: Returns the [`LightData`] for the light.
    /// * [`Hemisphere`]: Returns the [`HemisphereLightData`] for the light.
    ///
    /// The other object types do not have a user-facing way to represent their internal data,
    /// and so return `()`.
    ///
    /// [`Base`]: ../object/struct.Base.html
    /// [`ObjectType`]: ../object/enum.ObjectType.html
    /// [`Group`]: ../struct.Group.html
    /// [`Camera`]: ../camera/struct.Camera.html
    /// [`Projection`]: ../camera/enum.Projection.html
    /// [`LightData`]: ../light/struct.LightData.html
    /// [`Ambient`]: ../light/struct.Ambient.html
    /// [`Point`]: ../light/struct.Point.html
    /// [`Directional`]: ../light/struct.Directional.html
    /// [`Hemisphere`]: ../light/struct.Hemisphere.html
    /// [`HemisphereLightData`]: ../light/struct.HemisphereLightData.html
    pub fn resolve_data<T: 'a + Object>(
        &self,
        object: &T,
    ) -> T::Data {
        object.resolve_data(self)
    }

    /// Returns an iterator that walks all the objects in `root`'s hierarchy.
    ///
    /// Walks the children of `root`, recursively walking the children of any [`Group`] objects
    /// found until all objects in the hierarchy have been visited. The hierarchy is walked
    /// depth-first, and objects are yielded in the order they are visited.
    ///
    /// [`Group`]: ../struct.Group.html
    pub fn walk_hierarchy(&'a self, root: &Group) -> impl Iterator<Item = Base> + 'a {
        let root = root.as_ref().node.clone();
        let guard = &*self;
        self
            .hub
            .walk_all(&Some(root))
            .map(move |walked| guard.hub.upgrade_ptr(walked.node_ptr.clone()))
    }

    /// Finds a node in a group, or any of its children, by name.
    ///
    /// Performs a depth-first search starting with `root` looking for an object with `name`.
    /// Returns the [`Base`] for the first object found with a matching name, otherwise returns
    /// `None` if no such object is found. Note that if more than one such object exists in the
    /// hierarchy, then only the first one discovered will be returned.
    ///
    /// [`Base`]: ../object/struct.Base.html
    pub fn find_child_by_name(&self, root: &Group, name: &str) -> Option<Base> {
        let root = root.as_ref().node.clone();
        self
            .hub
            .walk_all(&Some(root))
            .find(|walked| walked.node.name.as_ref().map(|node_name| node_name == name).unwrap_or(false))
            .map(|walked| self.hub.upgrade_ptr(walked.node_ptr.clone()))
    }

    /// Returns an iterator of all objects under `root` with the specified name.
    ///
    /// Performs a depth-first search starting with `root`, yielding each object in the hierarchy
    /// matching `name`.
    ///
    /// [`Group`]: ../struct.Group.html
    pub fn find_children_by_name(
        &'a self,
        root: &Group,
        name: &'a str,
    ) -> impl Iterator<Item = Base> + 'a {
        let root = root.as_ref().node.clone();
        let guard = &*self;
        self
            .hub
            .walk_all(&Some(root))
            .filter(move |walked| {
                walked
                    .node
                    .name
                    .as_ref()
                    .map(|node_name| node_name == name)
                    .unwrap_or(false)
            })
            .map(move |walked| guard.hub.upgrade_ptr(walked.node_ptr.clone()))
    }

    /// Finds the first object in a group, or any of its children, of type `T`.
    ///
    /// Performs a depth-first search starting with `root`, recusively descending into any
    /// [`Group`] objects found. Returns the first object of type `T` encountered in the
    /// hierarchy.
    ///
    /// [`Group`]: ../struct.Group.html
    pub fn find_child_of_type<T: DowncastObject>(&'a self, root: &Group) -> Option<T> {
        self.find_children_of_type::<T>(root).next()
    }

    /// Returns an iterator yielding all objects in the hierarchy of `root` of type `T`.
    ///
    /// Performs a depth-first search starting with `root`, recursively descending into any
    /// [`Group`] objects found, yielding each object of type `T` found in the hierarchy.
    ///
    /// [`Group`]: ../struct.Group.html
    pub fn find_children_of_type<T: DowncastObject>(
        &'a self,
        root: &Group,
    ) -> impl Iterator<Item = T> + 'a {
        let root = root.as_ref().node.clone();
        let guard = &*self;
        self
            .hub
            .walk_all(&Some(root))
            .map(move |walked| guard.hub.upgrade_ptr(walked.node_ptr.clone()))
            .filter_map(move |base| guard.downcast(&base))
    }

    /// Attempts to find an object of type `T` in the group or any of its children.
    ///
    /// Performs a depth-first search starting with `root`, recursively searching [`Group`]
    /// objects, until an object of type `T` that matches `name` is found. Note that if `T` is
    /// [`Group`] and `root` matches `name`, then it will be returned.
    ///
    /// [`Group`]: ../struct.Group.html
    pub fn find_child_of_type_by_name<T: DowncastObject>(
        &'a self,
        root: &Group,
        name: &'a str,
    ) -> Option<T> {
        self.find_children_of_type_by_name(root, name).next()
    }

    /// Returns an iterator yielding all children of `root` of type `T` named `name`.
    ///
    /// Performs a depth-first search starting with `root`, recursively searching [`Group`]
    /// objects, yielding any objects of `T` that match `name`. Note that if `T` is [`Group`]
    /// and `root` matches `name`, then it will be the first object yielded by the iterator.
    ///
    /// [`Group`]: ../struct.Group.html
    pub fn find_children_of_type_by_name<T: DowncastObject>(
        &'a self,
        root: &Group,
        name: &'a str,
    ) -> impl Iterator<Item = T> + 'a {
        let guard = &*self;
        self
            .find_children_by_name(root, name)
            .filter_map(move |base| guard.downcast(&base))
    }

    /// Attempts to downcast a [`Base`] to its concrete object type.
    ///
    /// If the downcast succeeds, the concrete object is returned. Returns `None` if the
    /// downcast fails.
    ///
    /// [`Base`]: ../object/struct.Base.html
    pub fn downcast<T: DowncastObject>(&self, base: &Base) -> Option<T> {
        let object_type = self.resolve_data(base);
        T::downcast(object_type)
    }
}

impl Scene {
    /// Create new [`SyncGuard`](struct.SyncGuard.html).
    ///
    /// This is performance-costly operation, you should not use it many times per frame.
    pub fn sync_guard(&mut self) -> SyncGuard {
        let mut hub = self.hub.lock().unwrap();
        hub.process_messages();
        SyncGuard { scene: self, hub }
    }
}
<|endoftext|>


<commit_before>use rocket;
use rocket::http::hyper::header::*;
use rocket::response::{self, Responder};
use std::cmp;
use std::convert::From;
use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
use std::str::FromStr;

pub enum PartialFileRange {
	AllFrom(u64),
	FromTo(u64, u64),
	Last(u64),
}

impl From<ByteRangeSpec> for PartialFileRange {
	fn from(b: ByteRangeSpec) -> PartialFileRange {
		match b {
			ByteRangeSpec::AllFrom(from) => PartialFileRange::AllFrom(from),
			ByteRangeSpec::FromTo(from, to) => PartialFileRange::FromTo(from, to),
			ByteRangeSpec::Last(last) => PartialFileRange::Last(last),
		}
	}
}

impl From<Vec<ByteRangeSpec>> for PartialFileRange {
	fn from(v: Vec<ByteRangeSpec>) -> PartialFileRange {
		match v.into_iter().next() {
			None => PartialFileRange::AllFrom(0),
			Some(byte_range) => PartialFileRange::from(byte_range),
		}
	}
}

pub struct RangeResponder<R> {
	original: R,
}

impl<'r, R: Responder<'r>> RangeResponder<R> {
	pub fn new(original: R) -> RangeResponder<R> {
		RangeResponder { original }
	}

	fn ignore_range(self, request: &rocket::request::Request) -> response::Result<'r> {
		let mut response = self.original.respond_to(request)?;
		response.set_status(rocket::http::Status::RangeNotSatisfiable);
		Ok(response)
	}
}

fn truncate_range(range: &PartialFileRange, file_length: &Option<u64>) -> Option<(u64, u64)> {
	use self::PartialFileRange::*;

	match (range, file_length) {
		(FromTo(from, to), Some(file_length)) => {
			if from <= to && from < file_length {
				Some((*from, cmp::min(*to, file_length - 1)))
			} else {
				None
			}
		}
		(AllFrom(from), Some(file_length)) => {
			if from < file_length {
				Some((*from, file_length - 1))
			} else {
				None
			}
		}
		(Last(last), Some(file_length)) => {
			if last < file_length {
				Some((file_length - last, file_length - 1))
			} else {
				Some((0, file_length - 1))
			}
		}
		(_, None) => None,
	}
}

impl<'r> Responder<'r> for RangeResponder<File> {
	fn respond_to(mut self, request: &rocket::request::Request) -> response::Result<'r> {
		let range_header = request.headers().get_one("Range");
		let range_header = match range_header {
			None => return Ok(self.original.respond_to(request)?),
			Some(h) => h,
		};

		let vec_range = match Range::from_str(range_header) {
			Ok(Range::Bytes(v)) => v,
			_ => return self.ignore_range(request),
		};

		let partial_file_range = match vec_range.into_iter().next() {
			None => PartialFileRange::AllFrom(0),
			Some(byte_range) => PartialFileRange::from(byte_range),
		};

		let metadata: Option<_> = self.original.metadata().ok();
		let file_length: Option<u64> = metadata.map(|m| m.len());
		let range: Option<(u64, u64)> = truncate_range(&partial_file_range, &file_length);

		if let Some((from, to)) = range {
			let content_range = ContentRange(ContentRangeSpec::Bytes {
				range: range,
				instance_length: file_length,
			});
			let content_len = to - from + 1;

			match self.original.seek(SeekFrom::Start(from)) {
				Ok(_) => (),
				Err(_) => return Err(rocket::http::Status::InternalServerError),
			}
			let partial_original = self.original.take(content_len).into_inner();
			let mut response = partial_original.respond_to(request)?;
			response.set_header(ContentLength(content_len));
			response.set_header(content_range);
			response.set_status(rocket::http::Status::PartialContent);

			Ok(response)
		} else {
			self.ignore_range(request)
		}
	}
}
<commit_msg>Added logging around HTTP range handling<commit_after>use rocket;
use rocket::http::hyper::header::*;
use rocket::http::Status;
use rocket::Response;
use rocket::response::{self, Responder};
use std::cmp;
use std::convert::From;
use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
use std::str::FromStr;

#[derive(Debug)]
pub enum PartialFileRange {
	AllFrom(u64),
	FromTo(u64, u64),
	Last(u64),
}

impl From<ByteRangeSpec> for PartialFileRange {
	fn from(b: ByteRangeSpec) -> PartialFileRange {
		match b {
			ByteRangeSpec::AllFrom(from) => PartialFileRange::AllFrom(from),
			ByteRangeSpec::FromTo(from, to) => PartialFileRange::FromTo(from, to),
			ByteRangeSpec::Last(last) => PartialFileRange::Last(last),
		}
	}
}

impl From<Vec<ByteRangeSpec>> for PartialFileRange {
	fn from(v: Vec<ByteRangeSpec>) -> PartialFileRange {
		match v.into_iter().next() {
			None => PartialFileRange::AllFrom(0),
			Some(byte_range) => PartialFileRange::from(byte_range),
		}
	}
}

pub struct RangeResponder<R> {
	original: R,
}

impl<'r, R: Responder<'r>> RangeResponder<R> {
	pub fn new(original: R) -> RangeResponder<R> {
		RangeResponder { original }
	}

	fn ignore_range(self, request: &rocket::request::Request, file_length: Option<u64>) -> response::Result<'r> {
		let mut response = self.original.respond_to(request)?;
		if let Some(content_length) = file_length {
			response.set_header(ContentLength(content_length));
		}
		response.set_status(Status::Ok);
		Ok(response)
	}

	fn reject_range(self, file_length: Option<u64>) -> response::Result<'r> {
		let mut response = Response::build()
						.status(Status::RangeNotSatisfiable)
						.finalize();
		if file_length.is_some() {
			let content_range = ContentRange(ContentRangeSpec::Bytes {
				range: None,
				instance_length: file_length,
			});
			response.set_header(content_range);
		}
		response.set_status(Status::RangeNotSatisfiable);
		Ok(response)
	}
}

fn truncate_range(range: &PartialFileRange, file_length: &Option<u64>) -> Option<(u64, u64)> {
	use self::PartialFileRange::*;

	match (range, file_length) {
		(FromTo(from, to), Some(file_length)) => {
			if from <= to && from < file_length {
				Some((*from, cmp::min(*to, file_length - 1)))
			} else {
				None
			}
		}
		(AllFrom(from), Some(file_length)) => {
			if from < file_length {
				Some((*from, file_length - 1))
			} else {
				None
			}
		}
		(Last(last), Some(file_length)) => {
			if last < file_length {
				Some((file_length - last, file_length - 1))
			} else {
				Some((0, file_length - 1))
			}
		}
		(_, None) => None,
	}
}

impl<'r> Responder<'r> for RangeResponder<File> {
	fn respond_to(mut self, request: &rocket::request::Request) -> response::Result<'r> {

		let metadata: Option<_> = self.original.metadata().ok();
		let file_length: Option<u64> = metadata.map(|m| m.len());

		let range_header = request.headers().get_one("Range");
		let range_header = match range_header {
			None => return self.ignore_range(request, file_length),
			Some(h) => h,
		};

		let vec_range = match Range::from_str(range_header) {
			Ok(Range::Bytes(v)) => v,
			_ => {
				warn!("Ignoring range header that could not be parse {:?}, file length is {:?}", range_header, file_length);
				return self.ignore_range(request, file_length);
			},
		};

		let partial_file_range = match vec_range.into_iter().next() {
			None => PartialFileRange::AllFrom(0),
			Some(byte_range) => PartialFileRange::from(byte_range),
		};

		let range: Option<(u64, u64)> = truncate_range(&partial_file_range, &file_length);

		if let Some((from, to)) = range {
			let content_range = ContentRange(ContentRangeSpec::Bytes {
				range: range,
				instance_length: file_length,
			});
			let content_len = to - from + 1;

			match self.original.seek(SeekFrom::Start(from)) {
				Ok(_) => (),
				Err(_) => return Err(rocket::http::Status::InternalServerError),
			}
			let partial_original = self.original.take(content_len).into_inner();
			let mut response = partial_original.respond_to(request)?;
			response.set_header(ContentLength(content_len));
			response.set_header(content_range);
			response.set_status(rocket::http::Status::PartialContent);

			Ok(response)
		} else {
			warn!("Rejecting unsatisfiable range header {:?}, file length is {:?}", &partial_file_range, &file_length);
			self.reject_range(file_length)
		}
	}
}
<|endoftext|>


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

#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Point {
    pub x: f64,
    pub y: f64,
}

impl Point {
    pub fn new(x: f64, y: f64) -> Self {
        Point { x: x, y: y }
    }

    pub fn cross(self, other: Point) -> f64 {
        return self.x * other.y - other.x * self.y;
    }

    pub fn dot(self, other: Point) -> f64 {
        return self.x * other.x + self.y * other.y;
    }
}

impl Sub<Point> for Point {
    type Output = Point;

    fn sub(self, other: Point) -> Self::Output {
        return Point {
            x: self.x - other.x,
            y: self.y - other.y,
        };
    }
}

impl Div<f64> for Point {
    type Output = Point;

    fn div(self, other: f64) -> Self::Output {
        return Point {
            x: self.x / other,
            y: self.y / other,
        };
    }
}

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

    #[test]
    fn test_new() {
        expect!(Point::new(1.0, 1.0)).to(be_equal_to(Point { x: 1.0, y: 1.0 }));
    }
}
<commit_msg>Add dot and cross product tests + minor refactor<commit_after>use std::ops::{Sub, Div};

#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Point {
    pub x: f64,
    pub y: f64,
}

impl Point {
    pub fn new(x: f64, y: f64) -> Self {
        Point { x: x, y: y }
    }

    pub fn cross(self, other: Point) -> f64 {
        return self.x * other.y - other.x * self.y;
    }

    pub fn dot(self, other: Point) -> f64 {
        return self.x * other.x + self.y * other.y;
    }
}

impl Sub<Point> for Point {
    type Output = Point;

    fn sub(self, other: Point) -> Self::Output {
        return Point {
            x: self.x - other.x,
            y: self.y - other.y,
        };
    }
}

impl Div<f64> for Point {
    type Output = Point;

    fn div(self, other: f64) -> Self::Output {
        return Point {
            x: self.x / other,
            y: self.y / other,
        };
    }
}

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

    const P1: Point = Point { x: 2.0, y: 3.0 };
    const P2: Point = Point { x: 5.0, y: 7.0 };

    #[test]
    fn test_new() {
        expect!(Point::new(2.0, 3.0)).to(be_equal_to(P1));
    }

    #[test]
    fn test_cross() {
        expect!(P1.cross(P2)).to(be_equal_to(-1.0));
    }

    #[test]
    fn test_dot() {
        expect!(P1.dot(P2)).to(be_equal_to(31.0));
    }
}
<|endoftext|>


<commit_before>use rustc::lint::*;
use rustc::ty::subst::Subst;
use rustc::ty::TypeVariants;
use rustc::ty::fast_reject::simplify_type;
use rustc::ty;
use rustc::hir::*;
use syntax::ast::{Attribute, MetaItemKind};
use syntax::codemap::Span;
use utils::{CLONE_TRAIT_PATH, HASH_PATH};
use utils::{match_path, span_lint_and_then};

/// **What it does:** This lint warns about deriving `Hash` but implementing `PartialEq`
/// explicitly.
///
/// **Why is this bad?** The implementation of these traits must agree (for example for use with
/// `HashMap`) so it’s probably a bad idea to use a default-generated `Hash` implementation  with
/// an explicitly defined `PartialEq`. In particular, the following must hold for any type:
///
/// ```rust
/// k1 == k2 ⇒ hash(k1) == hash(k2)
/// ```
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// #[derive(Hash)]
/// struct Foo;
///
/// impl PartialEq for Foo {
///     ..
/// }
/// ```
declare_lint! {
    pub DERIVE_HASH_XOR_EQ,
    Warn,
    "deriving `Hash` but implementing `PartialEq` explicitly"
}

/// **What it does:** This lint warns about explicit `Clone` implementation for `Copy` types.
///
/// **Why is this bad?** To avoid surprising behaviour, these traits should agree and the behaviour
/// of `Copy` cannot be overridden. In almost all situations a `Copy` type should have a `Clone`
/// implementation that does nothing more than copy the object, which is what
/// `#[derive(Copy, Clone)]` gets you.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// #[derive(Copy)]
/// struct Foo;
///
/// impl Clone for Foo {
///     ..
/// }
/// ```
declare_lint! {
    pub EXPL_IMPL_CLONE_ON_COPY,
    Warn,
    "implementing `Clone` explicitly on `Copy` types"
}

pub struct Derive;

impl LintPass for Derive {
    fn get_lints(&self) -> LintArray {
        lint_array!(EXPL_IMPL_CLONE_ON_COPY, DERIVE_HASH_XOR_EQ)
    }
}

impl LateLintPass for Derive {
    fn check_item(&mut self, cx: &LateContext, item: &Item) {
        if_let_chain! {[
            let ItemImpl(_, _, _, Some(ref trait_ref), _, _) = item.node
        ], {
            let ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(item.id)).ty;
            let is_automatically_derived = item.attrs.iter().any(is_automatically_derived);

            check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);

            if !is_automatically_derived {
                check_copy_clone(cx, item, trait_ref, ty);
            }
        }}
    }
}

/// Implementation of the `DERIVE_HASH_XOR_EQ` lint.
fn check_hash_peq(cx: &LateContext, span: Span, trait_ref: &TraitRef, ty: ty::Ty, hash_is_automatically_derived: bool) {
    if_let_chain! {[
        match_path(&trait_ref.path, &HASH_PATH),
        let Some(peq_trait_def_id) = cx.tcx.lang_items.eq_trait()
    ], {
        let peq_trait_def = cx.tcx.lookup_trait_def(peq_trait_def_id);

        cx.tcx.populate_implementations_for_trait_if_necessary(peq_trait_def.trait_ref.def_id);
        let peq_impls = peq_trait_def.borrow_impl_lists(cx.tcx).1;

        // Look for the PartialEq implementations for `ty`
        if_let_chain! {[
            let Some(simpl_ty) = simplify_type(cx.tcx, ty, false),
            let Some(impl_ids) = peq_impls.get(&simpl_ty)
        ], {
            for &impl_id in impl_ids {
                let peq_is_automatically_derived = cx.tcx.get_attrs(impl_id).iter().any(is_automatically_derived);

                if peq_is_automatically_derived == hash_is_automatically_derived {
                    return;
                }

                let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation");

                // Only care about `impl PartialEq<Foo> for Foo`
                if trait_ref.input_types()[0] == ty {
                    let mess = if peq_is_automatically_derived {
                        "you are implementing `Hash` explicitly but have derived `PartialEq`"
                    } else {
                        "you are deriving `Hash` but have implemented `PartialEq` explicitly"
                    };

                    span_lint_and_then(
                        cx, DERIVE_HASH_XOR_EQ, span,
                        mess,
                        |db| {
                        if let Some(node_id) = cx.tcx.map.as_local_node_id(impl_id) {
                            db.span_note(
                                cx.tcx.map.span(node_id),
                                "`PartialEq` implemented here"
                            );
                        }
                    });
                }
            }
        }}
    }}
}

/// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint.
fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item, trait_ref: &TraitRef, ty: ty::Ty<'tcx>) {
    if match_path(&trait_ref.path, &CLONE_TRAIT_PATH) {
        let parameter_environment = ty::ParameterEnvironment::for_item(cx.tcx, item.id);
        let subst_ty = ty.subst(cx.tcx, &parameter_environment.free_substs);

        if subst_ty.moves_by_default(&parameter_environment, item.span) {
            return; // ty is not Copy
        }

        // Some types are not Clone by default but could be cloned `by hand` if necessary
        match ty.sty {
            TypeVariants::TyEnum(def, substs) | TypeVariants::TyStruct(def, substs) => {
                for variant in &def.variants {
                    for field in &variant.fields {
                        match field.ty(cx.tcx, substs).sty {
                            TypeVariants::TyArray(_, size) if size > 32 => {
                                return;
                            }
                            TypeVariants::TyFnPtr(..) => {
                                return;
                            }
                            TypeVariants::TyTuple(ref tys) if tys.len() > 12 => {
                                return;
                            }
                            _ => (),
                        }
                    }
                }
            }
            _ => (),
        }

        span_lint_and_then(cx,
                           EXPL_IMPL_CLONE_ON_COPY,
                           item.span,
                           "you are implementing `Clone` explicitly on a `Copy` type",
                           |db| {
                               db.span_note(item.span, "consider deriving `Clone` or removing `Copy`");
                           });
    }
}

/// Checks for the `#[automatically_derived]` attribute all `#[derive]`d implementations have.
fn is_automatically_derived(attr: &Attribute) -> bool {
    if let MetaItemKind::Word(ref word) = attr.node.value.node {
        word == &"automatically_derived"
    } else {
        false
    }
}
<commit_msg>Rustup to 1.9.0-nightly (7979dd608 2016-04-07)<commit_after>use rustc::lint::*;
use rustc::ty::subst::Subst;
use rustc::ty::TypeVariants;
use rustc::ty;
use rustc::hir::*;
use syntax::ast::{Attribute, MetaItemKind};
use syntax::codemap::Span;
use utils::{CLONE_TRAIT_PATH, HASH_PATH};
use utils::{match_path, span_lint_and_then};

/// **What it does:** This lint warns about deriving `Hash` but implementing `PartialEq`
/// explicitly.
///
/// **Why is this bad?** The implementation of these traits must agree (for example for use with
/// `HashMap`) so it’s probably a bad idea to use a default-generated `Hash` implementation  with
/// an explicitly defined `PartialEq`. In particular, the following must hold for any type:
///
/// ```rust
/// k1 == k2 ⇒ hash(k1) == hash(k2)
/// ```
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// #[derive(Hash)]
/// struct Foo;
///
/// impl PartialEq for Foo {
///     ..
/// }
/// ```
declare_lint! {
    pub DERIVE_HASH_XOR_EQ,
    Warn,
    "deriving `Hash` but implementing `PartialEq` explicitly"
}

/// **What it does:** This lint warns about explicit `Clone` implementation for `Copy` types.
///
/// **Why is this bad?** To avoid surprising behaviour, these traits should agree and the behaviour
/// of `Copy` cannot be overridden. In almost all situations a `Copy` type should have a `Clone`
/// implementation that does nothing more than copy the object, which is what
/// `#[derive(Copy, Clone)]` gets you.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// #[derive(Copy)]
/// struct Foo;
///
/// impl Clone for Foo {
///     ..
/// }
/// ```
declare_lint! {
    pub EXPL_IMPL_CLONE_ON_COPY,
    Warn,
    "implementing `Clone` explicitly on `Copy` types"
}

pub struct Derive;

impl LintPass for Derive {
    fn get_lints(&self) -> LintArray {
        lint_array!(EXPL_IMPL_CLONE_ON_COPY, DERIVE_HASH_XOR_EQ)
    }
}

impl LateLintPass for Derive {
    fn check_item(&mut self, cx: &LateContext, item: &Item) {
        if_let_chain! {[
            let ItemImpl(_, _, _, Some(ref trait_ref), _, _) = item.node
        ], {
            let ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(item.id)).ty;
            let is_automatically_derived = item.attrs.iter().any(is_automatically_derived);

            check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);

            if !is_automatically_derived {
                check_copy_clone(cx, item, trait_ref, ty);
            }
        }}
    }
}

/// Implementation of the `DERIVE_HASH_XOR_EQ` lint.
fn check_hash_peq<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, span: Span, trait_ref: &TraitRef, ty: ty::Ty<'tcx>, hash_is_automatically_derived: bool) {
    if_let_chain! {[
        match_path(&trait_ref.path, &HASH_PATH),
        let Some(peq_trait_def_id) = cx.tcx.lang_items.eq_trait()
    ], {
        let peq_trait_def = cx.tcx.lookup_trait_def(peq_trait_def_id);

        // Look for the PartialEq implementations for `ty`
        peq_trait_def.for_each_relevant_impl(&cx.tcx, ty, |impl_id| {
            let peq_is_automatically_derived = cx.tcx.get_attrs(impl_id).iter().any(is_automatically_derived);

            if peq_is_automatically_derived == hash_is_automatically_derived {
                return;
            }

            let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation");

            // Only care about `impl PartialEq<Foo> for Foo`
            if trait_ref.input_types()[0] == ty {
                let mess = if peq_is_automatically_derived {
                    "you are implementing `Hash` explicitly but have derived `PartialEq`"
                } else {
                    "you are deriving `Hash` but have implemented `PartialEq` explicitly"
                };

                span_lint_and_then(
                    cx, DERIVE_HASH_XOR_EQ, span,
                    mess,
                    |db| {
                    if let Some(node_id) = cx.tcx.map.as_local_node_id(impl_id) {
                        db.span_note(
                            cx.tcx.map.span(node_id),
                            "`PartialEq` implemented here"
                        );
                    }
                });
            }
        });
    }}
}

/// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint.
fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item, trait_ref: &TraitRef, ty: ty::Ty<'tcx>) {
    if match_path(&trait_ref.path, &CLONE_TRAIT_PATH) {
        let parameter_environment = ty::ParameterEnvironment::for_item(cx.tcx, item.id);
        let subst_ty = ty.subst(cx.tcx, &parameter_environment.free_substs);

        if subst_ty.moves_by_default(&parameter_environment, item.span) {
            return; // ty is not Copy
        }

        // Some types are not Clone by default but could be cloned `by hand` if necessary
        match ty.sty {
            TypeVariants::TyEnum(def, substs) | TypeVariants::TyStruct(def, substs) => {
                for variant in &def.variants {
                    for field in &variant.fields {
                        match field.ty(cx.tcx, substs).sty {
                            TypeVariants::TyArray(_, size) if size > 32 => {
                                return;
                            }
                            TypeVariants::TyFnPtr(..) => {
                                return;
                            }
                            TypeVariants::TyTuple(ref tys) if tys.len() > 12 => {
                                return;
                            }
                            _ => (),
                        }
                    }
                }
            }
            _ => (),
        }

        span_lint_and_then(cx,
                           EXPL_IMPL_CLONE_ON_COPY,
                           item.span,
                           "you are implementing `Clone` explicitly on a `Copy` type",
                           |db| {
                               db.span_note(item.span, "consider deriving `Clone` or removing `Copy`");
                           });
    }
}

/// Checks for the `#[automatically_derived]` attribute all `#[derive]`d implementations have.
fn is_automatically_derived(attr: &Attribute) -> bool {
    if let MetaItemKind::Word(ref word) = attr.node.value.node {
        word == &"automatically_derived"
    } else {
        false
    }
}
<|endoftext|>