<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 std::{str, run, task};
use std::rt::io;
use std::rt::io::Writer;
use extra::{tempfile, json};
use extra::json::ToJson;

use super::*;
use ast::*;

fn write_whole_file(path: &Path, data: &str) {
    match io::file::open(path, io::Create, io::Write) {
        Some(mut writer) => writer.write(data.as_bytes()),
        None => fail!("could not open file"),
    }
}

fn almost_equals(a: &json::Json, b: &json::Json) -> bool {
    match (a, b) {
        (&json::Number(a), &json::Number(b)) => (a - b).abs() < 1e-6,
        (&json::String(ref a), &json::String(ref b)) => a == b,
        (&json::Boolean(a), &json::Boolean(b)) => a == b,
        (&json::List(ref a), &json::List(ref b))
            => a.iter().zip(b.iter()).all(|(ref a, ref b)| almost_equals(*a, *b)),
        (&json::Object(_), &json::Object(_)) => fail!(~"Not implemented"),
        (&json::Null, &json::Null) => true,
        _ => false,
    }
}

fn assert_json_eq(results: json::Json, expected: json::Json, message: ~str) {
    if !almost_equals(&results, &expected) {
        let temp = tempfile::TempDir::new("rust-cssparser-tests").unwrap();
        let results = results.to_pretty_str() + "\n";
        let expected = expected.to_pretty_str() + "\n";
        do task::try {
            let mut result_path = temp.path().clone();
            result_path.push("results.json");
            let mut expected_path = temp.path().clone();
            expected_path.push("expected.json");
            write_whole_file(&result_path, results);
            write_whole_file(&expected_path, expected);
            run::process_status("colordiff", [~"-u1000", result_path.display().to_str(),
                                              expected_path.display().to_str()]);
        };

        fail!(message)
    }
}

fn run_json_tests<T: ToJson>(json_data: &str, parse: &fn (input: ~str) -> T) {
    let items = match json::from_str(json_data) {
        Ok(json::List(items)) => items,
        _ => fail!("Invalid JSON")
    };
    assert!(items.len() % 2 == 0);
    let mut input: Option<~str> = None;
    for item in items.move_iter() {
        match (&input, item) {
            (&None, json::String(string)) => input = Some(string),
            (&Some(_), expected) => {
                let input = input.take_unwrap();
                let result = parse(input.to_owned()).to_json();
                assert_json_eq(result, expected, input);
            },
            _ => fail!("Unexpected JSON")
        };
    }
}

#[test]
fn component_value_list() {
    do run_json_tests(include_str!("css-parsing-tests/component_value_list.json")) |input| {
        tokenize(input).map(|(c, _)| c).to_owned_vec()
    }
}

#[test]
fn one_component_value() {
    do run_json_tests(include_str!("css-parsing-tests/one_component_value.json")) |input| {
        parse_one_component_value(tokenize(input))
    }
}

#[test]
fn declaration_list() {
    do run_json_tests(include_str!("css-parsing-tests/declaration_list.json")) |input| {
        parse_declaration_list(tokenize(input)).to_owned_vec()
    }
}

#[test]
fn one_declaration() {
    do run_json_tests(include_str!("css-parsing-tests/one_declaration.json")) |input| {
        parse_one_declaration(tokenize(input))
    }
}

#[test]
fn rule_list() {
    do run_json_tests(include_str!("css-parsing-tests/rule_list.json")) |input| {
        parse_rule_list(tokenize(input)).to_owned_vec()
    }
}

#[test]
fn stylesheet() {
    do run_json_tests(include_str!("css-parsing-tests/stylesheet.json")) |input| {
        parse_stylesheet_rules(tokenize(input)).to_owned_vec()
    }
}

#[test]
fn one_rule() {
    do run_json_tests(include_str!("css-parsing-tests/one_rule.json")) |input| {
        parse_one_rule(tokenize(input))
    }
}

fn run_color_tests(json_data: &str, to_json: &fn(result: Option<Color>) -> json::Json) {
    do run_json_tests(json_data) |input| {
        match parse_one_component_value(tokenize(input)) {
            Ok(component_value) => to_json(Color::parse(&component_value)),
            Err(_reason) => json::Null,
        }
    }
}

#[test]
fn color3() {
    run_color_tests(include_str!("css-parsing-tests/color3.json"), |c| c.to_json())
}

#[test]
fn color3_hsl() {
    run_color_tests(include_str!("css-parsing-tests/color3_hsl.json"), |c| c.to_json())
}

/// color3_keywords.json is different: R, G and B are in 0..255 rather than 0..1
#[test]
fn color3_keywords() {
    do run_color_tests(include_str!("css-parsing-tests/color3_keywords.json")) |c| {
        match c {
            Some(RGBA(RGBA { red: r, green: g, blue: b, alpha: a }))
            => (~[r * 255., g * 255., b * 255., a]).to_json(),
            Some(CurrentColor) => json::String(~"currentColor"),
            None => json::Null,
        }
    }
}

#[test]
fn nth() {
    do run_json_tests(include_str!("css-parsing-tests/An+B.json")) |input| {
        parse_nth(tokenize(input).map(|(c, _)| c).to_owned_vec())
    }
}

#[test]
fn serializer() {
    do run_json_tests(include_str!("css-parsing-tests/component_value_list.json")) |input| {
        let component_values = tokenize(input).map(|(c, _)| c).to_owned_vec();
        let serialized = component_values.iter().to_css();
        tokenize(serialized).map(|(c, _)| c).to_owned_vec()
    }
}

impl ToJson for Result<Rule, SyntaxError> {
    fn to_json(&self) -> json::Json {
        match *self {
            Ok(ref a) => a.to_json(),
            Err(ref b) => b.to_json(),
        }
    }
}

impl ToJson for Result<DeclarationListItem, SyntaxError> {
    fn to_json(&self) -> json::Json {
        match *self {
            Ok(ref a) => a.to_json(),
            Err(ref b) => b.to_json(),
        }
    }
}

impl ToJson for Result<Declaration, SyntaxError> {
    fn to_json(&self) -> json::Json {
        match *self {
            Ok(ref a) => a.to_json(),
            Err(ref b) => b.to_json(),
        }
    }
}

impl ToJson for Result<ComponentValue, SyntaxError> {
    fn to_json(&self) -> json::Json {
        match *self {
            Ok(ref a) => a.to_json(),
            Err(ref b) => b.to_json(),
        }
    }
}

impl ToJson for SyntaxError {
    fn to_json(&self) -> json::Json {
        json::List(~[json::String(~"error"), json::String(match self.reason {
            ErrEmptyInput => ~"empty",
            ErrExtraInput => ~"extra-input",
            _ => ~"invalid",
        })])
    }
}

impl ToJson for Color {
    fn to_json(&self) -> json::Json {
        match *self {
            RGBA(RGBA { red: r, green: g, blue: b, alpha: a }) => (~[r, g, b, a]).to_json(),
            CurrentColor => json::String(~"currentColor"),
        }
    }
}

impl ToJson for Rule {
    fn to_json(&self) -> json::Json {
        match *self {
            QualifiedRule(ref rule) => rule.to_json(),
            AtRule(ref rule) => rule.to_json(),
        }
    }
}

impl ToJson for DeclarationListItem {
    fn to_json(&self) -> json::Json {
        match *self {
            Declaration(ref declaration) => declaration.to_json(),
            Decl_AtRule(ref at_rule) => at_rule.to_json(),
        }
    }
}

fn list_to_json(list: &~[(ComponentValue, SourceLocation)]) -> ~[json::Json] {
    list.map(|tuple| {
        match *tuple {
            (ref c, _) => c.to_json()
        }
    })
}

impl ToJson for AtRule {
    fn to_json(&self) -> json::Json {
        match *self {
            AtRule{name: ref name, prelude: ref prelude, block: ref block, _}
            => json::List(~[json::String(~"at-rule"), name.to_json(),
                            prelude.to_json(), block.as_ref().map(list_to_json).to_json()])
        }
    }
}

impl ToJson for QualifiedRule {
    fn to_json(&self) -> json::Json {
        match *self {
            QualifiedRule{prelude: ref prelude, block: ref block, _}
            => json::List(~[json::String(~"qualified rule"),
                            prelude.to_json(), json::List(list_to_json(block))])
        }
    }
}

impl ToJson for Declaration {
    fn to_json(&self) -> json::Json {
        match *self {
            Declaration{name: ref name, value: ref value, important: ref important, _}
            =>  json::List(~[json::String(~"declaration"), name.to_json(),
                             value.to_json(), important.to_json()])
        }
    }
}

impl ToJson for ComponentValue {
    fn to_json(&self) -> json::Json {
        use JList = extra::json::List;
        use JString = extra::json::String;

        fn numeric(value: &NumericValue) -> ~[json::Json] {
            match *value {
                NumericValue{representation: ref r, value: ref v, int_value: ref i}
                => ~[r.to_json(), v.to_json(),
                     JString(match *i { Some(_) => ~"integer", _ => ~"number" })]
            }
        }

        match *self {
            Ident(ref value) => JList(~[JString(~"ident"), value.to_json()]),
            AtKeyword(ref value) => JList(~[JString(~"at-keyword"), value.to_json()]),
            Hash(ref value) => JList(~[JString(~"hash"), value.to_json(),
                                       JString(~"unrestricted")]),
            IDHash(ref value) => JList(~[JString(~"hash"), value.to_json(), JString(~"id")]),
            String(ref value) => JList(~[JString(~"string"), value.to_json()]),
            URL(ref value) => JList(~[JString(~"url"), value.to_json()]),
            Delim('\\') => JString(~"\\"),
            Delim(value) => JString(str::from_char(value)),

            Number(ref value) => JList(~[JString(~"number")] + numeric(value)),
            Percentage(ref value) => JList(~[JString(~"percentage")] + numeric(value)),
            Dimension(ref value, ref unit)
            => JList(~[JString(~"dimension")] + numeric(value) + ~[unit.to_json()]),

            UnicodeRange(start, end)
            => JList(~[JString(~"unicode-range"), start.to_json(), end.to_json()]),

            WhiteSpace => JString(~" "),
            Colon => JString(~":"),
            Semicolon => JString(~";"),
            Comma => JString(~","),
            IncludeMatch => JString(~"~="),
            DashMatch => JString(~"|="),
            PrefixMatch => JString(~"^="),
            SuffixMatch => JString(~"$="),
            SubstringMatch => JString(~"*="),
            Column => JString(~"||"),
            CDO => JString(~"<!--"),
            CDC => JString(~"-->"),

            Function(ref name, ref arguments)
            => JList(~[JString(~"function"), name.to_json()] + arguments.map(|a| a.to_json())),
            ParenthesisBlock(ref content)
            => JList(~[JString(~"()")] + content.map(|c| c.to_json())),
            SquareBracketBlock(ref content)
            => JList(~[JString(~"[]")] + content.map(|c| c.to_json())),
            CurlyBracketBlock(ref content)
            => JList(~[JString(~"{}")] + list_to_json(content)),

            BadURL => JList(~[JString(~"error"), JString(~"bad-url")]),
            BadString => JList(~[JString(~"error"), JString(~"bad-string")]),
            CloseParenthesis => JList(~[JString(~"error"), JString(~")")]),
            CloseSquareBracket => JList(~[JString(~"error"), JString(~"]")]),
            CloseCurlyBracket => JList(~[JString(~"error"), JString(~"}")]),
        }
    }
}
<commit_msg>Add some keyword color lookup benchmarks.<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 std::{str, run, task};
use std::rt::io;
use std::rt::io::Writer;
use extra::{tempfile, json};
use extra::json::ToJson;
use extra::test;

