<commit_before>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast;
use crate::utils::{differing_macro_contexts, in_macro, snippet_opt, span_note_and_lint};
use crate::syntax::ptr::P;

/// **What it does:** Checks for use of the non-existent `=*`, `=!` and `=-`
/// operators.
///
/// **Why is this bad?** This is either a typo of `*=`, `!=` or `-=` or
/// confusing.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust,ignore
/// a =- 42; // confusing, should it be `a -= 42` or `a = -42`?
/// ```
declare_clippy_lint! {
    pub SUSPICIOUS_ASSIGNMENT_FORMATTING,
    style,
    "suspicious formatting of `*=`, `-=` or `!=`"
}

/// **What it does:** Checks for formatting of `else if`. It lints if the `else`
/// and `if` are not on the same line or the `else` seems to be missing.
///
/// **Why is this bad?** This is probably some refactoring remnant, even if the
/// code is correct, it might look confusing.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust,ignore
/// if foo {
/// } if bar { // looks like an `else` is missing here
/// }
///
/// if foo {
/// } else
///
/// if bar { // this is the `else` block of the previous `if`, but should it be?
/// }
/// ```
declare_clippy_lint! {
    pub SUSPICIOUS_ELSE_FORMATTING,
    style,
    "suspicious formatting of `else if`"
}

/// **What it does:** Checks for possible missing comma in an array. It lints if
/// an array element is a binary operator expression and it lies on two lines.
///
/// **Why is this bad?** This could lead to unexpected results.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust,ignore
/// let a = &[
///     -1, -2, -3 // <= no comma here
///     -4, -5, -6
/// ];
/// ```
declare_clippy_lint! {
    pub POSSIBLE_MISSING_COMMA,
    correctness,
    "possible missing comma in array"
}

#[derive(Copy, Clone)]
pub struct Formatting;

impl LintPass for Formatting {
    fn get_lints(&self) -> LintArray {
        lint_array!(
            SUSPICIOUS_ASSIGNMENT_FORMATTING,
            SUSPICIOUS_ELSE_FORMATTING,
            POSSIBLE_MISSING_COMMA
        )
    }
}

impl EarlyLintPass for Formatting {
    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
        for w in block.stmts.windows(2) {
            match (&w[0].node, &w[1].node) {
                (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Expr(ref second)) |
                (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Semi(ref second)) => {
                    check_consecutive_ifs(cx, first, second);
                },
                _ => (),
            }
        }
    }

    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
        check_assign(cx, expr);
        check_else_if(cx, expr);
        check_array(cx, expr);
    }
}

/// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint.
fn check_assign(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let ast::ExprKind::Assign(ref lhs, ref rhs) = expr.node {
        if !differing_macro_contexts(lhs.span, rhs.span) && !in_macro(lhs.span) {
            let eq_span = lhs.span.between(rhs.span);
            if let ast::ExprKind::Unary(op, ref sub_rhs) = rhs.node {
                if let Some(eq_snippet) = snippet_opt(cx, eq_span) {
                    let op = ast::UnOp::to_string(op);
                    let eqop_span = lhs.span.between(sub_rhs.span);
                    if eq_snippet.ends_with('=') {
                        span_note_and_lint(
                            cx,
                            SUSPICIOUS_ASSIGNMENT_FORMATTING,
                            eqop_span,
                            &format!(
                                "this looks like you are trying to use `.. {op}= ..`, but you \
                                 really are doing `.. = ({op} ..)`",
                                op = op
                            ),
                            eqop_span,
                            &format!("to remove this lint, use either `{op}=` or `= {op}`", op = op),
                        );
                    }
                }
            }
        }
    }
}

/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else if`.
fn check_else_if(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let Some((then, &Some(ref else_))) = unsugar_if(expr) {
        if unsugar_if(else_).is_some() && !differing_macro_contexts(then.span, else_.span) && !in_macro(then.span) {
            // this will be a span from the closing ‘}’ of the “then” block (excluding) to
            // the
            // “if” of the “else if” block (excluding)
            let else_span = then.span.between(else_.span);

            // the snippet should look like " else \n    " with maybe comments anywhere
            // it’s bad when there is a ‘\n’ after the “else”
            if let Some(else_snippet) = snippet_opt(cx, else_span) {
                let else_pos = else_snippet
                    .find("else")
                    .expect("there must be a `else` here");

                if else_snippet[else_pos..].contains('\n') {
                    span_note_and_lint(
                        cx,
                        SUSPICIOUS_ELSE_FORMATTING,
                        else_span,
                        "this is an `else if` but the formatting might hide it",
                        else_span,
                        "to remove this lint, remove the `else` or remove the new line between `else` \
                         and `if`",
                    );
                }
            }
        }
    }
}

fn has_unary_equivalent(bin_op: ast::BinOpKind) -> bool {
    //+, &, *, -
    bin_op == ast::BinOpKind::Add
    || bin_op == ast::BinOpKind::And
    || bin_op == ast::BinOpKind::Mul
    || bin_op == ast::BinOpKind::Sub
}

/// Implementation of the `POSSIBLE_MISSING_COMMA` lint for array
fn check_array(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let ast::ExprKind::Array(ref array) = expr.node {
        for element in array {
            if let ast::ExprKind::Binary(ref op, ref lhs, _) = element.node {
                if has_unary_equivalent(op.node) && !differing_macro_contexts(lhs.span, op.span) {
                    let space_span = lhs.span.between(op.span);
                    if let Some(space_snippet) = snippet_opt(cx, space_span) {
                        let lint_span = lhs.span.with_lo(lhs.span.hi());
                        if space_snippet.contains('\n') {
                            span_note_and_lint(
                                cx,
                                POSSIBLE_MISSING_COMMA,
                                lint_span,
                                "possibly missing a comma here",
                                lint_span,
                                "to remove this lint, add a comma or write the expr in a single line",
                            );
                        }
                    }
                }
            }
        }
    }
}

/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for consecutive ifs.
fn check_consecutive_ifs(cx: &EarlyContext<'_>, first: &ast::Expr, second: &ast::Expr) {
    if !differing_macro_contexts(first.span, second.span) && !in_macro(first.span) && unsugar_if(first).is_some()
        && unsugar_if(second).is_some()
    {
        // where the else would be
        let else_span = first.span.between(second.span);

        if let Some(else_snippet) = snippet_opt(cx, else_span) {
            if !else_snippet.contains('\n') {
                span_note_and_lint(
                    cx,
                    SUSPICIOUS_ELSE_FORMATTING,
                    else_span,
                    "this looks like an `else if` but the `else` is missing",
                    else_span,
                    "to remove this lint, add the missing `else` or add a new line before the second \
                     `if`",
                );
            }
        }
    }
}

/// Match `if` or `if let` expressions and return the `then` and `else` block.
fn unsugar_if(expr: &ast::Expr) -> Option<(&P<ast::Block>, &Option<P<ast::Expr>>)> {
    match expr.node {
        ast::ExprKind::If(_, ref then, ref else_) | ast::ExprKind::IfLet(_, _, ref then, ref else_) => {
            Some((then, else_))
        },
        _ => None,
    }
}
<commit_msg>Remove `+` from `has_unary_equivalent`<commit_after>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast;
use crate::utils::{differing_macro_contexts, in_macro, snippet_opt, span_note_and_lint};
use crate::syntax::ptr::P;

/// **What it does:** Checks for use of the non-existent `=*`, `=!` and `=-`
/// operators.
///
/// **Why is this bad?** This is either a typo of `*=`, `!=` or `-=` or
/// confusing.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust,ignore
/// a =- 42; // confusing, should it be `a -= 42` or `a = -42`?
/// ```
declare_clippy_lint! {
    pub SUSPICIOUS_ASSIGNMENT_FORMATTING,
    style,
    "suspicious formatting of `*=`, `-=` or `!=`"
}

/// **What it does:** Checks for formatting of `else if`. It lints if the `else`
/// and `if` are not on the same line or the `else` seems to be missing.
///
/// **Why is this bad?** This is probably some refactoring remnant, even if the
/// code is correct, it might look confusing.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust,ignore
/// if foo {
/// } if bar { // looks like an `else` is missing here
/// }
///
/// if foo {
/// } else
///
/// if bar { // this is the `else` block of the previous `if`, but should it be?
/// }
/// ```
declare_clippy_lint! {
    pub SUSPICIOUS_ELSE_FORMATTING,
    style,
    "suspicious formatting of `else if`"
}

/// **What it does:** Checks for possible missing comma in an array. It lints if
/// an array element is a binary operator expression and it lies on two lines.
///
/// **Why is this bad?** This could lead to unexpected results.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust,ignore
/// let a = &[
///     -1, -2, -3 // <= no comma here
///     -4, -5, -6
/// ];
/// ```
declare_clippy_lint! {
    pub POSSIBLE_MISSING_COMMA,
    correctness,
    "possible missing comma in array"
}

#[derive(Copy, Clone)]
pub struct Formatting;

impl LintPass for Formatting {
    fn get_lints(&self) -> LintArray {
        lint_array!(
            SUSPICIOUS_ASSIGNMENT_FORMATTING,
            SUSPICIOUS_ELSE_FORMATTING,
            POSSIBLE_MISSING_COMMA
        )
    }
}

impl EarlyLintPass for Formatting {
    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
        for w in block.stmts.windows(2) {
            match (&w[0].node, &w[1].node) {
                (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Expr(ref second)) |
                (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Semi(ref second)) => {
                    check_consecutive_ifs(cx, first, second);
                },
                _ => (),
            }
        }
    }

    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
        check_assign(cx, expr);
        check_else_if(cx, expr);
        check_array(cx, expr);
    }
}

/// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint.
fn check_assign(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let ast::ExprKind::Assign(ref lhs, ref rhs) = expr.node {
        if !differing_macro_contexts(lhs.span, rhs.span) && !in_macro(lhs.span) {
            let eq_span = lhs.span.between(rhs.span);
            if let ast::ExprKind::Unary(op, ref sub_rhs) = rhs.node {
                if let Some(eq_snippet) = snippet_opt(cx, eq_span) {
                    let op = ast::UnOp::to_string(op);
                    let eqop_span = lhs.span.between(sub_rhs.span);
                    if eq_snippet.ends_with('=') {
                        span_note_and_lint(
                            cx,
                            SUSPICIOUS_ASSIGNMENT_FORMATTING,
                            eqop_span,
                            &format!(
                                "this looks like you are trying to use `.. {op}= ..`, but you \
                                 really are doing `.. = ({op} ..)`",
                                op = op
                            ),
                            eqop_span,
                            &format!("to remove this lint, use either `{op}=` or `= {op}`", op = op),
                        );
                    }
                }
            }
        }
    }
}

