<commit_before>use std::ops::Range;
use std::sync::Arc;

use im::HashMap;

use super::ast::{self, Ast, AstKind, AstString, Identifier, Int, Lambda, Symbol, Text};
use super::cst::{self, Cst, CstDb, CstKind};
use super::error::CompilerError;
use super::string_to_cst::StringToCst;
use crate::compiler::ast::Struct;
use crate::input::Input;

#[salsa::query_group(CstToAstStorage)]
pub trait CstToAst: CstDb + StringToCst {
    fn ast_to_cst_id(&self, input: Input, id: ast::Id) -> Option<cst::Id>;
    fn ast_id_to_span(&self, input: Input, id: ast::Id) -> Option<Range<usize>>;

    fn cst_to_ast_id(&self, input: Input, id: cst::Id) -> Option<ast::Id>;

    fn ast(&self, input: Input) -> Option<(Arc<Vec<Ast>>, HashMap<ast::Id, cst::Id>)>;
    fn ast_raw(
        &self,
        input: Input,
    ) -> Option<(Arc<Vec<Ast>>, HashMap<ast::Id, cst::Id>, Vec<CompilerError>)>;
}

fn ast_to_cst_id(db: &dyn CstToAst, input: Input, id: ast::Id) -> Option<cst::Id> {
    let (_, ast_to_cst_id_mapping) = db.ast(input).unwrap();
    ast_to_cst_id_mapping.get(&id).cloned()
}
fn ast_id_to_span(db: &dyn CstToAst, input: Input, id: ast::Id) -> Option<Range<usize>> {
    let id = db.ast_to_cst_id(input.clone(), id)?;
    Some(db.find_cst(input, id).span())
}

fn cst_to_ast_id(db: &dyn CstToAst, input: Input, id: cst::Id) -> Option<ast::Id> {
    let (_, ast_to_cst_id_mapping) = db.ast(input).unwrap();
    ast_to_cst_id_mapping
        .iter()
        .find_map(|(key, &value)| if value == id { Some(key) } else { None })
        .cloned()
}

fn ast(db: &dyn CstToAst, input: Input) -> Option<(Arc<Vec<Ast>>, HashMap<ast::Id, cst::Id>)> {
    db.ast_raw(input)
        .map(|(ast, id_mapping, _)| (ast, id_mapping))
}
fn ast_raw(
    db: &dyn CstToAst,
    input: Input,
) -> Option<(Arc<Vec<Ast>>, HashMap<ast::Id, cst::Id>, Vec<CompilerError>)> {
    let cst = db.cst(input)?;
    let mut context = LoweringContext::new();
    let asts = (&mut context).lower_csts(&cst);
    Some((Arc::new(asts), context.id_mapping, context.errors))
}

struct LoweringContext {
    next_id: usize,
    id_mapping: HashMap<ast::Id, cst::Id>,
    errors: Vec<CompilerError>,
}
impl LoweringContext {
    fn new() -> LoweringContext {
        LoweringContext {
            next_id: 0,
            id_mapping: HashMap::new(),
            errors: vec![],
        }
    }
    fn lower_csts(&mut self, csts: &[Cst]) -> Vec<Ast> {
        csts.iter().map(|it| self.lower_cst(it)).collect()
    }
    fn lower_cst(&mut self, cst: &Cst) -> Ast {
        match &cst.kind {
            CstKind::EqualsSign { .. } => self.create_ast(cst.id, AstKind::Error),
            CstKind::Colon { .. } => self.create_ast(cst.id, AstKind::Error),
            CstKind::Comma { .. } => self.create_ast(cst.id, AstKind::Error),
            CstKind::OpeningParenthesis { .. } => self.create_ast(cst.id, AstKind::Error),
            CstKind::ClosingParenthesis { .. } => self.create_ast(cst.id, AstKind::Error),
            CstKind::OpeningBracket { .. } => self.create_ast(cst.id, AstKind::Error),
            CstKind::ClosingBracket { .. } => self.create_ast(cst.id, AstKind::Error),
            CstKind::OpeningCurlyBrace { .. } => self.create_ast(cst.id, AstKind::Error),
            CstKind::ClosingCurlyBrace { .. } => self.create_ast(cst.id, AstKind::Error),
            CstKind::Arrow { .. } => self.create_ast(cst.id, AstKind::Error),
            CstKind::Int { value, .. } => {
                self.create_ast(cst.id, AstKind::Int(Int(value.to_owned())))
            }
            CstKind::Text { value, .. } => {
                let string = self.create_string(cst.id, value.to_owned());
                self.create_ast(cst.id, AstKind::Text(Text(string)))
            }
            CstKind::Identifier { value, .. } => {
                let string = self.create_string(cst.id, value.to_owned());
                self.create_ast(cst.id, AstKind::Identifier(Identifier(string)))
            }
            CstKind::Symbol { value, .. } => {
                let string = self.create_string(cst.id, value.to_owned());
                self.create_ast(cst.id, AstKind::Symbol(Symbol(string)))
            }
            CstKind::LeadingWhitespace { child, .. } => self.lower_cst(child),
            CstKind::LeadingComment { child, .. } => self.lower_cst(child),
            CstKind::TrailingWhitespace { child, .. } => self.lower_cst(child),
            CstKind::TrailingComment { child, .. } => self.lower_cst(child),
            CstKind::Parenthesized {
                opening_parenthesis,
                inner,
                closing_parenthesis,
            } => {
                assert!(
                matches!(opening_parenthesis.unwrap_whitespace_and_comment().kind, CstKind::OpeningParenthesis { .. }),
                "Expected an opening parenthesis to start a parenthesized expression, but found `{}`.",
                *opening_parenthesis
            );
                assert!(
                matches!(
                    closing_parenthesis.unwrap_whitespace_and_comment().kind,
                    CstKind::ClosingParenthesis { .. }
                ),
                "Expected a closing parenthesis to end a parenthesized expression, but found `{}`.",
                *closing_parenthesis
            );
                self.lower_cst(inner)
            }
            CstKind::Struct {
                opening_bracket,
                entries,
                closing_bracket: _,
            } => {
                assert!(
                    matches!(
                        opening_bracket.unwrap_whitespace_and_comment().kind,
                        CstKind::OpeningBracket { .. }
                    ),
                    "Expected an opening bracket to start a struct, but found `{}`.",
                    *opening_bracket
                );
                let entries = entries
                    .into_iter()
                    .map(|entry| {
                        let entry = entry.unwrap_whitespace_and_comment();
                        if let CstKind::StructEntry {
                            key,
                            colon: _,
                            value,
                            comma: _,
                        } = &entry.kind
                        {
                            if key.is_none() {
                                self.errors.push(CompilerError {
                                    span: cst.span(),
                                    message: format!("Expected key, found `{}`.", cst),
                                });
                                return (
                                    self.create_ast(cst.id, AstKind::Error),
                                    self.create_ast(cst.id, AstKind::Error),
                                );
                            }

                            if value.is_none() {
                                self.errors.push(CompilerError {
                                    span: cst.span(),
                                    message: format!("Expected value, found `{}`.", cst),
                                });
                                return (
                                    self.create_ast(cst.id, AstKind::Error),
                                    self.create_ast(cst.id, AstKind::Error),
                                );
                            }
                            let key = self.lower_cst(&key.clone().unwrap());
                            let value = self.lower_cst(&value.clone().unwrap());
                            (key, value)
                        } else {
                            // TODO: Register error.
                            return (
                                self.create_ast(cst.id, AstKind::Error),
                                self.create_ast(cst.id, AstKind::Error),
                            );
                        }
                    })
                    .collect();
                self.create_ast(cst.id, AstKind::Struct(Struct { entries }))
            }
            CstKind::StructEntry { .. } => self.create_ast(cst.id, AstKind::Error),
            CstKind::Lambda {
                opening_curly_brace,
                parameters_and_arrow,
                body,
                closing_curly_brace,
            } => {
                assert!(
                    matches!(
                        opening_curly_brace.unwrap_whitespace_and_comment().kind,
                        CstKind::OpeningCurlyBrace { .. }
                    ),
                    "Expected an opening curly brace at the beginning of a lambda, but found {}.",
                    opening_curly_brace,
                );
                let parameters = if let Some((parameters, arrow)) = parameters_and_arrow {
                    let parameters = self.lower_parameters(parameters);

                    assert!(
                        matches!(
                            arrow.unwrap_whitespace_and_comment().kind,
                            CstKind::Arrow { .. }
                        ),
                        "Expected an arrow after the parameters in a lambda, but found `{}`.",
                        arrow
                    );

                    parameters
                } else {
                    vec![]
                };

                let body = self.lower_csts(body);

                assert!(
                    matches!(
                        closing_curly_brace.unwrap_whitespace_and_comment().kind,
                        CstKind::ClosingCurlyBrace { .. }
                    ),
                    "Expected a closing curly brace at the end of a lambda, but found {}.",
                    closing_curly_brace
                );

                self.create_ast(cst.id, AstKind::Lambda(Lambda { parameters, body }))
            }
            CstKind::Call { name, arguments } => {
                let name = name.unwrap_whitespace_and_comment();
                let name = match name {
                    Cst {
                        id,
                        kind: CstKind::Identifier { value, .. },
                    } => self.create_string(id.to_owned(), value.to_owned()),
                    _ => {
                        panic!(
                            "Expected a symbol for the name of a call, but found `{}`.",
                            name
                        );
                    }
                };

                let arguments = self.lower_csts(arguments);
                self.create_ast(cst.id, AstKind::Call(ast::Call { name, arguments }))
            }
            CstKind::Assignment {
                name,
                parameters,
                equals_sign,
                body,
            } => {
                let name = self.lower_identifier(name);

                let parameters = self.lower_parameters(parameters);
                assert!(
                    matches!(
                        equals_sign.unwrap_whitespace_and_comment().kind,
                        CstKind::EqualsSign { .. }
                    ),
                    "Expected an equals sign for the assignment."
                );

                let mut body = self.lower_csts(body);

                if !parameters.is_empty() {
                    body =
                        vec![self.create_ast(cst.id, AstKind::Lambda(Lambda { parameters, body }))];
                }

                self.create_ast(cst.id, AstKind::Assignment(ast::Assignment { name, body }))
            }
            CstKind::Error { ref message, .. } => {
                self.errors.push(CompilerError {
                    span: cst.span(),
                    message: message.to_owned(),
                });
                self.create_ast(cst.id, AstKind::Error)
            }
        }
    }