use super::*;
use ast::*;

fn write_whole_file(path: &Path, data: &str) {
    match io::file::open(path, io::Create, io::Write) {
        Some(mut writer) => writer.write(data.as_bytes()),
        None => fail!("could not open file"),
    }
}

fn almost_equals(a: &json::Json, b: &json::Json) -> bool {
    match (a, b) {
        (&json::Number(a), &json::Number(b)) => (a - b).abs() < 1e-6,
        (&json::String(ref a), &json::String(ref b)) => a == b,
        (&json::Boolean(a), &json::Boolean(b)) => a == b,
        (&json::List(ref a), &json::List(ref b))
            => a.iter().zip(b.iter()).all(|(ref a, ref b)| almost_equals(*a, *b)),
        (&json::Object(_), &json::Object(_)) => fail!(~"Not implemented"),
        (&json::Null, &json::Null) => true,
        _ => false,
    }
}

fn assert_json_eq(results: json::Json, expected: json::Json, message: ~str) {
    if !almost_equals(&results, &expected) {
        let temp = tempfile::TempDir::new("rust-cssparser-tests").unwrap();
        let results = results.to_pretty_str() + "\n";
        let expected = expected.to_pretty_str() + "\n";
        do task::try {
            let mut result_path = temp.path().clone();
            result_path.push("results.json");
            let mut expected_path = temp.path().clone();
            expected_path.push("expected.json");
            write_whole_file(&result_path, results);
            write_whole_file(&expected_path, expected);
            run::process_status("colordiff", [~"-u1000", result_path.display().to_str(),
                                              expected_path.display().to_str()]);
        };

        fail!(message)
    }
}

fn run_json_tests<T: ToJson>(json_data: &str, parse: &fn (input: ~str) -> T) {
    let items = match json::from_str(json_data) {
        Ok(json::List(items)) => items,
        _ => fail!("Invalid JSON")
    };
    assert!(items.len() % 2 == 0);
    let mut input: Option<~str> = None;
    for item in items.move_iter() {
        match (&input, item) {
            (&None, json::String(string)) => input = Some(string),
            (&Some(_), expected) => {
                let input = input.take_unwrap();
                let result = parse(input.to_owned()).to_json();
                assert_json_eq(result, expected, input);
            },
            _ => fail!("Unexpected JSON")
        };
    }
}

#[test]
fn component_value_list() {
    do run_json_tests(include_str!("css-parsing-tests/component_value_list.json")) |input| {
        tokenize(input).map(|(c, _)| c).to_owned_vec()
    }
}

#[test]
fn one_component_value() {
    do run_json_tests(include_str!("css-parsing-tests/one_component_value.json")) |input| {
        parse_one_component_value(tokenize(input))
    }
}

#[test]
fn declaration_list() {
    do run_json_tests(include_str!("css-parsing-tests/declaration_list.json")) |input| {
        parse_declaration_list(tokenize(input)).to_owned_vec()
    }
}

#[test]
fn one_declaration() {
    do run_json_tests(include_str!("css-parsing-tests/one_declaration.json")) |input| {
        parse_one_declaration(tokenize(input))
    }
}

#[test]
fn rule_list() {
    do run_json_tests(include_str!("css-parsing-tests/rule_list.json")) |input| {
        parse_rule_list(tokenize(input)).to_owned_vec()
    }
}

#[test]
fn stylesheet() {
    do run_json_tests(include_str!("css-parsing-tests/stylesheet.json")) |input| {
        parse_stylesheet_rules(tokenize(input)).to_owned_vec()
    }
}

#[test]
fn one_rule() {
    do run_json_tests(include_str!("css-parsing-tests/one_rule.json")) |input| {
        parse_one_rule(tokenize(input))
    }
}

fn run_color_tests(json_data: &str, to_json: &fn(result: Option<Color>) -> json::Json) {
    do run_json_tests(json_data) |input| {
        match parse_one_component_value(tokenize(input)) {
            Ok(component_value) => to_json(Color::parse(&component_value)),
            Err(_reason) => json::Null,
        }
    }
}

#[test]
fn color3() {
    run_color_tests(include_str!("css-parsing-tests/color3.json"), |c| c.to_json())
}

#[test]
fn color3_hsl() {
    run_color_tests(include_str!("css-parsing-tests/color3_hsl.json"), |c| c.to_json())
}

/// color3_keywords.json is different: R, G and B are in 0..255 rather than 0..1
#[test]
fn color3_keywords() {
    do run_color_tests(include_str!("css-parsing-tests/color3_keywords.json")) |c| {
        match c {
            Some(RGBA(RGBA { red: r, green: g, blue: b, alpha: a }))
            => (~[r * 255., g * 255., b * 255., a]).to_json(),
            Some(CurrentColor) => json::String(~"currentColor"),
            None => json::Null,
        }
    }
}

#[bench]
fn bench_color_lookup_red(b: &mut test::BenchHarness) {
    let ident = parse_one_component_value(tokenize("red")).unwrap();
    b.iter(|| assert!(Color::parse(&ident).is_some()));
}

#[bench]
fn bench_color_lookup_lightgoldenrodyellow(b: &mut test::BenchHarness) {
    let ident = parse_one_component_value(tokenize("lightgoldenrodyellow")).unwrap();
    b.iter(|| assert!(Color::parse(&ident).is_some()));
}

#[bench]
fn bench_color_lookup_fail(b: &mut test::BenchHarness) {
    let ident = parse_one_component_value(tokenize("lightgoldenrodyellowbazinga")).unwrap();
    b.iter(|| assert!(Color::parse(&ident).is_none()));
}

#[test]
fn nth() {
    do run_json_tests(include_str!("css-parsing-tests/An+B.json")) |input| {
        parse_nth(tokenize(input).map(|(c, _)| c).to_owned_vec())
    }
}

#[test]
fn serializer() {
    do run_json_tests(include_str!("css-parsing-tests/component_value_list.json")) |input| {
        let component_values = tokenize(input).map(|(c, _)| c).to_owned_vec();
        let serialized = component_values.iter().to_css();
        tokenize(serialized).map(|(c, _)| c).to_owned_vec()
    }
}

impl ToJson for Result<Rule, SyntaxError> {
    fn to_json(&self) -> json::Json {
        match *self {
            Ok(ref a) => a.to_json(),
            Err(ref b) => b.to_json(),
        }
    }
}

impl ToJson for Result<DeclarationListItem, SyntaxError> {
    fn to_json(&self) -> json::Json {
        match *self {
            Ok(ref a) => a.to_json(),
            Err(ref b) => b.to_json(),
        }
    }
}

impl ToJson for Result<Declaration, SyntaxError> {
    fn to_json(&self) -> json::Json {
        match *self {
            Ok(ref a) => a.to_json(),
            Err(ref b) => b.to_json(),
        }
    }
}

impl ToJson for Result<ComponentValue, SyntaxError> {
    fn to_json(&self) -> json::Json {
        match *self {
            Ok(ref a) => a.to_json(),
            Err(ref b) => b.to_json(),
        }
    }
}

impl ToJson for SyntaxError {
    fn to_json(&self) -> json::Json {
        json::List(~[json::String(~"error"), json::String(match self.reason {
            ErrEmptyInput => ~"empty",
            ErrExtraInput => ~"extra-input",
            _ => ~"invalid",
        })])
    }
}

impl ToJson for Color {
    fn to_json(&self) -> json::Json {
        match *self {
            RGBA(RGBA { red: r, green: g, blue: b, alpha: a }) => (~[r, g, b, a]).to_json(),
            CurrentColor => json::String(~"currentColor"),
        }
    }
}

impl ToJson for Rule {
    fn to_json(&self) -> json::Json {
        match *self {
            QualifiedRule(ref rule) => rule.to_json(),
            AtRule(ref rule) => rule.to_json(),
        }
    }
}

impl ToJson for DeclarationListItem {
    fn to_json(&self) -> json::Json {
        match *self {
            Declaration(ref declaration) => declaration.to_json(),
            Decl_AtRule(ref at_rule) => at_rule.to_json(),
        }
    }
}

fn list_to_json(list: &~[(ComponentValue, SourceLocation)]) -> ~[json::Json] {
    list.map(|tuple| {
        match *tuple {
            (ref c, _) => c.to_json()
        }
    })
}

impl ToJson for AtRule {
    fn to_json(&self) -> json::Json {
        match *self {
            AtRule{name: ref name, prelude: ref prelude, block: ref block, _}
            => json::List(~[json::String(~"at-rule"), name.to_json(),
                            prelude.to_json(), block.as_ref().map(list_to_json).to_json()])
        }
    }
}

impl ToJson for QualifiedRule {
    fn to_json(&self) -> json::Json {
        match *self {
            QualifiedRule{prelude: ref prelude, block: ref block, _}
            => json::List(~[json::String(~"qualified rule"),
                            prelude.to_json(), json::List(list_to_json(block))])
        }
    }
}

impl ToJson for Declaration {
    fn to_json(&self) -> json::Json {
        match *self {
            Declaration{name: ref name, value: ref value, important: ref important, _}
            =>  json::List(~[json::String(~"declaration"), name.to_json(),
                             value.to_json(), important.to_json()])
        }
    }
}