/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else if`.
fn check_else_if(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let Some((then, &Some(ref else_))) = unsugar_if(expr) {
        if unsugar_if(else_).is_some() && !differing_macro_contexts(then.span, else_.span) && !in_macro(then.span) {
            // this will be a span from the closing ‘}’ of the “then” block (excluding) to
            // the
            // “if” of the “else if” block (excluding)
            let else_span = then.span.between(else_.span);

            // the snippet should look like " else \n    " with maybe comments anywhere
            // it’s bad when there is a ‘\n’ after the “else”
            if let Some(else_snippet) = snippet_opt(cx, else_span) {
                let else_pos = else_snippet
                    .find("else")
                    .expect("there must be a `else` here");

                if else_snippet[else_pos..].contains('\n') {
                    span_note_and_lint(
                        cx,
                        SUSPICIOUS_ELSE_FORMATTING,
                        else_span,
                        "this is an `else if` but the formatting might hide it",
                        else_span,
                        "to remove this lint, remove the `else` or remove the new line between `else` \
                         and `if`",
                    );
                }
            }
        }
    }
}

fn has_unary_equivalent(bin_op: ast::BinOpKind) -> bool {
    // &, *, -
    bin_op == ast::BinOpKind::And
    || bin_op == ast::BinOpKind::Mul
    || bin_op == ast::BinOpKind::Sub
}

/// Implementation of the `POSSIBLE_MISSING_COMMA` lint for array
fn check_array(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let ast::ExprKind::Array(ref array) = expr.node {
        for element in array {
            if let ast::ExprKind::Binary(ref op, ref lhs, _) = element.node {
                if has_unary_equivalent(op.node) && !differing_macro_contexts(lhs.span, op.span) {
                    let space_span = lhs.span.between(op.span);
                    if let Some(space_snippet) = snippet_opt(cx, space_span) {
                        let lint_span = lhs.span.with_lo(lhs.span.hi());
                        if space_snippet.contains('\n') {
                            span_note_and_lint(
                                cx,
                                POSSIBLE_MISSING_COMMA,
                                lint_span,
                                "possibly missing a comma here",
                                lint_span,
                                "to remove this lint, add a comma or write the expr in a single line",
                            );
                        }
                    }
                }
            }
        }
    }
}

/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for consecutive ifs.
fn check_consecutive_ifs(cx: &EarlyContext<'_>, first: &ast::Expr, second: &ast::Expr) {
    if !differing_macro_contexts(first.span, second.span) && !in_macro(first.span) && unsugar_if(first).is_some()
        && unsugar_if(second).is_some()
    {
        // where the else would be
        let else_span = first.span.between(second.span);

        if let Some(else_snippet) = snippet_opt(cx, else_span) {
            if !else_snippet.contains('\n') {
                span_note_and_lint(
                    cx,
                    SUSPICIOUS_ELSE_FORMATTING,
                    else_span,
                    "this looks like an `else if` but the `else` is missing",
                    else_span,
                    "to remove this lint, add the missing `else` or add a new line before the second \
                     `if`",
                );
            }
        }
    }
}

/// Match `if` or `if let` expressions and return the `then` and `else` block.
fn unsugar_if(expr: &ast::Expr) -> Option<(&P<ast::Block>, &Option<P<ast::Expr>>)> {
    match expr.node {
        ast::ExprKind::If(_, ref then, ref else_) | ast::ExprKind::IfLet(_, _, ref then, ref else_) => {
            Some((then, else_))
        },
        _ => None,
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 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.

// Based on threadring.erlang by Jira Isa

use std::os;

fn start(n_tasks: int, token: int) {
    let (tx, mut rx) = channel();
    tx.send(token);
    //  FIXME could not get this to work with a range closure
    let mut i = 2;
    while i <= n_tasks {
        let (tx, next_rx) = channel();
        let imm_i = i;
        let imm_rx = rx;
        spawn(proc() {
            roundtrip(imm_i, n_tasks, &imm_rx, &tx);
        });
        rx = next_rx;
        i += 1;
    }
    let imm_rx = rx;
    spawn(proc() {
        roundtrip(1, n_tasks, &imm_rx, &tx);
    });
}

fn roundtrip(id: int, n_tasks: int, p: &Receiver<int>, ch: &Sender<int>) {
    loop {
        match p.recv() {
          1 => {
            println!("{}\n", id);
            return;
          }
          token => {
            println!("thread: {}   got token: {}", id, token);
            ch.send(token - 1);
            if token <= n_tasks {
                return;
            }
          }
        }
    }
}

fn main() {
    use std::from_str::FromStr;

    let args = if os::getenv("RUST_BENCH").is_some() {
        vec!("".to_owned(), "2000000".to_owned(), "503".to_owned())
    } else {
        os::args().move_iter().collect()
    };
    let token = if args.len() > 1u {
        FromStr::from_str(*args.get(1)).unwrap()
    }
    else {
        1000
    };
    let n_tasks = if args.len() > 2u {
        FromStr::from_str(*args.get(2)).unwrap()
    }
    else {
        503
    };
    start(n_tasks, token);

}
<commit_msg>shootout-threadring rewrite<commit_after>// Copyright 2012-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.

#![feature(phase)]
#[phase(syntax)] extern crate green;
green_start!(main)

fn start(n_tasks: int, token: int) {
    let (tx, mut rx) = channel();
    tx.send(token);
    for i in range(2, n_tasks + 1) {
        let (tx, next_rx) = channel();
        spawn(proc() roundtrip(i, tx, rx));
        rx = next_rx;
    }
    spawn(proc() roundtrip(1, tx, rx));
}

fn roundtrip(id: int, tx: Sender<int>, rx: Receiver<int>) {
    for token in rx.iter() {
        if token == 1 {
            println!("{}", id);
            break;
        }
        tx.send(token - 1);
    }
}

fn main() {
    let args = std::os::args();
    let token = if std::os::getenv("RUST_BENCH").is_some() {
        2000000
    } else {
        args.get(1).and_then(|arg| from_str(*arg)).unwrap_or(1000)
    };
    let n_tasks = args.get(2).and_then(|arg| from_str(*arg)).unwrap_or(503);

    start(n_tasks, token);
}
<|endoftext|>


<commit_before>// https://github.com/colin-kiegel/rust-derive-builder/issues/15
#[macro_use]
extern crate derive_builder;

#[derive(Debug, PartialEq, Default, Builder, Clone)]
#[builder(setter(skip="false"))]
struct SetterOptOut {
    setter_present_by_explicit_default: u32,
    #[builder(setter(skip="true"))]
    setter_skipped_by_explicit_opt_out: u32,
    #[builder(setter(skip))]
    setter_skipped_by_shorthand_opt_out: u32,
}

#[derive(Debug, PartialEq, Default, Builder, Clone)]
#[builder(setter(skip))]
struct SetterOptIn {
    setter_skipped_by_shorthand_default: u32,
    #[builder(setter(skip="false"))]
    setter_present_by_explicit_opt_in: u32,
    #[builder(setter)]
    setter_present_by_shorthand_opt_in: u32,
}

// compile test
#[allow(dead_code)]
impl SetterOptOut {
    // only possible if setter was skipped
    fn setter_skipped_by_explicit_opt_out() {}
    // only possible if setter was skipped
    fn setter_skipped_by_shorthand_opt_out() {}
}

// compile test
#[allow(dead_code)]
impl SetterOptIn {
    // only possible if setter was skipped
    fn setter_skipped_by_shorthand_default() {}
}

#[test]
fn setter_opt_out() {
    let x: SetterOptOut = SetterOptOutBuilder::default()
        .setter_present_by_explicit_default(42u32)
        .build()
        .unwrap();

    assert_eq!(x,
        SetterOptOut {
            setter_present_by_explicit_default: 42,
            setter_skipped_by_explicit_opt_out: 0,
            setter_skipped_by_shorthand_opt_out: 0,
        });
}

#[test]
fn setter_opt_in() {
    let x: SetterOptIn = SetterOptInBuilder::default()
        .setter_present_by_explicit_opt_in(47u32)
        .setter_present_by_shorthand_opt_in(11u32)
        .build()
        .unwrap();

    assert_eq!(x,
        SetterOptIn {
            setter_skipped_by_shorthand_default: 0,
            setter_present_by_explicit_opt_in: 47,
            setter_present_by_shorthand_opt_in: 11,
        });
}
<commit_msg>rustfmt<commit_after>// https://github.com/colin-kiegel/rust-derive-builder/issues/15
#[macro_use]
extern crate derive_builder;

#[derive(Debug, PartialEq, Default, Builder, Clone)]
#[builder(setter(skip="false"))]
struct SetterOptOut {
    setter_present_by_explicit_default: u32,
    #[builder(setter(skip="true"))]
    setter_skipped_by_explicit_opt_out: u32,
    #[builder(setter(skip))]
    setter_skipped_by_shorthand_opt_out: u32,
}

#[derive(Debug, PartialEq, Default, Builder, Clone)]
#[builder(setter(skip))]
struct SetterOptIn {
    setter_skipped_by_shorthand_default: u32,
    #[builder(setter(skip="false"))]
    setter_present_by_explicit_opt_in: u32,
    #[builder(setter)]
    setter_present_by_shorthand_opt_in: u32,
}

// compile test
#[allow(dead_code)]
impl SetterOptOut {
    // only possible if setter was skipped
    fn setter_skipped_by_explicit_opt_out() {}
    // only possible if setter was skipped
    fn setter_skipped_by_shorthand_opt_out() {}
}

// compile test
#[allow(dead_code)]
impl SetterOptIn {
    // only possible if setter was skipped
    fn setter_skipped_by_shorthand_default() {}
}

#[test]
fn setter_opt_out() {
    let x: SetterOptOut = SetterOptOutBuilder::default()
        .setter_present_by_explicit_default(42u32)
        .build()
        .unwrap();

    assert_eq!(x,
               SetterOptOut {
                   setter_present_by_explicit_default: 42,
                   setter_skipped_by_explicit_opt_out: 0,
                   setter_skipped_by_shorthand_opt_out: 0,
               });
}

#[test]
fn setter_opt_in() {
    let x: SetterOptIn = SetterOptInBuilder::default()
        .setter_present_by_explicit_opt_in(47u32)
        .setter_present_by_shorthand_opt_in(11u32)
        .build()
        .unwrap();

    assert_eq!(x,
               SetterOptIn {
                   setter_skipped_by_shorthand_default: 0,
                   setter_present_by_explicit_opt_in: 47,
                   setter_present_by_shorthand_opt_in: 11,
               });
}
<|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 app_units::Au;
use azure::scaled_font::ScaledFont;
use fnv::FnvHasher;
use font::{Font, FontGroup, FontHandleMethods};
use font_cache_thread::FontCacheThread;
use font_template::FontTemplateDescriptor;
use heapsize::HeapSizeOf;
use platform::font::FontHandle;
use platform::font_context::FontContextHandle;
use platform::font_template::FontTemplateData;
use smallvec::SmallVec;
use std::cell::RefCell;
use std::collections::HashMap;
use std::default::Default;
use std::hash::{BuildHasherDefault, Hash, Hasher};
use std::rc::Rc;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use string_cache::Atom;
use style::computed_values::{font_style, font_variant};
use style::properties::style_structs;
use webrender_traits;

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

#[derive(Debug)]
struct LayoutFontCacheEntry {
    family: String,
    font: Option<Rc<RefCell<Font>>>,
}

#[derive(Debug)]
struct FallbackFontCacheEntry {
    font: Rc<RefCell<Font>>,
}

/// A cached azure font (per paint thread) that
/// can be shared by multiple text runs.
#[derive(Debug)]
struct PaintFontCacheEntry {
    pt_size: Au,
    identifier: Atom,
    font: Rc<RefCell<ScaledFont>>,
}

/// An epoch for the font context cache. The cache is flushed if the current epoch does not match
/// this one.
static FONT_CACHE_EPOCH: AtomicUsize = ATOMIC_USIZE_INIT;

/// The FontContext represents the per-thread/thread state necessary for
/// working with fonts. It is the public API used by the layout and
/// paint code. It talks directly to the font cache thread where
/// required.
#[derive(Debug)]
pub struct FontContext {
    platform_handle: FontContextHandle,
    font_cache_thread: FontCacheThread,

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

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

    layout_font_group_cache:
        HashMap<LayoutFontGroupCacheKey, Rc<FontGroup>, BuildHasherDefault<FnvHasher>>,

    epoch: usize,
}

impl FontContext {
    pub fn new(font_cache_thread: FontCacheThread) -> FontContext {
        let handle = FontContextHandle::new();
        FontContext {
            platform_handle: handle,
            font_cache_thread: font_cache_thread,
            layout_font_cache: vec!(),
            fallback_font_cache: vec!(),
            paint_font_cache: vec!(),
            layout_font_group_cache: HashMap::with_hasher(Default::default()),
            epoch: 0,
        }
    }

    /// 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_key: webrender_traits::FontKey) -> Result<Font, ()> {
        // TODO: (Bug #3463): Currently we only support fake small-caps
        // painting. We should also support true small-caps (where the
        // font supports it) in the future.
        let actual_pt_size = match variant {
            font_variant::T::small_caps => pt_size.scale_by(SMALL_CAPS_SCALE_FACTOR),
            font_variant::T::normal => pt_size,
        };

        let handle = try!(FontHandle::new_from_template(&self.platform_handle,
                                                        template,
                                                        Some(actual_pt_size)));

        Ok(Font::new(handle, variant, descriptor, pt_size, actual_pt_size, font_key))
    }

    fn expire_font_caches_if_necessary(&mut self) {
        let current_epoch = FONT_CACHE_EPOCH.load(Ordering::SeqCst);
        if current_epoch == self.epoch {
            return
        }

        self.layout_font_cache.clear();
        self.fallback_font_cache.clear();
        self.paint_font_cache.clear();
        self.layout_font_group_cache.clear();
        self.epoch = current_epoch
    }

    /// 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 layout_font_group_for_style(&mut self, style: Arc<style_structs::Font>)
                                       -> Rc<FontGroup> {
        self.expire_font_caches_if_necessary();

        let layout_font_group_cache_key = LayoutFontGroupCacheKey {
            pointer: style.clone(),
            size: style.font_size,
        };
        if let Some(ref cached_font_group) = self.layout_font_group_cache.get(
                &layout_font_group_cache_key) {
            return (*cached_font_group).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_stretch,
                                               style.font_style == font_style::T::italic ||
                                                style.font_style == font_style::T::oblique);

        let mut fonts: SmallVec<[Rc<RefCell<Font>>; 8]> = SmallVec::new();

        for family in &style.font_family.0 {
            // 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 {
                if cached_font_entry.family == 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 template_info = self.font_cache_thread.find_font_template(family.clone(),
                                                                             desc.clone());
                match template_info {
                    Some(template_info) => {
                        let layout_font = self.create_layout_font(template_info.font_template,
                                                                  desc.clone(),
                                                                  style.font_size,
                                                                  style.font_variant,
                                                                  template_info.font_key
                                                                               .expect("No font key present!"));
                        let font = match layout_font {
                            Ok(layout_font) => {
                                let layout_font = Rc::new(RefCell::new(layout_font));
                                fonts.push(layout_font.clone());

                                Some(layout_font)
                            }
                            Err(_) => None
                        };

                        self.layout_font_cache.push(LayoutFontCacheEntry {
                            family: family.name().to_owned(),
                            font: font
                        });
                    }
                    None => {
                        self.layout_font_cache.push(LayoutFontCacheEntry {
                            family: family.name().to_owned(),
                            font: None,
                        });
                    }
                }
            }
        }

        // Add a last resort font as a fallback option.
        let mut cache_hit = false;
        for cached_font_entry in &self.fallback_font_cache {
            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 template_info = self.font_cache_thread.last_resort_font_template(desc.clone());
            let layout_font = self.create_layout_font(template_info.font_template,
                                                      desc.clone(),
                                                      style.font_size,
                                                      style.font_variant,
                                                      template_info.font_key.expect("No font key present!"));
            match layout_font {
                Ok(layout_font) => {
                    let layout_font = Rc::new(RefCell::new(layout_font));
                    self.fallback_font_cache.push(FallbackFontCacheEntry {
                        font: layout_font.clone(),
                    });
                    fonts.push(layout_font);
                }
                Err(_) => debug!("Failed to create fallback layout font!")
            }
        }

        let font_group = Rc::new(FontGroup::new(fonts));
        self.layout_font_group_cache.insert(layout_font_group_cache_key, font_group.clone());
        font_group
    }

    /// Returns a reference to the font cache thread.
    pub fn font_cache_thread(&self) -> FontCacheThread {
        self.font_cache_thread.clone()
    }
}

impl HeapSizeOf for FontContext {
    fn heap_size_of_children(&self) -> usize {
        // FIXME(njn): Measure other fields eventually.
        self.platform_handle.heap_size_of_children()
    }
}

#[derive(Debug)]
struct LayoutFontGroupCacheKey {
    pointer: Arc<style_structs::Font>,
    size: Au,
}

impl PartialEq for LayoutFontGroupCacheKey {
    fn eq(&self, other: &LayoutFontGroupCacheKey) -> bool {
        self.pointer == other.pointer && self.size == other.size
    }
}

impl Eq for LayoutFontGroupCacheKey {}

impl Hash for LayoutFontGroupCacheKey {
    fn hash<H>(&self, hasher: &mut H) where H: Hasher {
        self.pointer.hash.hash(hasher)
    }
}

#[inline]
pub fn invalidate_font_caches() {
    FONT_CACHE_EPOCH.fetch_add(1, Ordering::SeqCst);
}
<commit_msg>Remove always-empty FontContext::paint_font_cache.<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 app_units::Au;
use fnv::FnvHasher;
use font::{Font, FontGroup, FontHandleMethods};
use font_cache_thread::FontCacheThread;
use font_template::FontTemplateDescriptor;
use heapsize::HeapSizeOf;
use platform::font::FontHandle;
use platform::font_context::FontContextHandle;
use platform::font_template::FontTemplateData;
use smallvec::SmallVec;
use std::cell::RefCell;
use std::collections::HashMap;
use std::default::Default;
use std::hash::{BuildHasherDefault, Hash, Hasher};
use std::rc::Rc;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use style::computed_values::{font_style, font_variant};
use style::properties::style_structs;
use webrender_traits;

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

#[derive(Debug)]
struct LayoutFontCacheEntry {
    family: String,
    font: Option<Rc<RefCell<Font>>>,
}

#[derive(Debug)]
struct FallbackFontCacheEntry {
    font: Rc<RefCell<Font>>,
}

/// An epoch for the font context cache. The cache is flushed if the current epoch does not match
/// this one.
static FONT_CACHE_EPOCH: AtomicUsize = ATOMIC_USIZE_INIT;

/// The FontContext represents the per-thread/thread state necessary for
/// working with fonts. It is the public API used by the layout and
/// paint code. It talks directly to the font cache thread where
/// required.
#[derive(Debug)]
pub struct FontContext {
    platform_handle: FontContextHandle,
    font_cache_thread: FontCacheThread,

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

    layout_font_group_cache:
        HashMap<LayoutFontGroupCacheKey, Rc<FontGroup>, BuildHasherDefault<FnvHasher>>,

    epoch: usize,
}

impl FontContext {
    pub fn new(font_cache_thread: FontCacheThread) -> FontContext {
        let handle = FontContextHandle::new();
        FontContext {
            platform_handle: handle,
            font_cache_thread: font_cache_thread,
            layout_font_cache: vec!(),
            fallback_font_cache: vec!(),
            layout_font_group_cache: HashMap::with_hasher(Default::default()),
            epoch: 0,
        }
    }

    /// 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_key: webrender_traits::FontKey) -> Result<Font, ()> {
        // TODO: (Bug #3463): Currently we only support fake small-caps
        // painting. We should also support true small-caps (where the
        // font supports it) in the future.
        let actual_pt_size = match variant {
            font_variant::T::small_caps => pt_size.scale_by(SMALL_CAPS_SCALE_FACTOR),
            font_variant::T::normal => pt_size,
        };

        let handle = try!(FontHandle::new_from_template(&self.platform_handle,
                                                        template,
                                                        Some(actual_pt_size)));

        Ok(Font::new(handle, variant, descriptor, pt_size, actual_pt_size, font_key))
    }

    fn expire_font_caches_if_necessary(&mut self) {
        let current_epoch = FONT_CACHE_EPOCH.load(Ordering::SeqCst);
        if current_epoch == self.epoch {
            return
        }

        self.layout_font_cache.clear();
        self.fallback_font_cache.clear();
        self.layout_font_group_cache.clear();
        self.epoch = current_epoch
    }

    /// 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 layout_font_group_for_style(&mut self, style: Arc<style_structs::Font>)
                                       -> Rc<FontGroup> {
        self.expire_font_caches_if_necessary();

        let layout_font_group_cache_key = LayoutFontGroupCacheKey {
            pointer: style.clone(),
            size: style.font_size,
        };
        if let Some(ref cached_font_group) = self.layout_font_group_cache.get(
                &layout_font_group_cache_key) {
            return (*cached_font_group).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_stretch,
                                               style.font_style == font_style::T::italic ||
                                                style.font_style == font_style::T::oblique);

        let mut fonts: SmallVec<[Rc<RefCell<Font>>; 8]> = SmallVec::new();

        for family in &style.font_family.0 {
            // 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 {
                if cached_font_entry.family == 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 template_info = self.font_cache_thread.find_font_template(family.clone(),
                                                                             desc.clone());
                match template_info {
                    Some(template_info) => {
                        let layout_font = self.create_layout_font(template_info.font_template,
                                                                  desc.clone(),
                                                                  style.font_size,
                                                                  style.font_variant,
                                                                  template_info.font_key
                                                                               .expect("No font key present!"));
                        let font = match layout_font {
                            Ok(layout_font) => {
                                let layout_font = Rc::new(RefCell::new(layout_font));
                                fonts.push(layout_font.clone());

                                Some(layout_font)
                            }
                            Err(_) => None
                        };

                        self.layout_font_cache.push(LayoutFontCacheEntry {
                            family: family.name().to_owned(),
                            font: font
                        });
                    }
                    None => {
                        self.layout_font_cache.push(LayoutFontCacheEntry {
                            family: family.name().to_owned(),
                            font: None,
                        });
                    }
                }
            }
        }

        // Add a last resort font as a fallback option.
        let mut cache_hit = false;
        for cached_font_entry in &self.fallback_font_cache {
            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 template_info = self.font_cache_thread.last_resort_font_template(desc.clone());
            let layout_font = self.create_layout_font(template_info.font_template,
                                                      desc.clone(),
                                                      style.font_size,
                                                      style.font_variant,
                                                      template_info.font_key.expect("No font key present!"));
            match layout_font {
                Ok(layout_font) => {
                    let layout_font = Rc::new(RefCell::new(layout_font));
                    self.fallback_font_cache.push(FallbackFontCacheEntry {
                        font: layout_font.clone(),
                    });
                    fonts.push(layout_font);
                }
                Err(_) => debug!("Failed to create fallback layout font!")
            }
        }

        let font_group = Rc::new(FontGroup::new(fonts));
        self.layout_font_group_cache.insert(layout_font_group_cache_key, font_group.clone());
        font_group
    }

    /// Returns a reference to the font cache thread.
    pub fn font_cache_thread(&self) -> FontCacheThread {
        self.font_cache_thread.clone()
    }
}

impl HeapSizeOf for FontContext {
    fn heap_size_of_children(&self) -> usize {
        // FIXME(njn): Measure other fields eventually.
        self.platform_handle.heap_size_of_children()
    }
}

#[derive(Debug)]
struct LayoutFontGroupCacheKey {
    pointer: Arc<style_structs::Font>,
    size: Au,
}

impl PartialEq for LayoutFontGroupCacheKey {
    fn eq(&self, other: &LayoutFontGroupCacheKey) -> bool {
        self.pointer == other.pointer && self.size == other.size
    }
}

impl Eq for LayoutFontGroupCacheKey {}

impl Hash for LayoutFontGroupCacheKey {
    fn hash<H>(&self, hasher: &mut H) where H: Hasher {
        self.pointer.hash.hash(hasher)
    }
}

#[inline]
pub fn invalidate_font_caches() {
    FONT_CACHE_EPOCH.fetch_add(1, Ordering::SeqCst);
}
<|endoftext|>


<commit_before>#[cfg(feature = "chan_select")]
extern crate compiletest_rs as compiletest;

#[cfg(feature = "chan_select")]
use std::path::PathBuf;

#[cfg(feature = "chan_select")]
fn run_mode(mode: &'static str) {
    let mut config = compiletest::Config::default();
    let cfg_mode = mode.parse().ok().expect("Invalid mode");

    config.mode = cfg_mode;
    config.src_base = PathBuf::from(format!("tests/{}", mode));
    config.target_rustcflags = Some("-L target/debug".to_string());

    compiletest::run_tests(&config);
}

#[cfg(feature = "chan_select")]
#[test]
fn compile_test() {
    run_mode("compile-fail");
}
<commit_msg>Fix compiletest tests<commit_after>extern crate compiletest_rs as compiletest;

use std::path::PathBuf;

fn run_mode(mode: &'static str) {
    let mut config = compiletest::Config::default();

    config.mode = mode.parse().expect("Invalid mode");
    config.src_base = PathBuf::from(format!("tests/{}", mode));
    config.link_deps();

    compiletest::run_tests(&config);
}

#[test]
fn compile_test() {
    run_mode("compile-fail");
}
<|endoftext|>


<commit_before>use std::io::Command;
use std::os;

fn main() {
    let curr_dir = Path::new(os::getenv("CARGO_MANIFEST_DIR").unwrap());
    Command::new("git").arg("submodule").arg("update").arg("--init").cwd(&curr_dir).status().unwrap();

    let nvim_dir = curr_dir.join("neovim");
    Command::new("make").arg("libnvim").cwd(&nvim_dir).status().unwrap();

    let nvim_lib_dir = nvim_dir.join_many(&["build", "src", "nvim"]);
    let deps_lib_dir = nvim_dir.join_many(&[".deps", "usr", "lib"]);
    println!("cargo:rustc-flags=-L {} -L {} -l nvim:static",
        nvim_lib_dir.as_str().unwrap(),
        deps_lib_dir.as_str().unwrap());
}
<commit_msg>Only run  if neovim hasn't been cloned yet<commit_after>use std::io::Command;
use std::io::fs::PathExtensions;
use std::os;

fn main() {
    let curr_dir = Path::new(os::getenv("CARGO_MANIFEST_DIR").unwrap());
    let nvim_dir = curr_dir.join("neovim");

    if !nvim_dir.join("Makefile").exists() {
        Command::new("git")
            .arg("submodule")
            .arg("update")
            .arg("--init")
            .cwd(&curr_dir)
            .status()
            .unwrap();
    }

    Command::new("make").arg("libnvim").cwd(&nvim_dir).status().unwrap();

    let nvim_lib_dir = nvim_dir.join_many(&["build", "src", "nvim"]);
    let deps_lib_dir = nvim_dir.join_many(&[".deps", "usr", "lib"]);
    println!("cargo:rustc-flags=-L {} -L {} -l nvim:static",
        nvim_lib_dir.as_str().unwrap(),
        deps_lib_dir.as_str().unwrap());
}
<|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/. */

//! Common [values][values] used in CSS.
//!
//! [values]: https://drafts.csswg.org/css-values/

#![deny(missing_docs)]

use Atom;
pub use cssparser::{RGBA, Token, Parser, serialize_identifier, serialize_string};
use parser::{Parse, ParserContext};
use std::ascii::AsciiExt;
use std::borrow::Cow;
use std::fmt::{self, Debug};
use style_traits::ToCss;

macro_rules! define_numbered_css_keyword_enum {
    ($name: ident: $( $css: expr => $variant: ident = $value: expr ),+,) => {
        define_numbered_css_keyword_enum!($name: $( $css => $variant = $value ),+);
    };
    ($name: ident: $( $css: expr => $variant: ident = $value: expr ),+) => {
        #[allow(non_camel_case_types, missing_docs)]
        #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
        pub enum $name {
            $( $variant = $value ),+
        }

        impl Parse for $name {
            #[allow(missing_docs)]
            fn parse(_context: &ParserContext, input: &mut ::cssparser::Parser) -> Result<$name, ()> {
                match_ignore_ascii_case! { &try!(input.expect_ident()),
                    $( $css => Ok($name::$variant), )+
                    _ => Err(())
                }
            }
        }

        impl ToCss for $name {
            fn to_css<W>(&self, dest: &mut W) -> ::std::fmt::Result
                where W: ::std::fmt::Write,
            {
                match *self {
                    $( $name::$variant => dest.write_str($css) ),+
                }
            }
        }
    }
}

/// A macro used to implement HasViewportPercentage trait
/// for a given type that may never contain viewport units.
macro_rules! no_viewport_percentage {
    ($name: ident) => {
        impl HasViewportPercentage for $name {
            #[inline]
            fn has_viewport_percentage(&self) -> bool {
                false
            }
        }
    };
}

/// A macro for implementing `ComputedValueAsSpecified`, `Parse`
/// and `HasViewportPercentage` traits for the enums defined
/// using `define_css_keyword_enum` macro.
///
/// NOTE: We should either move `Parse` trait to `style_traits`
/// or `define_css_keyword_enum` macro to this crate, but that
/// may involve significant cleanup in both the crates.
macro_rules! add_impls_for_keyword_enum {
    ($name:ident) => {
        impl Parse for $name {
            #[inline]
            fn parse(_context: &ParserContext, input: &mut ::cssparser::Parser) -> Result<Self, ()> {
                $name::parse(input)
            }
        }

        impl ComputedValueAsSpecified for $name {}
        no_viewport_percentage!($name);
    };
}

pub mod computed;
pub mod generics;
pub mod specified;

/// A CSS float value.
pub type CSSFloat = f32;

/// A CSS integer value.
pub type CSSInteger = i32;

/// The default font size.
pub const FONT_MEDIUM_PX: i32 = 16;

/// A trait used to query whether this value has viewport units.
pub trait HasViewportPercentage {
    /// Returns true if this value has viewport units.
    fn has_viewport_percentage(&self) -> bool;
}

impl<T: HasViewportPercentage> HasViewportPercentage for Box<T> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool {
        (**self).has_viewport_percentage()
    }
}

use self::computed::ComputedValueAsSpecified;

macro_rules! define_keyword_type {
    ($name: ident, $css: expr) => {
        #[derive(Clone, PartialEq, Copy)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        #[allow(missing_docs)]
        pub struct $name;

        impl ::style_traits::ToCss for $name {
            fn to_css<W>(&self, dest: &mut W) -> ::std::fmt::Result where W: ::std::fmt::Write {
                write!(dest, $css)
            }
        }

        impl fmt::Debug for $name {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, $css)
            }
        }

        impl Parse for $name {
            fn parse(_context: &ParserContext, input: &mut ::cssparser::Parser) -> Result<$name, ()> {
                input.expect_ident_matching($css).map(|_| $name)
            }
        }

        impl ComputedValueAsSpecified for $name {}
        no_viewport_percentage!($name);
    };
}

define_keyword_type!(None_, "none");
define_keyword_type!(Auto, "auto");
define_keyword_type!(Normal, "normal");

#[derive(Clone, PartialEq, Copy)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A struct representing one of two kinds of values.
pub enum Either<A, B> {
    /// The first value.
    First(A),
    /// The second kind of value.
    Second(B),
}

impl<A: Debug, B: Debug> Debug for Either<A, B> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Either::First(ref v) => v.fmt(f),
            Either::Second(ref v) => v.fmt(f),
        }
    }
}

impl<A: ToCss, B: ToCss> ToCss for Either<A, B> {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        match *self {
            Either::First(ref v) => v.to_css(dest),
            Either::Second(ref v) => v.to_css(dest),
        }
    }
}

impl<A: HasViewportPercentage, B: HasViewportPercentage> HasViewportPercentage for Either<A, B> {
    fn has_viewport_percentage(&self) -> bool {
        match *self {
            Either::First(ref v) => v.has_viewport_percentage(),
            Either::Second(ref v) => v.has_viewport_percentage(),
        }
    }
}

impl<A: Parse, B: Parse> Parse for Either<A, B> {
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Either<A, B>, ()> {
        if let Ok(v) = input.try(|i| A::parse(context, i)) {
            Ok(Either::First(v))
        } else {
            B::parse(context, input).map(Either::Second)
        }
    }
}

use self::computed::{Context, ToComputedValue};

impl<A: ToComputedValue, B: ToComputedValue> ToComputedValue for Either<A, B> {
    type ComputedValue = Either<A::ComputedValue, B::ComputedValue>;

    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
        match *self {
            Either::First(ref a) => Either::First(a.to_computed_value(context)),
            Either::Second(ref a) => Either::Second(a.to_computed_value(context)),
        }
    }

    #[inline]
    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
        match *computed {
            Either::First(ref a) => Either::First(ToComputedValue::from_computed_value(a)),
            Either::Second(ref a) => Either::Second(ToComputedValue::from_computed_value(a)),
        }
    }
}

/// https://drafts.csswg.org/css-values-4/#custom-idents
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct CustomIdent(pub Atom);

impl CustomIdent {
    /// Parse an already-tokenizer identifier
    pub fn from_ident(ident: Cow<str>, excluding: &[&str]) -> Result<Self, ()> {
        match_ignore_ascii_case! { &ident,
            "initial" | "inherit" | "unset" | "default" => return Err(()),
            _ => {}
        };
        if excluding.iter().any(|s| ident.eq_ignore_ascii_case(s)) {
            Err(())
        } else {
            Ok(CustomIdent(ident.into()))
        }
    }
}

impl ToCss for CustomIdent {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        serialize_identifier(&self.0.to_string(), dest)
    }
}

/// https://drafts.csswg.org/css-animations/#typedef-keyframes-name
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum KeyframesName {
    /// <custom-ident>
    Ident(CustomIdent),
    /// <string>
    QuotedString(Atom),
}

impl KeyframesName {
    /// https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-name
    pub fn from_ident(value: String) -> Self {
        match CustomIdent::from_ident((&*value).into(), &["none"]) {
            Ok(ident) => KeyframesName::Ident(ident),
            Err(()) => KeyframesName::QuotedString(value.into()),
        }
    }

    /// The name as an Atom
    pub fn as_atom(&self) -> &Atom {
        match *self {
            KeyframesName::Ident(ref ident) => &ident.0,
            KeyframesName::QuotedString(ref atom) => atom,
        }
    }
}

impl Parse for KeyframesName {
    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        match input.next() {
            Ok(Token::Ident(s)) => Ok(KeyframesName::Ident(CustomIdent::from_ident(s, &["none"])?)),
            Ok(Token::QuotedString(s)) => Ok(KeyframesName::QuotedString(s.into())),
            _ => Err(())
        }
    }
}

impl ToCss for KeyframesName {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        match *self {
            KeyframesName::Ident(ref ident) => ident.to_css(dest),
            KeyframesName::QuotedString(ref atom) => serialize_string(&atom.to_string(), dest),
        }
    }
}

// A type for possible values for min- and max- flavors of width,
// height, block-size, and inline-size.
define_css_keyword_enum!(ExtremumLength:
                         "-moz-max-content" => MaxContent,
                         "-moz-min-content" => MinContent,
                         "-moz-fit-content" => FitContent,
                         "-moz-available" => FillAvailable);
<commit_msg>Consider `foo` and `"foo"` equal as keyframes/animation names.<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/. */

//! Common [values][values] used in CSS.
//!
//! [values]: https://drafts.csswg.org/css-values/

#![deny(missing_docs)]

use Atom;
pub use cssparser::{RGBA, Token, Parser, serialize_identifier, serialize_string};
use parser::{Parse, ParserContext};
use std::ascii::AsciiExt;
use std::borrow::Cow;
use std::fmt::{self, Debug};
use std::hash;
use style_traits::ToCss;

macro_rules! define_numbered_css_keyword_enum {
    ($name: ident: $( $css: expr => $variant: ident = $value: expr ),+,) => {
        define_numbered_css_keyword_enum!($name: $( $css => $variant = $value ),+);
    };
    ($name: ident: $( $css: expr => $variant: ident = $value: expr ),+) => {
        #[allow(non_camel_case_types, missing_docs)]
        #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
        pub enum $name {
            $( $variant = $value ),+
        }

        impl Parse for $name {
            #[allow(missing_docs)]
            fn parse(_context: &ParserContext, input: &mut ::cssparser::Parser) -> Result<$name, ()> {
                match_ignore_ascii_case! { &try!(input.expect_ident()),
                    $( $css => Ok($name::$variant), )+
                    _ => Err(())
                }
            }
        }

        impl ToCss for $name {
            fn to_css<W>(&self, dest: &mut W) -> ::std::fmt::Result
                where W: ::std::fmt::Write,
            {
                match *self {
                    $( $name::$variant => dest.write_str($css) ),+
                }
            }
        }
    }
}

/// A macro used to implement HasViewportPercentage trait
/// for a given type that may never contain viewport units.
macro_rules! no_viewport_percentage {
    ($name: ident) => {
        impl HasViewportPercentage for $name {
            #[inline]
            fn has_viewport_percentage(&self) -> bool {
                false
            }
        }
    };
}

/// A macro for implementing `ComputedValueAsSpecified`, `Parse`
/// and `HasViewportPercentage` traits for the enums defined
/// using `define_css_keyword_enum` macro.
///
/// NOTE: We should either move `Parse` trait to `style_traits`
/// or `define_css_keyword_enum` macro to this crate, but that
/// may involve significant cleanup in both the crates.
macro_rules! add_impls_for_keyword_enum {
    ($name:ident) => {
        impl Parse for $name {
            #[inline]
            fn parse(_context: &ParserContext, input: &mut ::cssparser::Parser) -> Result<Self, ()> {
                $name::parse(input)
            }
        }

        impl ComputedValueAsSpecified for $name {}
        no_viewport_percentage!($name);
    };
}

pub mod computed;
pub mod generics;
pub mod specified;

/// A CSS float value.
pub type CSSFloat = f32;

/// A CSS integer value.
pub type CSSInteger = i32;

/// The default font size.
pub const FONT_MEDIUM_PX: i32 = 16;

/// A trait used to query whether this value has viewport units.
pub trait HasViewportPercentage {
    /// Returns true if this value has viewport units.
    fn has_viewport_percentage(&self) -> bool;
}

impl<T: HasViewportPercentage> HasViewportPercentage for Box<T> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool {
        (**self).has_viewport_percentage()
    }
}

use self::computed::ComputedValueAsSpecified;

macro_rules! define_keyword_type {
    ($name: ident, $css: expr) => {
        #[derive(Clone, PartialEq, Copy)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        #[allow(missing_docs)]
        pub struct $name;

        impl ::style_traits::ToCss for $name {
            fn to_css<W>(&self, dest: &mut W) -> ::std::fmt::Result where W: ::std::fmt::Write {
                write!(dest, $css)
            }
        }

        impl fmt::Debug for $name {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, $css)
            }
        }

        impl Parse for $name {
            fn parse(_context: &ParserContext, input: &mut ::cssparser::Parser) -> Result<$name, ()> {
                input.expect_ident_matching($css).map(|_| $name)
            }
        }

        impl ComputedValueAsSpecified for $name {}
        no_viewport_percentage!($name);
    };
}

define_keyword_type!(None_, "none");
define_keyword_type!(Auto, "auto");
define_keyword_type!(Normal, "normal");

#[derive(Clone, PartialEq, Copy)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A struct representing one of two kinds of values.
pub enum Either<A, B> {
    /// The first value.
    First(A),
    /// The second kind of value.
    Second(B),
}

impl<A: Debug, B: Debug> Debug for Either<A, B> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Either::First(ref v) => v.fmt(f),
            Either::Second(ref v) => v.fmt(f),
        }
    }
}

impl<A: ToCss, B: ToCss> ToCss for Either<A, B> {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        match *self {
            Either::First(ref v) => v.to_css(dest),
            Either::Second(ref v) => v.to_css(dest),
        }
    }
}

impl<A: HasViewportPercentage, B: HasViewportPercentage> HasViewportPercentage for Either<A, B> {
    fn has_viewport_percentage(&self) -> bool {
        match *self {
            Either::First(ref v) => v.has_viewport_percentage(),
            Either::Second(ref v) => v.has_viewport_percentage(),
        }
    }
}

impl<A: Parse, B: Parse> Parse for Either<A, B> {
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Either<A, B>, ()> {
        if let Ok(v) = input.try(|i| A::parse(context, i)) {
            Ok(Either::First(v))
        } else {
            B::parse(context, input).map(Either::Second)
        }
    }
}

use self::computed::{Context, ToComputedValue};

impl<A: ToComputedValue, B: ToComputedValue> ToComputedValue for Either<A, B> {
    type ComputedValue = Either<A::ComputedValue, B::ComputedValue>;

    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
        match *self {
            Either::First(ref a) => Either::First(a.to_computed_value(context)),
            Either::Second(ref a) => Either::Second(a.to_computed_value(context)),
        }
    }

    #[inline]
    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
        match *computed {
            Either::First(ref a) => Either::First(ToComputedValue::from_computed_value(a)),
            Either::Second(ref a) => Either::Second(ToComputedValue::from_computed_value(a)),
        }
    }
}

/// https://drafts.csswg.org/css-values-4/#custom-idents
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct CustomIdent(pub Atom);

impl CustomIdent {
    /// Parse an already-tokenizer identifier
    pub fn from_ident(ident: Cow<str>, excluding: &[&str]) -> Result<Self, ()> {
        match_ignore_ascii_case! { &ident,
            "initial" | "inherit" | "unset" | "default" => return Err(()),
            _ => {}
        };
        if excluding.iter().any(|s| ident.eq_ignore_ascii_case(s)) {
            Err(())
        } else {
            Ok(CustomIdent(ident.into()))
        }
    }
}

impl ToCss for CustomIdent {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        serialize_identifier(&self.0.to_string(), dest)
    }
}

/// https://drafts.csswg.org/css-animations/#typedef-keyframes-name
#[derive(Debug, Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum KeyframesName {
    /// <custom-ident>
    Ident(CustomIdent),
    /// <string>
    QuotedString(Atom),
}

impl KeyframesName {
    /// https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-name
    pub fn from_ident(value: String) -> Self {
        match CustomIdent::from_ident((&*value).into(), &["none"]) {
            Ok(ident) => KeyframesName::Ident(ident),
            Err(()) => KeyframesName::QuotedString(value.into()),
        }
    }

    /// The name as an Atom
    pub fn as_atom(&self) -> &Atom {
        match *self {
            KeyframesName::Ident(ref ident) => &ident.0,
            KeyframesName::QuotedString(ref atom) => atom,
        }
    }
}

impl Eq for KeyframesName {}

impl PartialEq for KeyframesName {
    fn eq(&self, other: &Self) -> bool {
        self.as_atom() == other.as_atom()
    }
}

impl hash::Hash for KeyframesName {
    fn hash<H>(&self, state: &mut H) where H: hash::Hasher {
        self.as_atom().hash(state)
    }
}

impl Parse for KeyframesName {
    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        match input.next() {
            Ok(Token::Ident(s)) => Ok(KeyframesName::Ident(CustomIdent::from_ident(s, &["none"])?)),
            Ok(Token::QuotedString(s)) => Ok(KeyframesName::QuotedString(s.into())),
            _ => Err(())
        }
    }
}

impl ToCss for KeyframesName {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        match *self {
            KeyframesName::Ident(ref ident) => ident.to_css(dest),
            KeyframesName::QuotedString(ref atom) => serialize_string(&atom.to_string(), dest),
        }
    }
}

// A type for possible values for min- and max- flavors of width,
// height, block-size, and inline-size.
define_css_keyword_enum!(ExtremumLength:
                         "-moz-max-content" => MaxContent,
                         "-moz-min-content" => MinContent,
                         "-moz-fit-content" => FitContent,
                         "-moz-available" => FillAvailable);
<|endoftext|>


<commit_before>pub mod config;
pub mod downloader;
pub mod converter;

use mysql::conn::MyOpts;
use mysql::conn::pool;
use mysql::conn::pool::{MyPooledConn,MyPool};
use mysql::value::from_value;
use lib::downloader::{Downloader,DownloadDB};

use mysql::error::MyError;
use std::process::{Command,Output};
use std::error::Error;
use std::io;
use std::fs::remove_file;
use std::str;
use CONFIG;

use std::thread::sleep_ms;

use std::ascii::AsciiExt;

use std::fs::{rename};

macro_rules! try_option { ($e:expr) => (match $e { Some(x) => x, None => return None }) }

///Move result value out, return with none on err & print
macro_rules! try_reoption { ($e:expr) => (match $e { Ok(x) => x, Err(e) => {println!("{}",e);return None }}) }

#[derive(Debug)]
pub enum DownloadError{
    DownloadError(String),
    FFMPEGError(String),
    DMCAError,
    InternalError(String),
    DBError(String),
}

impl From<MyError> for DownloadError {
    fn from(err: MyError) -> DownloadError {
        DownloadError::DBError(err.description().into())
    }
}

impl From<io::Error> for DownloadError {
    fn from(err: io::Error) -> DownloadError {
        DownloadError::InternalError(err.description().into())
    }
}

pub fn db_connect(opts: MyOpts, sleep_time: u32) -> MyPool {
    loop {
        match pool::MyPool::new(opts.clone()) {
            Ok(conn) => {return conn;},
            Err(err) => println!("Unable to establish a connection:\n{}",err),
        };
        sleep_ms(sleep_time);
    }
}

///Return whether the quality is a split container or not: video only
///as specified in the docs
pub fn is_split_container(quality: &i16) -> bool {
    if CONFIG.extensions.mp3.contains(quality) {
        false
    } else if CONFIG.extensions.aac.contains(quality) {
        false
    } else if CONFIG.extensions.m4a.contains(quality) {
        false
    } else {
        true
    }
}

///Set the state of the current query, code dependent, see QueryCodes
pub fn set_query_state(pool: & pool::MyPool,qid: &i64 , state: &str, finished: bool){ // same here
    let mut conn = pool.get_conn().unwrap();
    let progress: i32 = if finished {
        100
    }else{
        0
    };
    let mut stmt = conn.prepare("UPDATE querydetails SET status = ? , progress = ? WHERE qid = ?").unwrap();
    let result = stmt.execute(&[&state,&progress,qid]); // why is this var needed ?!
    match result {
        Ok(_) => (),
        Err(why) => println!("Error setting query state: {}",why),
    }
}

///Update status code for query entry
pub fn set_query_code(conn: & mut MyPooledConn, code: &i8, qid: &i64) -> Result<(), DownloadError> { // same here
    let mut stmt = conn.prepare("UPDATE querydetails SET code = ? WHERE qid = ?").unwrap();
    let result = stmt.execute(&[code,qid]);
    match result {
        Ok(_) => Ok(()),
        Err(why) => Err(DownloadError::DBError(why.description().into())),
    }
}

///Update progress steps for db entry
pub fn update_steps(pool: & pool::MyPool, qid: &i64, step: i32, max_steps: i32, finished: bool){
    set_query_state(&pool,qid, &format!("{}|{}", step, max_steps), finished);
}

///add file to db including it's name & fid based on qid
pub fn add_file_entry(pool: & pool::MyPool, fid: &i64, name: &str, real_name: &str){
    println!("name: {}",name);
    let mut conn = pool.get_conn().unwrap();
    let mut stmt = conn.prepare("INSERT INTO files (fid,name,rname,valid) VALUES (?,?,?,?)").unwrap();
    let result = stmt.execute(&[fid,&real_name,&name,&1]); // why is this var needed ?!
    match result {
        Ok(_) => (),
        Err(why) => println!("Error adding file: {}",why),
    }
}

///Format file name for
pub fn format_file_name<'a>(name: &str, download: &'a Downloader, qid: &i64) -> String {
    println!("Fileextension: {:?}", get_file_ext(download));
    format!("{}-{}.{}",url_encode(name), qid, get_file_ext(download))
}

///Returns the file extension
pub fn get_file_ext<'a>(download: &Downloader) -> &'a str {
    if download.is_audio() {
        if CONFIG.extensions.aac.contains(&download.ddb.quality) {
            "aac"
        }else if CONFIG.extensions.mp3.contains(&download.ddb.quality) {
            "mp3"
        }else{
            "unknown"
        }
    }else{
        if CONFIG.extensions.mp4.contains(&download.ddb.quality) {
            "mp4"
        } else if CONFIG.extensions.flv.contains(&download.ddb.quality) {
            "flv"
        } else {
            "unknown"
        }
    }
}

///Move file to location
pub fn move_file(original: &str, destination: &str) -> Result<(),DownloadError> {
    match rename(original, destination) { // no try possible..
        Err(v) => Err(v.into()),
        Ok(_) => Ok(()),
    }
}

///Return an sanitized String (url encode still required)
pub fn url_encode(input: &str) -> String {
    // iterator over input, apply function to each element(function
    input.chars().map(|char| {
        match char {
            '\'' | '"' | '\\' => '_',
            '&' => '-',
            c if c.is_ascii() => c,
            _ => '_'
        }
    }).collect()
    // match for each char, then do collect: loop through the iterator, collect all elements
    // into container FromIterator
}

///Format save location for file, zip dependent
///audio files get an 'a' as suffix
pub fn format_file_path(qid: &i64, folder: Option<String>, audio: bool) -> String {
    let suffix = if audio {
        "a"
    }else {
        ""
    };
    match folder {
        Some(v) => format!("{}/{}/{}{}", &CONFIG.general.save_dir, v, qid,suffix),
        None => format!("{}/{}{}", &CONFIG.general.save_dir, qid,suffix),
    }
}

///Format save path, dependent on zip option.
pub fn format_save_path<'a>(folder: Option<String>, name: &str, download: &'a Downloader, qid: &i64) -> String {
    match folder {
        Some(v) => format!("{}/{}/{}", &CONFIG.general.save_dir, v, format_file_name(name,download,qid)),
        None => format!("{}/{}", &CONFIG.general.download_dir, format_file_name(name,download,qid)),
    }
}

///Request an entry from the DB to handle
pub fn request_entry(pool: & pool::MyPool) -> Option<DownloadDB> {
    let mut conn = try_reoption!(pool.get_conn());
    let mut stmt = try_reoption!(conn.prepare("SELECT queries.qid,url,`type`,quality,zip,`from`,`to` FROM querydetails \
                    INNER JOIN queries \
                    ON querydetails.qid = queries.qid \
                    LEFT JOIN playlists ON queries.qid = playlists.qid \
                    WHERE querydetails.code = 0 \
                    ORDER BY queries.created \
                    LIMIT 1"));
    let mut result = try_reoption!(stmt.execute(&[]));
    let result = try_reoption!(try_option!(result.next())); // result.next().'Some'->value.'unwrap'

    println!("Result: {:?}", result[0]);
    println!("result str: {}", result[1].into_str());
    let from;
    let to;
    let compress;
    let playlist = from_value::<Option<i16>>(&result[4]).is_some();
    if playlist {
        compress = from_value::<Option<i16>>(&result[4]).unwrap() == 1;
        from = from_value::<Option<i32>>(&result[5]).unwrap();
        to = from_value::<Option<i32>>(&result[6]).unwrap();
    } else {
        from = 0;
        to = 0;
        compress = false;
    }
    let download_db = DownloadDB { url: from_value::<String>(&result[1]),
                                    quality: from_value::<i16>(&result[3]),
                                    qid: from_value::<i64>(&result[0]),
                                    folder: CONFIG.general.save_dir.clone(),
                                    pool: pool.clone(),
                                    playlist: playlist,
                                    compress: compress,
                                    to: to,
                                    from: from };
    Some(download_db)
}

///Zip folder to file
pub fn zip_folder(folder: &str, zip_name: &str) -> Result<(), DownloadError> {
    let io = try!(create_zip_cmd(folder,zip_name));
    println!("zip stdout: {}\nzip stderr: {}", str::from_utf8(&io.stdout).unwrap(),str::from_utf8(&io.stderr).unwrap());
    if str::from_utf8(&io.stderr).unwrap().contains("error") {
        return Err(DownloadError::DownloadError(format!("error: {:?}",&io.stdout)))
    }
    Ok(())
}

fn create_zip_cmd(folder: &str, zip_file: &str) -> Result<Output, DownloadError> {
    match Command::new("tar").arg("-zcf").arg(zip_file).arg("-C").arg(folder).arg(".").output() {
                     Err(e) => Err(DownloadError::InternalError(format!("failed to zip: {}", e))),
                     Ok(v) => Ok(v),
    }
}

///Delete all files in the list
pub fn delete_files(files: Vec<String>) -> Result<(), DownloadError>{
    for file in files.iter() {
        println!("deleting {}",file);
        try!(remove_file(file));
    }
    Ok(())
}

///Set dbms connection settings
pub fn mysql_options() -> MyOpts {
    MyOpts {
        tcp_addr: Some(CONFIG.db.ip.clone()),
        tcp_port: CONFIG.db.port,
        user: Some(CONFIG.db.user.clone()),
        pass: Some(CONFIG.db.password.clone()),
        db_name: Some(CONFIG.db.db.clone()),
        ..Default::default() // set others to default
    }
}<commit_msg>added two error states<commit_after>pub mod config;
pub mod downloader;
pub mod converter;

use mysql::conn::MyOpts;
use mysql::conn::pool;
use mysql::conn::pool::{MyPooledConn,MyPool};
use mysql::value::from_value;
use lib::downloader::{Downloader,DownloadDB};

use mysql::error::MyError;
use std::process::{Command,Output};
use std::error::Error;
use std::io;
use std::fs::remove_file;
use std::str;
use CONFIG;

use std::thread::sleep_ms;

use std::ascii::AsciiExt;

use std::fs::{rename};

macro_rules! try_option { ($e:expr) => (match $e { Some(x) => x, None => return None }) }

///Move result value out, return with none on err & print
macro_rules! try_reoption { ($e:expr) => (match $e { Ok(x) => x, Err(e) => {println!("{}",e);return None }}) }

#[derive(Debug)]
pub enum DownloadError{
    DownloadError(String),
    FFMPEGError(String),
    DMCAError,
    NotAvailable,
    QualityNotAvailable,
    InternalError(String),
    DBError(String),
}

impl From<MyError> for DownloadError {
    fn from(err: MyError) -> DownloadError {
        DownloadError::DBError(err.description().into())
    }
}

impl From<io::Error> for DownloadError {
    fn from(err: io::Error) -> DownloadError {
        DownloadError::InternalError(err.description().into())
    }
}

pub fn db_connect(opts: MyOpts, sleep_time: u32) -> MyPool {
    loop {
        match pool::MyPool::new(opts.clone()) {
            Ok(conn) => {return conn;},
            Err(err) => println!("Unable to establish a connection:\n{}",err),
        };
        sleep_ms(sleep_time);
    }
}

///Return whether the quality is a split container or not: video only
///as specified in the docs
pub fn is_split_container(quality: &i16) -> bool {
    if CONFIG.extensions.mp3.contains(quality) {
        false
    } else if CONFIG.extensions.aac.contains(quality) {
        false
    } else if CONFIG.extensions.m4a.contains(quality) {
        false
    } else {
        true
    }
}

///Set the state of the current query, code dependent, see QueryCodes
pub fn set_query_state(pool: & pool::MyPool,qid: &i64 , state: &str, finished: bool){ // same here
    let mut conn = pool.get_conn().unwrap();
    let progress: i32 = if finished {
        100
    }else{
        0
    };
    let mut stmt = conn.prepare("UPDATE querydetails SET status = ? , progress = ? WHERE qid = ?").unwrap();
    let result = stmt.execute(&[&state,&progress,qid]); // why is this var needed ?!
    match result {
        Ok(_) => (),
        Err(why) => println!("Error setting query state: {}",why),
    }
}

///Update status code for query entry
pub fn set_query_code(conn: & mut MyPooledConn, code: &i8, qid: &i64) -> Result<(), DownloadError> { // same here
    let mut stmt = conn.prepare("UPDATE querydetails SET code = ? WHERE qid = ?").unwrap();
    let result = stmt.execute(&[code,qid]);
    match result {
        Ok(_) => Ok(()),
        Err(why) => Err(DownloadError::DBError(why.description().into())),
    }
}

///Update progress steps for db entry
pub fn update_steps(pool: & pool::MyPool, qid: &i64, step: i32, max_steps: i32, finished: bool){
    set_query_state(&pool,qid, &format!("{}|{}", step, max_steps), finished);
}

///add file to db including it's name & fid based on qid
pub fn add_file_entry(pool: & pool::MyPool, fid: &i64, name: &str, real_name: &str){
    println!("name: {}",name);
    let mut conn = pool.get_conn().unwrap();
    let mut stmt = conn.prepare("INSERT INTO files (fid,name,rname,valid) VALUES (?,?,?,?)").unwrap();
    let result = stmt.execute(&[fid,&real_name,&name,&1]); // why is this var needed ?!
    match result {
        Ok(_) => (),
        Err(why) => println!("Error adding file: {}",why),
    }
}

///Format file name for
pub fn format_file_name<'a>(name: &str, download: &'a Downloader, qid: &i64) -> String {
    println!("Fileextension: {:?}", get_file_ext(download));
    format!("{}-{}.{}",url_encode(name), qid, get_file_ext(download))
}

///Returns the file extension
pub fn get_file_ext<'a>(download: &Downloader) -> &'a str {
    if download.is_audio() {
        if CONFIG.extensions.aac.contains(&download.ddb.quality) {
            "aac"
        }else if CONFIG.extensions.mp3.contains(&download.ddb.quality) {
            "mp3"
        }else{
            "unknown"
        }
    }else{
        if CONFIG.extensions.mp4.contains(&download.ddb.quality) {
            "mp4"
        } else if CONFIG.extensions.flv.contains(&download.ddb.quality) {
            "flv"
        } else {
            "unknown"
        }
    }
}

///Move file to location
pub fn move_file(original: &str, destination: &str) -> Result<(),DownloadError> {
    match rename(original, destination) { // no try possible..
        Err(v) => Err(v.into()),
        Ok(_) => Ok(()),
    }
}

///Return an sanitized String (url encode still required)
pub fn url_encode(input: &str) -> String {
    // iterator over input, apply function to each element(function
    input.chars().map(|char| {
        match char {
            '\'' | '"' | '\\' => '_',
            '&' => '-',
            c if c.is_ascii() => c,
            _ => '_'
        }
    }).collect()
    // match for each char, then do collect: loop through the iterator, collect all elements
    // into container FromIterator
}

///Format save location for file, zip dependent
///audio files get an 'a' as suffix
pub fn format_file_path(qid: &i64, folder: Option<String>, audio: bool) -> String {
    let suffix = if audio {
        "a"
    }else {
        ""
    };
    match folder {
        Some(v) => format!("{}/{}/{}{}", &CONFIG.general.save_dir, v, qid,suffix),
        None => format!("{}/{}{}", &CONFIG.general.save_dir, qid,suffix),
    }
}

///Format save path, dependent on zip option.
pub fn format_save_path<'a>(folder: Option<String>, name: &str, download: &'a Downloader, qid: &i64) -> String {
    match folder {
        Some(v) => format!("{}/{}/{}", &CONFIG.general.save_dir, v, format_file_name(name,download,qid)),
        None => format!("{}/{}", &CONFIG.general.download_dir, format_file_name(name,download,qid)),
    }
}

///Request an entry from the DB to handle
pub fn request_entry(pool: & pool::MyPool) -> Option<DownloadDB> {
    let mut conn = try_reoption!(pool.get_conn());
    let mut stmt = try_reoption!(conn.prepare("SELECT queries.qid,url,`type`,quality,zip,`from`,`to` FROM querydetails \
                    INNER JOIN queries \
                    ON querydetails.qid = queries.qid \
                    LEFT JOIN playlists ON queries.qid = playlists.qid \
                    WHERE querydetails.code = 0 \
                    ORDER BY queries.created \
                    LIMIT 1"));
    let mut result = try_reoption!(stmt.execute(&[]));
    let result = try_reoption!(try_option!(result.next())); // result.next().'Some'->value.'unwrap'

    println!("Result: {:?}", result[0]);
    println!("result str: {}", result[1].into_str());
    let from;
    let to;
    let compress;
    let playlist = from_value::<Option<i16>>(&result[4]).is_some();
    if playlist {
        compress = from_value::<Option<i16>>(&result[4]).unwrap() == 1;
        from = from_value::<Option<i32>>(&result[5]).unwrap();
        to = from_value::<Option<i32>>(&result[6]).unwrap();
    } else {
        from = 0;
        to = 0;
        compress = false;
    }
    let download_db = DownloadDB { url: from_value::<String>(&result[1]),
                                    quality: from_value::<i16>(&result[3]),
                                    qid: from_value::<i64>(&result[0]),
                                    folder: CONFIG.general.save_dir.clone(),
                                    pool: pool.clone(),
                                    playlist: playlist,
                                    compress: compress,
                                    to: to,
                                    from: from };
    Some(download_db)
}

///Zip folder to file
pub fn zip_folder(folder: &str, zip_name: &str) -> Result<(), DownloadError> {
    let io = try!(create_zip_cmd(folder,zip_name));
    println!("zip stdout: {}\nzip stderr: {}", str::from_utf8(&io.stdout).unwrap(),str::from_utf8(&io.stderr).unwrap());
    if str::from_utf8(&io.stderr).unwrap().contains("error") {
        return Err(DownloadError::DownloadError(format!("error: {:?}",&io.stdout)))
    }
    Ok(())
}

fn create_zip_cmd(folder: &str, zip_file: &str) -> Result<Output, DownloadError> {
    match Command::new("tar").arg("-zcf").arg(zip_file).arg("-C").arg(folder).arg(".").output() {
                     Err(e) => Err(DownloadError::InternalError(format!("failed to zip: {}", e))),
                     Ok(v) => Ok(v),
    }
}

///Delete all files in the list
pub fn delete_files(files: Vec<String>) -> Result<(), DownloadError>{
    for file in files.iter() {
        println!("deleting {}",file);
        try!(remove_file(file));
    }
    Ok(())
}

///Set dbms connection settings
pub fn mysql_options() -> MyOpts {
    MyOpts {
        tcp_addr: Some(CONFIG.db.ip.clone()),
        tcp_port: CONFIG.db.port,
        user: Some(CONFIG.db.user.clone()),
        pass: Some(CONFIG.db.password.clone()),
        db_name: Some(CONFIG.db.db.clone()),
        ..Default::default() // set others to default
    }
}<|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/.

//! Communicating with `lvmetad`.

use unix_socket::UnixStream;

use std::io::{Result, Read, Write};
use std::io::Error;
use std::io::ErrorKind::Other;

use parser::{
    LvmTextMap,
    TextMapOps,
    buf_to_textmap,
    vg_from_textmap,
    textmap_to_buf,
};
use vg;

const LVMETAD_PATH: &'static str = "/run/lvm/lvmetad.socket";

fn collect_response(stream: &mut UnixStream) -> Result<Vec<u8>> {
    let mut response = [0; 32];
    let mut v = Vec::new();

    loop {
        let bytes_read = try!(stream.read(&mut response));

        v.extend(&response[..bytes_read]);

        if v.ends_with(b"\n##\n") {
            // drop the end marker
            let len = v.len() - 4;
            v.truncate(len);
            return Ok(v);
        }
    }
}

fn _request(s: &[u8],
                token: Option<&[u8]>,
                stream: &mut UnixStream,
                args: &Option<Vec<&[u8]>>) -> Result<Vec<u8>> {

    let mut v = Vec::new();
    v.extend(b"request = \"");
    v.extend(s);
    v.extend(b"\"\n");

    if let Some(token) = token {
        v.extend(b"token = \"filter:");
        v.extend(token);
        v.extend(b"\"\n");
    }

    if let &Some(ref args) = args {
        for arg in args {
            v.extend(arg.clone());
            v.extend(b"\n");
        }
    }

    try!(stream.write_all(&v));
    try!(stream.write_all(b"\n##\n"));

    collect_response(stream)
}

/// Make a request to the running lvmetad daemon.
///
/// # Examples
///
/// ```
///    use melvin::lvmetad::request;
///
///    let vg_list = request(b"vg_list", None);
/// ```
pub fn request(s: &[u8], args: Option<Vec<&[u8]>>) -> Result<LvmTextMap> {
    let err = || Error::new(Other, "response parsing error");
    let token = b"0";

    let mut stream = try!(UnixStream::connect(LVMETAD_PATH));

    let txt = try!(_request(s, Some(token), &mut stream, &args));
    let mut response = try!(buf_to_textmap(&txt));

    if try!(response.string_from_textmap("response").ok_or(err())) == "token_mismatch" {
        try!(_request(b"token_update", Some(token), &mut stream, &None));
        response = try!(_request(s, Some(token), &mut stream, &args)
            .and_then(|r| buf_to_textmap(&r)));
    }

    if response.get("global_invalid").is_some() || response.get("vg_invalid").is_some() {
        return Err(Error::new(Other, "cached metadata flagged as invalid"));
    }

    if try!(response.string_from_textmap("response").ok_or(err())) != "OK" {
        let reason = match response.string_from_textmap("reason") {
            Some(x) => x,
            None => "no reason given",
        };
        return Err(Error::new(Other, reason));
    }

    response.remove("response");

    Ok(response)
}