    fn lower_parameters(&mut self, csts: &[Cst]) -> Vec<AstString> {
        csts.into_iter()
            .enumerate()
            .map(|(index, it)| {
                self.lower_parameter(it)
                    .unwrap_or_else(|| self.create_string(it.id, format!("<invalid#{}", index)))
            })
            .collect()
    }
    fn lower_parameter(&mut self, cst: &Cst) -> Option<AstString> {
        let cst = cst.unwrap_whitespace_and_comment();
        match &cst.kind {
            CstKind::Identifier { value, .. } => {
                Some(self.create_string(cst.id.to_owned(), value.clone()))
            }
            _ => {
                self.errors.push(CompilerError {
                    span: cst.span(),
                    message: format!("Expected parameter, found `{}`.", cst),
                });
                None
            }
        }
    }
    fn lower_identifier(&mut self, cst: &Cst) -> AstString {
        let cst = cst.unwrap_whitespace_and_comment();
        match cst {
            Cst {
                id,
                kind: CstKind::Identifier { value, .. },
            } => self.create_string(id.to_owned(), value.clone()),
            _ => {
                panic!("Expected an identifier, but found `{}`.", cst);
            }
        }
    }

    fn create_ast(&mut self, cst_id: cst::Id, kind: AstKind) -> Ast {
        Ast {
            id: self.create_next_id(cst_id),
            kind,
        }
    }
    fn create_string(&mut self, cst_id: cst::Id, value: String) -> AstString {
        AstString {
            id: self.create_next_id(cst_id),
            value,
        }
    }
    fn create_next_id(&mut self, cst_id: cst::Id) -> ast::Id {
        let id = ast::Id(self.next_id);
        assert!(matches!(self.id_mapping.insert(id, cst_id), None));
        self.next_id += 1;
        id
    }
}
<commit_msg>fix(compiler): don't create multiple AST → CST ID mappings for AstStrings<commit_after>use std::ops::Range;
use std::sync::Arc;

use im::HashMap;

use super::ast::{self, Ast, AstKind, AstString, Identifier, Int, Lambda, Symbol, Text};
use super::cst::{self, Cst, CstDb, CstKind};
use super::error::CompilerError;
use super::string_to_cst::StringToCst;
use crate::compiler::ast::Struct;
use crate::input::Input;

#[salsa::query_group(CstToAstStorage)]
pub trait CstToAst: CstDb + StringToCst {
    fn ast_to_cst_id(&self, input: Input, id: ast::Id) -> Option<cst::Id>;
    fn ast_id_to_span(&self, input: Input, id: ast::Id) -> Option<Range<usize>>;

    fn cst_to_ast_id(&self, input: Input, id: cst::Id) -> Option<ast::Id>;

    fn ast(&self, input: Input) -> Option<(Arc<Vec<Ast>>, HashMap<ast::Id, cst::Id>)>;
    fn ast_raw(
        &self,
        input: Input,
    ) -> Option<(Arc<Vec<Ast>>, HashMap<ast::Id, cst::Id>, Vec<CompilerError>)>;
}

fn ast_to_cst_id(db: &dyn CstToAst, input: Input, id: ast::Id) -> Option<cst::Id> {
    let (_, ast_to_cst_id_mapping) = db.ast(input).unwrap();
    ast_to_cst_id_mapping.get(&id).cloned()
}
fn ast_id_to_span(db: &dyn CstToAst, input: Input, id: ast::Id) -> Option<Range<usize>> {
    let id = db.ast_to_cst_id(input.clone(), id)?;
    Some(db.find_cst(input, id).span())
}

fn cst_to_ast_id(db: &dyn CstToAst, input: Input, id: cst::Id) -> Option<ast::Id> {
    let (_, ast_to_cst_id_mapping) = db.ast(input).unwrap();
    ast_to_cst_id_mapping
        .iter()
        .find_map(|(key, &value)| if value == id { Some(key) } else { None })
        .cloned()
}

fn ast(db: &dyn CstToAst, input: Input) -> Option<(Arc<Vec<Ast>>, HashMap<ast::Id, cst::Id>)> {
    db.ast_raw(input)
        .map(|(ast, id_mapping, _)| (ast, id_mapping))
}
fn ast_raw(
    db: &dyn CstToAst,
    input: Input,
) -> Option<(Arc<Vec<Ast>>, HashMap<ast::Id, cst::Id>, Vec<CompilerError>)> {
    let cst = db.cst(input)?;
    let mut context = LoweringContext::new();
    let asts = (&mut context).lower_csts(&cst);
    Some((Arc::new(asts), context.id_mapping, context.errors))
}

struct LoweringContext {
    next_id: usize,
    id_mapping: HashMap<ast::Id, cst::Id>,
    errors: Vec<CompilerError>,
}
impl LoweringContext {
    fn new() -> LoweringContext {
        LoweringContext {
            next_id: 0,
            id_mapping: HashMap::new(),
            errors: vec![],
        }
    }
    fn lower_csts(&mut self, csts: &[Cst]) -> Vec<Ast> {
        csts.iter().map(|it| self.lower_cst(it)).collect()
    }
    fn lower_cst(&mut self, cst: &Cst) -> Ast {
        match &cst.kind {
            CstKind::EqualsSign { .. } => self.create_ast(cst.id, AstKind::Error),
            CstKind::Colon { .. } => self.create_ast(cst.id, AstKind::Error),
            CstKind::Comma { .. } => self.create_ast(cst.id, AstKind::Error),
            CstKind::OpeningParenthesis { .. } => self.create_ast(cst.id, AstKind::Error),
            CstKind::ClosingParenthesis { .. } => self.create_ast(cst.id, AstKind::Error),
            CstKind::OpeningBracket { .. } => self.create_ast(cst.id, AstKind::Error),
            CstKind::ClosingBracket { .. } => self.create_ast(cst.id, AstKind::Error),
            CstKind::OpeningCurlyBrace { .. } => self.create_ast(cst.id, AstKind::Error),
            CstKind::ClosingCurlyBrace { .. } => self.create_ast(cst.id, AstKind::Error),
            CstKind::Arrow { .. } => self.create_ast(cst.id, AstKind::Error),
            CstKind::Int { value, .. } => {
                self.create_ast(cst.id, AstKind::Int(Int(value.to_owned())))
            }
            CstKind::Text { value, .. } => {
                let string = self.create_string_without_id_mapping(value.to_owned());
                self.create_ast(cst.id, AstKind::Text(Text(string)))
            }
            CstKind::Identifier { value, .. } => {
                let string = self.create_string_without_id_mapping(value.to_owned());
                self.create_ast(cst.id, AstKind::Identifier(Identifier(string)))
            }
            CstKind::Symbol { value, .. } => {
                let string = self.create_string_without_id_mapping(value.to_owned());
                self.create_ast(cst.id, AstKind::Symbol(Symbol(string)))
            }
            CstKind::LeadingWhitespace { child, .. } => self.lower_cst(child),
            CstKind::LeadingComment { child, .. } => self.lower_cst(child),
            CstKind::TrailingWhitespace { child, .. } => self.lower_cst(child),
            CstKind::TrailingComment { child, .. } => self.lower_cst(child),
            CstKind::Parenthesized {
                opening_parenthesis,
                inner,
                closing_parenthesis,
            } => {
                assert!(
                matches!(opening_parenthesis.unwrap_whitespace_and_comment().kind, CstKind::OpeningParenthesis { .. }),
                "Expected an opening parenthesis to start a parenthesized expression, but found `{}`.",
                *opening_parenthesis
            );
                assert!(
                matches!(
                    closing_parenthesis.unwrap_whitespace_and_comment().kind,
                    CstKind::ClosingParenthesis { .. }
                ),
                "Expected a closing parenthesis to end a parenthesized expression, but found `{}`.",
                *closing_parenthesis
            );
                self.lower_cst(inner)
            }
            CstKind::Struct {
                opening_bracket,
                entries,
                closing_bracket: _,
            } => {
                assert!(
                    matches!(
                        opening_bracket.unwrap_whitespace_and_comment().kind,
                        CstKind::OpeningBracket { .. }
                    ),
                    "Expected an opening bracket to start a struct, but found `{}`.",
                    *opening_bracket
                );
                let entries = entries
                    .into_iter()
                    .map(|entry| {
                        let entry = entry.unwrap_whitespace_and_comment();
                        if let CstKind::StructEntry {
                            key,
                            colon: _,
                            value,
                            comma: _,
                        } = &entry.kind
                        {
                            if key.is_none() {
                                self.errors.push(CompilerError {
                                    span: cst.span(),
                                    message: format!("Expected key, found `{}`.", cst),
                                });
                                return (
                                    self.create_ast(cst.id, AstKind::Error),
                                    self.create_ast(cst.id, AstKind::Error),
                                );
                            }

                            if value.is_none() {
                                self.errors.push(CompilerError {
                                    span: cst.span(),
                                    message: format!("Expected value, found `{}`.", cst),
                                });
                                return (
                                    self.create_ast(cst.id, AstKind::Error),
                                    self.create_ast(cst.id, AstKind::Error),
                                );
                            }
                            let key = self.lower_cst(&key.clone().unwrap());
                            let value = self.lower_cst(&value.clone().unwrap());
                            (key, value)
                        } else {
                            // TODO: Register error.
                            return (
                                self.create_ast(cst.id, AstKind::Error),
                                self.create_ast(cst.id, AstKind::Error),
                            );
                        }
                    })
                    .collect();
                self.create_ast(cst.id, AstKind::Struct(Struct { entries }))
            }
            CstKind::StructEntry { .. } => self.create_ast(cst.id, AstKind::Error),
            CstKind::Lambda {
                opening_curly_brace,
                parameters_and_arrow,
                body,
                closing_curly_brace,
            } => {
                assert!(
                    matches!(
                        opening_curly_brace.unwrap_whitespace_and_comment().kind,
                        CstKind::OpeningCurlyBrace { .. }
                    ),
                    "Expected an opening curly brace at the beginning of a lambda, but found {}.",
                    opening_curly_brace,
                );
                let parameters = if let Some((parameters, arrow)) = parameters_and_arrow {
                    let parameters = self.lower_parameters(parameters);

                    assert!(
                        matches!(
                            arrow.unwrap_whitespace_and_comment().kind,
                            CstKind::Arrow { .. }
                        ),
                        "Expected an arrow after the parameters in a lambda, but found `{}`.",
                        arrow
                    );

                    parameters
                } else {
                    vec![]
                };

                let body = self.lower_csts(body);

                assert!(
                    matches!(
                        closing_curly_brace.unwrap_whitespace_and_comment().kind,
                        CstKind::ClosingCurlyBrace { .. }
                    ),
                    "Expected a closing curly brace at the end of a lambda, but found {}.",
                    closing_curly_brace
                );

                self.create_ast(cst.id, AstKind::Lambda(Lambda { parameters, body }))
            }
            CstKind::Call { name, arguments } => {
                let name = name.unwrap_whitespace_and_comment();
                let name = match name {
                    Cst {
                        id,
                        kind: CstKind::Identifier { value, .. },
                    } => self.create_string(id.to_owned(), value.to_owned()),
                    _ => {
                        panic!(
                            "Expected a symbol for the name of a call, but found `{}`.",
                            name
                        );
                    }
                };

                let arguments = self.lower_csts(arguments);
                self.create_ast(cst.id, AstKind::Call(ast::Call { name, arguments }))
            }
            CstKind::Assignment {
                name,
                parameters,
                equals_sign,
                body,
            } => {
                let name = self.lower_identifier(name);

                let parameters = self.lower_parameters(parameters);
                assert!(
                    matches!(
                        equals_sign.unwrap_whitespace_and_comment().kind,
                        CstKind::EqualsSign { .. }
                    ),
                    "Expected an equals sign for the assignment."
                );

                let mut body = self.lower_csts(body);

                if !parameters.is_empty() {
                    body =
                        vec![self.create_ast(cst.id, AstKind::Lambda(Lambda { parameters, body }))];
                }

                self.create_ast(cst.id, AstKind::Assignment(ast::Assignment { name, body }))
            }
            CstKind::Error { ref message, .. } => {
                self.errors.push(CompilerError {
                    span: cst.span(),
                    message: message.to_owned(),
                });
                self.create_ast(cst.id, AstKind::Error)
            }
        }
    }

