<commit_before>use std::fmt::{Display, Formatter, Result, Write};

use frontend::lexer::Token;
use frontend::lexer::LexerError;
use frontend::parser::ParserError;
use frontend::expressionparser::ExpressionParserError;
use frontend::codegen::CodeGenError;
use frontend::evaluate_expression::EvaluateExpressionError;

macro_rules! error_panic(
    ($cfg:expr => $($arg:tt)+) => (
        {
            if !$cfg.force {
                error!("{}", $($arg)*);
                panic!("Config is set to panic at any error. Try setting the --force flag to ignore this and other errors.")
            } else {
                warn!("{}", $($arg)*);
            }
        }
    )
);

macro_rules! error_force_panic(
    ($($arg:tt)+) => (
        {
            error!("{}", $($arg)*);
            panic!("Can't continue. This error is not recoverable and not ignorable through --force.");
        }
    )
);

impl Display for Token {
    fn fmt(&self, f: &mut Formatter) -> Result {
        match self {
            &Token::TokError{ref message, ..} => try!(f.write_str(&*message)),
            _ => try!(f.write_fmt(format_args!("{:?}", self))),
        };
        Ok(())
    }
}

impl Display for LexerError {
    fn fmt(&self, f: &mut Formatter) -> Result {
        try!(f.write_str("[!!!] Critical Lexer Error\n[!!!] "));
        match self {
            &LexerError::UnexpectedCharacter { character, location } => {
                try!(f.write_fmt(format_args!("Unexpected character '{}' at {}:{}", character, location.0, location.1)))
            }
        };
        Ok(())
    }
}

impl Display for ParserError {
    fn fmt(&self, f: &mut Formatter) -> Result {
        try!(f.write_str("[!!!] Critical Parser Error\n[!!!] "));
        match self {
            &ParserError::TokenDoNotMatch{ref token, ref stack} =>
                match token {
                    &Some(ref token) => try!(f.write_fmt(format_args!("Stack Token does not match. Token:{:?} Stack:{:?}", token, stack))),
                    &None => try!(f.write_fmt(format_args!("No Tokens left, but Terminal is left on Stack. Token:{:?}", stack))),
                },
            &ParserError::StackIsEmpty{ref token} => try!(f.write_fmt(format_args!("Tokens left but Stack is empty. Token:{:?}", token))),
            &ParserError::NoProjection{ref token, ref stack} => try!(f.write_fmt(format_args!("No Projection found for Token:{:?} and NonTerminal:{:?}", token, stack))),
            &ParserError::NonTerminalEnd{ref stack} => try!(f.write_fmt(format_args!("NonTerminal:{:?} is no allowed End", stack))),
        };
        Ok(())
    }
}

impl Display for ExpressionParserError {
    fn fmt(&self, f: &mut Formatter) -> Result {
        try!(f.write_str("[!!!] Critical Expression Parser Error\n[!!!] "));
        match self {
            &ExpressionParserError::OperStackIsEmpty => {
                try!(f.write_str("No token in the operators stack."))
            },
            &ExpressionParserError::NoParseableSubExpression => {
                try!(f.write_str("No parsable sub-expression"))
            },
            &ExpressionParserError::MoreThanOneRootExpression { count, ref stack } => {
                try!(f.write_fmt(format_args!("Only one expression can be the root. But there are {}. Stack: {:?}", count, stack)))
            },
            &ExpressionParserError::NotEnoughElementsOnStack => {
                try!(f.write_str("Not enough elements on the stack to create a node"))
            },
            &ExpressionParserError::MissingNodeForBinaryNode => {
                try!(f.write_str("Missing Node to create binary node"))
            },
            &ExpressionParserError::DisallowedOperator { ref op } => {
                try!(f.write_fmt(format_args!("Checking the operator ranking for operator '{:?}' failed: The operator is not allowed in this context.", op)))
            },
            &ExpressionParserError::NotImplementedOperator { ref op } => {
                try!(f.write_fmt(format_args!("This operator is not implemented: '{}'", op)))
            }
        };
        Ok(())
    }
}

impl Display for CodeGenError {
    fn fmt(&self, f: &mut Formatter) -> Result {
        try!(f.write_str("[!!!] Critical Codegen Error:\n[!!!] "));
        match self {
            &CodeGenError::CouldNotWriteToOutput { ref why } => {
                try!(f.write_fmt(format_args!("Could not write to output: {}", why)))
            },
            &CodeGenError::UnsupportedExpression { ref token } => {
                try!(f.write_fmt(format_args!("Unsupported expression at {}:{}", token.location().0, token.location().1)))
            },
            &CodeGenError::UnsupportedIfExpression { ref token } => {
                try!(f.write_fmt(format_args!("Unsupported if-expression at {}:{}", token.location().0, token.location().1)))
            },
            &CodeGenError::UnsupportedElseIfExpression { ref token } => {
                try!(f.write_fmt(format_args!("Unsupported else-if-expression at {}:{}", token.location().0, token.location().1)))
            },
            &CodeGenError::UnsupportedExpressionType { ref name } => {
                try!(f.write_fmt(format_args!("This expression type is not supported right now: {}", name)))
            },
            &CodeGenError::UnsupportedLongExpression { ref name, ref token } => {
                try!(f.write_fmt(format_args!("Error at {}:{}: {} does not support any kind of expression, only variables or constants.", token.location().0, token.location().1, name)))
            },
            &CodeGenError::NoMatch { ref token } => {
                try!(f.write_fmt(format_args!("Can't find any AST operation for token: {}", token)))
            },
            &CodeGenError::PassageDoesNotExist { ref name, ref token } => {
                try!(f.write_fmt(format_args!("Referenced passage '{}' at {}:{} but the passage does not exist", name, token.location().0, token.location().1)))
            },
            &CodeGenError::InvalidAST => {
                try!(f.write_str("Internal error: Unexpected AST node. This should not happen. Report a bug please."))
            },
            &CodeGenError::NoStartPassage => {
                try!(f.write_str("Start passage does not exist or can not be found. Every Twee file needs a passage with the name 'Start'."))
            },
            &CodeGenError::IdentifierStackEmpty => {
                try!(f.write_str("Identifier stack is empty. Operation wasn't possible."))
            },
            &CodeGenError::SymbolMapEmpty => {
                try!(f.write_str("Symbol map is empty. Operation wasn't possible."))
            },
            &CodeGenError::CouldNotFindSymbolId => {
                try!(f.write_str("Could not find symbol ID in symbol table. Report a bug."))
            }
        };
        Ok(())
    }
}

impl Display for EvaluateExpressionError {
    fn fmt(&self, f: &mut Formatter) -> Result {
        try!(f.write_str("[!!!] Critical Error while evaluating expression:\n[!!!] "));
        match self {
            &EvaluateExpressionError::NumericOperatorNeedsTwoArguments { ref op_name, location: (line, ch) } => {
                try!(f.write_fmt(format_args!("Numeric Operator '{}' at {}:{} needs two arguments", op_name, line, ch)))
            },
            &EvaluateExpressionError::UnsupportedOperator { ref op_name, location: (line, ch) } => {
                try!(f.write_fmt(format_args!("Operator '{}' at {}:{} is not supported right now", op_name, line, ch)))
            },
            &EvaluateExpressionError::UnsupportedFunctionArgsLen { ref name, location: (line, ch), expected } => {
                try!(f.write_fmt(format_args!("Function '{}' at {}:{} can only take {} arguments", name, line, ch, expected)))
            },
            &EvaluateExpressionError::UnsupportedFunctionArgType { ref name, index, location: (line, ch) } => {
                try!(f.write_fmt(format_args!("Function '{}' at {}:{}: Unsupported argument type at argument #{}", name, line, ch, index)))
            }
            &EvaluateExpressionError::InvalidAST => {
                try!(f.write_str("Internal error: Unsupported AST node. This should not happen. Report a bug please."));
            },
            &EvaluateExpressionError::UnsupportedFunction { ref name, location: (line, ch) } => {
                try!(f.write_fmt(format_args!("Function '{}' at {}:{} is not supported right now", name, line, ch)))
            },
            &EvaluateExpressionError::NoTempIdLeftOnStack => {
                try!(f.write_str("No temporary identifier left on the stack. Expression is too long."))
            },
            &EvaluateExpressionError::UnhandledToken { ref token } => {
                try!(f.write_fmt(format_args!("Unhandled token in expression: {:?}", token)))
            }
        };
        Ok(())
    }
}

<commit_msg>Made PassageDoesNotExists not contain the passage name for optimization reasons<commit_after>use std::fmt::{Display, Formatter, Result, Write};

use frontend::lexer::Token;
use frontend::lexer::LexerError;
use frontend::parser::ParserError;
use frontend::expressionparser::ExpressionParserError;
use frontend::evaluate_expression::EvaluateExpressionError;
use backend::codegen::CodeGenError;

macro_rules! error_panic(
    ($cfg:expr => $($arg:tt)+) => (
        {
            if !$cfg.force {
                error!("{}", $($arg)*);
                panic!("Config is set to panic at any error. Try setting the --force flag to ignore this and other errors.")
            } else {
                warn!("{}", $($arg)*);
            }
        }
    )
);

macro_rules! error_force_panic(
    ($($arg:tt)+) => (
        {
            error!("{}", $($arg)*);
            panic!("Can't continue. This error is not recoverable and not ignorable through --force.");
        }
    )
);

impl Display for Token {
    fn fmt(&self, f: &mut Formatter) -> Result {
        match self {
            &Token::TokError{ref message, ..} => try!(f.write_str(&*message)),
            _ => try!(f.write_fmt(format_args!("{:?}", self))),
        };
        Ok(())
    }
}

impl Display for LexerError {
    fn fmt(&self, f: &mut Formatter) -> Result {
        try!(f.write_str("[!!!] Critical Lexer Error\n[!!!] "));
        match self {
            &LexerError::UnexpectedCharacter { character, location } => {
                try!(f.write_fmt(format_args!("Unexpected character '{}' at {}:{}", character, location.0, location.1)))
            }
        };
        Ok(())
    }
}

impl Display for ParserError {
    fn fmt(&self, f: &mut Formatter) -> Result {
        try!(f.write_str("[!!!] Critical Parser Error\n[!!!] "));
        match self {
            &ParserError::TokenDoNotMatch{ref token, ref stack} =>
                match token {
                    &Some(ref token) => try!(f.write_fmt(format_args!("Stack Token does not match. Token:{:?} Stack:{:?}", token, stack))),
                    &None => try!(f.write_fmt(format_args!("No Tokens left, but Terminal is left on Stack. Token:{:?}", stack))),
                },
            &ParserError::StackIsEmpty{ref token} => try!(f.write_fmt(format_args!("Tokens left but Stack is empty. Token:{:?}", token))),
            &ParserError::NoProjection{ref token, ref stack} => try!(f.write_fmt(format_args!("No Projection found for Token:{:?} and NonTerminal:{:?}", token, stack))),
            &ParserError::NonTerminalEnd{ref stack} => try!(f.write_fmt(format_args!("NonTerminal:{:?} is no allowed End", stack))),
        };
        Ok(())
    }
}