/// Query `lvmetad` for a list of Volume Groups on the system.
pub fn vgs_from_lvmetad() -> Result<Vec<vg::VG>> {
    let err = || Error::new(Other, "response parsing error");
    let mut v = Vec::new();

    let vg_list = try!(request(b"vg_list", None));
    let vgs = try!(vg_list.textmap_from_textmap("volume_groups").ok_or(err()));

    for id in vgs.keys() {
        let name = try!(vgs.textmap_from_textmap(id)
                        .and_then(|val| val.string_from_textmap("name"))
                        .ok_or(err()));

        let mut option: Vec<u8> = Vec::new();
        option.extend(b"uuid = \"");
        option.extend(id.as_bytes());
        option.extend(b"\"");
        let options = vec!(&option[..]);

        let vg_info = try!(request(b"vg_lookup", Some(options)));
        let md = try!(vg_info.textmap_from_textmap("metadata").ok_or(err()));

        let vg = vg_from_textmap(&name, md).expect("didn't get vg!");

        v.push(vg);
    }

    Ok(v)
}

/// Tell `lvmetad` about the current state of a Volume Group.
pub fn vg_update_lvmetad(map: &LvmTextMap) -> Result<()> {

    assert_eq!(map.len(), 1);

    let k = map.keys().next().unwrap();
    let v = map.textmap_from_textmap(k).unwrap();

    let option = format!("vgname = \"{}\"", k);

    let mut option2 = Vec::new();
    option2.extend(b"metadata {");
    option2.extend(textmap_to_buf(v));
    option2.extend(b"}");

    let mut options: Vec<&[u8]> = Vec::new();

    options.push(&option.as_bytes());
    options.push(&option2);

    try!(request(b"vg_update", Some(options)));

    Ok(())
}
<commit_msg>Change name of param to something more descriptive<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/.