    fn lower_parameters(&mut self, csts: &[Cst]) -> Vec<AstString> {
        csts.into_iter()
            .enumerate()
            .map(|(index, it)| {
                self.lower_parameter(it)
                    .unwrap_or_else(|| self.create_string(it.id, format!("<invalid#{}", index)))
            })
            .collect()
    }
    fn lower_parameter(&mut self, cst: &Cst) -> Option<AstString> {
        let cst = cst.unwrap_whitespace_and_comment();
        match &cst.kind {
            CstKind::Identifier { value, .. } => {
                Some(self.create_string(cst.id.to_owned(), value.clone()))
            }
            _ => {
                self.errors.push(CompilerError {
                    span: cst.span(),
                    message: format!("Expected parameter, found `{}`.", cst),
                });
                None
            }
        }
    }
    fn lower_identifier(&mut self, cst: &Cst) -> AstString {
        let cst = cst.unwrap_whitespace_and_comment();
        match cst {
            Cst {
                id,
                kind: CstKind::Identifier { value, .. },
            } => self.create_string(id.to_owned(), value.clone()),
            _ => {
                panic!("Expected an identifier, but found `{}`.", cst);
            }
        }
    }

    fn create_ast(&mut self, cst_id: cst::Id, kind: AstKind) -> Ast {
        Ast {
            id: self.create_next_id(cst_id),
            kind,
        }
    }
    fn create_string(&mut self, cst_id: cst::Id, value: String) -> AstString {
        AstString {
            id: self.create_next_id(cst_id),
            value,
        }
    }
    fn create_string_without_id_mapping(&mut self, value: String) -> AstString {
        AstString {
            id: self.create_next_id_without_mapping(),
            value,
        }
    }
    fn create_next_id(&mut self, cst_id: cst::Id) -> ast::Id {
        let id = self.create_next_id_without_mapping();
        assert!(matches!(self.id_mapping.insert(id, cst_id), None));
        id
    }
    fn create_next_id_without_mapping(&mut self) -> ast::Id {
        let id = ast::Id(self.next_id);
        self.next_id += 1;
        id
    }
}
<|endoftext|>


<commit_before>use std::default::Default;
use std::collections::BTreeMap;

use url::{Url, ParseError};
use sidekiq::{Job, JobOpts, Value};
use url_serde::Serde;
use html5ever::tokenizer::{TokenSink, Token, TagToken, TokenSinkResult};

#[derive(Serialize, Debug)]
pub struct Page {
    pub url: Serde<Url>,
    pub document: String,
    pub headers: BTreeMap<String, String>,
    pub status: String,
    pub http_version: String,
    pub urls: Vec<Serde<Url>>,
}

impl TokenSink for Page {
    type Handle = ();

    #[cfg_attr(feature = "clippy", allow(single_match))]
    fn process_token(&mut self, token: Token) -> TokenSinkResult<()> {
        if let TagToken(tag) = token {
            match tag.name {
                local_name!("a") => {
                    for attr in &tag.attrs {
                        if attr.name.local.to_string() == "href" {
                            if let Some(u) = self.can_enqueue(&attr.value) {
                                self.urls.push(Serde(u));
                            }
                        }
                    }
                }
                _ => {}
            }
        }
        TokenSinkResult::Continue
    }
}

impl Page {
    pub fn new(url: Url,
               document: String,
               headers: BTreeMap<String, String>,
               status: String,
               http_version: String)
               -> Self {
        Page {
            url: Serde(url),
            document: document,
            headers: headers,
            status: status,
            http_version: http_version,
            urls: Vec::new(),
        }
    }

    pub fn to_job(&self) -> Job {
        let job_opts = JobOpts {
            queue: maman_name!().to_string().to_lowercase(),
            ..Default::default()
        };
        Job::new(maman_name!().to_string(), vec![self.as_object()], job_opts)
    }

    pub fn as_object(&self) -> Value {
        json!({
            "url": &self.url,
            "document": &self.document,
            "headers": &self.headers,
            "status": &self.status,
            "http_version": &self.http_version,
            "urls": &self.urls,
        })
    }

    fn normalize_url(&self, url: &str) -> Option<Url> {
        match Url::parse(url) {
            Ok(u) => Some(u),
            Err(ParseError::RelativeUrlWithoutBase) => Some(self.url.join(url).unwrap()),
            Err(_) => None,
        }
    }

    fn url_without_fragment(&self, url: &str) -> Option<Url> {
        match self.normalize_url(url) {
            Some(mut u) => {
                u.set_fragment(None);
                Some(u)
            }
            None => None,
        }
    }

    fn url_eq(&self, url: &Url) -> bool {
        self.url == *url
    }

    fn domain_eq(&self, url: &Url) -> bool {
        self.url.domain() == url.domain()
    }

    fn can_enqueue(&self, url: &str) -> Option<Url> {
        match self.url_without_fragment(url) {
            Some(u) => {
                match u.scheme() {
                    "http" | "https" => {
                        if !self.url_eq(&u) && self.domain_eq(&u) {
                            Some(u)
                        } else {
                            None
                        }
                    }
                    _ => None,
                }
            }
            None => None,
        }
    }
}
<commit_msg>Fix owned instance just for comparison<commit_after>use std::default::Default;
use std::collections::BTreeMap;

use url::{Url, ParseError};
use sidekiq::{Job, JobOpts, Value};
use url_serde::Serde;
use html5ever::tokenizer::{TokenSink, Token, TagToken, TokenSinkResult};

#[derive(Serialize, Debug)]
pub struct Page {
    pub url: Serde<Url>,
    pub document: String,
    pub headers: BTreeMap<String, String>,
    pub status: String,
    pub http_version: String,
    pub urls: Vec<Serde<Url>>,
}

impl TokenSink for Page {
    type Handle = ();

    #[cfg_attr(feature = "clippy", allow(single_match))]
    fn process_token(&mut self, token: Token) -> TokenSinkResult<()> {
        if let TagToken(tag) = token {
            match tag.name {
                local_name!("a") => {
                    for attr in &tag.attrs {
                        if &*attr.name.local == "href" {
                            if let Some(u) = self.can_enqueue(&attr.value) {
                                self.urls.push(Serde(u));
                            }
                        }
                    }
                }
                _ => {}
            }
        }
        TokenSinkResult::Continue
    }
}

impl Page {
    pub fn new(url: Url,
               document: String,
               headers: BTreeMap<String, String>,
               status: String,
               http_version: String)
               -> Self {
        Page {
            url: Serde(url),
            document: document,
            headers: headers,
            status: status,
            http_version: http_version,
            urls: Vec::new(),
        }
    }

    pub fn to_job(&self) -> Job {
        let job_opts = JobOpts {
            queue: maman_name!().to_string().to_lowercase(),
            ..Default::default()
        };
        Job::new(maman_name!().to_string(), vec![self.as_object()], job_opts)
    }

    pub fn as_object(&self) -> Value {
        json!({
            "url": &self.url,
            "document": &self.document,
            "headers": &self.headers,
            "status": &self.status,
            "http_version": &self.http_version,
            "urls": &self.urls,
        })
    }

    fn normalize_url(&self, url: &str) -> Option<Url> {
        match Url::parse(url) {
            Ok(u) => Some(u),
            Err(ParseError::RelativeUrlWithoutBase) => Some(self.url.join(url).unwrap()),
            Err(_) => None,
        }
    }

    fn url_without_fragment(&self, url: &str) -> Option<Url> {
        match self.normalize_url(url) {
            Some(mut u) => {
                u.set_fragment(None);
                Some(u)
            }
            None => None,
        }
    }

    fn url_eq(&self, url: &Url) -> bool {
        self.url == *url
    }

    fn domain_eq(&self, url: &Url) -> bool {
        self.url.domain() == url.domain()
    }