impl ToJson for ComponentValue {
    fn to_json(&self) -> json::Json {
        use JList = extra::json::List;
        use JString = extra::json::String;

        fn numeric(value: &NumericValue) -> ~[json::Json] {
            match *value {
                NumericValue{representation: ref r, value: ref v, int_value: ref i}
                => ~[r.to_json(), v.to_json(),
                     JString(match *i { Some(_) => ~"integer", _ => ~"number" })]
            }
        }

        match *self {
            Ident(ref value) => JList(~[JString(~"ident"), value.to_json()]),
            AtKeyword(ref value) => JList(~[JString(~"at-keyword"), value.to_json()]),
            Hash(ref value) => JList(~[JString(~"hash"), value.to_json(),
                                       JString(~"unrestricted")]),
            IDHash(ref value) => JList(~[JString(~"hash"), value.to_json(), JString(~"id")]),
            String(ref value) => JList(~[JString(~"string"), value.to_json()]),
            URL(ref value) => JList(~[JString(~"url"), value.to_json()]),
            Delim('\\') => JString(~"\\"),
            Delim(value) => JString(str::from_char(value)),

            Number(ref value) => JList(~[JString(~"number")] + numeric(value)),
            Percentage(ref value) => JList(~[JString(~"percentage")] + numeric(value)),
            Dimension(ref value, ref unit)
            => JList(~[JString(~"dimension")] + numeric(value) + ~[unit.to_json()]),

            UnicodeRange(start, end)
            => JList(~[JString(~"unicode-range"), start.to_json(), end.to_json()]),

            WhiteSpace => JString(~" "),
            Colon => JString(~":"),
            Semicolon => JString(~";"),
            Comma => JString(~","),
            IncludeMatch => JString(~"~="),
            DashMatch => JString(~"|="),
            PrefixMatch => JString(~"^="),
            SuffixMatch => JString(~"$="),
            SubstringMatch => JString(~"*="),
            Column => JString(~"||"),
            CDO => JString(~"<!--"),
            CDC => JString(~"-->"),

            Function(ref name, ref arguments)
            => JList(~[JString(~"function"), name.to_json()] + arguments.map(|a| a.to_json())),
            ParenthesisBlock(ref content)
            => JList(~[JString(~"()")] + content.map(|c| c.to_json())),
            SquareBracketBlock(ref content)
            => JList(~[JString(~"[]")] + content.map(|c| c.to_json())),
            CurlyBracketBlock(ref content)
            => JList(~[JString(~"{}")] + list_to_json(content)),

            BadURL => JList(~[JString(~"error"), JString(~"bad-url")]),
            BadString => JList(~[JString(~"error"), JString(~"bad-string")]),
            CloseParenthesis => JList(~[JString(~"error"), JString(~")")]),
            CloseSquareBracket => JList(~[JString(~"error"), JString(~"]")]),
            CloseCurlyBracket => JList(~[JString(~"error"), JString(~"}")]),
        }
    }
}
<|endoftext|>


<commit_before>use CL::*;
use hl::*;
use error::check;

// These are basically types that can be safely memcpyed.
trait VectorType {}

impl int: VectorType;
impl i32: VectorType;
impl u32: VectorType;
impl float: VectorType;
impl f64: VectorType;
impl f32: VectorType;

struct Vector<T: VectorType> {
    cl_buffer: cl_mem,
    size: uint,
    context: @ComputeContext,

    drop {
        clReleaseMemObject(self.cl_buffer);
    }
}

impl<T: VectorType> Vector<T> {
    static fn from_vec(ctx: @ComputeContext, v: &[const T]) -> Vector<T> {
        do vec::as_const_buf(v) |p, len| {
            let mut status = 0;
            let byte_size = len * sys::size_of::<T>() as libc::size_t;

            let buf = clCreateBuffer(ctx.ctx.ctx,
                                     CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR,
                                     byte_size,
                                     p as *libc::c_void,
                                     ptr::addr_of(&status));
            check(status, "Could not allocate buffer");

            //let status = clEnqueueWriteBuffer(
            //    ctx.q, buf, CL_TRUE, 0, byte_size, p as *libc::c_void,
            //    0, ptr::null(), ptr::null());

            Vector {
                cl_buffer: buf,
                size: len,
                context: ctx,
            }
        }
    }

    fn to_vec(self) -> ~[T] unsafe {
        let mut result = ~[];
        vec::reserve(&mut result, self.size);
        vec::raw::set_len(&mut result, self.size);
        do vec::as_imm_buf(result) |p, len| {
            clEnqueueReadBuffer(
                self.context.q.cqueue, self.cl_buffer, CL_TRUE, 0,
                len * sys::size_of::<T>() as libc::size_t,
                p as *libc::c_void, 0, ptr::null(), ptr::null());

        }
        result
    }
}

impl<T: VectorType> Vector<T>: ::hl::KernelArg {
    pure fn get_value(&self) -> (libc::size_t, *libc::c_void) {
        (sys::size_of::<cl_mem>() as libc::size_t,
         ptr::addr_of(&self.cl_buffer) as *libc::c_void)
    }
}

#[cfg(test)]
mod test {
    macro_rules! expect (
        ($test: expr, $expected: expr) => ({
            let test = $test;
            let expected = $expected;
            if test != expected {
                fail fmt!("Test failure in %s: expected %?, got %?",
                          stringify!($test),
                          expected, test)
            }
        })
    )

    #[test]
    fn gpu_vector() {
        let ctx = create_compute_context();

        let x = ~[1, 2, 3, 4, 5];
        let gx = Vector::from_vec(ctx, x);
        let y = gx.to_vec();
        expect!(x, y);
    }
}
<commit_msg>Marking some things as pub.<commit_after>use CL::*;
use hl::*;
use error::check;

// These are basically types that can be safely memcpyed.
trait VectorType {}

impl int: VectorType;
impl i32: VectorType;
impl u32: VectorType;
impl float: VectorType;
impl f64: VectorType;
impl f32: VectorType;

pub struct Vector<T: VectorType> {
    cl_buffer: cl_mem,
    size: uint,
    context: @ComputeContext,

    drop {
        clReleaseMemObject(self.cl_buffer);
    }
}

pub impl<T: VectorType> Vector<T> {
    static pub fn from_vec(ctx: @ComputeContext, v: &[const T]) -> Vector<T> {
        do vec::as_const_buf(v) |p, len| {
            let mut status = 0;
            let byte_size = len * sys::size_of::<T>() as libc::size_t;

            let buf = clCreateBuffer(ctx.ctx.ctx,
                                     CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR,
                                     byte_size,
                                     p as *libc::c_void,
                                     ptr::addr_of(&status));
            check(status, "Could not allocate buffer");

            //let status = clEnqueueWriteBuffer(
            //    ctx.q, buf, CL_TRUE, 0, byte_size, p as *libc::c_void,
            //    0, ptr::null(), ptr::null());

            Vector {
                cl_buffer: buf,
                size: len,
                context: ctx,
            }
        }
    }

    pub fn to_vec(self) -> ~[T] unsafe {
        let mut result = ~[];
        vec::reserve(&mut result, self.size);
        vec::raw::set_len(&mut result, self.size);
        do vec::as_imm_buf(result) |p, len| {
            clEnqueueReadBuffer(
                self.context.q.cqueue, self.cl_buffer, CL_TRUE, 0,
                len * sys::size_of::<T>() as libc::size_t,
                p as *libc::c_void, 0, ptr::null(), ptr::null());

        }
        result
    }
}

impl<T: VectorType> Vector<T>: ::hl::KernelArg {
    pure fn get_value(&self) -> (libc::size_t, *libc::c_void) {
        (sys::size_of::<cl_mem>() as libc::size_t,
         ptr::addr_of(&self.cl_buffer) as *libc::c_void)
    }
}

#[cfg(test)]
mod test {
    macro_rules! expect (
        ($test: expr, $expected: expr) => ({
            let test = $test;
            let expected = $expected;
            if test != expected {
                fail fmt!("Test failure in %s: expected %?, got %?",
                          stringify!($test),
                          expected, test)
            }
        })
    )

    #[test]
    fn gpu_vector() {
        let ctx = create_compute_context();

        let x = ~[1, 2, 3, 4, 5];
        let gx = Vector::from_vec(ctx, x);
        let y = gx.to_vec();
        expect!(x, y);
    }
}
<|endoftext|>


<commit_before>extern crate hyper;
#[macro_use(trace, is_file)]
extern crate rusty_cute_macros;
extern crate regex;

use std::io::{Read, Write};
use std::borrow::Borrow;

macro_rules! input {
    ($msg:expr) => {{
        use std::io::{Read, Write};
        print!($msg);
        std::io::stdout().flush().unwrap();
        std::io::stdin().bytes().next();
    }}
}

/// Extract tuple from date's string in format [yyyy-mm-dd]
fn get_date(str_date: &str) -> (usize, usize, usize) {
    let mut result: (usize, usize, usize) = (0, 0, 0);
    let mut date_split = str_date.split("-");

    result.0 = date_split.next().unwrap().parse::<usize>().unwrap_or(0);
    result.1 = date_split.next().unwrap().parse::<usize>().unwrap_or(0);
    result.2 = date_split.next().unwrap().parse::<usize>().unwrap_or(0);
    result
}

fn main() {
    println!("###################################################");
    println!("#Source: https://tuxproject.de/projects/vim/");
    println!("#Visit site to give thanks(donate button at bottom)");
    println!("###################################################\n");

    let mut http_client = hyper::client::Client::new();
    let mut tux_data: String = String::with_capacity(6200);
    let mut result = http_client.get("https://tuxproject.de/projects/vim").send().unwrap();

    if result.status != hyper::Ok {
        trace!("Failed to connect to tuxproject.de with result={}", result.status);
        return;
    }

    if result.read_to_string(&mut tux_data).unwrap_or(0) == 0 { trace!("Failed to retrieve data"); return; }
    let re_get_date = regex::Regex::new(r"(?m)\d{4}-\d{2}-\d{2}").unwrap();
    let vim_cur_date: (usize, usize, usize);

    if let Some(cap_date) = re_get_date.captures_iter(&tux_data).next() {
        vim_cur_date = get_date(cap_date.at(0).unwrap());
    }
    else { trace!("Failed to find build's date"); return; }

    drop(tux_data);
    drop(result);
    drop(re_get_date);
    //Get config file
    let mut config_file = match is_file!("vim_updater.cfg") {
        true => std::fs::File::open("vim_updater.cfg").unwrap(),
        false => std::fs::File::create("vim_updater.cfg").unwrap(),
    };
    let mut build_date: String = String::with_capacity(10);
    let to_update: bool;

    if config_file.read_to_string(&mut build_date).unwrap_or(0) == 0 { to_update = true; }
    else {
        let vim_old_date = get_date(build_date.borrow());
        to_update = vim_cur_date > vim_old_date;
    }

    if !to_update {
        println!("Vim is up-to-date");
        input!("Press Enter to exit...");
        return;
    }
    drop(build_date);
    drop(config_file);

    println!("Found new vim build:");
    println!("Date: {}-{}-{}", vim_cur_date.0, vim_cur_date.1, vim_cur_date.2);

    //Update config file
    if let Ok(mut file) = std::fs::File::create("vim_updater.cfg") {
        if file.write_fmt(format_args!("{}-{}-{}", vim_cur_date.0, vim_cur_date.1, vim_cur_date.2)).is_err() {
            trace!("Failed to write new data into config file");
            return;
        }
    }
    else { trace!("Unable to update config file"); return; }

    drop(vim_cur_date);
    //download new builds
    let mut download_res = http_client.get("https://tuxproject.de/projects/vim/complete-x64.7z").send().unwrap();
    if download_res.status != hyper::Ok { trace!("Failed to download vim build. Response status={}", download_res.status); return; }

    if let Ok(mut file) = std::fs::File::create("vim-x64.7z") {
        if std::io::copy(&mut download_res, &mut file).is_err() { trace!("Unable to save file"); return; }
    }
    else { trace!("Unable to create file"); return; }

    println!("Succesfully downloaded vim-x64.7z");
    let mut download_res = http_client.get("https://tuxproject.de/projects/vim/complete-x86.7z").send().unwrap();
    if download_res.status != hyper::Ok { trace!("Failed to download vim build. Response status={}", download_res.status); return; }

    if let Ok(mut file) = std::fs::File::create("vim-x86.7z") {
        if std::io::copy(&mut download_res, &mut file).is_err() { trace!("Unable to save file"); return; }
    }
    else { trace!("Unable to create file"); return; }
    println!("Succesfully downloaded vim-x86.7z");

    input!("Press Enter to exit...");
}
<commit_msg>Rust vimp_updater add RETURN macro<commit_after>extern crate hyper;
#[macro_use(trace, is_file)]
extern crate rusty_cute_macros;
extern crate regex;