//! Communicating with `lvmetad`.

use unix_socket::UnixStream;

use std::io::{Result, Read, Write};
use std::io::Error;
use std::io::ErrorKind::Other;

use parser::{
    LvmTextMap,
    TextMapOps,
    buf_to_textmap,
    vg_from_textmap,
    textmap_to_buf,
};
use vg;

const LVMETAD_PATH: &'static str = "/run/lvm/lvmetad.socket";

fn collect_response(stream: &mut UnixStream) -> Result<Vec<u8>> {
    let mut response = [0; 32];
    let mut v = Vec::new();

    loop {
        let bytes_read = try!(stream.read(&mut response));

        v.extend(&response[..bytes_read]);

        if v.ends_with(b"\n##\n") {
            // drop the end marker
            let len = v.len() - 4;
            v.truncate(len);
            return Ok(v);
        }
    }
}

fn _request(req: &[u8],
                token: Option<&[u8]>,
                stream: &mut UnixStream,
                args: &Option<Vec<&[u8]>>) -> Result<Vec<u8>> {

    let mut v = Vec::new();
    v.extend(b"request = \"");
    v.extend(req);
    v.extend(b"\"\n");

    if let Some(token) = token {
        v.extend(b"token = \"filter:");
        v.extend(token);
        v.extend(b"\"\n");
    }

    if let &Some(ref args) = args {
        for arg in args {
            v.extend(arg.clone());
            v.extend(b"\n");
        }
    }

    try!(stream.write_all(&v));
    try!(stream.write_all(b"\n##\n"));

    collect_response(stream)
}