    fn can_enqueue(&self, url: &str) -> Option<Url> {
        match self.url_without_fragment(url) {
            Some(u) => {
                match u.scheme() {
                    "http" | "https" => {
                        if !self.url_eq(&u) && self.domain_eq(&u) {
                            Some(u)
                        } else {
                            None
                        }
                    }
                    _ => None,
                }
            }
            None => None,
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate enum_map;

use enum_map::{Enum, EnumMap, IntoIter};

use std::cell::RefCell;
use std::collections::HashSet;
use std::convert::Infallible;
use std::marker::PhantomData;

trait From<T>: Sized {
    fn from(_: T) -> Self {
        unreachable!();
    }
}

impl<T, U> From<T> for U {}

#[derive(Copy, Clone, Debug, Enum, PartialEq)]
enum Example {
    A,
    B,
    C,
}

#[test]
fn test_bool() {
    let mut map = enum_map! { false => 24, true => 42 };
    assert_eq!(map[false], 24);
    assert_eq!(map[true], 42);
    map[false] += 1;
    assert_eq!(map[false], 25);
    for (key, item) in &mut map {
        if !key {
            *item += 1;
        }
    }
    assert_eq!(map[false], 26);
    assert_eq!(map[true], 42);
}

#[test]
fn test_clone() {
    let map = enum_map! { false => 3, true => 5 };
    assert_eq!(map.clone(), map);
}

#[test]
fn test_debug() {
    let map = enum_map! { false => 3, true => 5 };
    assert_eq!(format!("{:?}", map), "{false: 3, true: 5}");
}

#[test]
fn test_hash() {
    let map = enum_map! { false => 3, true => 5 };
    let mut set = HashSet::new();
    set.insert(map);
    assert!(set.contains(&map));
}

#[test]
fn test_clear() {
    let mut map = enum_map! { false => 1, true => 2 };
    map.clear();
    assert_eq!(map[true], 0);
    assert_eq!(map[false], 0);
}

#[test]
fn discriminants() {
    #[derive(Debug, Enum, PartialEq)]
    enum Discriminants {
        A = 2000,
        B = 3000,
        C = 1000,
    }
    let mut map = EnumMap::new();
    map[Discriminants::A] = 3;
    map[Discriminants::B] = 2;
    map[Discriminants::C] = 1;
    let mut pairs = map.iter();
    assert_eq!(pairs.next(), Some((Discriminants::A, &3)));
    assert_eq!(pairs.next(), Some((Discriminants::B, &2)));
    assert_eq!(pairs.next(), Some((Discriminants::C, &1)));
    assert_eq!(pairs.next(), None);
}

#[test]
fn extend() {
    let mut map = enum_map! { _ => 0 };
    map.extend(vec![(Example::A, 3)]);
    map.extend(vec![(&Example::B, &4)]);
    assert_eq!(
        map,
        enum_map! { Example::A => 3, Example::B => 4, Example::C => 0 }
    );
}

#[test]
fn huge_enum() {
    #[derive(Enum)]
    enum Example {
        A,
        B,
        C,
        D,
        E,
        F,
        G,
        H,
        I,
        J,
        K,
        L,
        M,
        N,
        O,
        P,
        Q,
        R,
        S,
        T,
        U,
        V,
        W,
        X,
        Y,
        Z,
        Aa,
        Bb,
        Cc,
        Dd,
        Ee,
        Ff,
        Gg,
        Hh,
        Ii,
        Jj,
        Kk,
        Ll,
        Mm,
        Nn,
        Oo,
        Pp,
        Qq,
        Rr,
        Ss,
        Tt,
        Uu,
        Vv,
        Ww,
        Xx,
        Yy,
        Zz,
    }

    let map = enum_map! { _ => 2 };
    assert_eq!(map[Example::Xx], 2);
}

#[test]
fn iterator_len() {
    assert_eq!(
        enum_map! { Example::A | Example::B | Example::C => 0 }
            .iter()
            .len(),
        3
    );
}

#[test]
fn iter_mut_len() {
    assert_eq!(
        enum_map! { Example::A | Example::B | Example::C => 0 }
            .iter_mut()
            .len(),
        3
    );
}

#[test]
fn into_iter_len() {
    assert_eq!(enum_map! { Example::A | _ => 0 }.into_iter().len(), 3);
}

#[test]
fn iterator_next_back() {
    assert_eq!(
        enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 }
            .iter()
            .next_back(),
        Some((Example::C, &3))
    );
}

#[test]
fn iter_mut_next_back() {
    assert_eq!(
        enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 }
            .iter_mut()
            .next_back(),
        Some((Example::C, &mut 3))
    );
}

#[test]
fn into_iter() {
    let mut iter = enum_map! { true => 5, false => 7 }.into_iter();
    assert_eq!(iter.next(), Some((false, 7)));
    assert_eq!(iter.next(), Some((true, 5)));
    assert_eq!(iter.next(), None);
    assert_eq!(iter.next(), None);
}

#[test]
fn into_iter_u8() {
    assert_eq!(
        <EnumMap<_, _> as core::convert::From<_>>::from(|i: u8| i)
            .into_iter()
            .collect::<Vec<_>>(),
        (0..256).map(|x| (x as u8, x as u8)).collect::<Vec<_>>()
    );
}

struct DropReporter<'a> {
    into: &'a RefCell<Vec<usize>>,
    value: usize,
}

impl<'a> Drop for DropReporter<'a> {
    fn drop(&mut self) {
        self.into.borrow_mut().push(self.value);
    }
}

#[test]
fn into_iter_drop() {
    let dropped = RefCell::new(Vec::new());
    let mut a: IntoIter<Example, _> = enum_map! {
        k => DropReporter {
            into: &dropped,
            value: k as usize,
        },
    }
    .into_iter();
    assert_eq!(a.next().unwrap().0, Example::A);
    assert_eq!(*dropped.borrow(), &[0]);
    drop(a);
    assert_eq!(*dropped.borrow(), &[0, 1, 2]);
}

#[test]
fn values_rev_collect() {
    assert_eq!(
        vec![3, 2, 1],
        enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 }
            .values()
            .rev()
            .cloned()
            .collect::<Vec<_>>()
    );
}

#[test]
fn values_len() {
    assert_eq!(enum_map! { false => 0, true => 1 }.values().len(), 2);
}

#[test]
fn values_mut_next_back() {
    let mut map = enum_map! { false => 0, true => 1 };
    assert_eq!(map.values_mut().next_back(), Some(&mut 1));
}
#[test]
fn test_u8() {
    let mut map = enum_map! { b'a' => 4, _ => 0 };
    map[b'c'] = 3;
    assert_eq!(map[b'a'], 4);
    assert_eq!(map[b'b'], 0);
    assert_eq!(map[b'c'], 3);
    assert_eq!(map.iter().next(), Some((0, &0)));
}

#[derive(Enum)]
enum Void {}

#[test]
fn empty_map() {
    let void: EnumMap<Void, Void> = enum_map! {};
    assert!(void.is_empty());
}

#[test]
#[should_panic]
fn empty_value() {
    let _void: EnumMap<bool, Void> = enum_map! { _ => unreachable!() };
}

#[test]
fn empty_infallible_map() {
    let void: EnumMap<Infallible, Infallible> = enum_map! {};
    assert!(void.is_empty());
}

#[derive(Clone, Copy)]
enum X {
    A(PhantomData<*const ()>),
}

impl<V> Enum<V> for X {
    type Array = [V; 1];
    const POSSIBLE_VALUES: usize = 1;

    fn slice(array: &[V; 1]) -> &[V] {
        array
    }

    fn slice_mut(array: &mut [V; 1]) -> &mut [V] {
        array
    }

    fn from_usize(arg: usize) -> X {
        assert_eq!(arg, 0);
        X::A(PhantomData)
    }

    fn to_usize(self) -> usize {
        0
    }

    fn from_function<F: FnMut(Self) -> V>(mut f: F) -> [V; 1] {
        [f(X::A(PhantomData))]
    }
}

fn assert_sync_send<T: Sync + Send>(_: T) {}

#[test]
fn assert_enum_map_does_not_copy_sync_send_dependency_of_keys() {
    let mut map = enum_map! { X::A(PhantomData) => true };
    assert_sync_send(map);
    assert_sync_send(&map);
    assert_sync_send(&mut map);
    assert_sync_send(map.iter());
    assert_sync_send(map.iter_mut());
    assert_sync_send(map.into_iter());
    assert_eq!(map[X::A(PhantomData)], true);
}

#[test]
fn test_sum() {
    assert_eq!(
        enum_map! { i => u8::into(i) }
            .iter()
            .map(|(_, v)| v)
            .sum::<u32>(),
        32_640
    );
}

#[test]
fn test_sum_mut() {
    assert_eq!(
        enum_map! { i => u8::into(i) }
            .iter_mut()
            .map(|(_, &mut v)| -> u32 { v })
            .sum::<u32>(),
        32_640
    );
}

#[test]
fn test_iter_clone() {
    let map = enum_map! { Example::A => 3, Example::B => 4, Example::C => 1 };
    let iter = map.iter();
    assert_eq!(iter.clone().map(|(_, v)| v).sum::<u32>(), 8);
    assert_eq!(iter.map(|(_, v)| v).sum::<u32>(), 8);
    let values = map.values();
    assert_eq!(values.clone().sum::<u32>(), 8);
    assert_eq!(values.sum::<u32>(), 8);
}
<commit_msg>Use Mutex to test clonable iterators<commit_after>#[macro_use]
extern crate enum_map;

use enum_map::{Enum, EnumMap, IntoIter};

use std::cell::RefCell;
use std::collections::HashSet;
use std::convert::Infallible;
use std::marker::PhantomData;

trait From<T>: Sized {
    fn from(_: T) -> Self {
        unreachable!();
    }
}

impl<T, U> From<T> for U {}

#[derive(Copy, Clone, Debug, Enum, PartialEq)]
enum Example {
    A,
    B,
    C,
}

#[test]
fn test_bool() {
    let mut map = enum_map! { false => 24, true => 42 };
    assert_eq!(map[false], 24);
    assert_eq!(map[true], 42);
    map[false] += 1;
    assert_eq!(map[false], 25);
    for (key, item) in &mut map {
        if !key {
            *item += 1;
        }
    }
    assert_eq!(map[false], 26);
    assert_eq!(map[true], 42);
}

#[test]
fn test_clone() {
    let map = enum_map! { false => 3, true => 5 };
    assert_eq!(map.clone(), map);
}

#[test]
fn test_debug() {
    let map = enum_map! { false => 3, true => 5 };
    assert_eq!(format!("{:?}", map), "{false: 3, true: 5}");
}

#[test]
fn test_hash() {
    let map = enum_map! { false => 3, true => 5 };
    let mut set = HashSet::new();
    set.insert(map);
    assert!(set.contains(&map));
}

#[test]
fn test_clear() {
    let mut map = enum_map! { false => 1, true => 2 };
    map.clear();
    assert_eq!(map[true], 0);
    assert_eq!(map[false], 0);
}

#[test]
fn discriminants() {
    #[derive(Debug, Enum, PartialEq)]
    enum Discriminants {
        A = 2000,
        B = 3000,
        C = 1000,
    }
    let mut map = EnumMap::new();
    map[Discriminants::A] = 3;
    map[Discriminants::B] = 2;
    map[Discriminants::C] = 1;
    let mut pairs = map.iter();
    assert_eq!(pairs.next(), Some((Discriminants::A, &3)));
    assert_eq!(pairs.next(), Some((Discriminants::B, &2)));
    assert_eq!(pairs.next(), Some((Discriminants::C, &1)));
    assert_eq!(pairs.next(), None);
}

#[test]
fn extend() {
    let mut map = enum_map! { _ => 0 };
    map.extend(vec![(Example::A, 3)]);
    map.extend(vec![(&Example::B, &4)]);
    assert_eq!(
        map,
        enum_map! { Example::A => 3, Example::B => 4, Example::C => 0 }
    );
}