use std::io::{Read, Write};
use std::borrow::Borrow;

/// RETURN macro.
///
/// @msg_type - macro identfier which will be called to print
macro_rules! RETURN {
    (msg_type=>$msg_type:ident, $($arg:tt)+) => {{
        $msg_type!($($arg)+);
        print!("Press Enter to exit...");
        std::io::stdout().flush().unwrap();
        std::io::stdin().bytes().next();
        return;
    }};
    ($($arg:tt)+) => {{ RETURN!(msg_type=>println, $($arg)+); }};
}

/// Extract tuple from date's string in format [yyyy-mm-dd]
fn get_date(str_date: &str) -> (usize, usize, usize) {
    let mut result: (usize, usize, usize) = (0, 0, 0);
    let mut date_split = str_date.split("-");

    result.0 = date_split.next().unwrap().parse::<usize>().unwrap_or(0);
    result.1 = date_split.next().unwrap().parse::<usize>().unwrap_or(0);
    result.2 = date_split.next().unwrap().parse::<usize>().unwrap_or(0);
    result
}

fn main() {
    println!("###################################################");
    println!("#Source: https://tuxproject.de/projects/vim/");
    println!("#Visit site to give thanks(donate button at bottom)");
    println!("###################################################\n");

    let mut http_client = hyper::client::Client::new();
    let mut tux_data: String = String::with_capacity(6200);
    let mut result = http_client.get("https://tuxproject.de/projects/vim").send().unwrap();

    if result.status != hyper::Ok {
        RETURN!(msg_type=>trace, "Failed to connect to tuxproject.de with result={}", result.status);
    }

    if result.read_to_string(&mut tux_data).unwrap_or(0) == 0 {
        RETURN!(msg_type=>trace, "Failed to retrieve data");
    }
    let re_get_date = regex::Regex::new(r"(?m)\d{4}-\d{2}-\d{2}").unwrap();
    let vim_cur_date: (usize, usize, usize);

    if let Some(cap_date) = re_get_date.captures_iter(&tux_data).next() {
        vim_cur_date = get_date(cap_date.at(0).unwrap());
    }
    else {
        RETURN!(msg_type=>trace, "Failed to find build's date");
    }

    drop(tux_data);
    drop(result);
    drop(re_get_date);
    //Get config file
    let mut config_file = match is_file!("vim_updater.cfg") {
        true => std::fs::File::open("vim_updater.cfg").unwrap(),
        false => std::fs::File::create("vim_updater.cfg").unwrap(),
    };
    let mut build_date: String = String::with_capacity(10);
    let to_update: bool;

    if config_file.read_to_string(&mut build_date).unwrap_or(0) == 0 { to_update = true; }
    else {
        let vim_old_date = get_date(build_date.borrow());
        to_update = vim_cur_date > vim_old_date;
    }

    if !to_update {
        RETURN!("Vim is up-to-date");
    }
    drop(build_date);
    drop(config_file);

    println!("Found new vim build:");
    println!("Date: {}-{}-{}", vim_cur_date.0, vim_cur_date.1, vim_cur_date.2);

    //Update config file
    if let Ok(mut file) = std::fs::File::create("vim_updater.cfg") {
        if file.write_fmt(format_args!("{}-{}-{}", vim_cur_date.0, vim_cur_date.1, vim_cur_date.2)).is_err() {
            RETURN!(msg_type=>trace, "Failed to write new data into config file");
        }
    }
    else {
        RETURN!(msg_type=>trace, "Unable to update config file");
    }

    drop(vim_cur_date);
    //download new builds
    let mut download_res = http_client.get("https://tuxproject.de/projects/vim/complete-x64.7z").send().unwrap();
    if download_res.status != hyper::Ok {
        RETURN!(msg_type=>trace, "Failed to download vim build. Response status={}", download_res.status);
    }

    if let Ok(mut file) = std::fs::File::create("vim-x64.7z") {
        if std::io::copy(&mut download_res, &mut file).is_err() {
            RETURN!(msg_type=>trace, "Unable to save file");
        }
    }
    else {
        RETURN!(msg_type=>trace, "Unable to create file");
    }

    println!("Succesfully downloaded vim-x64.7z");
    let mut download_res = http_client.get("https://tuxproject.de/projects/vim/complete-x86.7z").send().unwrap();
    if download_res.status != hyper::Ok {
        RETURN!(msg_type=>trace, "Failed to download vim build. Response status={}", download_res.status);
    }

    if let Ok(mut file) = std::fs::File::create("vim-x86.7z") {
        if std::io::copy(&mut download_res, &mut file).is_err() {
            RETURN!(msg_type=>trace, "Unable to save file");
        }
    }
    else {
        RETURN!(msg_type=>trace, "Unable to create file");
    }

    RETURN!("Succesfully downloaded vim-x86.7z");
}
<|endoftext|>


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

use build::{BlockAnd, BlockAndExtension, Builder};
use hair::*;
use rustc::mir::*;
use rustc::hir;
use syntax_pos::Span;

impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
    pub fn ast_block(&mut self,
                     destination: &Place<'tcx>,
                     block: BasicBlock,
                     ast_block: &'tcx hir::Block,
                     source_info: SourceInfo)
                     -> BlockAnd<()> {
        let Block {
            region_scope,
            opt_destruction_scope,
            span,
            stmts,
            expr,
            targeted_by_break,
            safety_mode
        } =
            self.hir.mirror(ast_block);
        self.in_opt_scope(opt_destruction_scope.map(|de|(de, source_info)), block, move |this| {
            this.in_scope((region_scope, source_info), LintLevel::Inherited, block, move |this| {
                if targeted_by_break {
                    // This is a `break`-able block (currently only `catch { ... }`)
                    let exit_block = this.cfg.start_new_block();
                    let block_exit = this.in_breakable_scope(
                        None, exit_block, destination.clone(), |this| {
                            this.ast_block_stmts(destination, block, span, stmts, expr,
                                                 safety_mode)
                        });
                    this.cfg.terminate(unpack!(block_exit), source_info,
                                       TerminatorKind::Goto { target: exit_block });
                    exit_block.unit()
                } else {
                    this.ast_block_stmts(destination, block, span, stmts, expr,
                                         safety_mode)
                }
            })
        })
    }

    fn ast_block_stmts(&mut self,
                       destination: &Place<'tcx>,
                       mut block: BasicBlock,
                       span: Span,
                       stmts: Vec<StmtRef<'tcx>>,
                       expr: Option<ExprRef<'tcx>>,
                       safety_mode: BlockSafety)
                       -> BlockAnd<()> {
        let this = self;

        // This convoluted structure is to avoid using recursion as we walk down a list
        // of statements. Basically, the structure we get back is something like:
        //
        //    let x = <init> in {
        //       expr1;
        //       let y = <init> in {
        //           expr2;
        //           expr3;
        //           ...
        //       }
        //    }
        //
        // The let bindings are valid till the end of block so all we have to do is to pop all
        // the let-scopes at the end.
        //
        // First we build all the statements in the block.
        let mut let_scope_stack = Vec::with_capacity(8);
        let outer_visibility_scope = this.visibility_scope;
        let outer_push_unsafe_count = this.push_unsafe_count;
        let outer_unpushed_unsafe = this.unpushed_unsafe;
        this.update_visibility_scope_for_safety_mode(span, safety_mode);

        let source_info = this.source_info(span);
        for stmt in stmts {
            let Stmt { kind, opt_destruction_scope } = this.hir.mirror(stmt);
            match kind {
                StmtKind::Expr { scope, expr } => {
                    unpack!(block = this.in_opt_scope(
                        opt_destruction_scope.map(|de|(de, source_info)), block, |this| {
                            let si = (scope, source_info);
                            this.in_scope(si, LintLevel::Inherited, block, |this| {
                                let expr = this.hir.mirror(expr);
                                this.stmt_expr(block, expr)
                            })
                        }));
                }
                StmtKind::Let {
                    remainder_scope,
                    init_scope,
                    pattern,
                    ty,
                    initializer,
                    lint_level
                } => {
                    // Enter the remainder scope, i.e. the bindings' destruction scope.
                    this.push_scope((remainder_scope, source_info));
                    let_scope_stack.push(remainder_scope);

                    // Declare the bindings, which may create a visibility scope.
                    let remainder_span = remainder_scope.span(this.hir.tcx(),
                                                              &this.hir.region_scope_tree);
                    let scope = this.declare_bindings(None, remainder_span, lint_level, &pattern);

                    // Evaluate the initializer, if present.
                    if let Some(init) = initializer {
                        unpack!(block = this.in_opt_scope(
                            opt_destruction_scope.map(|de|(de, source_info)), block, |this| {
                                let scope = (init_scope, source_info);
                                this.in_scope(scope, lint_level, block, |this| {
                                    this.expr_into_pattern(block, ty, pattern, init)
                                })
                            }));
                    } else {
                        this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| {
                            this.storage_live_binding(block, node, span);
                            if let Some(ty) = ty {
                                this.user_assert_ty(block, ty, node, span);
                            }
                            this.schedule_drop_for_binding(node, span);
                        })
                    }

                    // Enter the visibility scope, after evaluating the initializer.
                    if let Some(visibility_scope) = scope {
                        this.visibility_scope = visibility_scope;
                    }
                }
            }
        }
        // Then, the block may have an optional trailing expression which is a “return” value
        // of the block.
        if let Some(expr) = expr {
            unpack!(block = this.into(destination, block, expr));
        } else {
            // If a block has no trailing expression, then it is given an implicit return type.
            // This return type is usually `()`, unless the block is diverging, in which case the
            // return type is `!`. For the unit type, we need to actually return the unit, but in
            // the case of `!`, no return value is required, as the block will never return.
            let tcx = this.hir.tcx();
            let ty = destination.ty(&this.local_decls, tcx).to_ty(tcx);
            if ty.is_nil() {
                // We only want to assign an implicit `()` as the return value of the block if the
                // block does not diverge. (Otherwise, we may try to assign a unit to a `!`-type.)
                this.cfg.push_assign_unit(block, source_info, destination);
            }
        }
        // Finally, we pop all the let scopes before exiting out from the scope of block
        // itself.
        for scope in let_scope_stack.into_iter().rev() {
            unpack!(block = this.pop_scope((scope, source_info), block));
        }
        // Restore the original visibility scope.
        this.visibility_scope = outer_visibility_scope;
        this.push_unsafe_count = outer_push_unsafe_count;
        this.unpushed_unsafe = outer_unpushed_unsafe;
        block.unit()
    }

    /// If we are changing the safety mode, create a new visibility scope
    fn update_visibility_scope_for_safety_mode(&mut self,
                                               span: Span,
                                               safety_mode: BlockSafety)
    {
        debug!("update_visibility_scope_for({:?}, {:?})", span, safety_mode);
        let new_unsafety = match safety_mode {
            BlockSafety::Safe => None,
            BlockSafety::ExplicitUnsafe(node_id) => {
                assert_eq!(self.push_unsafe_count, 0);
                match self.unpushed_unsafe {
                    Safety::Safe => {}
                    _ => return
                }
                self.unpushed_unsafe = Safety::ExplicitUnsafe(node_id);
                Some(Safety::ExplicitUnsafe(node_id))
            }
            BlockSafety::PushUnsafe => {
                self.push_unsafe_count += 1;
                Some(Safety::BuiltinUnsafe)
            }
            BlockSafety::PopUnsafe => {
                self.push_unsafe_count =
                    self.push_unsafe_count.checked_sub(1).unwrap_or_else(|| {
                        span_bug!(span, "unsafe count underflow")
                    });
                if self.push_unsafe_count == 0 {
                    Some(self.unpushed_unsafe)
                } else {
                    None
                }
            }
        };

        if let Some(unsafety) = new_unsafety {
            self.visibility_scope = self.new_visibility_scope(
                span, LintLevel::Inherited, Some(unsafety));
        }
    }
}
<commit_msg>Temporarily only adding UserAssertTy on binding patterns.<commit_after>// Copyright 2015 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.