/// Make a request to the running lvmetad daemon.
///
/// # Examples
///
/// ```
///    use melvin::lvmetad::request;
///
///    let vg_list = request(b"vg_list", None);
/// ```
pub fn request(req: &[u8], args: Option<Vec<&[u8]>>) -> Result<LvmTextMap> {
    let err = || Error::new(Other, "response parsing error");
    let token = b"0";

    let mut stream = try!(UnixStream::connect(LVMETAD_PATH));

    let txt = try!(_request(req, Some(token), &mut stream, &args));
    let mut response = try!(buf_to_textmap(&txt));

    if try!(response.string_from_textmap("response").ok_or(err())) == "token_mismatch" {
        try!(_request(b"token_update", Some(token), &mut stream, &None));
        response = try!(_request(req, Some(token), &mut stream, &args)
            .and_then(|r| buf_to_textmap(&r)));
    }

    if response.get("global_invalid").is_some() || response.get("vg_invalid").is_some() {
        return Err(Error::new(Other, "cached metadata flagged as invalid"));
    }

    if try!(response.string_from_textmap("response").ok_or(err())) != "OK" {
        let reason = match response.string_from_textmap("reason") {
            Some(x) => x,
            None => "no reason given",
        };
        return Err(Error::new(Other, reason));
    }

    response.remove("response");

    Ok(response)
}