#[test]
fn huge_enum() {
    #[derive(Enum)]
    enum Example {
        A,
        B,
        C,
        D,
        E,
        F,
        G,
        H,
        I,
        J,
        K,
        L,
        M,
        N,
        O,
        P,
        Q,
        R,
        S,
        T,
        U,
        V,
        W,
        X,
        Y,
        Z,
        Aa,
        Bb,
        Cc,
        Dd,
        Ee,
        Ff,
        Gg,
        Hh,
        Ii,
        Jj,
        Kk,
        Ll,
        Mm,
        Nn,
        Oo,
        Pp,
        Qq,
        Rr,
        Ss,
        Tt,
        Uu,
        Vv,
        Ww,
        Xx,
        Yy,
        Zz,
    }

    let map = enum_map! { _ => 2 };
    assert_eq!(map[Example::Xx], 2);
}

#[test]
fn iterator_len() {
    assert_eq!(
        enum_map! { Example::A | Example::B | Example::C => 0 }
            .iter()
            .len(),
        3
    );
}

#[test]
fn iter_mut_len() {
    assert_eq!(
        enum_map! { Example::A | Example::B | Example::C => 0 }
            .iter_mut()
            .len(),
        3
    );
}

#[test]
fn into_iter_len() {
    assert_eq!(enum_map! { Example::A | _ => 0 }.into_iter().len(), 3);
}

#[test]
fn iterator_next_back() {
    assert_eq!(
        enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 }
            .iter()
            .next_back(),
        Some((Example::C, &3))
    );
}

#[test]
fn iter_mut_next_back() {
    assert_eq!(
        enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 }
            .iter_mut()
            .next_back(),
        Some((Example::C, &mut 3))
    );
}

#[test]
fn into_iter() {
    let mut iter = enum_map! { true => 5, false => 7 }.into_iter();
    assert_eq!(iter.next(), Some((false, 7)));
    assert_eq!(iter.next(), Some((true, 5)));
    assert_eq!(iter.next(), None);
    assert_eq!(iter.next(), None);
}

#[test]
fn into_iter_u8() {
    assert_eq!(
        <EnumMap<_, _> as core::convert::From<_>>::from(|i: u8| i)
            .into_iter()
            .collect::<Vec<_>>(),
        (0..256).map(|x| (x as u8, x as u8)).collect::<Vec<_>>()
    );
}

struct DropReporter<'a> {
    into: &'a RefCell<Vec<usize>>,
    value: usize,
}

impl<'a> Drop for DropReporter<'a> {
    fn drop(&mut self) {
        self.into.borrow_mut().push(self.value);
    }
}

#[test]
fn into_iter_drop() {
    let dropped = RefCell::new(Vec::new());
    let mut a: IntoIter<Example, _> = enum_map! {
        k => DropReporter {
            into: &dropped,
            value: k as usize,
        },
    }
    .into_iter();
    assert_eq!(a.next().unwrap().0, Example::A);
    assert_eq!(*dropped.borrow(), &[0]);
    drop(a);
    assert_eq!(*dropped.borrow(), &[0, 1, 2]);
}

#[test]
fn values_rev_collect() {
    assert_eq!(
        vec![3, 2, 1],
        enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 }
            .values()
            .rev()
            .cloned()
            .collect::<Vec<_>>()
    );
}

#[test]
fn values_len() {
    assert_eq!(enum_map! { false => 0, true => 1 }.values().len(), 2);
}

#[test]
fn values_mut_next_back() {
    let mut map = enum_map! { false => 0, true => 1 };
    assert_eq!(map.values_mut().next_back(), Some(&mut 1));
}
#[test]
fn test_u8() {
    let mut map = enum_map! { b'a' => 4, _ => 0 };
    map[b'c'] = 3;
    assert_eq!(map[b'a'], 4);
    assert_eq!(map[b'b'], 0);
    assert_eq!(map[b'c'], 3);
    assert_eq!(map.iter().next(), Some((0, &0)));
}

#[derive(Enum)]
enum Void {}

#[test]
fn empty_map() {
    let void: EnumMap<Void, Void> = enum_map! {};
    assert!(void.is_empty());
}

#[test]
#[should_panic]
fn empty_value() {
    let _void: EnumMap<bool, Void> = enum_map! { _ => unreachable!() };
}

#[test]
fn empty_infallible_map() {
    let void: EnumMap<Infallible, Infallible> = enum_map! {};
    assert!(void.is_empty());
}

#[derive(Clone, Copy)]
enum X {
    A(PhantomData<*const ()>),
}

impl<V> Enum<V> for X {
    type Array = [V; 1];
    const POSSIBLE_VALUES: usize = 1;

    fn slice(array: &[V; 1]) -> &[V] {
        array
    }

    fn slice_mut(array: &mut [V; 1]) -> &mut [V] {
        array
    }

    fn from_usize(arg: usize) -> X {
        assert_eq!(arg, 0);
        X::A(PhantomData)
    }

    fn to_usize(self) -> usize {
        0
    }

    fn from_function<F: FnMut(Self) -> V>(mut f: F) -> [V; 1] {
        [f(X::A(PhantomData))]
    }
}

fn assert_sync_send<T: Sync + Send>(_: T) {}

#[test]
fn assert_enum_map_does_not_copy_sync_send_dependency_of_keys() {
    let mut map = enum_map! { X::A(PhantomData) => true };
    assert_sync_send(map);
    assert_sync_send(&map);
    assert_sync_send(&mut map);
    assert_sync_send(map.iter());
    assert_sync_send(map.iter_mut());
    assert_sync_send(map.into_iter());
    assert_eq!(map[X::A(PhantomData)], true);
}

#[test]
fn test_sum() {
    assert_eq!(
        enum_map! { i => u8::into(i) }
            .iter()
            .map(|(_, v)| v)
            .sum::<u32>(),
        32_640
    );
}

#[test]
fn test_sum_mut() {
    assert_eq!(
        enum_map! { i => u8::into(i) }
            .iter_mut()
            .map(|(_, &mut v)| -> u32 { v })
            .sum::<u32>(),
        32_640
    );
}