use build::{BlockAnd, BlockAndExtension, Builder};
use hair::*;
use rustc::mir::*;
use rustc::hir;
use syntax_pos::Span;

impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
    pub fn ast_block(&mut self,
                     destination: &Place<'tcx>,
                     block: BasicBlock,
                     ast_block: &'tcx hir::Block,
                     source_info: SourceInfo)
                     -> BlockAnd<()> {
        let Block {
            region_scope,
            opt_destruction_scope,
            span,
            stmts,
            expr,
            targeted_by_break,
            safety_mode
        } =
            self.hir.mirror(ast_block);
        self.in_opt_scope(opt_destruction_scope.map(|de|(de, source_info)), block, move |this| {
            this.in_scope((region_scope, source_info), LintLevel::Inherited, block, move |this| {
                if targeted_by_break {
                    // This is a `break`-able block (currently only `catch { ... }`)
                    let exit_block = this.cfg.start_new_block();
                    let block_exit = this.in_breakable_scope(
                        None, exit_block, destination.clone(), |this| {
                            this.ast_block_stmts(destination, block, span, stmts, expr,
                                                 safety_mode)
                        });
                    this.cfg.terminate(unpack!(block_exit), source_info,
                                       TerminatorKind::Goto { target: exit_block });
                    exit_block.unit()
                } else {
                    this.ast_block_stmts(destination, block, span, stmts, expr,
                                         safety_mode)
                }
            })
        })
    }

    fn ast_block_stmts(&mut self,
                       destination: &Place<'tcx>,
                       mut block: BasicBlock,
                       span: Span,
                       stmts: Vec<StmtRef<'tcx>>,
                       expr: Option<ExprRef<'tcx>>,
                       safety_mode: BlockSafety)
                       -> BlockAnd<()> {
        let this = self;

        // This convoluted structure is to avoid using recursion as we walk down a list
        // of statements. Basically, the structure we get back is something like:
        //
        //    let x = <init> in {
        //       expr1;
        //       let y = <init> in {
        //           expr2;
        //           expr3;
        //           ...
        //       }
        //    }
        //
        // The let bindings are valid till the end of block so all we have to do is to pop all
        // the let-scopes at the end.
        //
        // First we build all the statements in the block.
        let mut let_scope_stack = Vec::with_capacity(8);
        let outer_visibility_scope = this.visibility_scope;
        let outer_push_unsafe_count = this.push_unsafe_count;
        let outer_unpushed_unsafe = this.unpushed_unsafe;
        this.update_visibility_scope_for_safety_mode(span, safety_mode);

        let source_info = this.source_info(span);
        for stmt in stmts {
            let Stmt { kind, opt_destruction_scope } = this.hir.mirror(stmt);
            match kind {
                StmtKind::Expr { scope, expr } => {
                    unpack!(block = this.in_opt_scope(
                        opt_destruction_scope.map(|de|(de, source_info)), block, |this| {
                            let si = (scope, source_info);
                            this.in_scope(si, LintLevel::Inherited, block, |this| {
                                let expr = this.hir.mirror(expr);
                                this.stmt_expr(block, expr)
                            })
                        }));
                }
                StmtKind::Let {
                    remainder_scope,
                    init_scope,
                    pattern,
                    ty,
                    initializer,
                    lint_level
                } => {
                    // Enter the remainder scope, i.e. the bindings' destruction scope.
                    this.push_scope((remainder_scope, source_info));
                    let_scope_stack.push(remainder_scope);

                    // Declare the bindings, which may create a visibility scope.
                    let remainder_span = remainder_scope.span(this.hir.tcx(),
                                                              &this.hir.region_scope_tree);
                    let scope = this.declare_bindings(None, remainder_span, lint_level, &pattern);

                    // Evaluate the initializer, if present.
                    if let Some(init) = initializer {
                        unpack!(block = this.in_opt_scope(
                            opt_destruction_scope.map(|de|(de, source_info)), block, |this| {
                                let scope = (init_scope, source_info);
                                this.in_scope(scope, lint_level, block, |this| {
                                    this.expr_into_pattern(block, ty, pattern, init)
                                })
                            }));
                    } else {
                        // FIXME: We currently only insert `UserAssertTy` statements for patterns
                        // that are bindings, this is as we do not want to deconstruct the type
                        // being assertion to match the pattern.
                        if let PatternKind::Binding { var, .. } = *pattern.kind {
                            if let Some(ty) = ty {
                                this.user_assert_ty(block, ty, var, span);
                            }
                        }

                        this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| {
                            this.storage_live_binding(block, node, span);
                            this.schedule_drop_for_binding(node, span);
                        })
                    }

                    // Enter the visibility scope, after evaluating the initializer.
                    if let Some(visibility_scope) = scope {
                        this.visibility_scope = visibility_scope;
                    }
                }
            }
        }
        // Then, the block may have an optional trailing expression which is a “return” value
        // of the block.
        if let Some(expr) = expr {
            unpack!(block = this.into(destination, block, expr));
        } else {
            // If a block has no trailing expression, then it is given an implicit return type.
            // This return type is usually `()`, unless the block is diverging, in which case the
            // return type is `!`. For the unit type, we need to actually return the unit, but in
            // the case of `!`, no return value is required, as the block will never return.
            let tcx = this.hir.tcx();
            let ty = destination.ty(&this.local_decls, tcx).to_ty(tcx);
            if ty.is_nil() {
                // We only want to assign an implicit `()` as the return value of the block if the
                // block does not diverge. (Otherwise, we may try to assign a unit to a `!`-type.)
                this.cfg.push_assign_unit(block, source_info, destination);
            }
        }
        // Finally, we pop all the let scopes before exiting out from the scope of block
        // itself.
        for scope in let_scope_stack.into_iter().rev() {
            unpack!(block = this.pop_scope((scope, source_info), block));
        }
        // Restore the original visibility scope.
        this.visibility_scope = outer_visibility_scope;
        this.push_unsafe_count = outer_push_unsafe_count;
        this.unpushed_unsafe = outer_unpushed_unsafe;
        block.unit()
    }

    /// If we are changing the safety mode, create a new visibility scope
    fn update_visibility_scope_for_safety_mode(&mut self,
                                               span: Span,
                                               safety_mode: BlockSafety)
    {
        debug!("update_visibility_scope_for({:?}, {:?})", span, safety_mode);
        let new_unsafety = match safety_mode {
            BlockSafety::Safe => None,
            BlockSafety::ExplicitUnsafe(node_id) => {
                assert_eq!(self.push_unsafe_count, 0);
                match self.unpushed_unsafe {
                    Safety::Safe => {}
                    _ => return
                }
                self.unpushed_unsafe = Safety::ExplicitUnsafe(node_id);
                Some(Safety::ExplicitUnsafe(node_id))
            }
            BlockSafety::PushUnsafe => {
                self.push_unsafe_count += 1;
                Some(Safety::BuiltinUnsafe)
            }
            BlockSafety::PopUnsafe => {
                self.push_unsafe_count =
                    self.push_unsafe_count.checked_sub(1).unwrap_or_else(|| {
                        span_bug!(span, "unsafe count underflow")
                    });
                if self.push_unsafe_count == 0 {
                    Some(self.unpushed_unsafe)
                } else {
                    None
                }
            }
        };

        if let Some(unsafety) = new_unsafety {
            self.visibility_scope = self.new_visibility_scope(
                span, LintLevel::Inherited, Some(unsafety));
        }
    }
}
<|endoftext|>


<commit_before>use cuckoofilter::*;
use index::EntryKey;
use index::Slice;
use itertools::Itertools;
use parking_lot::RwLock;
use ram::types::Id;
use std::cell::RefCell;
use std::collections::hash_map::DefaultHasher;
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::fmt::Debug;
use std::mem;
use std::sync::Arc;

// LevelTree items cannot been added or removed individually
// Items must been merged from higher level in bulk
// Deletion will be performed when merging to or from higher level tree
// Because tree update will not to be performed in parallel. Unlike memtable, a single r/w lock
// should be sufficient. Thus concurrency control will be simple and efficient.

type Tombstones = BTreeSet<EntryKey>;

pub struct LevelTree<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    index: BTreeMap<EntryKey, SSPage<S>>,
    tombstones: Tombstones,
    filter: CuckooFilter<DefaultHasher>,
}
struct SSPage<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    slice: S,
}