impl Display for ExpressionParserError {
    fn fmt(&self, f: &mut Formatter) -> Result {
        try!(f.write_str("[!!!] Critical Expression Parser Error\n[!!!] "));
        match self {
            &ExpressionParserError::OperStackIsEmpty => {
                try!(f.write_str("No token in the operators stack."))
            },
            &ExpressionParserError::NoParseableSubExpression => {
                try!(f.write_str("No parsable sub-expression"))
            },
            &ExpressionParserError::MoreThanOneRootExpression { count, ref stack } => {
                try!(f.write_fmt(format_args!("Only one expression can be the root. But there are {}. Stack: {:?}", count, stack)))
            },
            &ExpressionParserError::NotEnoughElementsOnStack => {
                try!(f.write_str("Not enough elements on the stack to create a node"))
            },
            &ExpressionParserError::MissingNodeForBinaryNode => {
                try!(f.write_str("Missing Node to create binary node"))
            },
            &ExpressionParserError::DisallowedOperator { ref op } => {
                try!(f.write_fmt(format_args!("Checking the operator ranking for operator '{:?}' failed: The operator is not allowed in this context.", op)))
            },
            &ExpressionParserError::NotImplementedOperator { ref op } => {
                try!(f.write_fmt(format_args!("This operator is not implemented: '{}'", op)))
            }
        };
        Ok(())
    }
}

impl Display for CodeGenError {
    fn fmt(&self, f: &mut Formatter) -> Result {
        try!(f.write_str("[!!!] Critical Codegen Error:\n[!!!] "));
        match self {
            &CodeGenError::CouldNotWriteToOutput { ref why } => {
                try!(f.write_fmt(format_args!("Could not write to output: {}", why)))
            },
            &CodeGenError::UnsupportedExpression { ref token } => {
                try!(f.write_fmt(format_args!("Unsupported expression at {}:{}", token.location().0, token.location().1)))
            },
            &CodeGenError::UnsupportedIfExpression { ref token } => {
                try!(f.write_fmt(format_args!("Unsupported if-expression at {}:{}", token.location().0, token.location().1)))
            },
            &CodeGenError::UnsupportedElseIfExpression { ref token } => {
                try!(f.write_fmt(format_args!("Unsupported else-if-expression at {}:{}", token.location().0, token.location().1)))
            },
            &CodeGenError::UnsupportedExpressionType { ref name } => {
                try!(f.write_fmt(format_args!("This expression type is not supported right now: {}", name)))
            },
            &CodeGenError::UnsupportedLongExpression { ref name, ref token } => {
                try!(f.write_fmt(format_args!("Error at {}:{}: {} does not support any kind of expression, only variables or constants.", token.location().0, token.location().1, name)))
            },
            &CodeGenError::NoMatch { ref token } => {
                try!(f.write_fmt(format_args!("Can't find any AST operation for token: {}", token)))
            },
            &CodeGenError::PassageDoesNotExist { ref name } => {
                try!(f.write_fmt(format_args!("Referenced passage '{}' but the passage does not exist", name)))
            },
            &CodeGenError::InvalidAST => {
                try!(f.write_str("Internal error: Unexpected AST node. This should not happen. Report a bug please."))
            },
            &CodeGenError::NoStartPassage => {
                try!(f.write_str("Start passage does not exist or can not be found. Every Twee file needs a passage with the name 'Start'."))
            },
            &CodeGenError::IdentifierStackEmpty => {
                try!(f.write_str("Identifier stack is empty. Operation wasn't possible."))
            },
            &CodeGenError::SymbolMapEmpty => {
                try!(f.write_str("Symbol map is empty. Operation wasn't possible."))
            },
            &CodeGenError::CouldNotFindSymbolId => {
                try!(f.write_str("Could not find symbol ID in symbol table. Report a bug."))
            }
        };
        Ok(())
    }
}