#[test]
fn test_iter_clone() {
    // Mutex doesn't implement Clone, but iterators should still be Clone.
    use std::sync::Mutex;
    let map = enum_map! {
        Example::A => Mutex::new(3),
        Example::B => Mutex::new(4),
        Example::C => Mutex::new(1),
    };
    let iter = map.iter();
    assert_eq!(
        iter.clone().map(|(_, v)| *v.lock().unwrap()).sum::<u32>(),
        8
    );
    assert_eq!(iter.map(|(_, v)| *v.lock().unwrap()).sum::<u32>(), 8);
    let values = map.values();
    assert_eq!(values.clone().map(|v| *v.lock().unwrap()).sum::<u32>(), 8);
    assert_eq!(values.map(|v| *v.lock().unwrap()).sum::<u32>(), 8);
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate serde_derive;
extern crate docopt;
extern crate image;
extern crate gpx;
extern crate geo;
extern crate chrono;
extern crate rayon;

use std::fs;
use std::fs::File;
use std::io::BufReader;
use std::path;

use docopt::Docopt;
use gpx::read;
use gpx::{Gpx, Track};
use geo::Point;
use image::ImageBuffer;
use rayon::prelude::*;

const USAGE: &'static str = "
Generate video from GPX files.

Usage:
  derivers <top-lat> <left-lng> <bottom-lat> <right-lng> <width> <height> <directory>
";

#[derive(Debug, Deserialize)]
struct CommandArgs {
    arg_top_lat: f64,
    arg_left_lng: f64,
    arg_bottom_lat: f64,
    arg_right_lng: f64,
    arg_width: u32,
    arg_height: u32,
    arg_directory: String,
}

#[derive(Debug)]
struct ImageFrame {
    top_left: Point<f64>,
    bottom_right: Point<f64>,
    buf: image::RgbImage
}

impl ImageFrame {
    pub fn from(args: &CommandArgs) -> ImageFrame {

        // h == w * (top - bottom) / (right - left)
        let height = (args.arg_width as f64) *
            ((args.arg_top_lat - args.arg_bottom_lat) /
             (args.arg_right_lng - args.arg_left_lng));

        println!("Computed height: {:?}", height);

        ImageFrame {
            top_left: Point::new(args.arg_left_lng, args.arg_top_lat),
            bottom_right: Point::new(args.arg_right_lng, args.arg_bottom_lat),
            buf: ImageBuffer::from_pixel(args.arg_width, height as u32,
                                         image::Rgb([0, 0, 0]))
        }
    }

    // Using simple equirectangular projection for now
    pub fn project_to_screen(&self, coord: &Point<f64>) -> Option<(u32, u32)> {
        // lng is x pos
        let x_pos = self.top_left.lng() - coord.lng();
        let y_pos = self.top_left.lat() - coord.lat();

        let x_offset = x_pos / (self.top_left.lng() - self.bottom_right.lng());
        let y_offset = y_pos / (self.top_left.lat() - self.bottom_right.lat());

        let (x, y) = ((x_offset * self.buf.width() as f64),
                      (y_offset * self.buf.height() as f64));

        if (x < 0.0 || x as u32 >= self.buf.width()) ||
            (y < 0.0 || y as u32 >= self.buf.height()) {
            None
        } else {
            Some((x as u32, y as u32))
        }
    }
}

#[derive(Debug)]
struct Activity {
    name: String,
    date: chrono::DateTime<chrono::Utc>,
    track_points: Vec<Point<f64>>,
}

fn parse_gpx(path: &path::PathBuf) -> Option<Activity> {
    let file = File::open(path).unwrap();
    let reader = BufReader::new(file);

    let gpx: Gpx = read(reader).unwrap();

    // Nothing to do if there are no tracks
    if gpx.tracks.len() == 0 {
        return None;
    } else if gpx.tracks.len() > 1 {
        println!("Warning! more than 1 track, just taking first");
    }

    let track: &Track = &gpx.tracks[0];

    let mut activity = Activity {
        name: track.name.clone().unwrap_or(String::from("Untitled")),
        date: chrono::Utc::now(),
        track_points: vec![],
    };

    if let Some(metadata) = gpx.metadata {
        if let Some(time) = metadata.time {
            activity.date = time;
        }
    }

    // Append all the waypoints.
    for seg in track.segments.iter() {
        let points = seg.points.iter().map(|ref wpt| wpt.point());
        activity.track_points.extend(points);
    }

    if activity.track_points.len() == 0 {
        None
    } else {
        Some(activity)
    }
}

fn main() {
    let args: CommandArgs = Docopt::new(USAGE)
        .and_then(|d| d.deserialize())
        .unwrap_or_else(|e| e.exit());

    println!("{:?}", args);

    let mut img = ImageFrame::from(&args);

    let paths: Vec<path::PathBuf> = fs::read_dir(args.arg_directory)
        .unwrap()
        .into_iter()
        .map(|p| p.unwrap().path())
        .collect();

    let activities: Vec<Activity> = paths
        .into_par_iter()
        .filter_map(|ref p| parse_gpx(p))
        .collect();

    let fout = &mut File::create("heatmap.ppm").unwrap();
    let cloned_buf = img.buf.clone();
    let dyn_image = image::ImageRgb8(img.buf.clone());

    for act in activities {
        println!("Activity: {:?}", act.name);

        for pt in act.track_points.iter() {
            if let Some((x, y)) = img.project_to_screen(pt) {
                let pixel = img.buf.get_pixel_mut(x, y);
                let c = if pixel[0] == 255 {
                    pixel[0]
                } else if pixel[0] == 0{
                    25
                } else {
                    pixel[0] + 5
                };

                *pixel = image::Rgb([c, c, c]);
            }
        }

        image::ImageRgb8(img.buf.clone()).save(fout, image::PPM).unwrap();
    }
}
<commit_msg>Slight cleanup<commit_after>#[macro_use]
extern crate serde_derive;
extern crate docopt;
extern crate image;
extern crate gpx;
extern crate geo;
extern crate chrono;
extern crate rayon;

use std::fs;
use std::fs::File;
use std::io::BufReader;
use std::path;

use docopt::Docopt;
use gpx::read;
use gpx::{Gpx, Track};
use geo::Point;
use image::ImageBuffer;
use rayon::prelude::*;

const USAGE: &'static str = "
Generate video from GPX files.

Usage:
  derivers <top-lat> <left-lng> <bottom-lat> <right-lng> <width> <height> <directory>
";

#[derive(Debug, Deserialize)]
struct CommandArgs {
    arg_top_lat: f64,
    arg_left_lng: f64,
    arg_bottom_lat: f64,
    arg_right_lng: f64,
    arg_width: u32,
    arg_height: u32,
    arg_directory: String,
}

#[derive(Debug)]
struct ImageFrame {
    top_left: Point<f64>,
    bottom_right: Point<f64>,
    width: u32,
    height: u32,
}

impl ImageFrame {
    pub fn from(args: &CommandArgs) -> ImageFrame {
        // h == w * (top - bottom) / (right - left)
        let height = (args.arg_width as f64) *
            ((args.arg_top_lat - args.arg_bottom_lat) /
             (args.arg_right_lng - args.arg_left_lng));

        println!("Computed height: {:?}", height);

        ImageFrame {
            top_left: Point::new(args.arg_left_lng, args.arg_top_lat),
            bottom_right: Point::new(args.arg_right_lng, args.arg_bottom_lat),
            width: args.arg_width,
            height: args.arg_height,
        }
    }

    pub fn get_image(&self) -> image::DynamicImage {
        let buf = ImageBuffer::from_pixel(self.width, self.height, image::Rgb([0, 0, 0]));

        image::ImageRgb8(buf)
    }

    // Using simple equirectangular projection for now
    pub fn project_to_screen(&self, coord: &Point<f64>) -> Option<(u32, u32)> {
        // lng is x pos
        let x_pos = self.top_left.lng() - coord.lng();
        let y_pos = self.top_left.lat() - coord.lat();

        let x_offset = x_pos / (self.top_left.lng() - self.bottom_right.lng());
        let y_offset = y_pos / (self.top_left.lat() - self.bottom_right.lat());

        let (x, y) = ((x_offset * self.width as f64),
                      (y_offset * self.height as f64));

        if (x < 0.0 || x as u32 >= self.width) ||
            (y < 0.0 || y as u32 >= self.height) {
            None
        } else {
            Some((x as u32, y as u32))
        }
    }
}

#[derive(Debug)]
struct Activity {
    name: String,
    date: chrono::DateTime<chrono::Utc>,
    track_points: Vec<Point<f64>>,
}

fn parse_gpx(path: &path::PathBuf) -> Option<Activity> {
    let file = File::open(path).unwrap();
    let reader = BufReader::new(file);

    let gpx: Gpx = read(reader).unwrap();

    // Nothing to do if there are no tracks
    if gpx.tracks.len() == 0 {
        return None;
    } else if gpx.tracks.len() > 1 {
        println!("Warning! more than 1 track, just taking first");
    }

    let track: &Track = &gpx.tracks[0];

    let mut activity = Activity {
        name: track.name.clone().unwrap_or(String::from("Untitled")),
        date: chrono::Utc::now(),
        track_points: vec![],
    };

    if let Some(metadata) = gpx.metadata {
        if let Some(time) = metadata.time {
            activity.date = time;
        }
    }

    // Append all the waypoints.
    for seg in track.segments.iter() {
        let points = seg.points.iter().map(|ref wpt| wpt.point());
        activity.track_points.extend(points);
    }

    if activity.track_points.len() == 0 {
        None
    } else {
        Some(activity)
    }
}

fn main() {
    let args: CommandArgs = Docopt::new(USAGE)
        .and_then(|d| d.deserialize())
        .unwrap_or_else(|e| e.exit());

    println!("{:?}", args);

    let frame = ImageFrame::from(&args);
    let mut image = frame.get_image();

    let paths: Vec<path::PathBuf> = fs::read_dir(args.arg_directory)
        .unwrap()
        .into_iter()
        .map(|p| p.unwrap().path())
        .collect();

    let activities: Vec<Activity> = paths
        .into_par_iter()
        .filter_map(|ref p| parse_gpx(p))
        .collect();

    let fout = &mut File::create("heatmap.ppm").unwrap();

    for act in activities {
        println!("Activity: {:?}", act.name);

        let pixels: Vec<(u32, u32)> = act.track_points
            .par_iter()
            .filter_map(|ref pt| frame.project_to_screen(pt))
            .collect();

        for (x, y) in pixels.into_iter() {
            let pixel = image.as_mut_rgb8().unwrap().get_pixel_mut(x, y);

            let c = if pixel[0] == 255 {
                pixel[0]
            } else if pixel[0] == 0 {
                25
            } else {
                pixel[0] + 5
            };

            *pixel = image::Rgb([c, c, c]);
        }

        image.save(fout, image::PPM).unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate libracerd;
extern crate json_request;
extern crate rustc_serialize;
mod util;

mod http {
    use util::http::{self, UrlBuilder};

    use rustc_serialize::json::{Json};
    use json_request::{request_str, Method};

    #[test]
    fn find_definition() {
        http::with_server(|server| {
            // Build request args
            let url = server.url("/find_definition");
            let request_obj = stringify!({
                "buffers": [{
                    "file_path": "src.rs",
                    "contents": "fn foo() {}\nfn bar() {}\nfn main() {\nfoo();\n}"
                }],
                "file_path": "src.rs",
                "line": 4,
                "column": 3
            });

            // Make request
            let res = request_str(Method::Post, &url[..], Some(request_obj)).unwrap().unwrap();

            // Build actual/expected objects
            let actual = Json::from_str(&res[..]).unwrap();
            let expected = Json::from_str(stringify!({
                "text": "foo",
                "line": 1,
                "column": 3,
                "file_path": "src.rs"
            })).unwrap();

            // They should be equal
            assert_eq!(actual, expected);
        });
    }

    #[test]
    fn ping_pong() {
        http::with_server(|server| {
            let url = server.url("/ping");
            let res = request_str(Method::Get, &url[..], None).unwrap().unwrap();
            let actual = Json::from_str(&res[..]).unwrap();

            let expected = Json::from_str(stringify!({
                "pong": true
            })).unwrap();

            assert_eq!(actual, expected);
        });
    }
}
<commit_msg>Add /find_definition test for multiple dirty files<commit_after>extern crate libracerd;
extern crate json_request;
extern crate rustc_serialize;
mod util;

mod http {
    use util::http::{self, UrlBuilder};

    use rustc_serialize::json::{Json};
    use json_request::{request_str, Method};
    use libracerd::util::fs::TmpFile;

    /// Checks that /find_definition works within a single buffer
    #[test]
    fn find_definition() {
        http::with_server(|server| {
            // Build request args
            let url = server.url("/find_definition");
            let request_obj = stringify!({
                "buffers": [{
                    "file_path": "src.rs",
                    "contents": "fn foo() {}\nfn bar() {}\nfn main() {\nfoo();\n}"
                }],
                "file_path": "src.rs",
                "line": 4,
                "column": 3
            });

            // Make request
            let res = request_str(Method::Post, &url[..], Some(request_obj)).unwrap().unwrap();

            // Build actual/expected objects
            let actual = Json::from_str(&res[..]).unwrap();
            let expected = Json::from_str(stringify!({
                "text": "foo",
                "line": 1,
                "column": 3,
                "file_path": "src.rs"
            })).unwrap();

            // They should be equal
            assert_eq!(actual, expected);
        });
    }

    /// Checks that /find_definition correctly resolves cross file definitions when the buffers have
    /// not been written to disk.
    #[test]
    fn find_definition_multiple_dirty_buffers() {

        http::with_server(|server| {
            // Build request args
            let url = server.url("/find_definition");
            let request_obj = stringify!({
                "buffers": [{
                    "file_path": "src.rs",
                    "contents": "mod src2;\nuse src2::{foo,myfn};\nfn main() {\n    myfn();\n}\n"
                }, {
                    "file_path": "src2.rs",
                    "contents": "\npub fn myfn()\npub fn foo() {}\n"
                }],
                "file_path": "src.rs",
                "line": 4,
                "column": 7
            });

            // Create an *empty* temporary file. The request contains unsaved file contents. For
            // rust module inclusions to work, the compiler checks certain locations on the file
            // system where a module file could be located. It simply doesn't work with unnamed
            // files.
            let _f = TmpFile::with_name("src2.rs", "");

            // Make request
            let res = request_str(Method::Post, &url[..], Some(request_obj)).unwrap().unwrap();

            // Build actual/expected objects
            let actual = Json::from_str(&res[..]).unwrap();
            let expected = Json::from_str(stringify!({
                "text": "myfn",
                "line": 2,
                "column": 7,
                "file_path": "src2.rs"
            })).unwrap();

            // They should be equal
            assert_eq!(actual, expected);
        });
    }

    #[test]
    fn ping_pong() {
        http::with_server(|server| {
            let url = server.url("/ping");
            let res = request_str(Method::Get, &url[..], None).unwrap().unwrap();
            let actual = Json::from_str(&res[..]).unwrap();

            let expected = Json::from_str(stringify!({
                "pong": true
            })).unwrap();

            assert_eq!(actual, expected);
        });
    }
}
<|endoftext|>


<commit_before>extern crate sorting;

use std::fmt::Debug;

/// Verify order of input vector as sorted by indices.
///
/// # Details
///
/// This function takes as arguments a vector of data and a vector representing the indices of the
/// first vector making it sorted.
///
/// The elements of the sorted vector are compared to the next ones to make sure they are less
/// or equal.
///
/// # Panics
///
/// The sorting of the data vector is enforced using `assert!()`.
///
/// # Examples
///
/// ```
/// let data: Vec<i32> = vec![4, 2, 3, 1];
/// let sorted_indices: Vec<usize> = vec![3, 1, 2, 0];
/// verify_sorting(&data, &sorted_indices);
/// ```
///
fn verify_sorting<T: Debug + PartialOrd>(array: &Vec<T>, sorted_indices: &Vec<usize>) {
    let n = array.len();
    assert_eq!(n , sorted_indices.len());

    if !array.is_empty() {
        for i in 0..n-1 {
            println!("array[sorted_indices[i={:?}]]={:?}   array[sorted_indices[i+1={:?}]]={:?}",
                i, array[sorted_indices[i]], i+1, array[sorted_indices[i+1]]);
            assert!(array[sorted_indices[i]] <= array[sorted_indices[i+1]]);
        }
    }
}

fn test_empty_vec<T: PartialOrd>(sorting_fct: fn(&Vec<T>) -> Vec<usize>) {
    let to_sort: Vec<T> = vec![];
    let sorted_indices = sorting_fct(&to_sort);
    assert_eq!(sorted_indices, vec![]);
}

/// Validate against empty vector (i8).
#[test]
fn simple_insertion_empty_vec_i8() {
    test_empty_vec::<i8>(sorting::simplesorts::insertion::sort);
}
/// Validate against empty vector (i32).
#[test]
fn simple_insertion_empty_vec_i16() {
    test_empty_vec::<i16>(sorting::simplesorts::insertion::sort);
}
/// Validate against empty vector (i32).
#[test]
fn simple_insertion_empty_vec_i32() {
    test_empty_vec::<i32>(sorting::simplesorts::insertion::sort);
}
/// Validate against empty vector (i64).
#[test]
fn simple_insertion_empty_vec_i64() {
    test_empty_vec::<i64>(sorting::simplesorts::insertion::sort);
}

/// Validate against empty vector (u8).
#[test]
fn simple_insertion_empty_vec_u8() {
    test_empty_vec::<u8>(sorting::simplesorts::insertion::sort);
}
/// Validate against empty vector (u32).
#[test]
fn simple_insertion_empty_vec_u16() {
    test_empty_vec::<u16>(sorting::simplesorts::insertion::sort);
}
/// Validate against empty vector (u32).
#[test]
fn simple_insertion_empty_vec_u32() {
    test_empty_vec::<u32>(sorting::simplesorts::insertion::sort);
}
/// Validate against empty vector (u64).
#[test]
fn simple_insertion_empty_vec_u64() {
    test_empty_vec::<u64>(sorting::simplesorts::insertion::sort);
}

/// Validate a vector of double precision values.
#[test]
fn simple_insertion_vec_f64() {
    let to_sort: Vec<f64> = vec![6.0,   5.0,  3.0,  1.0,  2.4, 4.0, 10.0, 7.0,
                                 3.42, 32.2, 44.2, 56.3, 67.9, 3.2, 44.2, 2.0];

    let sorted_indices = sorting::simplesorts::insertion::sort(&to_sort);

    verify_sorting(&to_sort, &sorted_indices);

    assert_eq!(sorted_indices, vec![3, 15, 4, 2, 13, 8, 5, 1, 0, 7, 6, 9, 10, 14, 11, 12]);
}
<commit_msg>Assert is empty.<commit_after>extern crate sorting;

use std::fmt::Debug;

/// Verify order of input vector as sorted by indices.
///
/// # Details
///
/// This function takes as arguments a vector of data and a vector representing the indices of the
/// first vector making it sorted.
///
/// The elements of the sorted vector are compared to the next ones to make sure they are less
/// or equal.
///
/// # Panics
///
/// The sorting of the data vector is enforced using `assert!()`.
///
/// # Examples
///
/// ```
/// let data: Vec<i32> = vec![4, 2, 3, 1];
/// let sorted_indices: Vec<usize> = vec![3, 1, 2, 0];
/// verify_sorting(&data, &sorted_indices);
/// ```
///
fn verify_sorting<T: Debug + PartialOrd>(array: &Vec<T>, sorted_indices: &Vec<usize>) {
    let n = array.len();
    assert_eq!(n , sorted_indices.len());

    if !array.is_empty() {
        for i in 0..n-1 {
            println!("array[sorted_indices[i={:?}]]={:?}   array[sorted_indices[i+1={:?}]]={:?}",
                i, array[sorted_indices[i]], i+1, array[sorted_indices[i+1]]);
            assert!(array[sorted_indices[i]] <= array[sorted_indices[i+1]]);
        }
    }
}

fn test_empty_vec<T: PartialOrd>(sorting_fct: fn(&Vec<T>) -> Vec<usize>) {
    let to_sort: Vec<T> = vec![];
    let sorted_indices = sorting_fct(&to_sort);
    assert_eq!(sorted_indices, vec![]);
    assert!(sorted_indices.is_empty());
}

/// Validate against empty vector (i8).
#[test]
fn simple_insertion_empty_vec_i8() {
    test_empty_vec::<i8>(sorting::simplesorts::insertion::sort);
}
/// Validate against empty vector (i32).
#[test]
fn simple_insertion_empty_vec_i16() {
    test_empty_vec::<i16>(sorting::simplesorts::insertion::sort);
}
/// Validate against empty vector (i32).
#[test]
fn simple_insertion_empty_vec_i32() {
    test_empty_vec::<i32>(sorting::simplesorts::insertion::sort);
}
/// Validate against empty vector (i64).
#[test]
fn simple_insertion_empty_vec_i64() {
    test_empty_vec::<i64>(sorting::simplesorts::insertion::sort);
}

/// Validate against empty vector (u8).
#[test]
fn simple_insertion_empty_vec_u8() {
    test_empty_vec::<u8>(sorting::simplesorts::insertion::sort);
}
/// Validate against empty vector (u32).
#[test]
fn simple_insertion_empty_vec_u16() {
    test_empty_vec::<u16>(sorting::simplesorts::insertion::sort);
}
/// Validate against empty vector (u32).
#[test]
fn simple_insertion_empty_vec_u32() {
    test_empty_vec::<u32>(sorting::simplesorts::insertion::sort);
}
/// Validate against empty vector (u64).
#[test]
fn simple_insertion_empty_vec_u64() {
    test_empty_vec::<u64>(sorting::simplesorts::insertion::sort);
}

/// Validate a vector of double precision values.
#[test]
fn simple_insertion_vec_f64() {
    let to_sort: Vec<f64> = vec![6.0,   5.0,  3.0,  1.0,  2.4, 4.0, 10.0, 7.0,
                                 3.42, 32.2, 44.2, 56.3, 67.9, 3.2, 44.2, 2.0];

    let sorted_indices = sorting::simplesorts::insertion::sort(&to_sort);

    verify_sorting(&to_sort, &sorted_indices);

    assert_eq!(sorted_indices, vec![3, 15, 4, 2, 13, 8, 5, 1, 0, 7, 6, 9, 10, 14, 11, 12]);
}
<|endoftext|>


<commit_before>extern crate time;
extern crate stopwatch;

use stopwatch::{Stopwatch};
use std::num::SignedInt;
use std::old_io::timer;
use std::time::Duration;

static SLEEP_MS: i64 = 50;
static TOLERANCE_PERCENTAGE: f64 = 0.3;

#[test]
fn repeated_stops() {
	let mut sw = Stopwatch::start_new();
	for _ in (0..1000i32) {
		sw.stop();
		sw.start();
	}
	assert_sw_near(sw, 0);
}

#[test]
fn elapsed_none() {
	let sw = Stopwatch::new();
	assert_eq!(sw.elapsed_ms(), 0);
}

#[test]
fn elapsed_ms() {
	let sw = Stopwatch::start_new();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	assert_sw_near(sw, SLEEP_MS);
}

#[test]
fn stop() {
	let mut sw = Stopwatch::start_new();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	sw.stop();
	assert_sw_near(sw, SLEEP_MS);

	timer::sleep(Duration::milliseconds(SLEEP_MS));
	assert_sw_near(sw, SLEEP_MS);
}

#[test]
fn resume_once() {
	let mut sw = Stopwatch::start_new();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	sw.stop();
	assert_sw_near(sw, SLEEP_MS);
	sw.start();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	assert_sw_near(sw, 2 * SLEEP_MS);
}

#[test]
fn resume_twice() {
	let mut sw = Stopwatch::start_new();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	sw.stop();
	assert_sw_near(sw, SLEEP_MS);
	sw.start();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	sw.stop();
	assert_sw_near(sw, 2 * SLEEP_MS);
	sw.start();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	assert_sw_near(sw, 3 * SLEEP_MS);
}

#[test]
fn is_running() {
	let mut sw = Stopwatch::new();
	assert!(!sw.is_running());
	sw.start();
	assert!(sw.is_running());
	sw.stop();
	assert!(!sw.is_running());
}

#[test]
fn restart() {
	let mut sw = Stopwatch::start_new();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	sw.restart();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	assert_sw_near(sw, SLEEP_MS);
}

#[test]
fn reset() {
	let mut sw = Stopwatch::start_new();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	sw.reset();
	assert!(!sw.is_running());
	assert_eq!(sw.elapsed_ms(), 0);
}

/////////////// helpers

fn assert_near(x: i64, y: i64, tolerance: i64) {
	let diff = (x - y).abs();
	if diff > tolerance {
		panic!("Expected {:?}, got {:?}", x, y);
	}
}

fn assert_sw_near(sw: Stopwatch, elapsed: i64) {
	let tolerance_value = (TOLERANCE_PERCENTAGE * elapsed as f64) as i64;
	assert_near(elapsed, sw.elapsed_ms(), tolerance_value);
}<commit_msg>Some whitespace.<commit_after>extern crate time;
extern crate stopwatch;

use stopwatch::{Stopwatch};
use std::num::SignedInt;
use std::old_io::timer;
use std::time::Duration;

static SLEEP_MS: i64 = 50;
static TOLERANCE_PERCENTAGE: f64 = 0.3;

#[test]
fn repeated_stops() {
	let mut sw = Stopwatch::start_new();
	for _ in (0..1000i32) {
		sw.stop();
		sw.start();
	}
	assert_sw_near(sw, 0);
}

#[test]
fn elapsed_none() {
	let sw = Stopwatch::new();
	assert_eq!(sw.elapsed_ms(), 0);
}

#[test]
fn elapsed_ms() {
	let sw = Stopwatch::start_new();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	assert_sw_near(sw, SLEEP_MS);
}

#[test]
fn stop() {
	let mut sw = Stopwatch::start_new();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	sw.stop();
	assert_sw_near(sw, SLEEP_MS);

	timer::sleep(Duration::milliseconds(SLEEP_MS));
	assert_sw_near(sw, SLEEP_MS);
}

#[test]
fn resume_once() {
	let mut sw = Stopwatch::start_new();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	sw.stop();
	assert_sw_near(sw, SLEEP_MS);
	sw.start();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	assert_sw_near(sw, 2 * SLEEP_MS);
}

#[test]
fn resume_twice() {
	let mut sw = Stopwatch::start_new();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	sw.stop();
	assert_sw_near(sw, SLEEP_MS);
	sw.start();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	sw.stop();
	assert_sw_near(sw, 2 * SLEEP_MS);
	sw.start();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	assert_sw_near(sw, 3 * SLEEP_MS);
}

#[test]
fn is_running() {
	let mut sw = Stopwatch::new();
	assert!(!sw.is_running());
	sw.start();
	assert!(sw.is_running());
	sw.stop();
	assert!(!sw.is_running());
}

#[test]
fn restart() {
	let mut sw = Stopwatch::start_new();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	sw.restart();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	assert_sw_near(sw, SLEEP_MS);
}

#[test]
fn reset() {
	let mut sw = Stopwatch::start_new();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	sw.reset();
	assert!(!sw.is_running());
	assert_eq!(sw.elapsed_ms(), 0);
}

/////////////// helpers

fn assert_near(x: i64, y: i64, tolerance: i64) {
	let diff = (x - y).abs();
	if diff > tolerance {
		panic!("Expected {:?}, got {:?}", x, y);
	}
}

fn assert_sw_near(sw: Stopwatch, elapsed: i64) {
	let tolerance_value = (TOLERANCE_PERCENTAGE * elapsed as f64) as i64;
	assert_near(elapsed, sw.elapsed_ms(), tolerance_value);
}<|endoftext|>


<commit_before>extern crate glib;

use glib::*;

use std::sync::{Arc, Mutex};

#[derive(Default)]
struct Counters {
    criticals: usize,
    warnings: usize,
    messages: usize,
    infos: usize,
    debugs: usize,
}

fn assert_counts(
    count: &Arc<Mutex<Counters>>,
    criticals: usize,
    warnings: usize,
    messages: usize,
    infos: usize,
    debugs: usize,
) {
    let count = count.lock().expect("failed to lock 1");
    assert_eq!(count.criticals, criticals);
    assert_eq!(count.warnings, warnings);
    assert_eq!(count.messages, messages);
    assert_eq!(count.infos, infos);
    assert_eq!(count.debugs, debugs);
}

#[test]
fn check_log_handlers() {
    //
    // log_set_default_handler check part
    //
    let count = Arc::new(Mutex::new(Counters::default()));
    log_set_default_handler(clone!(@weak count => move |_, level, _| {
        match level {
            LogLevel::Critical => { (*count.lock().expect("failed to lock 3")).criticals += 1; }
            LogLevel::Warning => { (*count.lock().expect("failed to lock 4")).warnings += 1; }
            LogLevel::Message => { (*count.lock().expect("failed to lock 5")).messages += 1; }
            LogLevel::Info => { (*count.lock().expect("failed to lock 6")).infos += 1; }
            LogLevel::Debug => { (*count.lock().expect("failed to lock 7")).debugs += 1; }
            _ => unreachable!(),
        }
    }));
    assert_counts(&count, 0, 0, 0, 0, 0);
    g_warning!("domain", "hello");
    assert_counts(&count, 0, 1, 0, 0, 0);
    g_warning!("domain", "hello");
    g_critical!("domain", "hello");
    g_warning!("domain", "hello");
    g_message!("domain", "hello");
    g_info!("domain", "hello");
    g_debug!("domain", "hello");
    g_info!("domain", "hello");
    assert_counts(&count, 1, 3, 1, 2, 1);

    // We now unset our callback and check if it has really been unset.
    log_unset_default_handler();
    g_info!("domain", "hello");
    g_debug!("domain", "hello");
    assert_counts(&count, 1, 3, 1, 2, 1);

    //
    // log_set_handler check part
    //
    #[cfg(feature = "v2_46")]
    {
        let count = Arc::new(Mutex::new(Counters::default()));
        // We set the handler for both warning and debug.
        let handler_id = log_set_handler(
            "domain",
            LogLevels::LEVEL_WARNING | LogLevels::LEVEL_DEBUG,
            false,
            false,
            clone!(@weak count => move |_, level, _| {
                match level {
                    LogLevel::Critical => { (*count.lock().expect("failed to lock 3")).criticals += 1; }
                    LogLevel::Warning => { (*count.lock().expect("failed to lock 4")).warnings += 1; }
                    LogLevel::Message => { (*count.lock().expect("failed to lock 5")).messages += 1; }
                    LogLevel::Info => { (*count.lock().expect("failed to lock 6")).infos += 1; }
                    LogLevel::Debug => { (*count.lock().expect("failed to lock 7")).debugs += 1; }
                    _ => unreachable!(),
                }
            }));
        assert_counts(&count, 0, 0, 0, 0, 0);
        g_warning!("domain", "hello");
        assert_counts(&count, 0, 1, 0, 0, 0);
        g_critical!("domain", "hello");
        g_message!("domain", "hello");
        g_info!("domain", "hello");
        assert_counts(&count, 0, 1, 0, 0, 0);
        g_debug!("domain", "hello");
        assert_counts(&count, 0, 1, 0, 0, 1);
        log_remove_handler("domain", handler_id);
        g_critical!("domain", "hello");
        g_message!("domain", "hello");
        g_info!("domain", "hello");
        g_debug!("domain", "hello");
        g_warning!("domain", "hello");
        assert_counts(&count, 0, 1, 0, 0, 1);
    }
}
<commit_msg>Extend log tests<commit_after>extern crate glib;

use glib::*;

use std::sync::{Arc, Mutex};

#[derive(Default)]
struct Counters {
    criticals: usize,
    warnings: usize,
    messages: usize,
    infos: usize,
    debugs: usize,
}

fn assert_counts(
    count: &Arc<Mutex<Counters>>,
    criticals: usize,
    warnings: usize,
    messages: usize,
    infos: usize,
    debugs: usize,
) {
    let count = count.lock().expect("failed to lock 1");
    assert_eq!(count.criticals, criticals);
    assert_eq!(count.warnings, warnings);
    assert_eq!(count.messages, messages);
    assert_eq!(count.infos, infos);
    assert_eq!(count.debugs, debugs);
}

#[test]
fn check_log_handlers() {
    // We set the fatal level explicitly in case it's set outside of the test.
    log_set_fatal_mask("domain", LogLevels::LEVEL_ERROR);

    //
    // log_set_default_handler check part
    //
    let count = Arc::new(Mutex::new(Counters::default()));
    log_set_default_handler(clone!(@weak count => move |_, level, _| {
        match level {
            LogLevel::Critical => { (*count.lock().expect("failed to lock 3")).criticals += 1; }
            LogLevel::Warning => { (*count.lock().expect("failed to lock 4")).warnings += 1; }
            LogLevel::Message => { (*count.lock().expect("failed to lock 5")).messages += 1; }
            LogLevel::Info => { (*count.lock().expect("failed to lock 6")).infos += 1; }
            LogLevel::Debug => { (*count.lock().expect("failed to lock 7")).debugs += 1; }
            _ => unreachable!(),
        }
    }));
    assert_counts(&count, 0, 0, 0, 0, 0);
    g_warning!("domain", "hello");
    assert_counts(&count, 0, 1, 0, 0, 0);
    g_warning!("domain", "hello");
    g_critical!("domain", "hello");
    g_warning!("domain", "hello");
    g_message!("domain", "hello");
    g_info!("domain", "hello");
    g_debug!("domain", "hello");
    g_info!("domain", "hello");
    assert_counts(&count, 1, 3, 1, 2, 1);

    // We now unset our callback and check if it has really been unset.
    log_unset_default_handler();
    g_info!("domain", "hello");
    g_debug!("domain", "hello");
    assert_counts(&count, 1, 3, 1, 2, 1);

    //
    // log_set_handler check part
    //
    #[cfg(feature = "v2_46")]
    {
        let count = Arc::new(Mutex::new(Counters::default()));
        // We set the handler for both warning and debug.
        let handler_id = log_set_handler(
            "domain",
            LogLevels::LEVEL_WARNING | LogLevels::LEVEL_DEBUG,
            false,
            false,
            clone!(@weak count => move |_, level, _| {
                match level {
                    LogLevel::Critical => { (*count.lock().expect("failed to lock 3")).criticals += 1; }
                    LogLevel::Warning => { (*count.lock().expect("failed to lock 4")).warnings += 1; }
                    LogLevel::Message => { (*count.lock().expect("failed to lock 5")).messages += 1; }
                    LogLevel::Info => { (*count.lock().expect("failed to lock 6")).infos += 1; }
                    LogLevel::Debug => { (*count.lock().expect("failed to lock 7")).debugs += 1; }
                    _ => unreachable!(),
                }
            }));
        assert_counts(&count, 0, 0, 0, 0, 0);
        g_warning!("domain", "hello");
        assert_counts(&count, 0, 1, 0, 0, 0);
        g_critical!("domain", "hello");
        g_message!("domain", "hello");
        g_info!("domain", "hello");
        assert_counts(&count, 0, 1, 0, 0, 0);
        g_debug!("domain", "hello");
        assert_counts(&count, 0, 1, 0, 0, 1);
        // We check that only "domain" messages are calling our callback.
        g_debug!("not-domain", "hello");
        g_warning!("not-domain", "hello");
        assert_counts(&count, 0, 1, 0, 0, 1);

        log_remove_handler("domain", handler_id);
        g_critical!("domain", "hello");
        g_message!("domain", "hello");
        g_info!("domain", "hello");
        g_debug!("domain", "hello");
        g_warning!("domain", "hello");
        assert_counts(&count, 0, 1, 0, 0, 1);
    }
}
<|endoftext|>