impl<S> LevelTree<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    pub fn new() -> Self {
        Self {
            index: BTreeMap::new(),
            tombstones: Tombstones::new(),
            filter: CuckooFilter::new(), // TODO: carefully set the capacity
        }
    }

    pub fn merge(&mut self, mut source: Vec<EntryKey>, tombstones: &mut Tombstones) {
        let (keys_to_removed, mut merged) = {
            let (target_keys, target_pages) : (Vec<_>, Vec<_>) = {
                let first = source.first().unwrap();
                let last = source.last().unwrap();
                self.index.range_mut::<EntryKey, _>(first ..= last).unzip()
            };
            let page_size = target_pages.first().unwrap().slice.len();
            let mut target = target_pages
                .into_iter()
                .map(|p| p.slice.as_slice())
                .flat_map(|ps| ps)
                .map(|x| mem::replace(x, EntryKey::default()))
                .collect_vec();

            let mut merged: Vec<S> = vec![S::init()];
            let src_len = source.len();
            let tgt_len = target.len();
            let mut srci = 0;
            let mut tgti = 0;

            let mut merging_slice_i = 0;

            while srci < src_len || tgti < tgt_len {
                let mut lowest = if srci >= src_len {
                    // source overflowed
                    tgti += 1;
                    &mut target[tgti - 1]
                } else if tgti >= tgt_len {
                    // target overflowed
                    srci += 1;
                    &mut source[srci - 1]
                } else {
                    // normal case, compare
                    let t = &mut target[tgti];
                    let s = &mut source[srci];
                    if t <= s {
                        tgti += 1;
                        t
                    } else {
                        srci += 1;
                        s
                    }
                };
                mem::swap(&mut merged.last_mut().unwrap().as_slice()[merging_slice_i], lowest);
                merging_slice_i += 1;
                if merging_slice_i >= page_size {
                    merging_slice_i = 0;
                    merged.push(S::init());
                }
            }
            if merging_slice_i == 0 {
                let merged_len = merged.len();
                merged.remove( merged_len - 1);
            }
            (target_keys.into_iter().map(|x| x.clone()).collect_vec(), merged)
        };

        for k in keys_to_removed {
            self.index.remove(&k).unwrap();
        }

        for mut page in merged {
            let index = page.as_slice()[0].clone();
            self.index.insert(index, SSPage { slice: page });
        }
    }
}

pub trait SortableEntrySlice: Sized + Slice<Item = EntryKey> {
    fn merge_sorted_with(
        &mut self,
        y_slice: &mut [EntryKey],
        xlen: &mut usize,
        ylen: &mut usize,
        xtombstones: &mut Tombstones,
        ytombstones: &mut Tombstones,
    ) -> Self {
        let mut x_pos = 0;
        let mut y_pos = 0;
        let mut pos = 0;
        let mut new_x = Self::init();
        let mut new_y = Self::init();
        {
            let mut x_slice = self.as_slice();
            let x_slice_len = x_slice.len();
            debug_assert!(*ylen <= x_slice_len);
            let mut new_slice_x = new_x.as_slice();
            let mut new_slice_y = new_y.as_slice();
            let mut new_x_len = 0;
            let mut new_y_len = 0;
            let mut use_slice_at = |slice: &mut [EntryKey], slice_pos: &mut usize| {
                let item = mem::replace(&mut slice[*slice_pos], EntryKey::default());
                *slice_pos += 1;
                if xtombstones.remove(&item) || ytombstones.remove(&item) {
                    None
                } else {
                    Some(item)
                }
            };
            loop {
                let item_or_removed = if x_pos < *xlen && y_pos < *ylen {
                    if x_slice[x_pos] < y_slice[y_pos] {
                        use_slice_at(x_slice, &mut x_pos)
                    } else {
                        use_slice_at(y_slice, &mut y_pos)
                    }
                } else if x_pos < *xlen {
                    use_slice_at(x_slice, &mut x_pos)
                } else if y_pos < *ylen {
                    use_slice_at(y_slice, &mut y_pos)
                } else {
                    break;
                };

                if let Some(item) = item_or_removed {
                    if pos < x_slice_len {
                        new_slice_x[pos] = item;
                        new_x_len += 1;
                    } else {
                        new_slice_y[pos - x_slice_len] = item;
                        new_y_len += 1;
                    }
                    pos += 1;
                }
            }
            *xlen = new_x_len;
            *ylen = new_y_len;
        }
        mem::swap(self, &mut new_x);
        return new_y;
    }
}

#[cfg(test)]
mod test {}
<commit_msg>handle tombstones<commit_after>use cuckoofilter::*;
use index::EntryKey;
use index::Slice;
use itertools::Itertools;
use parking_lot::RwLock;
use ram::types::Id;
use std::cell::RefCell;
use std::collections::hash_map::DefaultHasher;
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::fmt::Debug;
use std::mem;
use std::sync::Arc;

// LevelTree items cannot been added or removed individually
// Items must been merged from higher level in bulk
// Deletion will be performed when merging to or from higher level tree
// Because tree update will not to be performed in parallel. Unlike memtable, a single r/w lock
// should be sufficient. Thus concurrency control will be simple and efficient.

type Tombstones = BTreeSet<EntryKey>;

pub struct LevelTree<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    index: BTreeMap<EntryKey, SSPage<S>>,
    tombstones: Tombstones,
    filter: CuckooFilter<DefaultHasher>,
}
struct SSPage<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    slice: S,
}

impl<S> LevelTree<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    pub fn new() -> Self {
        Self {
            index: BTreeMap::new(),
            tombstones: Tombstones::new(),
            filter: CuckooFilter::new(), // TODO: carefully set the capacity
        }
    }

    pub fn merge(&mut self, mut source: Vec<EntryKey>, tombstones: &mut Tombstones) {
        let (keys_to_removed, mut merged) = {
            let (target_keys, target_pages) : (Vec<_>, Vec<_>) = {
                let first = source.first().unwrap();
                let last = source.last().unwrap();
                self.index.range_mut::<EntryKey, _>(first ..= last).unzip()
            };
            let page_size = target_pages.first().unwrap().slice.len();
            let mut target = target_pages
                .into_iter()
                .map(|p| p.slice.as_slice())
                .flat_map(|ps| ps)
                .map(|x| mem::replace(x, EntryKey::default()))
                .collect_vec();

            let mut merged: Vec<S> = vec![S::init()];
            let src_len = source.len();
            let tgt_len = target.len();
            let mut srci = 0;
            let mut tgti = 0;

            let mut merging_slice_i = 0;

            while srci < src_len || tgti < tgt_len {
                let mut from_source = false;
                let mut lowest = if srci >= src_len {
                    // source overflowed
                    tgti += 1;
                    &mut target[tgti - 1]
                } else if tgti >= tgt_len {
                    // target overflowed
                    srci += 1;
                    from_source = true;
                    &mut source[srci - 1]
                } else {
                    // normal case, compare
                    let t = &mut target[tgti];
                    let s = &mut source[srci];
                    if t <= s {
                        tgti += 1;
                        t
                    } else {
                        srci += 1;
                        from_source = true;
                        s
                    }
                };
                if from_source {
                    if tombstones.remove(lowest) {
                        continue
                    }
                } else {
                    if self.tombstones.remove(lowest) {
                        continue
                    }
                }
                mem::swap(&mut merged.last_mut().unwrap().as_slice()[merging_slice_i], lowest);
                merging_slice_i += 1;
                if merging_slice_i >= page_size {
                    merging_slice_i = 0;
                    merged.push(S::init());
                }
            }
            if merging_slice_i == 0 {
                let merged_len = merged.len();
                merged.remove( merged_len - 1);
            }
            (target_keys.into_iter().map(|x| x.clone()).collect_vec(), merged)
        };

        for k in keys_to_removed {
            self.index.remove(&k).unwrap();
        }

        for mut page in merged {
            let index = page.as_slice()[0].clone();
            self.index.insert(index, SSPage { slice: page });
        }
    }
}

pub trait SortableEntrySlice: Sized + Slice<Item = EntryKey> {
    fn merge_sorted_with(
        &mut self,
        y_slice: &mut [EntryKey],
        xlen: &mut usize,
        ylen: &mut usize,
        xtombstones: &mut Tombstones,
        ytombstones: &mut Tombstones,
    ) -> Self {
        let mut x_pos = 0;
        let mut y_pos = 0;
        let mut pos = 0;
        let mut new_x = Self::init();
        let mut new_y = Self::init();
        {
            let mut x_slice = self.as_slice();
            let x_slice_len = x_slice.len();
            debug_assert!(*ylen <= x_slice_len);
            let mut new_slice_x = new_x.as_slice();
            let mut new_slice_y = new_y.as_slice();
            let mut new_x_len = 0;
            let mut new_y_len = 0;
            let mut use_slice_at = |slice: &mut [EntryKey], slice_pos: &mut usize| {
                let item = mem::replace(&mut slice[*slice_pos], EntryKey::default());
                *slice_pos += 1;
                if xtombstones.remove(&item) || ytombstones.remove(&item) {
                    None
                } else {
                    Some(item)
                }
            };
            loop {
                let item_or_removed = if x_pos < *xlen && y_pos < *ylen {
                    if x_slice[x_pos] < y_slice[y_pos] {
                        use_slice_at(x_slice, &mut x_pos)
                    } else {
                        use_slice_at(y_slice, &mut y_pos)
                    }
                } else if x_pos < *xlen {
                    use_slice_at(x_slice, &mut x_pos)
                } else if y_pos < *ylen {
                    use_slice_at(y_slice, &mut y_pos)
                } else {
                    break;
                };

                if let Some(item) = item_or_removed {
                    if pos < x_slice_len {
                        new_slice_x[pos] = item;
                        new_x_len += 1;
                    } else {
                        new_slice_y[pos - x_slice_len] = item;
                        new_y_len += 1;
                    }
                    pos += 1;
                }
            }
            *xlen = new_x_len;
            *ylen = new_y_len;
        }
        mem::swap(self, &mut new_x);
        return new_y;
    }
}

#[cfg(test)]
mod test {}
<|endoftext|>


<commit_before>// Copyright 2018 The Grin Developers
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Logging wrapper to be used throughout all crates in the workspace
use std::ops::Deref;
use Mutex;

use backtrace::Backtrace;
use std::{panic, thread};

use types::{LogLevel, LoggingConfig};

use log::{LevelFilter, Record};
use log4rs;
use log4rs::append::console::ConsoleAppender;
use log4rs::append::file::FileAppender;
use log4rs::append::rolling_file::{
	policy::compound::roll::fixed_window::FixedWindowRoller,
	policy::compound::trigger::size::SizeTrigger, policy::compound::CompoundPolicy,
	RollingFileAppender,
};
use log4rs::append::Append;
use log4rs::config::{Appender, Config, Root};
use log4rs::encode::pattern::PatternEncoder;
use log4rs::filter::{threshold::ThresholdFilter, Filter, Response};

fn convert_log_level(in_level: &LogLevel) -> LevelFilter {
	match *in_level {
		LogLevel::Info => LevelFilter::Info,
		LogLevel::Warning => LevelFilter::Warn,
		LogLevel::Debug => LevelFilter::Debug,
		LogLevel::Trace => LevelFilter::Trace,
		LogLevel::Error => LevelFilter::Error,
	}
}

lazy_static! {
	/// Flag to observe whether logging was explicitly initialised (don't output otherwise)
	static ref WAS_INIT: Mutex<bool> = Mutex::new(false);
	/// Flag to observe whether tui is running, and we therefore don't want to attempt to write
	/// panics to stdout
	static ref TUI_RUNNING: Mutex<bool> = Mutex::new(false);
	/// Static Logging configuration, should only be set once, before first logging call
	static ref LOGGING_CONFIG: Mutex<LoggingConfig> = Mutex::new(LoggingConfig::default());
}

const LOGGING_PATTERN: &str = "{d(%Y%m%d %H:%M:%S%.3f)} {h({l})} {M} - {m}{n}";

/// This filter is rejecting messages that doesn't start with "grin"
/// in order to save log space for only Grin-related records
#[derive(Debug)]
struct GrinFilter;