/// Query `lvmetad` for a list of Volume Groups on the system.
pub fn vgs_from_lvmetad() -> Result<Vec<vg::VG>> {
    let err = || Error::new(Other, "response parsing error");
    let mut v = Vec::new();

    let vg_list = try!(request(b"vg_list", None));
    let vgs = try!(vg_list.textmap_from_textmap("volume_groups").ok_or(err()));

    for id in vgs.keys() {
        let name = try!(vgs.textmap_from_textmap(id)
                        .and_then(|val| val.string_from_textmap("name"))
                        .ok_or(err()));

        let mut option: Vec<u8> = Vec::new();
        option.extend(b"uuid = \"");
        option.extend(id.as_bytes());
        option.extend(b"\"");
        let options = vec!(&option[..]);

        let vg_info = try!(request(b"vg_lookup", Some(options)));
        let md = try!(vg_info.textmap_from_textmap("metadata").ok_or(err()));

        let vg = vg_from_textmap(&name, md).expect("didn't get vg!");

        v.push(vg);
    }

    Ok(v)
}

/// Tell `lvmetad` about the current state of a Volume Group.
pub fn vg_update_lvmetad(map: &LvmTextMap) -> Result<()> {

    assert_eq!(map.len(), 1);

    let k = map.keys().next().unwrap();
    let v = map.textmap_from_textmap(k).unwrap();

    let option = format!("vgname = \"{}\"", k);

    let mut option2 = Vec::new();
    option2.extend(b"metadata {");
    option2.extend(textmap_to_buf(v));
    option2.extend(b"}");

    let mut options: Vec<&[u8]> = Vec::new();

    options.push(&option.as_bytes());
    options.push(&option2);

    try!(request(b"vg_update", Some(options)));

    Ok(())
}
<|endoftext|>