impl Display for EvaluateExpressionError {
    fn fmt(&self, f: &mut Formatter) -> Result {
        try!(f.write_str("[!!!] Critical Error while evaluating expression:\n[!!!] "));
        match self {
            &EvaluateExpressionError::NumericOperatorNeedsTwoArguments { ref op_name, location: (line, ch) } => {
                try!(f.write_fmt(format_args!("Numeric Operator '{}' at {}:{} needs two arguments", op_name, line, ch)))
            },
            &EvaluateExpressionError::UnsupportedOperator { ref op_name, location: (line, ch) } => {
                try!(f.write_fmt(format_args!("Operator '{}' at {}:{} is not supported right now", op_name, line, ch)))
            },
            &EvaluateExpressionError::UnsupportedFunctionArgsLen { ref name, location: (line, ch), expected } => {
                try!(f.write_fmt(format_args!("Function '{}' at {}:{} can only take {} arguments", name, line, ch, expected)))
            },
            &EvaluateExpressionError::UnsupportedFunctionArgType { ref name, index, location: (line, ch) } => {
                try!(f.write_fmt(format_args!("Function '{}' at {}:{}: Unsupported argument type at argument #{}", name, line, ch, index)))
            }
            &EvaluateExpressionError::InvalidAST => {
                try!(f.write_str("Internal error: Unsupported AST node. This should not happen. Report a bug please."));
            },
            &EvaluateExpressionError::UnsupportedFunction { ref name, location: (line, ch) } => {
                try!(f.write_fmt(format_args!("Function '{}' at {}:{} is not supported right now", name, line, ch)))
            },
            &EvaluateExpressionError::NoTempIdLeftOnStack => {
                try!(f.write_str("No temporary identifier left on the stack. Expression is too long."))
            },
            &EvaluateExpressionError::UnhandledToken { ref token } => {
                try!(f.write_fmt(format_args!("Unhandled token in expression: {:?}", token)))
            }
        };
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::fs::{self, File};
use std::io::Write;
use std::net::TcpListener;
use std::process::Stdio;
use std::thread;

use git2;
use hamcrest::{assert_that, existing_file};

use support::{execs, project, ERROR};
use support::git;
use support::registry::Package;
use test_cargo_install::{cargo_home, has_installed_exe};

fn setup() {}

test!(multiple_installs {
    let p = project("foo")
        .file("a/Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.0"
        "#)
        .file("a/src/main.rs", "fn main() {}")
        .file("b/Cargo.toml", r#"
            [package]
            name = "bar"
            authors = []
            version = "0.0.0"
        "#)
        .file("b/src/main.rs", "fn main() {}");
    p.build();

    let mut a = p.cargo("install").cwd(p.root().join("a")).build_command();
    let mut b = p.cargo("install").cwd(p.root().join("b")).build_command();

    a.stdout(Stdio::piped()).stderr(Stdio::piped());
    b.stdout(Stdio::piped()).stderr(Stdio::piped());

    let a = a.spawn().unwrap();
    let b = b.spawn().unwrap();
    let a = thread::spawn(move || a.wait_with_output().unwrap());
    let b = b.wait_with_output().unwrap();
    let a = a.join().unwrap();

    assert_that(a, execs().with_status(0));
    assert_that(b, execs().with_status(0));

    assert_that(cargo_home(), has_installed_exe("foo"));
    assert_that(cargo_home(), has_installed_exe("bar"));
});

test!(one_install_should_be_bad {
    let p = project("foo")
        .file("a/Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.0"
        "#)
        .file("a/src/main.rs", "fn main() {}")
        .file("b/Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.0"
        "#)
        .file("b/src/main.rs", "fn main() {}");
    p.build();

    let mut a = p.cargo("install").cwd(p.root().join("a")).build_command();
    let mut b = p.cargo("install").cwd(p.root().join("b")).build_command();

    a.stdout(Stdio::piped()).stderr(Stdio::piped());
    b.stdout(Stdio::piped()).stderr(Stdio::piped());

    let a = a.spawn().unwrap();
    let b = b.spawn().unwrap();
    let a = thread::spawn(move || a.wait_with_output().unwrap());
    let b = b.wait_with_output().unwrap();
    let a = a.join().unwrap();

    let (bad, good) = if a.status.code() == Some(101) {(a, b)} else {(b, a)};
    assert_that(bad, execs().with_status(101).with_stderr_contains(&format!("\
{error} binary `foo[..]` already exists in destination as part of `[..]`
", error = ERROR)));
    assert_that(good, execs().with_status(0).with_stderr("\
warning: be sure to add `[..]` to your PATH [..]
"));

    assert_that(cargo_home(), has_installed_exe("foo"));
});

test!(multiple_registry_fetches {
    let mut pkg = Package::new("bar", "1.0.2");
    for i in 0..10 {
        let name = format!("foo{}", i);
        Package::new(&name, "1.0.0").publish();
        pkg.dep(&name, "*");
    }
    pkg.publish();

    let p = project("foo")
        .file("a/Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.0"

            [dependencies]
            bar = "*"
        "#)
        .file("a/src/main.rs", "fn main() {}")
        .file("b/Cargo.toml", r#"
            [package]
            name = "bar"
            authors = []
            version = "0.0.0"

            [dependencies]
            bar = "*"
        "#)
        .file("b/src/main.rs", "fn main() {}");
    p.build();

    let mut a = p.cargo("build").cwd(p.root().join("a")).build_command();
    let mut b = p.cargo("build").cwd(p.root().join("b")).build_command();

    a.stdout(Stdio::piped()).stderr(Stdio::piped());
    b.stdout(Stdio::piped()).stderr(Stdio::piped());

    let a = a.spawn().unwrap();
    let b = b.spawn().unwrap();
    let a = thread::spawn(move || a.wait_with_output().unwrap());
    let b = b.wait_with_output().unwrap();
    let a = a.join().unwrap();

    assert_that(a, execs().with_status(0));
    assert_that(b, execs().with_status(0));

    let suffix = env::consts::EXE_SUFFIX;
    assert_that(&p.root().join("a/target/debug").join(format!("foo{}", suffix)),
                existing_file());
    assert_that(&p.root().join("b/target/debug").join(format!("bar{}", suffix)),
                existing_file());
});

test!(git_same_repo_different_tags {
    let a = git::new("dep", |project| {
        project.file("Cargo.toml", r#"
            [project]
            name = "dep"
            version = "0.5.0"
            authors = []
        "#).file("src/lib.rs", "pub fn tag1() {}")
    }).unwrap();

    let repo = git2::Repository::open(&a.root()).unwrap();
    git::tag(&repo, "tag1");

    File::create(a.root().join("src/lib.rs")).unwrap()
         .write_all(b"pub fn tag2() {}").unwrap();
    git::add(&repo);
    git::commit(&repo);
    git::tag(&repo, "tag2");

    let p = project("foo")
        .file("a/Cargo.toml", &format!(r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.0"

            [dependencies]
            dep = {{ git = '{}', tag = 'tag1' }}
        "#, a.url()))
        .file("a/src/main.rs", "extern crate dep; fn main() { dep::tag1(); }")
        .file("b/Cargo.toml", &format!(r#"
            [package]
            name = "bar"
            authors = []
            version = "0.0.0"

            [dependencies]
            dep = {{ git = '{}', tag = 'tag2' }}
        "#, a.url()))
        .file("b/src/main.rs", "extern crate dep; fn main() { dep::tag2(); }");
    p.build();

    let mut a = p.cargo("build").arg("-v").cwd(p.root().join("a")).build_command();
    let mut b = p.cargo("build").arg("-v").cwd(p.root().join("b")).build_command();

    a.stdout(Stdio::piped()).stderr(Stdio::piped());
    b.stdout(Stdio::piped()).stderr(Stdio::piped());

    let a = a.spawn().unwrap();
    let b = b.spawn().unwrap();
    let a = thread::spawn(move || a.wait_with_output().unwrap());
    let b = b.wait_with_output().unwrap();
    let a = a.join().unwrap();

    assert_that(a, execs().with_status(0));
    assert_that(b, execs().with_status(0));
});

test!(git_same_branch_different_revs {
    let a = git::new("dep", |project| {
        project.file("Cargo.toml", r#"
            [project]
            name = "dep"
            version = "0.5.0"
            authors = []
        "#).file("src/lib.rs", "pub fn f1() {}")
    }).unwrap();

    let p = project("foo")
        .file("a/Cargo.toml", &format!(r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.0"

            [dependencies]
            dep = {{ git = '{}' }}
        "#, a.url()))
        .file("a/src/main.rs", "extern crate dep; fn main() { dep::f1(); }")
        .file("b/Cargo.toml", &format!(r#"
            [package]
            name = "bar"
            authors = []
            version = "0.0.0"

            [dependencies]
            dep = {{ git = '{}' }}
        "#, a.url()))
        .file("b/src/main.rs", "extern crate dep; fn main() { dep::f2(); }");
    p.build();

    // Generate a Cargo.lock pointing at the current rev, then clear out the
    // target directory
    assert_that(p.cargo("build").cwd(p.root().join("a")),
                execs().with_status(0));
    fs::remove_dir_all(p.root().join("a/target")).unwrap();

    // Make a new commit on the master branch
    let repo = git2::Repository::open(&a.root()).unwrap();
    File::create(a.root().join("src/lib.rs")).unwrap()
         .write_all(b"pub fn f2() {}").unwrap();
    git::add(&repo);
    git::commit(&repo);

    // Now run both builds in parallel. The build of `b` should pick up the
    // newest commit while the build of `a` should use the locked old commit.
    let mut a = p.cargo("build").cwd(p.root().join("a")).build_command();
    let mut b = p.cargo("build").cwd(p.root().join("b")).build_command();

    a.stdout(Stdio::piped()).stderr(Stdio::piped());
    b.stdout(Stdio::piped()).stderr(Stdio::piped());

    let a = a.spawn().unwrap();
    let b = b.spawn().unwrap();
    let a = thread::spawn(move || a.wait_with_output().unwrap());
    let b = b.wait_with_output().unwrap();
    let a = a.join().unwrap();

    assert_that(a, execs().with_status(0));
    assert_that(b, execs().with_status(0));
});

test!(same_project {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.0"
        "#)
        .file("src/main.rs", "fn main() {}")
        .file("src/lib.rs", "");
    p.build();

    let mut a = p.cargo("build").build_command();
    let mut b = p.cargo("build").build_command();

    a.stdout(Stdio::piped()).stderr(Stdio::piped());
    b.stdout(Stdio::piped()).stderr(Stdio::piped());

    let a = a.spawn().unwrap();
    let b = b.spawn().unwrap();
    let a = thread::spawn(move || a.wait_with_output().unwrap());
    let b = b.wait_with_output().unwrap();
    let a = a.join().unwrap();

    assert_that(a, execs().with_status(0));
    assert_that(b, execs().with_status(0));
});

// Make sure that if Cargo dies while holding a lock that it's released and the
// next Cargo to come in will take over cleanly.
test!(killing_cargo_releases_the_lock {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.0"
            build = "build.rs"
        "#)
        .file("src/main.rs", "fn main() {}")
        .file("build.rs", r#"
            use std::net::TcpStream;

            fn main() {
                if std::env::var("A").is_ok() {
                    TcpStream::connect(&std::env::var("ADDR").unwrap()[..])
                              .unwrap();
                    std::thread::sleep(std::time::Duration::new(10, 0));
                }
            }
        "#);
    p.build();

    // Our build script will connect to our local TCP socket to inform us that
    // it's started running, and that's how we know that `a` will have the lock
    // when we kill it.
    let l = TcpListener::bind("127.0.0.1:0").unwrap();
    let mut a = p.cargo("build").build_command();
    let mut b = p.cargo("build").build_command();
    a.stdout(Stdio::piped()).stderr(Stdio::piped());
    b.stdout(Stdio::piped()).stderr(Stdio::piped());
    a.env("ADDR", l.local_addr().unwrap().to_string()).env("A", "a");
    b.env("ADDR", l.local_addr().unwrap().to_string()).env_remove("A");

    // Spawn `a`, wait for it to get to the build script (at which point the
    // lock is held), then kill it.
    let mut a = a.spawn().unwrap();
    l.accept().unwrap();
    a.kill().unwrap();

    // Spawn `b`, then just finish the output of a/b the same way the above
    // tests does.
    let b = b.spawn().unwrap();
    let a = thread::spawn(move || a.wait_with_output().unwrap());
    let b = b.wait_with_output().unwrap();
    let a = a.join().unwrap();

    // We killed `a`, so it shouldn't succeed, but `b` should have succeeded.
    assert!(!a.status.success());
    assert_that(b, execs().with_status(0));
});
<commit_msg>Auto merge of #2496 - alexcrichton:fix-concurrent, r=alexcrichton<commit_after>use std::env;
use std::fs::{self, File};
use std::io::Write;
use std::net::TcpListener;
use std::process::Stdio;
use std::thread;

use git2;
use hamcrest::{assert_that, existing_file};

use support::{execs, project, ERROR};
use support::git;
use support::registry::Package;
use test_cargo_install::{cargo_home, has_installed_exe};

fn setup() {}

test!(multiple_installs {
    let p = project("foo")
        .file("a/Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.0"
        "#)
        .file("a/src/main.rs", "fn main() {}")
        .file("b/Cargo.toml", r#"
            [package]
            name = "bar"
            authors = []
            version = "0.0.0"
        "#)
        .file("b/src/main.rs", "fn main() {}");
    p.build();

    let mut a = p.cargo("install").cwd(p.root().join("a")).build_command();
    let mut b = p.cargo("install").cwd(p.root().join("b")).build_command();

    a.stdout(Stdio::piped()).stderr(Stdio::piped());
    b.stdout(Stdio::piped()).stderr(Stdio::piped());

    let a = a.spawn().unwrap();
    let b = b.spawn().unwrap();
    let a = thread::spawn(move || a.wait_with_output().unwrap());
    let b = b.wait_with_output().unwrap();
    let a = a.join().unwrap();

    assert_that(a, execs().with_status(0));
    assert_that(b, execs().with_status(0));

    assert_that(cargo_home(), has_installed_exe("foo"));
    assert_that(cargo_home(), has_installed_exe("bar"));
});

test!(one_install_should_be_bad {
    let p = project("foo")
        .file("a/Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.0"
        "#)
        .file("a/src/main.rs", "fn main() {}")
        .file("b/Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.0"
        "#)
        .file("b/src/main.rs", "fn main() {}");
    p.build();

    let mut a = p.cargo("install").cwd(p.root().join("a")).build_command();
    let mut b = p.cargo("install").cwd(p.root().join("b")).build_command();

    a.stdout(Stdio::piped()).stderr(Stdio::piped());
    b.stdout(Stdio::piped()).stderr(Stdio::piped());

    let a = a.spawn().unwrap();
    let b = b.spawn().unwrap();
    let a = thread::spawn(move || a.wait_with_output().unwrap());
    let b = b.wait_with_output().unwrap();
    let a = a.join().unwrap();

    let (bad, good) = if a.status.code() == Some(101) {(a, b)} else {(b, a)};
    assert_that(bad, execs().with_status(101).with_stderr_contains(&format!("\
{error} binary `foo[..]` already exists in destination as part of `[..]`
", error = ERROR)));
    assert_that(good, execs().with_status(0).with_stderr_contains("\
warning: be sure to add `[..]` to your PATH [..]
"));

    assert_that(cargo_home(), has_installed_exe("foo"));
});

test!(multiple_registry_fetches {
    let mut pkg = Package::new("bar", "1.0.2");
    for i in 0..10 {
        let name = format!("foo{}", i);
        Package::new(&name, "1.0.0").publish();
        pkg.dep(&name, "*");
    }
    pkg.publish();

    let p = project("foo")
        .file("a/Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.0"

            [dependencies]
            bar = "*"
        "#)
        .file("a/src/main.rs", "fn main() {}")
        .file("b/Cargo.toml", r#"
            [package]
            name = "bar"
            authors = []
            version = "0.0.0"

            [dependencies]
            bar = "*"
        "#)
        .file("b/src/main.rs", "fn main() {}");
    p.build();

    let mut a = p.cargo("build").cwd(p.root().join("a")).build_command();
    let mut b = p.cargo("build").cwd(p.root().join("b")).build_command();

    a.stdout(Stdio::piped()).stderr(Stdio::piped());
    b.stdout(Stdio::piped()).stderr(Stdio::piped());

    let a = a.spawn().unwrap();
    let b = b.spawn().unwrap();
    let a = thread::spawn(move || a.wait_with_output().unwrap());
    let b = b.wait_with_output().unwrap();
    let a = a.join().unwrap();

    assert_that(a, execs().with_status(0));
    assert_that(b, execs().with_status(0));

    let suffix = env::consts::EXE_SUFFIX;
    assert_that(&p.root().join("a/target/debug").join(format!("foo{}", suffix)),
                existing_file());
    assert_that(&p.root().join("b/target/debug").join(format!("bar{}", suffix)),
                existing_file());
});

test!(git_same_repo_different_tags {
    let a = git::new("dep", |project| {
        project.file("Cargo.toml", r#"
            [project]
            name = "dep"
            version = "0.5.0"
            authors = []
        "#).file("src/lib.rs", "pub fn tag1() {}")
    }).unwrap();

    let repo = git2::Repository::open(&a.root()).unwrap();
    git::tag(&repo, "tag1");

    File::create(a.root().join("src/lib.rs")).unwrap()
         .write_all(b"pub fn tag2() {}").unwrap();
    git::add(&repo);
    git::commit(&repo);
    git::tag(&repo, "tag2");

    let p = project("foo")
        .file("a/Cargo.toml", &format!(r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.0"

            [dependencies]
            dep = {{ git = '{}', tag = 'tag1' }}
        "#, a.url()))
        .file("a/src/main.rs", "extern crate dep; fn main() { dep::tag1(); }")
        .file("b/Cargo.toml", &format!(r#"
            [package]
            name = "bar"
            authors = []
            version = "0.0.0"

            [dependencies]
            dep = {{ git = '{}', tag = 'tag2' }}
        "#, a.url()))
        .file("b/src/main.rs", "extern crate dep; fn main() { dep::tag2(); }");
    p.build();

    let mut a = p.cargo("build").arg("-v").cwd(p.root().join("a")).build_command();
    let mut b = p.cargo("build").arg("-v").cwd(p.root().join("b")).build_command();

    a.stdout(Stdio::piped()).stderr(Stdio::piped());
    b.stdout(Stdio::piped()).stderr(Stdio::piped());

    let a = a.spawn().unwrap();
    let b = b.spawn().unwrap();
    let a = thread::spawn(move || a.wait_with_output().unwrap());
    let b = b.wait_with_output().unwrap();
    let a = a.join().unwrap();

    assert_that(a, execs().with_status(0));
    assert_that(b, execs().with_status(0));
});

test!(git_same_branch_different_revs {
    let a = git::new("dep", |project| {
        project.file("Cargo.toml", r#"
            [project]
            name = "dep"
            version = "0.5.0"
            authors = []
        "#).file("src/lib.rs", "pub fn f1() {}")
    }).unwrap();

    let p = project("foo")
        .file("a/Cargo.toml", &format!(r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.0"

            [dependencies]
            dep = {{ git = '{}' }}
        "#, a.url()))
        .file("a/src/main.rs", "extern crate dep; fn main() { dep::f1(); }")
        .file("b/Cargo.toml", &format!(r#"
            [package]
            name = "bar"
            authors = []
            version = "0.0.0"

            [dependencies]
            dep = {{ git = '{}' }}
        "#, a.url()))
        .file("b/src/main.rs", "extern crate dep; fn main() { dep::f2(); }");
    p.build();

    // Generate a Cargo.lock pointing at the current rev, then clear out the
    // target directory
    assert_that(p.cargo("build").cwd(p.root().join("a")),
                execs().with_status(0));
    fs::remove_dir_all(p.root().join("a/target")).unwrap();

    // Make a new commit on the master branch
    let repo = git2::Repository::open(&a.root()).unwrap();
    File::create(a.root().join("src/lib.rs")).unwrap()
         .write_all(b"pub fn f2() {}").unwrap();
    git::add(&repo);
    git::commit(&repo);

    // Now run both builds in parallel. The build of `b` should pick up the
    // newest commit while the build of `a` should use the locked old commit.
    let mut a = p.cargo("build").cwd(p.root().join("a")).build_command();
    let mut b = p.cargo("build").cwd(p.root().join("b")).build_command();

    a.stdout(Stdio::piped()).stderr(Stdio::piped());
    b.stdout(Stdio::piped()).stderr(Stdio::piped());

    let a = a.spawn().unwrap();
    let b = b.spawn().unwrap();
    let a = thread::spawn(move || a.wait_with_output().unwrap());
    let b = b.wait_with_output().unwrap();
    let a = a.join().unwrap();

    assert_that(a, execs().with_status(0));
    assert_that(b, execs().with_status(0));
});

test!(same_project {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.0"
        "#)
        .file("src/main.rs", "fn main() {}")
        .file("src/lib.rs", "");
    p.build();

    let mut a = p.cargo("build").build_command();
    let mut b = p.cargo("build").build_command();

    a.stdout(Stdio::piped()).stderr(Stdio::piped());
    b.stdout(Stdio::piped()).stderr(Stdio::piped());

    let a = a.spawn().unwrap();
    let b = b.spawn().unwrap();
    let a = thread::spawn(move || a.wait_with_output().unwrap());
    let b = b.wait_with_output().unwrap();
    let a = a.join().unwrap();

    assert_that(a, execs().with_status(0));
    assert_that(b, execs().with_status(0));
});

// Make sure that if Cargo dies while holding a lock that it's released and the
// next Cargo to come in will take over cleanly.
test!(killing_cargo_releases_the_lock {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.0"
            build = "build.rs"
        "#)
        .file("src/main.rs", "fn main() {}")
        .file("build.rs", r#"
            use std::net::TcpStream;

            fn main() {
                if std::env::var("A").is_ok() {
                    TcpStream::connect(&std::env::var("ADDR").unwrap()[..])
                              .unwrap();
                    std::thread::sleep(std::time::Duration::new(10, 0));
                }
            }
        "#);
    p.build();

    // Our build script will connect to our local TCP socket to inform us that
    // it's started running, and that's how we know that `a` will have the lock
    // when we kill it.
    let l = TcpListener::bind("127.0.0.1:0").unwrap();
    let mut a = p.cargo("build").build_command();
    let mut b = p.cargo("build").build_command();
    a.stdout(Stdio::piped()).stderr(Stdio::piped());
    b.stdout(Stdio::piped()).stderr(Stdio::piped());
    a.env("ADDR", l.local_addr().unwrap().to_string()).env("A", "a");
    b.env("ADDR", l.local_addr().unwrap().to_string()).env_remove("A");

    // Spawn `a`, wait for it to get to the build script (at which point the
    // lock is held), then kill it.
    let mut a = a.spawn().unwrap();
    l.accept().unwrap();
    a.kill().unwrap();

    // Spawn `b`, then just finish the output of a/b the same way the above
    // tests does.
    let b = b.spawn().unwrap();
    let a = thread::spawn(move || a.wait_with_output().unwrap());
    let b = b.wait_with_output().unwrap();
    let a = a.join().unwrap();

    // We killed `a`, so it shouldn't succeed, but `b` should have succeeded.
    assert!(!a.status.success());
    assert_that(b, execs().with_status(0));
});
<|endoftext|>


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

/*! Task-local garbage-collected boxes

The `Gc` type provides shared ownership of an immutable value. Destruction is not deterministic, and
will occur some time between every `Gc` handle being gone and the end of the task. The garbage
collector is task-local so `Gc<T>` is not sendable.

*/

use kinds::Send;
use clone::{Clone, DeepClone};

/// Immutable garbage-collected pointer type
#[no_send]
#[deriving(Clone)]
pub struct Gc<T> {
    priv ptr: @T
}

impl<T: 'static> Gc<T> {
    /// Construct a new garbage-collected box
    #[inline]
    pub fn new(value: T) -> Gc<T> {
        Gc { ptr: @value }
    }
}

impl<T: 'static> Gc<T> {
    /// Borrow the value contained in the garbage-collected box
    #[inline]
    pub fn borrow<'r>(&'r self) -> &'r T {
        &*self.ptr
    }
}

/// The `Send` bound restricts this to acyclic graphs where it is well-defined.
///
/// A `Freeze` bound would also work, but `Send` *or* `Freeze` cannot be expressed.
impl<T: DeepClone + Send + 'static> DeepClone for Gc<T> {
    #[inline]
    fn deep_clone(&self) -> Gc<T> {
        Gc::new(self.borrow().deep_clone())
    }
}

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

    #[test]
    fn test_clone() {
        let x = Gc::new(RefCell::new(5));
        let y = x.clone();
        x.borrow().with_mut(|inner| {
            *inner = 20;
        });
        assert_eq!(y.borrow().with(|x| *x), 20);
    }

    #[test]
    fn test_deep_clone() {
        let x = Gc::new(RefCell::new(5));
        let y = x.deep_clone();
        x.borrow().with_mut(|inner| {
            *inner = 20;
        });
        assert_eq!(y.borrow().with(|x| *x), 5);
    }

    #[test]
    fn test_simple() {
        let x = Gc::new(5);
        assert_eq!(*x.borrow(), 5);
    }

    #[test]
    fn test_simple_clone() {
        let x = Gc::new(5);
        let y = x.clone();
        assert_eq!(*x.borrow(), 5);
        assert_eq!(*y.borrow(), 5);
    }

    #[test]
    fn test_destructor() {
        let x = Gc::new(~5);
        assert_eq!(**x.borrow(), 5);
    }
}
<commit_msg>Fixed Gc::clone, implemented Gc::ptr_eq<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*! Task-local garbage-collected boxes

The `Gc` type provides shared ownership of an immutable value. Destruction is not deterministic, and
will occur some time between every `Gc` handle being gone and the end of the task. The garbage
collector is task-local so `Gc<T>` is not sendable.

*/

use kinds::Send;
use clone::{Clone, DeepClone};
use managed;

/// Immutable garbage-collected pointer type
#[no_send]
pub struct Gc<T> {
    priv ptr: @T
}

impl<T: 'static> Gc<T> {
    /// Construct a new garbage-collected box
    #[inline]
    pub fn new(value: T) -> Gc<T> {
        Gc { ptr: @value }
    }

    /// Borrow the value contained in the garbage-collected box
    #[inline]
    pub fn borrow<'r>(&'r self) -> &'r T {
        &*self.ptr
    }

    /// Determine if two garbage-collected boxes point to the same object
    #[inline]
    pub fn ptr_eq(&self, other: &Gc<T>) -> bool {
        managed::ptr_eq(self.ptr, other.ptr)
    }
}

impl<T> Clone for Gc<T> {
    /// Clone the pointer only
    #[inline]
    fn clone(&self) -> Gc<T> {
        Gc{ ptr: self.ptr }
    }
}

/// The `Send` bound restricts this to acyclic graphs where it is well-defined.
///
/// A `Freeze` bound would also work, but `Send` *or* `Freeze` cannot be expressed.
impl<T: DeepClone + Send + 'static> DeepClone for Gc<T> {
    #[inline]
    fn deep_clone(&self) -> Gc<T> {
        Gc::new(self.borrow().deep_clone())
    }
}

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

    #[test]
    fn test_clone() {
        let x = Gc::new(RefCell::new(5));
        let y = x.clone();
        x.borrow().with_mut(|inner| {
            *inner = 20;
        });
        assert_eq!(y.borrow().with(|x| *x), 20);
    }

    #[test]
    fn test_deep_clone() {
        let x = Gc::new(RefCell::new(5));
        let y = x.deep_clone();
        x.borrow().with_mut(|inner| {
            *inner = 20;
        });
        assert_eq!(y.borrow().with(|x| *x), 5);
    }

    #[test]
    fn test_simple() {
        let x = Gc::new(5);
        assert_eq!(*x.borrow(), 5);
    }

    #[test]
    fn test_simple_clone() {
        let x = Gc::new(5);
        let y = x.clone();
        assert_eq!(*x.borrow(), 5);
        assert_eq!(*y.borrow(), 5);
    }

    #[test]
    fn test_ptr_eq() {
        let x = Gc::new(5);
        let y = x.clone();
        let z = Gc::new(7);
        assert!(x.ptr_eq(&x));
        assert!(x.ptr_eq(&y));
        assert!(!x.ptr_eq(&z));
    }

    #[test]
    fn test_destructor() {
        let x = Gc::new(~5);
        assert_eq!(**x.borrow(), 5);
    }
}
<|endoftext|>


<commit_before>use ::{KeyType, ValueType};

use wal_file::KeyValuePair;

use std::iter::{Peekable, empty, Map};
use std::collections::{BTreeMap, BTreeSet};
use std::collections::btree_map;
use std::collections::btree_set;

pub struct MultiMap<K: KeyType, V: ValueType> {
    multi_map: BTreeMap<K, BTreeSet<V>>,
    count: usize  // total number of KV pairs
}

pub struct MultiMapIterator<'a, K: KeyType + 'a, V: ValueType + 'a> {
    cur_key: Option<&'a K>,
    key_it: btree_map::Iter<'a,K,BTreeSet<V>>,
    value_it: Option<btree_set::Iter<'a,V>>,
}

impl <'a, K: KeyType, V: ValueType> MultiMap<K,V> {
    pub fn new() -> MultiMap<K,V> {
        return MultiMap{multi_map: BTreeMap::<K,BTreeSet<V>>::new(), count: 0};
    }

    pub fn insert(&mut self, key: K, value: V) -> usize {
        self.count += 1;

        if let Some(set) = self.multi_map.get_mut(&key) {
            set.insert(value);
            return self.count;
        }

        let mut set = BTreeSet::<V>::new();

        set.insert(value);

        self.multi_map.insert(key, set);

        return self.count;
    }

    pub fn delete(&mut self, key: K, value: V) -> usize {
        if let Some(set) = self.multi_map.get_mut(&key) {
            if set.remove(&value) {
                self.count -= 1;
            }

/* NOT WORKING: cannot borrow `self.multi_map` as mutable more than once at a time [E0499]
            if set.is_empty() {
                self.multi_map.remove(&key);
            }
*/
        }

        return self.count;
    }
}

impl <'a, K: KeyType, V: ValueType> IntoIterator for &'a mut MultiMap<K,V> {
    type Item = KeyValuePair<K,V>;
    type IntoIter = MultiMapIterator<'a,K,V>;

    fn into_iter(self) -> Self::IntoIter {
        let mut key_it = self.multi_map.iter();
        let cur_entry = key_it.next();

        // check to see if our map is empty
        if cur_entry.is_none() {
            return MultiMapIterator{cur_key: None, key_it: key_it, value_it: None};
        }

        // safe to call unwrap as we tested above
        let (cur_key, cur_set) = cur_entry.unwrap();

        return MultiMapIterator{cur_key: Some(cur_key), key_it: key_it, value_it: Some(cur_set.iter())};
    }
}

impl <'a, K: KeyType, V: ValueType> Iterator for MultiMapIterator<'a,K,V> {
    type Item = KeyValuePair<K,V>;

    fn next(&mut self) -> Option<Self::Item> {
        // this is our invariant, when it's None we've gone through everything
        if self.cur_key.is_none() {
            return None
        }

        // should be safe to call unwrap here, because we checked for None above
        let mut cur_val = self.value_it.as_mut().unwrap().next();

        // check to see if we've gone through everything in the set
        if cur_val.is_none() {
            let cur_entry = self.key_it.next(); // increment our key iterator

            if cur_entry.is_none() {
                self.cur_key = None; // set our invariant
                return None;
            }

            // safe to call unwrap because we checked it above
            let (cur_key, cur_set) = cur_entry.unwrap();

            self.cur_key = Some(cur_key); // set our key
            self.value_it = Some(cur_set.iter()); // set our value iterator
            cur_val = self.value_it.as_mut().unwrap().next(); // set our current value
        }

        return Some(KeyValuePair{key: self.cur_key.unwrap().clone(), value: cur_val.unwrap().clone()});
    }
}

#[cfg(test)]
mod tests {
    use multi_map::{MultiMap, MultiMapIterator};
    use wal_file::KeyValuePair;

    #[test]
    fn test_insert() {
        let mut mmap = MultiMap::<i32,String>::new();

        assert!(mmap.insert(12, String::from("abc")) == 1);
        assert!(mmap.insert(23, String::from("abc")) == 2);
        assert!(mmap.insert(23, String::from("def")) == 3);

        let mut it = mmap.into_iter();

        let e1 = it.next().unwrap();
        assert!(12 == e1.key);
        assert!(String::from("abc") == e1.value);

        let e2 = it.next().unwrap();
        assert!(23 == e2.key);
        assert!(String::from("abc") == e2.value);

        let e3 = it.next().unwrap();
        assert!(23 == e3.key);
        assert!(String::from("def") == e3.value);
    }
}

<commit_msg>Added a delete method<commit_after>use ::{KeyType, ValueType};

use wal_file::KeyValuePair;

use std::iter::{Peekable, empty, Map};
use std::collections::{BTreeMap, BTreeSet};
use std::collections::btree_map::Entry;
use std::collections::btree_map::Entry::{Occupied, Vacant};
use std::collections::btree_map;
use std::collections::btree_set;

pub struct MultiMap<K: KeyType, V: ValueType> {
    multi_map: BTreeMap<K, BTreeSet<V>>,
    count: usize  // total number of KV pairs
}

pub struct MultiMapIterator<'a, K: KeyType + 'a, V: ValueType + 'a> {
    cur_key: Option<&'a K>,
    key_it: btree_map::Iter<'a,K,BTreeSet<V>>,
    value_it: Option<btree_set::Iter<'a,V>>,
}

impl <'a, K: KeyType, V: ValueType> MultiMap<K,V> {
    pub fn new() -> MultiMap<K,V> {
        return MultiMap{multi_map: BTreeMap::<K,BTreeSet<V>>::new(), count: 0};
    }

    pub fn insert(&mut self, key: K, value: V) -> usize {
        self.count += 1;

        if let Some(set) = self.multi_map.get_mut(&key) {
            set.insert(value);
            return self.count;
        }

        let mut set = BTreeSet::<V>::new();

        set.insert(value);

        self.multi_map.insert(key, set);

        return self.count;
    }

    pub fn delete(&mut self, key: K, value: V) -> usize {
        if let Occupied(mut entry) = self.multi_map.entry(key) {

            if entry.get_mut().remove(&value) {
                self.count -= 1;
            } else {
                println!("DID NOT FIND");
            }

            if entry.get().is_empty() {
                entry.remove_entry();
            }
        } else {
            println!("NOT FOUND!!!");
        }

        return self.count;
    }

    pub fn size(&self) -> usize {
        return self.count;
    }
}

impl <'a, K: KeyType, V: ValueType> IntoIterator for &'a mut MultiMap<K,V> {
    type Item = KeyValuePair<K,V>;
    type IntoIter = MultiMapIterator<'a,K,V>;

    fn into_iter(self) -> Self::IntoIter {
        let mut key_it = self.multi_map.iter();
        let cur_entry = key_it.next();

        // check to see if our map is empty
        if cur_entry.is_none() {
            return MultiMapIterator{cur_key: None, key_it: key_it, value_it: None};
        }

        // safe to call unwrap as we tested above
        let (cur_key, cur_set) = cur_entry.unwrap();

        return MultiMapIterator{cur_key: Some(cur_key), key_it: key_it, value_it: Some(cur_set.iter())};
    }
}

impl <'a, K: KeyType, V: ValueType> Iterator for MultiMapIterator<'a,K,V> {
    type Item = KeyValuePair<K,V>;

    fn next(&mut self) -> Option<Self::Item> {
        // this is our invariant, when it's None we've gone through everything
        if self.cur_key.is_none() {
            return None
        }

        // should be safe to call unwrap here, because we checked for None above
        let mut cur_val = self.value_it.as_mut().unwrap().next();

        // check to see if we've gone through everything in the set
        if cur_val.is_none() {
            let cur_entry = self.key_it.next(); // increment our key iterator

            if cur_entry.is_none() {
                self.cur_key = None; // set our invariant
                return None;
            }

            // safe to call unwrap because we checked it above
            let (cur_key, cur_set) = cur_entry.unwrap();

            self.cur_key = Some(cur_key); // set our key
            self.value_it = Some(cur_set.iter()); // set our value iterator
            cur_val = self.value_it.as_mut().unwrap().next(); // set our current value
        }

        return Some(KeyValuePair{key: self.cur_key.unwrap().clone(), value: cur_val.unwrap().clone()});
    }
}

#[cfg(test)]
mod tests {
    use multi_map::{MultiMap, MultiMapIterator};
    use wal_file::KeyValuePair;

    #[test]
    fn test_insert() {
        let mut mmap = MultiMap::<i32,String>::new();

        assert!(mmap.insert(12, String::from("abc")) == 1);
        assert!(mmap.insert(23, String::from("abc")) == 2);
        assert!(mmap.insert(23, String::from("def")) == 3);

        let mut it = mmap.into_iter();

        let e1 = it.next().unwrap();
        assert!(12 == e1.key);
        assert!(String::from("abc") == e1.value);

        let e2 = it.next().unwrap();
        assert!(23 == e2.key);
        assert!(String::from("abc") == e2.value);

        let e3 = it.next().unwrap();
        assert!(23 == e3.key);
        assert!(String::from("def") == e3.value);
    }

    #[test]
    fn test_delete() {
        let mut mmap = MultiMap::<i32,String>::new();

        assert!(mmap.insert(12, String::from("abc")) == 1);
        assert!(mmap.insert(23, String::from("abc")) == 2);
        assert!(mmap.insert(23, String::from("def")) == 3);

        assert!(mmap.size() == 3);

        assert!(mmap.delete(12, String::from("abc")) == 2);
        assert!(mmap.delete(23, String::from("abc")) == 1);
        assert!(mmap.delete(23, String::from("abc")) == 1); // should NOT find this one
        assert!(mmap.delete(23, String::from("def")) == 0);

        assert!(mmap.size() == 0);

        let mut it = mmap.into_iter();

        assert!(it.next() == None);
    }
}

<|endoftext|>


<commit_before>//! Queue family and groups.

use crate::backend::RawQueueGroup;
use crate::queue::capability::{Capability, Compute, Graphics, Transfer};
use crate::queue::{CommandQueue, QueueType};
use crate::Backend;

use std::any::Any;
use std::fmt::Debug;

/// General information about a queue family, available upon adapter discovery.
///
/// Note that a backend can expose multiple queue families with the same properties.
pub trait QueueFamily: Debug + Any + Send + Sync {
    /// Returns the type of queues.
    fn queue_type(&self) -> QueueType;
    /// Returns maximum number of queues created from this family.
    fn max_queues(&self) -> usize;
    /// Returns true if the queue supports graphics operations.
    fn supports_graphics(&self) -> bool {
        Graphics::supported_by(self.queue_type())
    }
    /// Returns true if the queue supports compute operations.
    fn supports_compute(&self) -> bool {
        Compute::supported_by(self.queue_type())
    }
    /// Returns true if the queue supports transfer operations.
    fn supports_transfer(&self) -> bool {
        Transfer::supported_by(self.queue_type())
    }
    /// Returns the queue family ID.
    fn id(&self) -> QueueFamilyId;
}

/// Identifier for a queue family of a physical device.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct QueueFamilyId(pub usize);

/// Strong-typed group of queues of the same queue family.
pub struct QueueGroup<B: Backend, C> {
    family: QueueFamilyId,
    /// Command queues created in this family.
    pub queues: Vec<CommandQueue<B, C>>,
}

impl<B: Backend, C> QueueGroup<B, C> {
    /// Return the associated queue family id.
    pub fn family(&self) -> QueueFamilyId {
        self.family
    }
}

impl<B: Backend, C: Capability> QueueGroup<B, C> {
    /// Create a new strongly typed queue group from a raw one.
    ///
    /// # Panics
    ///
    /// Panics if the family doesn't expose required queue capabilities.
    fn new(raw: RawQueueGroup<B>) -> Self {
        assert!(C::supported_by(raw.family.queue_type()));
        QueueGroup {
            family: raw.family.id(),
            queues: raw
                .queues
                .into_iter()
                .map(|q| unsafe { CommandQueue::new(q) })
                .collect(),
        }
    }
}

/// Contains a list of all instantiated queues. Conceptually structured as a collection of
/// `QueueGroup`s, one for each queue family.
pub struct Queues<B: Backend>(pub(crate) Vec<RawQueueGroup<B>>);

impl<B: Backend> Queues<B> {
    /// Removes the queue family with the passed id from the queue list and
    /// returns the queue group.
    ///
    /// # Panics
    ///
    /// Panics if the family doesn't expose required queue capabilities.
    pub fn take<C: Capability>(&mut self, id: QueueFamilyId) -> Option<QueueGroup<B, C>> {
        self.0
            .iter()
            .position(|raw| raw.family.id() == id)
            .map(|index| QueueGroup::new(self.0.swap_remove(index)))
    }

    /// Removes the queue family with the passed id from the queue list and
    /// returns the command queues.
    pub fn take_raw(&mut self, id: QueueFamilyId) -> Option<Vec<B::CommandQueue>> {
        self.0
            .iter()
            .position(|raw| raw.family.id() == id)
            .map(|index| self.0.swap_remove(index).queues)
    }
}
<commit_msg>Add serde derives to QueueFamilyId<commit_after>//! Queue family and groups.

use crate::backend::RawQueueGroup;
use crate::queue::capability::{Capability, Compute, Graphics, Transfer};
use crate::queue::{CommandQueue, QueueType};
use crate::Backend;

use std::any::Any;
use std::fmt::Debug;

/// General information about a queue family, available upon adapter discovery.
///
/// Note that a backend can expose multiple queue families with the same properties.
pub trait QueueFamily: Debug + Any + Send + Sync {
    /// Returns the type of queues.
    fn queue_type(&self) -> QueueType;
    /// Returns maximum number of queues created from this family.
    fn max_queues(&self) -> usize;
    /// Returns true if the queue supports graphics operations.
    fn supports_graphics(&self) -> bool {
        Graphics::supported_by(self.queue_type())
    }
    /// Returns true if the queue supports compute operations.
    fn supports_compute(&self) -> bool {
        Compute::supported_by(self.queue_type())
    }
    /// Returns true if the queue supports transfer operations.
    fn supports_transfer(&self) -> bool {
        Transfer::supported_by(self.queue_type())
    }
    /// Returns the queue family ID.
    fn id(&self) -> QueueFamilyId;
}

/// Identifier for a queue family of a physical device.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct QueueFamilyId(pub usize);

/// Strong-typed group of queues of the same queue family.
pub struct QueueGroup<B: Backend, C> {
    family: QueueFamilyId,
    /// Command queues created in this family.
    pub queues: Vec<CommandQueue<B, C>>,
}

impl<B: Backend, C> QueueGroup<B, C> {
    /// Return the associated queue family id.
    pub fn family(&self) -> QueueFamilyId {
        self.family
    }
}

impl<B: Backend, C: Capability> QueueGroup<B, C> {
    /// Create a new strongly typed queue group from a raw one.
    ///
    /// # Panics
    ///
    /// Panics if the family doesn't expose required queue capabilities.
    fn new(raw: RawQueueGroup<B>) -> Self {
        assert!(C::supported_by(raw.family.queue_type()));
        QueueGroup {
            family: raw.family.id(),
            queues: raw
                .queues
                .into_iter()
                .map(|q| unsafe { CommandQueue::new(q) })
                .collect(),
        }
    }
}

/// Contains a list of all instantiated queues. Conceptually structured as a collection of
/// `QueueGroup`s, one for each queue family.
pub struct Queues<B: Backend>(pub(crate) Vec<RawQueueGroup<B>>);

impl<B: Backend> Queues<B> {
    /// Removes the queue family with the passed id from the queue list and
    /// returns the queue group.
    ///
    /// # Panics
    ///
    /// Panics if the family doesn't expose required queue capabilities.
    pub fn take<C: Capability>(&mut self, id: QueueFamilyId) -> Option<QueueGroup<B, C>> {
        self.0
            .iter()
            .position(|raw| raw.family.id() == id)
            .map(|index| QueueGroup::new(self.0.swap_remove(index)))
    }

    /// Removes the queue family with the passed id from the queue list and
    /// returns the command queues.
    pub fn take_raw(&mut self, id: QueueFamilyId) -> Option<Vec<B::CommandQueue>> {
        self.0
            .iter()
            .position(|raw| raw.family.id() == id)
            .map(|index| self.0.swap_remove(index).queues)
    }
}
<|endoftext|>


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

// Check that we correctly prevent users from making trait objects
// from traits with associated consts.

trait Bar {
    const X: usize;
}

fn make_bar<T:Bar>(t: &T) -> &Bar {
        //~^ ERROR E0038
        //~| NOTE the trait cannot contain associated consts like `X`
        //~| NOTE the trait `Bar` cannot be made into an object
    t
}

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

// Check that we correctly prevent users from making trait objects
// from traits with associated consts.

trait Bar {
    const X: usize;
}

fn make_bar<T:Bar>(t: &T) -> &Bar {
    //~^ ERROR E0038
    //~| NOTE the trait cannot contain associated consts like `X`
    //~| NOTE the trait `Bar` cannot be made into an object
    t
}

fn main() {
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;

use num::BigUint;
use num::pow::Pow;

use Construct;
use Of;
use ToPos;
use Count;
use Data;
use ToIndex;
use Zero;

/// Dimension is natural number, position is a list of numbers.
pub struct PowerSet<T = Data>(PhantomData<T>);

impl<T> Construct for PowerSet<T> {
    fn new() -> PowerSet<T> { PowerSet(PhantomData) }
}

impl Count<usize> for PowerSet<Data> {
    type N = usize;
    fn count(&self, dim: &usize) -> usize {
        1 << *dim
    }
}

impl Count<BigUint> for PowerSet<Data> {
    type N = BigUint;
    fn count(&self, dim: &BigUint) -> BigUint {
        use std::convert::TryInto;

        let _two: BigUint = 2usize.into();
        let dim: u32 = dim.try_into().unwrap();
        _two.pow(dim)
    }
}

impl<T, U> Count<U> for PowerSet<Of<T>>
    where
        T: Construct + Count<U>,
        <T as Count<U>>::N: From<usize> + Pow<<T as Count<U>>::N, Output = <T as Count<U>>::N>,
{
    type N = <T as Count<U>>::N;
    fn count(&self, dim: &U) -> Self::N {
        let _two: Self::N = 2usize.into();
        let of: T = Construct::new();
        _two.pow(of.count(dim))
    }
}

impl Zero<usize, Vec<usize>> for PowerSet<Data> {
    fn zero(&self, _dim: &usize) -> Vec<usize> {
        vec![]
    }
}

impl<T, U, V> Zero<U, Vec<V>> for PowerSet<Of<T>>
    where T: Construct + Count<U> + Zero<U, V>
{
    fn zero(&self, _dim: &U) -> Vec<V> {
        vec![]
    }
}

impl ToIndex<usize, Vec<usize>> for PowerSet<Data> {
    fn to_index(
        &self,
        _dim: &usize,
        pos: &Vec<usize>
    ) -> usize {
        let mut index = 0;
        for &i in pos.iter() {
            index |= 1 << i;
        }
        index
    }
}

impl<T, U, V>
ToIndex<U, Vec<V>> for PowerSet<Of<T>>
    where
        T: Construct + ToIndex<U, V>,
        V: Clone
{
    fn to_index(
        &self,
        dim: &U,
        pos: &Vec<V>
    ) -> usize {
        let of: T = Construct::new();
        let mut index = 0;
        for i in pos.iter() {
            index |= 1 << of.to_index(dim, i);
        }
        index
    }
}

impl ToPos<usize, Vec<usize>> for PowerSet<Data> {
    fn to_pos(
        &self,
        dim: &usize,
        index: usize,
        pos: &mut Vec<usize>
    ) {
        unsafe { pos.set_len(0); }
        for i in 0..*dim {
            if ((index >> i) & 1) == 1 {
                pos.push(i);
            }
        }
    }
}

impl<T, U, V>
ToPos<U, Vec<V>>
for PowerSet<Of<T>>
    where T: Construct + Count<U, N = usize> + ToPos<U, V> + Zero<U, V>
{
    fn to_pos(
        &self,
        dim: &U,
        index: usize,
        pos: &mut Vec<V>
    ) {
        let of: T = Construct::new();
        let count = of.count(dim);
        pos.clear();
        pos.reserve_exact(count);
        for j in 0..count {
            if ((index >> j) & 1) == 1 {
                let mut p = of.zero(dim);
                of.to_pos(dim, j, &mut p);
                pos.push(p);
            }
        }
    }
}

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

    #[test]
    fn features() {
        is_complete::<PowerSet, usize, Vec<usize>>();
        is_complete::<PowerSet<Of<Pair>>, usize, Vec<(usize, usize)>>();
    }

    #[test]
    fn data() {
        let x: PowerSet = Construct::new();
        let ref dim = 6;
        assert_eq!(x.count(dim), 64);
        assert_eq!(x.to_index(dim, &vec![]), 0);
        assert_eq!(x.to_index(dim, &vec![0]), 1);
        assert_eq!(x.to_index(dim, &vec![1]), 2);
        assert_eq!(x.to_index(dim, &vec![0, 1]), 3);
        let mut a = vec![];
        x.to_pos(dim, 9, &mut a);
        assert_eq!(&a, &[0, 3]);
    }

    #[test]
    fn of() {
        let x: PowerSet<Of<Pair>> = Construct::new();
        let ref dim = 4;
        assert_eq!(x.count(dim), 64);
        assert_eq!(x.to_index(dim, &vec![]), 0);
        assert_eq!(x.to_index(dim, &vec![(0, 1)]), 1);
        assert_eq!(x.to_index(dim, &vec![(0, 2)]), 2);
        assert_eq!(x.to_index(dim, &vec![(0, 1), (0, 2)]), 3);
        assert_eq!(x.to_index(dim, &vec![(1, 2)]), 4);
        assert_eq!(x.to_index(dim, &vec![(0, 1), (1, 2)]), 5);
        assert_eq!(x.to_index(dim, &vec![(0, 2), (1, 2)]), 6);
        assert_eq!(x.to_index(dim, &vec![(0, 1), (0, 2), (1, 2)]), 7);
        let mut a = vec![(0, 0); 64];
        x.to_pos(dim, 7, &mut a);
        assert_eq!(a[0], (0, 1));
    }
}
<commit_msg>Impl `Zero<BigUint, Vec<BigUint>>` for `PowerSet`<commit_after>use std::marker::PhantomData;

use num::BigUint;
use num::pow::Pow;

use Construct;
use Of;
use ToPos;
use Count;
use Data;
use ToIndex;
use Zero;

/// Dimension is natural number, position is a list of numbers.
pub struct PowerSet<T = Data>(PhantomData<T>);

impl<T> Construct for PowerSet<T> {
    fn new() -> PowerSet<T> { PowerSet(PhantomData) }
}

impl Count<usize> for PowerSet<Data> {
    type N = usize;
    fn count(&self, dim: &usize) -> usize {
        1 << *dim
    }
}

impl Count<BigUint> for PowerSet<Data> {
    type N = BigUint;
    fn count(&self, dim: &BigUint) -> BigUint {
        use std::convert::TryInto;

        let _two: BigUint = 2usize.into();
        let dim: u32 = dim.try_into().unwrap();
        _two.pow(dim)
    }
}

impl<T, U> Count<U> for PowerSet<Of<T>>
    where
        T: Construct + Count<U>,
        <T as Count<U>>::N: From<usize> + Pow<<T as Count<U>>::N, Output = <T as Count<U>>::N>,
{
    type N = <T as Count<U>>::N;
    fn count(&self, dim: &U) -> Self::N {
        let _two: Self::N = 2usize.into();
        let of: T = Construct::new();
        _two.pow(of.count(dim))
    }
}

impl Zero<usize, Vec<usize>> for PowerSet<Data> {
    fn zero(&self, _dim: &usize) -> Vec<usize> {
        vec![]
    }
}

impl Zero<BigUint, Vec<BigUint>> for PowerSet<Data> {
    fn zero(&self, _dim: &BigUint) -> Vec<BigUint> {
        vec![]
    }
}

impl<T, U, V> Zero<U, Vec<V>> for PowerSet<Of<T>>
    where T: Construct + Count<U> + Zero<U, V>
{
    fn zero(&self, _dim: &U) -> Vec<V> {
        vec![]
    }
}

impl ToIndex<usize, Vec<usize>> for PowerSet<Data> {
    fn to_index(
        &self,
        _dim: &usize,
        pos: &Vec<usize>
    ) -> usize {
        let mut index = 0;
        for &i in pos.iter() {
            index |= 1 << i;
        }
        index
    }
}

impl<T, U, V>
ToIndex<U, Vec<V>> for PowerSet<Of<T>>
    where
        T: Construct + ToIndex<U, V>,
        V: Clone
{
    fn to_index(
        &self,
        dim: &U,
        pos: &Vec<V>
    ) -> usize {
        let of: T = Construct::new();
        let mut index = 0;
        for i in pos.iter() {
            index |= 1 << of.to_index(dim, i);
        }
        index
    }
}

impl ToPos<usize, Vec<usize>> for PowerSet<Data> {
    fn to_pos(
        &self,
        dim: &usize,
        index: usize,
        pos: &mut Vec<usize>
    ) {
        unsafe { pos.set_len(0); }
        for i in 0..*dim {
            if ((index >> i) & 1) == 1 {
                pos.push(i);
            }
        }
    }
}

impl<T, U, V>
ToPos<U, Vec<V>>
for PowerSet<Of<T>>
    where T: Construct + Count<U, N = usize> + ToPos<U, V> + Zero<U, V>
{
    fn to_pos(
        &self,
        dim: &U,
        index: usize,
        pos: &mut Vec<V>
    ) {
        let of: T = Construct::new();
        let count = of.count(dim);
        pos.clear();
        pos.reserve_exact(count);
        for j in 0..count {
            if ((index >> j) & 1) == 1 {
                let mut p = of.zero(dim);
                of.to_pos(dim, j, &mut p);
                pos.push(p);
            }
        }
    }
}

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

    #[test]
    fn features() {
        is_complete::<PowerSet, usize, Vec<usize>>();
        is_complete::<PowerSet<Of<Pair>>, usize, Vec<(usize, usize)>>();
    }

    #[test]
    fn data() {
        let x: PowerSet = Construct::new();
        let ref dim = 6;
        assert_eq!(x.count(dim), 64);
        assert_eq!(x.to_index(dim, &vec![]), 0);
        assert_eq!(x.to_index(dim, &vec![0]), 1);
        assert_eq!(x.to_index(dim, &vec![1]), 2);
        assert_eq!(x.to_index(dim, &vec![0, 1]), 3);
        let mut a = vec![];
        x.to_pos(dim, 9, &mut a);
        assert_eq!(&a, &[0, 3]);
    }

    #[test]
    fn of() {
        let x: PowerSet<Of<Pair>> = Construct::new();
        let ref dim = 4;
        assert_eq!(x.count(dim), 64);
        assert_eq!(x.to_index(dim, &vec![]), 0);
        assert_eq!(x.to_index(dim, &vec![(0, 1)]), 1);
        assert_eq!(x.to_index(dim, &vec![(0, 2)]), 2);
        assert_eq!(x.to_index(dim, &vec![(0, 1), (0, 2)]), 3);
        assert_eq!(x.to_index(dim, &vec![(1, 2)]), 4);
        assert_eq!(x.to_index(dim, &vec![(0, 1), (1, 2)]), 5);
        assert_eq!(x.to_index(dim, &vec![(0, 2), (1, 2)]), 6);
        assert_eq!(x.to_index(dim, &vec![(0, 1), (0, 2), (1, 2)]), 7);
        let mut a = vec![(0, 0); 64];
        x.to_pos(dim, 7, &mut a);
        assert_eq!(a[0], (0, 1));
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use font::{Font, FontGroup};
use font::SpecifiedFontStyle;
use platform::font_context::FontContextHandle;
use style::computed_values::{font_style, font_variant};

use font_cache_task::FontCacheTask;
use font_template::FontTemplateDescriptor;
use platform::font_template::FontTemplateData;
use font::FontHandleMethods;
use platform::font::FontHandle;
use servo_util::cache::HashCache;
use servo_util::smallvec::{SmallVec, SmallVec8};
use servo_util::geometry::Au;
use servo_util::arc_ptr_eq;

use std::rc::Rc;
use std::cell::RefCell;
use sync::Arc;

use azure::AzFloat;
use azure::azure_hl::SkiaBackend;
use azure::scaled_font::ScaledFont;

#[cfg(any(target_os="linux", target_os = "android"))]
use azure::scaled_font::FontData;

#[cfg(any(target_os="linux", target_os = "android"))]
fn create_scaled_font(template: &Arc<FontTemplateData>, pt_size: Au) -> ScaledFont {
    ScaledFont::new(SkiaBackend, FontData(&template.bytes), pt_size.to_subpx() as AzFloat)
}

#[cfg(target_os="macos")]
fn create_scaled_font(template: &Arc<FontTemplateData>, pt_size: Au) -> ScaledFont {
    let cgfont = template.ctfont.as_ref().unwrap().copy_to_CGFont();
    ScaledFont::new(SkiaBackend, &cgfont, pt_size.to_subpx() as AzFloat)
}

static SMALL_CAPS_SCALE_FACTOR: f64 = 0.8;      // Matches FireFox (see gfxFont.h)

struct LayoutFontCacheEntry {
    family: String,
    font: Option<Rc<RefCell<Font>>>,
}

struct FallbackFontCacheEntry {
    font: Rc<RefCell<Font>>,
}

/// A cached azure font (per render task) that
/// can be shared by multiple text runs.
struct RenderFontCacheEntry {
    pt_size: Au,
    identifier: String,
    font: Rc<RefCell<ScaledFont>>,
}

/// The FontContext represents the per-thread/task state necessary for
/// working with fonts. It is the public API used by the layout and
/// render code. It talks directly to the font cache task where
/// required.
pub struct FontContext {
    platform_handle: FontContextHandle,
    font_cache_task: FontCacheTask,

    /// TODO: See bug https://github.com/servo/servo/issues/3300.
    layout_font_cache: Vec<LayoutFontCacheEntry>,
    fallback_font_cache: Vec<FallbackFontCacheEntry>,

    /// Strong reference as the render FontContext is (for now) recycled
    /// per frame. TODO: Make this weak when incremental redraw is done.
    render_font_cache: Vec<RenderFontCacheEntry>,

    last_style: Option<Arc<SpecifiedFontStyle>>,
    last_fontgroup: Option<Rc<FontGroup>>,
}

impl FontContext {
    pub fn new(font_cache_task: FontCacheTask) -> FontContext {
        let handle = FontContextHandle::new();
        FontContext {
            platform_handle: handle,
            font_cache_task: font_cache_task,
            layout_font_cache: vec!(),
            fallback_font_cache: vec!(),
            render_font_cache: vec!(),
            last_style: None,
            last_fontgroup: None,
        }
    }

    /// Create a font for use in layout calculations.
    fn create_layout_font(&self, template: Arc<FontTemplateData>,
                            descriptor: FontTemplateDescriptor, pt_size: Au,
                            variant: font_variant::T) -> Font {
        // TODO: (Bug #3463): Currently we only support fake small-caps
        // rendering. We should also support true small-caps (where the
        // font supports it) in the future.
        let actual_pt_size = match variant {
            font_variant::small_caps => pt_size.scale_by(SMALL_CAPS_SCALE_FACTOR),
            font_variant::normal => pt_size,
        };

        let handle: FontHandle = FontHandleMethods::new_from_template(&self.platform_handle,
                                    template, Some(actual_pt_size)).unwrap();
        let metrics = handle.get_metrics();

        Font {
            handle: handle,
            shaper: None,
            variant: variant,
            descriptor: descriptor,
            requested_pt_size: pt_size,
            actual_pt_size: actual_pt_size,
            metrics: metrics,
            shape_cache: HashCache::new(),
            glyph_advance_cache: HashCache::new(),
        }
    }

    /// Create a group of fonts for use in layout calculations. May return
    /// a cached font if this font instance has already been used by
    /// this context.
    pub fn get_layout_font_group_for_style(&mut self, style: Arc<SpecifiedFontStyle>)
                                            -> Rc<FontGroup> {
        let matches = match self.last_style {
            Some(ref last_style) => arc_ptr_eq(&style, last_style),
            None => false,
        };
        if matches {
            return self.last_fontgroup.as_ref().unwrap().clone();
        }

        // TODO: The font context holds a strong ref to the cached fonts
        // so they will never be released. Find out a good time to drop them.

        let desc = FontTemplateDescriptor::new(style.font_weight,
                                               style.font_style == font_style::italic);
        let mut fonts = SmallVec8::new();

        for family in style.font_family.iter() {
            // GWTODO: Check on real pages if this is faster as Vec() or HashMap().
            let mut cache_hit = false;
            for cached_font_entry in self.layout_font_cache.iter() {
                if cached_font_entry.family.as_slice() == family.name() {
                    match cached_font_entry.font {
                        None => {
                            cache_hit = true;
                            break;
                        }
                        Some(ref cached_font_ref) => {
                            let cached_font = cached_font_ref.borrow();
                            if cached_font.descriptor == desc &&
                               cached_font.requested_pt_size == style.font_size &&
                               cached_font.variant == style.font_variant {
                                fonts.push((*cached_font_ref).clone());
                                cache_hit = true;
                                break;
                            }
                        }
                    }
                }
            }

            if !cache_hit {
                let font_template = self.font_cache_task.get_font_template(family.name()
                                                                                .to_string(),
                                                                           desc.clone());
                match font_template {
                    Some(font_template) => {
                        let layout_font = self.create_layout_font(font_template,
                                                                  desc.clone(),
                                                                  style.font_size,
                                                                  style.font_variant);
                        let layout_font = Rc::new(RefCell::new(layout_font));
                        self.layout_font_cache.push(LayoutFontCacheEntry {
                            family: family.name().to_string(),
                            font: Some(layout_font.clone()),
                        });
                        fonts.push(layout_font);
                    }
                    None => {
                        self.layout_font_cache.push(LayoutFontCacheEntry {
                            family: family.name().to_string(),
                            font: None,
                        });
                    }
                }
            }
        }

        // If unable to create any of the specified fonts, create one from the
        // list of last resort fonts for this platform.
        if fonts.len() == 0 {
            let mut cache_hit = false;
            for cached_font_entry in self.fallback_font_cache.iter() {
                let cached_font = cached_font_entry.font.borrow();
                if cached_font.descriptor == desc &&
                            cached_font.requested_pt_size == style.font_size &&
                            cached_font.variant == style.font_variant {
                    fonts.push(cached_font_entry.font.clone());
                    cache_hit = true;
                    break;
                }
            }

            if !cache_hit {
                let font_template = self.font_cache_task.get_last_resort_font_template(desc.clone());
                let layout_font = self.create_layout_font(font_template,
                                                          desc.clone(),
                                                          style.font_size,
                                                          style.font_variant);
                let layout_font = Rc::new(RefCell::new(layout_font));
                self.fallback_font_cache.push(FallbackFontCacheEntry {
                    font: layout_font.clone(),
                });
                fonts.push(layout_font);
            }
        }

        let font_group = Rc::new(FontGroup::new(fonts));
        self.last_style = Some(style);
        self.last_fontgroup = Some(font_group.clone());
        font_group
    }

    /// Create a render font for use with azure. May return a cached
    /// reference if already used by this font context.
    pub fn get_render_font_from_template(&mut self,
                                         template: &Arc<FontTemplateData>,
                                         pt_size: Au)
                                         -> Rc<RefCell<ScaledFont>> {
        for cached_font in self.render_font_cache.iter() {
            if cached_font.pt_size == pt_size &&
               cached_font.identifier == template.identifier {
                return cached_font.font.clone();
            }
        }

        let render_font = Rc::new(RefCell::new(create_scaled_font(template, pt_size)));
        self.render_font_cache.push(RenderFontCacheEntry{
            font: render_font.clone(),
            pt_size: pt_size,
            identifier: template.identifier.clone(),
        });
        render_font
    }

    /// Returns a reference to the font cache task.
    pub fn font_cache_task(&self) -> FontCacheTask {
        self.font_cache_task.clone()
    }
}
<commit_msg>Rename RenderFontCacheEntry -> PaintFontCacheEntry.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use font::{Font, FontGroup};
use font::SpecifiedFontStyle;
use platform::font_context::FontContextHandle;
use style::computed_values::{font_style, font_variant};

use font_cache_task::FontCacheTask;
use font_template::FontTemplateDescriptor;
use platform::font_template::FontTemplateData;
use font::FontHandleMethods;
use platform::font::FontHandle;
use servo_util::cache::HashCache;
use servo_util::smallvec::{SmallVec, SmallVec8};
use servo_util::geometry::Au;
use servo_util::arc_ptr_eq;

use std::rc::Rc;
use std::cell::RefCell;
use sync::Arc;

use azure::AzFloat;
use azure::azure_hl::SkiaBackend;
use azure::scaled_font::ScaledFont;

#[cfg(any(target_os="linux", target_os = "android"))]
use azure::scaled_font::FontData;

#[cfg(any(target_os="linux", target_os = "android"))]
fn create_scaled_font(template: &Arc<FontTemplateData>, pt_size: Au) -> ScaledFont {
    ScaledFont::new(SkiaBackend, FontData(&template.bytes), pt_size.to_subpx() as AzFloat)
}

#[cfg(target_os="macos")]
fn create_scaled_font(template: &Arc<FontTemplateData>, pt_size: Au) -> ScaledFont {
    let cgfont = template.ctfont.as_ref().unwrap().copy_to_CGFont();
    ScaledFont::new(SkiaBackend, &cgfont, pt_size.to_subpx() as AzFloat)
}

static SMALL_CAPS_SCALE_FACTOR: f64 = 0.8;      // Matches FireFox (see gfxFont.h)

struct LayoutFontCacheEntry {
    family: String,
    font: Option<Rc<RefCell<Font>>>,
}

struct FallbackFontCacheEntry {
    font: Rc<RefCell<Font>>,
}

/// A cached azure font (per render task) that
/// can be shared by multiple text runs.
struct PaintFontCacheEntry {
    pt_size: Au,
    identifier: String,
    font: Rc<RefCell<ScaledFont>>,
}

/// The FontContext represents the per-thread/task state necessary for
/// working with fonts. It is the public API used by the layout and
/// render code. It talks directly to the font cache task where
/// required.
pub struct FontContext {
    platform_handle: FontContextHandle,
    font_cache_task: FontCacheTask,

    /// TODO: See bug https://github.com/servo/servo/issues/3300.
    layout_font_cache: Vec<LayoutFontCacheEntry>,
    fallback_font_cache: Vec<FallbackFontCacheEntry>,

    /// Strong reference as the render FontContext is (for now) recycled
    /// per frame. TODO: Make this weak when incremental redraw is done.
    render_font_cache: Vec<PaintFontCacheEntry>,

    last_style: Option<Arc<SpecifiedFontStyle>>,
    last_fontgroup: Option<Rc<FontGroup>>,
}

impl FontContext {
    pub fn new(font_cache_task: FontCacheTask) -> FontContext {
        let handle = FontContextHandle::new();
        FontContext {
            platform_handle: handle,
            font_cache_task: font_cache_task,
            layout_font_cache: vec!(),
            fallback_font_cache: vec!(),
            render_font_cache: vec!(),
            last_style: None,
            last_fontgroup: None,
        }
    }

    /// Create a font for use in layout calculations.
    fn create_layout_font(&self, template: Arc<FontTemplateData>,
                            descriptor: FontTemplateDescriptor, pt_size: Au,
                            variant: font_variant::T) -> Font {
        // TODO: (Bug #3463): Currently we only support fake small-caps
        // rendering. We should also support true small-caps (where the
        // font supports it) in the future.
        let actual_pt_size = match variant {
            font_variant::small_caps => pt_size.scale_by(SMALL_CAPS_SCALE_FACTOR),
            font_variant::normal => pt_size,
        };

        let handle: FontHandle = FontHandleMethods::new_from_template(&self.platform_handle,
                                    template, Some(actual_pt_size)).unwrap();
        let metrics = handle.get_metrics();

        Font {
            handle: handle,
            shaper: None,
            variant: variant,
            descriptor: descriptor,
            requested_pt_size: pt_size,
            actual_pt_size: actual_pt_size,
            metrics: metrics,
            shape_cache: HashCache::new(),
            glyph_advance_cache: HashCache::new(),
        }
    }

    /// Create a group of fonts for use in layout calculations. May return
    /// a cached font if this font instance has already been used by
    /// this context.
    pub fn get_layout_font_group_for_style(&mut self, style: Arc<SpecifiedFontStyle>)
                                            -> Rc<FontGroup> {
        let matches = match self.last_style {
            Some(ref last_style) => arc_ptr_eq(&style, last_style),
            None => false,
        };
        if matches {
            return self.last_fontgroup.as_ref().unwrap().clone();
        }

        // TODO: The font context holds a strong ref to the cached fonts
        // so they will never be released. Find out a good time to drop them.

        let desc = FontTemplateDescriptor::new(style.font_weight,
                                               style.font_style == font_style::italic);
        let mut fonts = SmallVec8::new();

        for family in style.font_family.iter() {
            // GWTODO: Check on real pages if this is faster as Vec() or HashMap().
            let mut cache_hit = false;
            for cached_font_entry in self.layout_font_cache.iter() {
                if cached_font_entry.family.as_slice() == family.name() {
                    match cached_font_entry.font {
                        None => {
                            cache_hit = true;
                            break;
                        }
                        Some(ref cached_font_ref) => {
                            let cached_font = cached_font_ref.borrow();
                            if cached_font.descriptor == desc &&
                               cached_font.requested_pt_size == style.font_size &&
                               cached_font.variant == style.font_variant {
                                fonts.push((*cached_font_ref).clone());
                                cache_hit = true;
                                break;
                            }
                        }
                    }
                }
            }

            if !cache_hit {
                let font_template = self.font_cache_task.get_font_template(family.name()
                                                                                .to_string(),
                                                                           desc.clone());
                match font_template {
                    Some(font_template) => {
                        let layout_font = self.create_layout_font(font_template,
                                                                  desc.clone(),
                                                                  style.font_size,
                                                                  style.font_variant);
                        let layout_font = Rc::new(RefCell::new(layout_font));
                        self.layout_font_cache.push(LayoutFontCacheEntry {
                            family: family.name().to_string(),
                            font: Some(layout_font.clone()),
                        });
                        fonts.push(layout_font);
                    }
                    None => {
                        self.layout_font_cache.push(LayoutFontCacheEntry {
                            family: family.name().to_string(),
                            font: None,
                        });
                    }
                }
            }
        }

        // If unable to create any of the specified fonts, create one from the
        // list of last resort fonts for this platform.
        if fonts.len() == 0 {
            let mut cache_hit = false;
            for cached_font_entry in self.fallback_font_cache.iter() {
                let cached_font = cached_font_entry.font.borrow();
                if cached_font.descriptor == desc &&
                            cached_font.requested_pt_size == style.font_size &&
                            cached_font.variant == style.font_variant {
                    fonts.push(cached_font_entry.font.clone());
                    cache_hit = true;
                    break;
                }
            }

            if !cache_hit {
                let font_template = self.font_cache_task.get_last_resort_font_template(desc.clone());
                let layout_font = self.create_layout_font(font_template,
                                                          desc.clone(),
                                                          style.font_size,
                                                          style.font_variant);
                let layout_font = Rc::new(RefCell::new(layout_font));
                self.fallback_font_cache.push(FallbackFontCacheEntry {
                    font: layout_font.clone(),
                });
                fonts.push(layout_font);
            }
        }

        let font_group = Rc::new(FontGroup::new(fonts));
        self.last_style = Some(style);
        self.last_fontgroup = Some(font_group.clone());
        font_group
    }

    /// Create a render font for use with azure. May return a cached
    /// reference if already used by this font context.
    pub fn get_render_font_from_template(&mut self,
                                         template: &Arc<FontTemplateData>,
                                         pt_size: Au)
                                         -> Rc<RefCell<ScaledFont>> {
        for cached_font in self.render_font_cache.iter() {
            if cached_font.pt_size == pt_size &&
               cached_font.identifier == template.identifier {
                return cached_font.font.clone();
            }
        }

        let render_font = Rc::new(RefCell::new(create_scaled_font(template, pt_size)));
        self.render_font_cache.push(PaintFontCacheEntry{
            font: render_font.clone(),
            pt_size: pt_size,
            identifier: template.identifier.clone(),
        });
        render_font
    }

    /// Returns a reference to the font cache task.
    pub fn font_cache_task(&self) -> FontCacheTask {
        self.font_cache_task.clone()
    }
}
<|endoftext|>