impl Filter for GrinFilter {
	fn filter(&self, record: &Record) -> Response {
		if let Some(module_path) = record.module_path() {
			if module_path.starts_with("grin") {
				return Response::Neutral;
			}
		}

		Response::Reject
	}
}

/// Initialize the logger with the given configuration
pub fn init_logger(config: Option<LoggingConfig>) {
	if let Some(c) = config {
		let tui_running = c.tui_running.unwrap_or(false);
		if tui_running {
			let mut tui_running_ref = TUI_RUNNING.lock();
			*tui_running_ref = true;
		}

		// Save current logging configuration
		let mut config_ref = LOGGING_CONFIG.lock();
		*config_ref = c.clone();

		let level_stdout = convert_log_level(&c.stdout_log_level);
		let level_file = convert_log_level(&c.file_log_level);
		let level_minimum;

		// Determine minimum logging level for Root logger
		if level_stdout > level_file {
			level_minimum = level_stdout;
		} else {
			level_minimum = level_file;
		}

		// Start logger
		let stdout = ConsoleAppender::builder()
			.encoder(Box::new(PatternEncoder::new(&LOGGING_PATTERN)))
			.build();

		let mut root = Root::builder();

		let mut appenders = vec![];

		if c.log_to_stdout && !tui_running {
			let filter = Box::new(ThresholdFilter::new(level_stdout));
			appenders.push(
				Appender::builder()
					.filter(filter)
					.filter(Box::new(GrinFilter))
					.build("stdout", Box::new(stdout)),
			);

			root = root.appender("stdout");
		}

		if c.log_to_file {
			// If maximum log size is specified, use rolling file appender
			// or use basic one otherwise
			let filter = Box::new(ThresholdFilter::new(level_file));
			let file: Box<Append> = {
				if let Some(size) = c.log_max_size {
					let roller = FixedWindowRoller::builder()
						.build(&format!("{}.{{}}.gz", c.log_file_path), 32)
						.unwrap();
					let trigger = SizeTrigger::new(size);

					let policy = CompoundPolicy::new(Box::new(trigger), Box::new(roller));

					Box::new(
						RollingFileAppender::builder()
							.append(c.log_file_append)
							.encoder(Box::new(PatternEncoder::new(&LOGGING_PATTERN)))
							.build(c.log_file_path, Box::new(policy))
							.unwrap(),
					)
				} else {
					Box::new(
						FileAppender::builder()
							.append(c.log_file_append)
							.encoder(Box::new(PatternEncoder::new(&LOGGING_PATTERN)))
							.build(c.log_file_path)
							.unwrap(),
					)
				}
			};

			appenders.push(
				Appender::builder()
					.filter(filter)
					.filter(Box::new(GrinFilter))
					.build("file", file),
			);
			root = root.appender("file");
		}

		let config = Config::builder()
			.appenders(appenders)
			.build(root.build(level_minimum))
			.unwrap();

		let _ = log4rs::init_config(config).unwrap();

		info!(
			"log4rs is initialized, file level: {:?}, stdout level: {:?}, min. level: {:?}",
			level_file, level_stdout, level_minimum
		);

		// Mark logger as initialized
		let mut was_init_ref = WAS_INIT.lock();
		*was_init_ref = true;
	}

	send_panic_to_log();
}

/// Initializes the logger for unit and integration tests
pub fn init_test_logger() {
	let mut was_init_ref = WAS_INIT.lock();
	if *was_init_ref.deref() {
		return;
	}
	let mut logger = LoggingConfig::default();
	logger.log_to_file = false;
	logger.stdout_log_level = LogLevel::Debug;
	let mut config_ref = LOGGING_CONFIG.lock();
	*config_ref = logger;
	*was_init_ref = true;
}

/// hook to send panics to logs as well as stderr
fn send_panic_to_log() {
	panic::set_hook(Box::new(|info| {
		let backtrace = Backtrace::new();

		let thread = thread::current();
		let thread = thread.name().unwrap_or("unnamed");

		let msg = match info.payload().downcast_ref::<&'static str>() {
			Some(s) => *s,
			None => match info.payload().downcast_ref::<String>() {
				Some(s) => &**s,
				None => "Box<Any>",
			},
		};

		match info.location() {
			Some(location) => {
				error!(
					"\nthread '{}' panicked at '{}': {}:{}{:?}\n\n",
					thread,
					msg,
					location.file(),
					location.line(),
					backtrace
				);
			}
			None => error!("thread '{}' panicked at '{}'{:?}", thread, msg, backtrace),
		}
		//also print to stderr
		let tui_running = TUI_RUNNING.lock().clone();
		if !tui_running {
			let config = LOGGING_CONFIG.lock();

			eprintln!(
				"Thread '{}' panicked with message:\n\"{}\"\nSee {} for further details.",
				thread, msg, config.log_file_path
			);
		}
	}));
}
<commit_msg>fix: init_test_logger update for log4rs (#1921)<commit_after>// Copyright 2018 The Grin Developers
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Logging wrapper to be used throughout all crates in the workspace
use std::ops::Deref;
use Mutex;

use backtrace::Backtrace;
use std::{panic, thread};

use types::{LogLevel, LoggingConfig};

use log::{LevelFilter, Record};
use log4rs;
use log4rs::append::console::ConsoleAppender;
use log4rs::append::file::FileAppender;
use log4rs::append::rolling_file::{
	policy::compound::roll::fixed_window::FixedWindowRoller,
	policy::compound::trigger::size::SizeTrigger, policy::compound::CompoundPolicy,
	RollingFileAppender,
};
use log4rs::append::Append;
use log4rs::config::{Appender, Config, Root};
use log4rs::encode::pattern::PatternEncoder;
use log4rs::filter::{threshold::ThresholdFilter, Filter, Response};

fn convert_log_level(in_level: &LogLevel) -> LevelFilter {
	match *in_level {
		LogLevel::Info => LevelFilter::Info,
		LogLevel::Warning => LevelFilter::Warn,
		LogLevel::Debug => LevelFilter::Debug,
		LogLevel::Trace => LevelFilter::Trace,
		LogLevel::Error => LevelFilter::Error,
	}
}

lazy_static! {
	/// Flag to observe whether logging was explicitly initialised (don't output otherwise)
	static ref WAS_INIT: Mutex<bool> = Mutex::new(false);
	/// Flag to observe whether tui is running, and we therefore don't want to attempt to write
	/// panics to stdout
	static ref TUI_RUNNING: Mutex<bool> = Mutex::new(false);
	/// Static Logging configuration, should only be set once, before first logging call
	static ref LOGGING_CONFIG: Mutex<LoggingConfig> = Mutex::new(LoggingConfig::default());
}

const LOGGING_PATTERN: &str = "{d(%Y%m%d %H:%M:%S%.3f)} {h({l})} {M} - {m}{n}";

/// This filter is rejecting messages that doesn't start with "grin"
/// in order to save log space for only Grin-related records
#[derive(Debug)]
struct GrinFilter;

impl Filter for GrinFilter {
	fn filter(&self, record: &Record) -> Response {
		if let Some(module_path) = record.module_path() {
			if module_path.starts_with("grin") {
				return Response::Neutral;
			}
		}

		Response::Reject
	}
}

/// Initialize the logger with the given configuration
pub fn init_logger(config: Option<LoggingConfig>) {
	if let Some(c) = config {
		let tui_running = c.tui_running.unwrap_or(false);
		if tui_running {
			let mut tui_running_ref = TUI_RUNNING.lock();
			*tui_running_ref = true;
		}

		// Save current logging configuration
		let mut config_ref = LOGGING_CONFIG.lock();
		*config_ref = c.clone();

		let level_stdout = convert_log_level(&c.stdout_log_level);
		let level_file = convert_log_level(&c.file_log_level);
		let level_minimum;

		// Determine minimum logging level for Root logger
		if level_stdout > level_file {
			level_minimum = level_stdout;
		} else {
			level_minimum = level_file;
		}

		// Start logger
		let stdout = ConsoleAppender::builder()
			.encoder(Box::new(PatternEncoder::new(&LOGGING_PATTERN)))
			.build();

		let mut root = Root::builder();

		let mut appenders = vec![];

		if c.log_to_stdout && !tui_running {
			let filter = Box::new(ThresholdFilter::new(level_stdout));
			appenders.push(
				Appender::builder()
					.filter(filter)
					.filter(Box::new(GrinFilter))
					.build("stdout", Box::new(stdout)),
			);

			root = root.appender("stdout");
		}

		if c.log_to_file {
			// If maximum log size is specified, use rolling file appender
			// or use basic one otherwise
			let filter = Box::new(ThresholdFilter::new(level_file));
			let file: Box<Append> = {
				if let Some(size) = c.log_max_size {
					let roller = FixedWindowRoller::builder()
						.build(&format!("{}.{{}}.gz", c.log_file_path), 32)
						.unwrap();
					let trigger = SizeTrigger::new(size);

					let policy = CompoundPolicy::new(Box::new(trigger), Box::new(roller));

					Box::new(
						RollingFileAppender::builder()
							.append(c.log_file_append)
							.encoder(Box::new(PatternEncoder::new(&LOGGING_PATTERN)))
							.build(c.log_file_path, Box::new(policy))
							.unwrap(),
					)
				} else {
					Box::new(
						FileAppender::builder()
							.append(c.log_file_append)
							.encoder(Box::new(PatternEncoder::new(&LOGGING_PATTERN)))
							.build(c.log_file_path)
							.unwrap(),
					)
				}
			};

			appenders.push(
				Appender::builder()
					.filter(filter)
					.filter(Box::new(GrinFilter))
					.build("file", file),
			);
			root = root.appender("file");
		}

		let config = Config::builder()
			.appenders(appenders)
			.build(root.build(level_minimum))
			.unwrap();

		let _ = log4rs::init_config(config).unwrap();

		info!(
			"log4rs is initialized, file level: {:?}, stdout level: {:?}, min. level: {:?}",
			level_file, level_stdout, level_minimum
		);

		// Mark logger as initialized
		let mut was_init_ref = WAS_INIT.lock();
		*was_init_ref = true;
	}

	send_panic_to_log();
}

/// Initializes the logger for unit and integration tests
pub fn init_test_logger() {
	let mut was_init_ref = WAS_INIT.lock();
	if *was_init_ref.deref() {
		return;
	}
	let mut logger = LoggingConfig::default();
	logger.log_to_file = false;
	logger.stdout_log_level = LogLevel::Debug;

	// Save current logging configuration
	let mut config_ref = LOGGING_CONFIG.lock();
	*config_ref = logger;

	let level_stdout = convert_log_level(&config_ref.stdout_log_level);
	let level_minimum = level_stdout; // minimum logging level for Root logger

	// Start logger
	let stdout = ConsoleAppender::builder()
		.encoder(Box::new(PatternEncoder::default()))
		.build();

	let mut root = Root::builder();

	let mut appenders = vec![];

	{
		let filter = Box::new(ThresholdFilter::new(level_stdout));
		appenders.push(
			Appender::builder()
				.filter(filter)
				.filter(Box::new(GrinFilter))
				.build("stdout", Box::new(stdout)),
		);

		root = root.appender("stdout");
	}

	let config = Config::builder()
		.appenders(appenders)
		.build(root.build(level_minimum))
		.unwrap();

	let _ = log4rs::init_config(config).unwrap();

	info!(
		"log4rs is initialized, stdout level: {:?}, min. level: {:?}",
		level_stdout, level_minimum
	);

	*was_init_ref = true;
}

/// hook to send panics to logs as well as stderr
fn send_panic_to_log() {
	panic::set_hook(Box::new(|info| {
		let backtrace = Backtrace::new();

		let thread = thread::current();
		let thread = thread.name().unwrap_or("unnamed");

		let msg = match info.payload().downcast_ref::<&'static str>() {
			Some(s) => *s,
			None => match info.payload().downcast_ref::<String>() {
				Some(s) => &**s,
				None => "Box<Any>",
			},
		};

		match info.location() {
			Some(location) => {
				error!(
					"\nthread '{}' panicked at '{}': {}:{}{:?}\n\n",
					thread,
					msg,
					location.file(),
					location.line(),
					backtrace
				);
			}
			None => error!("thread '{}' panicked at '{}'{:?}", thread, msg, backtrace),
		}
		//also print to stderr
		let tui_running = TUI_RUNNING.lock().clone();
		if !tui_running {
			let config = LOGGING_CONFIG.lock();

			eprintln!(
				"Thread '{}' panicked with message:\n\"{}\"\nSee {} for further details.",
				thread, msg, config.log_file_path
			);
		}
	}));
}
<|endoftext|>


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

use error::{Error, Result, Source};
use book::Book;
use std::io::Write;
use std::fs::File;
use std::path::Path;

/// Thait that must be implemented by the various renderers to render a whole book.

pub trait BookRenderer: Sync {
    /// Render the book and write the result to the specified writer
    fn render(&self, book: &Book, to: &mut Write) -> Result<()>;

    /// Render the book to a given file.
    ///
    /// The default implementation creates a file and calls `render` to write to it,
    /// but in some cases it might be useful to override it.
    fn render_to_file(&self, book: &Book, path: &Path) -> Result<()> {
        let mut file = File::create(path)
            .map_err(|err| Error::default(Source::empty(),
                                    lformat!("could not create file '{file}': {err}",
                                             file = path.display(),
                                             err = err)))?;
        self.render(book, &mut file)?;
        Ok(())
    }
}
<commit_msg>Avoid creating an empty file if a renderer fails<commit_after>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Crowbook is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use error::{Error, Result, Source};
use book::Book;
use std::io::Write;
use std::fs::File;
use std::path::Path;

/// Thait that must be implemented by the various renderers to render a whole book.

pub trait BookRenderer: Sync {
    /// Render the book and write the result to the specified writer
    fn render(&self, book: &Book, to: &mut Write) -> Result<()>;

    /// Render the book to a given file.
    ///
    /// The default implementation creates a file and calls `render` to write to it,
    /// but in some cases it might be useful to override it.
    fn render_to_file(&self, book: &Book, path: &Path) -> Result<()> {
        // Not optimal but avoid creating an empty file if it fails
        let mut content = vec![];
        self.render(book, &mut content)?;
        let mut file = File::create(path)
            .map_err(|err| Error::default(Source::empty(),
                                    lformat!("could not create file '{file}': {err}",
                                             file = path.display(),
                                             err = err)))?;
        file.write_all(&content)
            .map_err(|err| Error::default(Source::empty(),
                                          lformat!("could not write book content to file '{file}': {err}",
                                                   file = path.display(),
                                                   err = err)))?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>#![unstable(feature = "futures_api",
            reason = "futures in libcore are unstable",
            issue = "50547")]

use ops::Try;
use result::Result;

/// Indicates whether a value is available or if the current task has been
/// scheduled to receive a wakeup instead.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Poll<T> {
    /// Represents that a value is immediately ready.
    Ready(T),

    /// Represents that a value is not ready yet.
    ///
    /// When a function returns `Pending`, the function *must* also
    /// ensure that the current task is scheduled to be awoken when
    /// progress can be made.
    Pending,
}

impl<T> Poll<T> {
    /// Change the ready value of this `Poll` with the closure provided
    pub fn map<U, F>(self, f: F) -> Poll<U>
        where F: FnOnce(T) -> U
    {
        match self {
            Poll::Ready(t) => Poll::Ready(f(t)),
            Poll::Pending => Poll::Pending,
        }
    }

    /// Returns whether this is `Poll::Ready`
    #[inline]
    pub fn is_ready(&self) -> bool {
        match *self {
            Poll::Ready(_) => true,
            Poll::Pending => false,
        }
    }

    /// Returns whether this is `Poll::Pending`
    #[inline]
    pub fn is_pending(&self) -> bool {
        !self.is_ready()
    }
}

impl<T, E> Poll<Result<T, E>> {
    /// Change the success value of this `Poll` with the closure provided
    pub fn map_ok<U, F>(self, f: F) -> Poll<Result<U, E>>
        where F: FnOnce(T) -> U
    {
        match self {
            Poll::Ready(Ok(t)) => Poll::Ready(Ok(f(t))),
            Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
            Poll::Pending => Poll::Pending,
        }
    }

    /// Change the error value of this `Poll` with the closure provided
    pub fn map_err<U, F>(self, f: F) -> Poll<Result<T, U>>
        where F: FnOnce(E) -> U
    {
        match self {
            Poll::Ready(Ok(t)) => Poll::Ready(Ok(t)),
            Poll::Ready(Err(e)) => Poll::Ready(Err(f(e))),
            Poll::Pending => Poll::Pending,
        }
    }
}

impl<T> From<T> for Poll<T> {
    fn from(t: T) -> Poll<T> {
        Poll::Ready(t)
    }
}

impl<T, E> Try for Poll<Result<T, E>> {
    type Ok = Poll<T>;
    type Error = E;

    #[inline]
    fn into_result(self) -> Result<Self::Ok, Self::Error> {
        match self {
            Poll::Ready(Ok(x)) => Ok(Poll::Ready(x)),
            Poll::Ready(Err(e)) => Err(e),
            Poll::Pending => Ok(Poll::Pending),
        }
    }

    #[inline]
    fn from_error(e: Self::Error) -> Self {
        Poll::Ready(Err(e))
    }

    #[inline]
    fn from_ok(x: Self::Ok) -> Self {
        x.map(Ok)
    }
}

impl<T, E> Try for Poll<Option<Result<T, E>>> {
    type Ok = Poll<Option<T>>;
    type Error = E;

    #[inline]
    fn into_result(self) -> Result<Self::Ok, Self::Error> {
        match self {
            Poll::Ready(Some(Ok(x))) => Ok(Poll::Ready(Some(x))),
            Poll::Ready(Some(Err(e))) => Err(e),
            Poll::Ready(None) => Ok(Poll::Ready(None)),
            Poll::Pending => Ok(Poll::Pending),
        }
    }

    #[inline]
    fn from_error(e: Self::Error) -> Self {
        Poll::Ready(Some(Err(e)))
    }

    #[inline]
    fn from_ok(x: Self::Ok) -> Self {
        x.map(|x| x.map(Ok))
    }
}
<commit_msg>Add #[must_use] to core::task::Poll<commit_after>#![unstable(feature = "futures_api",
            reason = "futures in libcore are unstable",
            issue = "50547")]

use ops::Try;
use result::Result;

/// Indicates whether a value is available or if the current task has been
/// scheduled to receive a wakeup instead.
#[must_use = "this `Poll` may be a `Pending` variant, which should be handled"]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Poll<T> {
    /// Represents that a value is immediately ready.
    Ready(T),

    /// Represents that a value is not ready yet.
    ///
    /// When a function returns `Pending`, the function *must* also
    /// ensure that the current task is scheduled to be awoken when
    /// progress can be made.
    Pending,
}

impl<T> Poll<T> {
    /// Change the ready value of this `Poll` with the closure provided
    pub fn map<U, F>(self, f: F) -> Poll<U>
        where F: FnOnce(T) -> U
    {
        match self {
            Poll::Ready(t) => Poll::Ready(f(t)),
            Poll::Pending => Poll::Pending,
        }
    }

    /// Returns whether this is `Poll::Ready`
    #[inline]
    pub fn is_ready(&self) -> bool {
        match *self {
            Poll::Ready(_) => true,
            Poll::Pending => false,
        }
    }

    /// Returns whether this is `Poll::Pending`
    #[inline]
    pub fn is_pending(&self) -> bool {
        !self.is_ready()
    }
}

impl<T, E> Poll<Result<T, E>> {
    /// Change the success value of this `Poll` with the closure provided
    pub fn map_ok<U, F>(self, f: F) -> Poll<Result<U, E>>
        where F: FnOnce(T) -> U
    {
        match self {
            Poll::Ready(Ok(t)) => Poll::Ready(Ok(f(t))),
            Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
            Poll::Pending => Poll::Pending,
        }
    }

    /// Change the error value of this `Poll` with the closure provided
    pub fn map_err<U, F>(self, f: F) -> Poll<Result<T, U>>
        where F: FnOnce(E) -> U
    {
        match self {
            Poll::Ready(Ok(t)) => Poll::Ready(Ok(t)),
            Poll::Ready(Err(e)) => Poll::Ready(Err(f(e))),
            Poll::Pending => Poll::Pending,
        }
    }
}

impl<T> From<T> for Poll<T> {
    fn from(t: T) -> Poll<T> {
        Poll::Ready(t)
    }
}

impl<T, E> Try for Poll<Result<T, E>> {
    type Ok = Poll<T>;
    type Error = E;

    #[inline]
    fn into_result(self) -> Result<Self::Ok, Self::Error> {
        match self {
            Poll::Ready(Ok(x)) => Ok(Poll::Ready(x)),
            Poll::Ready(Err(e)) => Err(e),
            Poll::Pending => Ok(Poll::Pending),
        }
    }

    #[inline]
    fn from_error(e: Self::Error) -> Self {
        Poll::Ready(Err(e))
    }

    #[inline]
    fn from_ok(x: Self::Ok) -> Self {
        x.map(Ok)
    }
}

impl<T, E> Try for Poll<Option<Result<T, E>>> {
    type Ok = Poll<Option<T>>;
    type Error = E;

    #[inline]
    fn into_result(self) -> Result<Self::Ok, Self::Error> {
        match self {
            Poll::Ready(Some(Ok(x))) => Ok(Poll::Ready(Some(x))),
            Poll::Ready(Some(Err(e))) => Err(e),
            Poll::Ready(None) => Ok(Poll::Ready(None)),
            Poll::Pending => Ok(Poll::Pending),
        }
    }

    #[inline]
    fn from_error(e: Self::Error) -> Self {
        Poll::Ready(Some(Err(e)))
    }

    #[inline]
    fn from_ok(x: Self::Ok) -> Self {
        x.map(|x| x.map(Ok))
    }
}
<|endoftext|>