<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 script::dom::characterdata::CharacterData;
use script::dom::element::Element;
use script::dom::eventtarget::EventTarget;
use script::dom::htmldivelement::HTMLDivElement;
use script::dom::htmlelement::HTMLElement;
use script::dom::htmlspanelement::HTMLSpanElement;
use script::dom::node::Node;
use script::dom::text::Text;
use std::mem::size_of;

// Macro so that we can stringify type names
// I'd really prefer the tests themselves to be run at plugin time,
// however rustc::middle doesn't have access to the full type data
macro_rules! sizeof_checker (
    ($testname: ident, $t:ty, $known_size:expr) => (
        #[test]
        fn $testname() {
            let new = size_of::<$t>();
            let old = $known_size;
            if new < old {
                panic!("Your changes have decreased the stack size of commonly used DOM struct {} from {} to {}. \
                        Good work! Please update the size in script/tests.rs",
                        stringify!($t), old, new)
            } else if new > old {
                panic!("Your changes have increased the stack size of commonly used DOM struct {} from {} to {}. \
                        These structs are present in large quantities in the DOM, and increasing the size \
                        may dramatically affect our memory footprint. Please consider choosing a design which \
                        avoids this increase. If you feel that the increase is necessary, \
                        update to the new size in script/tests.rs.",
                        stringify!($t), old, new)
        }
    });
);

// Update the sizes here
sizeof_checker!(size_event_target, EventTarget, 40);
sizeof_checker!(size_node, Node, 168);
sizeof_checker!(size_element, Element, 304);
sizeof_checker!(size_htmlelement, HTMLElement, 320);
sizeof_checker!(size_div, HTMLDivElement, 320);
sizeof_checker!(size_span, HTMLSpanElement, 320);
sizeof_checker!(size_text, Text, 200);
sizeof_checker!(size_characterdata, CharacterData, 200);
<commit_msg>Bump the expected sizes for Element.<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 script::dom::characterdata::CharacterData;
use script::dom::element::Element;
use script::dom::eventtarget::EventTarget;
use script::dom::htmldivelement::HTMLDivElement;
use script::dom::htmlelement::HTMLElement;
use script::dom::htmlspanelement::HTMLSpanElement;
use script::dom::node::Node;
use script::dom::text::Text;
use std::mem::size_of;

// Macro so that we can stringify type names
// I'd really prefer the tests themselves to be run at plugin time,
// however rustc::middle doesn't have access to the full type data
macro_rules! sizeof_checker (
    ($testname: ident, $t:ty, $known_size:expr) => (
        #[test]
        fn $testname() {
            let new = size_of::<$t>();
            let old = $known_size;
            if new < old {
                panic!("Your changes have decreased the stack size of commonly used DOM struct {} from {} to {}. \
                        Good work! Please update the size in script/tests.rs",
                        stringify!($t), old, new)
            } else if new > old {
                panic!("Your changes have increased the stack size of commonly used DOM struct {} from {} to {}. \
                        These structs are present in large quantities in the DOM, and increasing the size \
                        may dramatically affect our memory footprint. Please consider choosing a design which \
                        avoids this increase. If you feel that the increase is necessary, \
                        update to the new size in script/tests.rs.",
                        stringify!($t), old, new)
        }
    });
);

// Update the sizes here
sizeof_checker!(size_event_target, EventTarget, 40);
sizeof_checker!(size_node, Node, 168);
sizeof_checker!(size_element, Element, 312);
sizeof_checker!(size_htmlelement, HTMLElement, 328);
sizeof_checker!(size_div, HTMLDivElement, 328);
sizeof_checker!(size_span, HTMLSpanElement, 328);
sizeof_checker!(size_text, Text, 200);
sizeof_checker!(size_characterdata, CharacterData, 200);
<|endoftext|>


<commit_before>// pest. The Elegant Parser
// Copyright (C) 2017  Dragoș Tiselice
//
// 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/.

//! # pest. The Elegant Parser
//!
//! pest is a [PEG](https://en.wikipedia.org/wiki/Parsing_expression_grammar) parser built with
//! *simplicity* and *speed* in mind.
//!
//! This crate works in conjunction with the [`pest` crate](https://docs.rs/pest) by
//! deriving a grammar implementation based on a provided grammar.
//!
//! ## `.pest` files
//!
//! Grammar definitions reside in custom `.pest` files located in the `src` directory. Their path is
//! relative to `src` and is specified between the `derive` attribute and empty `struct` that
//! `Parser` will be derived on.
//!
//! Because of a limitation in procedural macros, there is no way for Cargo to know that a module
//! needs to be recompiled based on the file that the procedural macro is opening. This leads to the
//! case where modifying a `.pest` file without touching the file where the `derive` is does not
//! recompile it if it already has a working binary in the cache. To avoid this issue, the grammar
//! file can be included in a dummy `const` definition while debugging.
//!
//! ```ignore
//! const _GRAMMAR: &'static str = include_str!("path/to/my_grammar.pest"); // relative to this file
//!
//! #[derive(Parser)]
//! #[grammar = "path/to/my_grammar.pest"] // relative to src
//! struct MyParser;
//! ```
//!
//! ## Grammar
//!
//! A grammar is a series of rules separated by whitespace, possibly containing comments.
//!
//! ### Comments
//!
//! Comments start with `//` and end at the end of the line.
//!
//! ```ignore
//! // a comment
//! ```
//!
//! ### Rules
//!
//! Rules have the following form:
//!
//! ```ignore
//! name = optional_modifier { expression }
//! ```
//!
//! The name of the rule is formed from alphanumeric characters or `_` with the condition that the
//! first character is not a digit and is used to create token pairs. When the rule starts being
//! parsed, the starting part of the token is being produced, with the ending part being produced
//! when the rule finishes parsing.
//!
//! The following token pair notation `a(b(), c())` denotes the tokens: start `a`, start `b`, end
//! `b`, start `c`, end `c`, end `a`.
//!
//! #### Modifiers
//!
//! Modifiers are optional and can be one of `_`, `@`, `$`, or `!`. These modifiers change the
//! behavior of the rules.
//!
//! 1. Silent (`_`)
//!
//!     Silent rules do not create token pairs during parsing, nor are they error-reported.
//!
//!     ```ignore
//!     a = _{ "a" }
//!     b =  { a ~ "b" }
//!     ```
//!
//!     Parsing `"ab"` produces the token pair `b()`.
//!
//! 2. Atomic (`@`)
//!
//!     Atomic rules do not accept whitespace or comments within their expressions and have a
//!     cascading effect on any rule they call. I.e. rules that are not atomic but are called by atomic
//!     rules behave atomically.
//!
//!     Any rules called by atomic rules do not generate token pairs.
//!
//!     ```ignore
//!     a =  { "a" }
//!     b = @{ a ~ "b" }
//!
//!     whitespace = _{ " " }
//!     ```
//!
//!     Parsing `"ab"` produces the token pair `b()`, while `"a   b"` produces an error.
//!
//! 3. Compound-atomic (`$`)
//!
//!     Compound-atomic are identical to atomic rules with the exception that rules called by them are
//!     not forbidden from generating token pairs.
//!
//!     ```ignore
//!     a =  { "a" }
//!     b = ${ a ~ "b" }
//!
//!     whitespace = _{ " " }
//!     ```
//!
//!     Parsing `"ab"` produces the token pairs `b(a())`, while `"a   b"` produces an error.
//!
//! 4. Non-atomic (`!`)
//!
//!     Non-atomic are identical to normal rules with the exception that they stop the cascading effect
//!     of atomic and compound-atomic rules.
//!
//!     ```ignore
//!     a =  { "a" }
//!     b = !{ a ~ "b" }
//!     c = @{ b }
//!
//!     whitespace = _{ " " }
//!     ```
//!
//!     Parsing both `"ab"` and `"a   b"` produce the token pairs `c(b(a()))`.
//!
//! #### Expressions
//!
//! Expressions can be either terminals or non-terminals.
//!
//! 1. Terminals
//!
//!     | Terminal   | Usage                                                          |
//!     |------------|----------------------------------------------------------------|
//!     | `"a"`      | matches the exact string `"a"`                                 |
//!     | `^"a"`     | matches the exact string `"a"` case insensitively (ASCII only) |
//!     | `'a'..'z'` | matches one character between `'a'` and `'z'`                  |
//!     | `a`        | matches rule `a`                                               |
//!
//! 2. Non-terminals
//!
//!     | Non-terminal | Usage                                                      |
//!     |--------------|------------------------------------------------------------|
//!     | `(e)`        | matches `e`                                                |
//!     | `e1 ~ e2`    | matches the sequence `e1` `e2`                             |
//!     | `e1 | e2`    | matches either `e1` or `e1`                                |
//!     | `e*`         | matches `e` zero or more times                             |
//!     | `e+`         | matches `e` one or more times                              |
//!     | `e?`         | optionally matches `e`                                     |
//!     | `&e`         | matches `e` without making progress                        |
//!     | `!e`         | matches if `e` doesn't match without making progress       |
//!     | `push(e)`    | matches `e` and pushes it's captured string down the stack |
//!
//!     where `e`, `e1`, and `e2` are expressions.
//!
//! ## Special rules
//!
//! Special rules can be called within the grammar. They are:
//!
//! * `whitespace` - gets run between rules and sub-rules
//! * `comment` - gets run between rules and sub-rules
//! * `any` - matches exactly one `char`
//! * `soi` - (start-of-input) matches only when a `Parser` is still at the starting position
//! * `eoi` - (end-of-input) matches only when a `Parser` has reached its end
//! * `pop` - pops a string from the stack and matches it
//! * `peek` - peeks a string from the stack and matches it
//!
//! `whitespace` and `comment` should be defined manually if needed. All other rules cannot be
//! overridden.
//!
//! ## `Rule`
//!
//! All rules defined or used in the grammar populate a generated `enum` called `Rule`. This
//! implements `pest`'s `RuleType` and can be used throughout the API.

#![doc(html_root_url = "https://docs.rs/pest_derive")]
#![recursion_limit="256"]

#[macro_use]
extern crate pest;
extern crate proc_macro;
#[macro_use]
extern crate quote;
extern crate syn;

use std::env;
use std::path::Path;
use std::rc::Rc;

use pest::inputs::FileInput;
use pest::Parser;
use proc_macro::TokenStream;
use quote::Ident;
use syn::{Attribute, Lit, MetaItem};

mod ast;
mod generator;
mod optimizer;
mod parser;
mod validator;

use parser::{GrammarParser, GrammarRule};

#[proc_macro_derive(Parser, attributes(grammar))]
pub fn derive_parser(input: TokenStream) -> TokenStream {
    let source = input.to_string();

    let (name, path) = parse_derive(source);

    let root = env::var("CARGO_MANIFEST_DIR").unwrap_or(".".into());
    let path = Path::new(&root).join("src/").join(&path);
    let file_name = match path.file_name() {
        Some(file_name) => file_name,
        None => panic!("grammar attribute should point to a file")
    };

    let input = match FileInput::new(&path) {
        Ok(input) => Rc::new(input),
        Err(error) => panic!("error opening {:?}: {}", file_name, error)
    };
    let pairs = match GrammarParser::parse(GrammarRule::grammar_rules, input) {
        Ok(pairs) => pairs,
        Err(error) => panic!("error parsing {:?}\n\n{}", file_name, error.renamed_rules(|rule| {
            match *rule {
                GrammarRule::grammar_rule => "rule".to_owned(),
                GrammarRule::eoi => "end-of-input".to_owned(),
                GrammarRule::assignment_operator => "`=`".to_owned(),
                GrammarRule::silent_modifier => "`_`".to_owned(),
                GrammarRule::atomic_modifier => "`@`".to_owned(),
                GrammarRule::compound_atomic_modifier => "`$`".to_owned(),
                GrammarRule::non_atomic_modifier => "`!`".to_owned(),
                GrammarRule::opening_brace => "`{`".to_owned(),
                GrammarRule::closing_brace => "`}`".to_owned(),
                GrammarRule::opening_paren => "`(`".to_owned(),
                GrammarRule::positive_predicate_operator => "`&`".to_owned(),
                GrammarRule::negative_predicate_operator => "`!`".to_owned(),
                GrammarRule::sequence_operator => "`&`".to_owned(),
                GrammarRule::choice_operator => "`|`".to_owned(),
                GrammarRule::optional_operator => "`?`".to_owned(),
                GrammarRule::repeat_operator => "`*`".to_owned(),
                GrammarRule::repeat_once_operator => "`+`".to_owned(),
                GrammarRule::closing_paren => "`)`".to_owned(),
                GrammarRule::quote => "`\"`".to_owned(),
                GrammarRule::insensitive_string => "`^`".to_owned(),
                GrammarRule::range_operator => "`..`".to_owned(),
                GrammarRule::single_quote => "`'`".to_owned(),
                other_rule => format!("{:?}", other_rule)
            }
        }))
    };

    let (ast, defaults) = parser::consume_rules(pairs);
    let optimized = optimizer::optimize(ast);
    let generated = generator::generate(name, optimized, defaults);

    generated.as_ref().parse().unwrap()
}

fn parse_derive(source: String) -> (Ident, String) {
    let ast = syn::parse_macro_input(&source).unwrap();
    let name = Ident::new(ast.ident.as_ref());

    let grammar: Vec<_> = ast.attrs.iter().filter(|attr| {
        match attr.value {
            MetaItem::NameValue(ref ident, _) => format!("{}", ident) == "grammar",
            _ => false
        }
    }).collect();

    let filename = match grammar.len() {
        0 => panic!("a grammar file needs to be provided with the #[grammar(\"...\")] attribute"),
        1 => get_filename(grammar[0]),
        _ => panic!("only 1 grammar file can be provided")
    };

    (name, filename)
}

fn get_filename(attr: &Attribute) -> String {
    if let MetaItem::NameValue(_, ref lit) = attr.value {
        if let &Lit::Str(ref string, _) = lit {
            string.clone()
        } else {
            panic!("grammar attribute must be a string")
        }
    } else {
        unreachable!();
    }
}

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

    #[test]
    fn derive_ok() {
        let (_, filename) = parse_derive("
            #[other_attr]
            #[grammar = \"myfile.pest\"]
            pub struct MyParser<'a, T>;
        ".to_owned());

        assert_eq!(filename, "myfile.pest");
    }

    #[test]
    #[should_panic(expected = "only 1 grammar file can be provided")]
    fn derive_multiple_grammars() {
        parse_derive("
            #[other_attr]
            #[grammar = \"myfile1.pest\"]
            #[grammar = \"myfile2.pest\"]
            pub struct MyParser<'a, T>;
        ".to_owned());
    }

    #[test]
    #[should_panic(expected = "grammar attribute must be a string")]
    fn derive_wrong_arg() {
        parse_derive("
            #[other_attr]
            #[grammar = 1]
            pub struct MyParser<'a, T>;
        ".to_owned());
    }
}
<commit_msg>Fixed non-atomic example.<commit_after>// pest. The Elegant Parser
// Copyright (C) 2017  Dragoș Tiselice
//
// 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/.

//! # pest. The Elegant Parser
//!
//! pest is a [PEG](https://en.wikipedia.org/wiki/Parsing_expression_grammar) parser built with
//! *simplicity* and *speed* in mind.
//!
//! This crate works in conjunction with the [`pest` crate](https://docs.rs/pest) by
//! deriving a grammar implementation based on a provided grammar.
//!
//! ## `.pest` files
//!
//! Grammar definitions reside in custom `.pest` files located in the `src` directory. Their path is
//! relative to `src` and is specified between the `derive` attribute and empty `struct` that
//! `Parser` will be derived on.
//!
//! Because of a limitation in procedural macros, there is no way for Cargo to know that a module
//! needs to be recompiled based on the file that the procedural macro is opening. This leads to the
//! case where modifying a `.pest` file without touching the file where the `derive` is does not
//! recompile it if it already has a working binary in the cache. To avoid this issue, the grammar
//! file can be included in a dummy `const` definition while debugging.
//!
//! ```ignore
//! const _GRAMMAR: &'static str = include_str!("path/to/my_grammar.pest"); // relative to this file
//!
//! #[derive(Parser)]
//! #[grammar = "path/to/my_grammar.pest"] // relative to src
//! struct MyParser;
//! ```
//!
//! ## Grammar
//!
//! A grammar is a series of rules separated by whitespace, possibly containing comments.
//!
//! ### Comments
//!
//! Comments start with `//` and end at the end of the line.
//!
//! ```ignore
//! // a comment
//! ```
//!
//! ### Rules
//!
//! Rules have the following form:
//!
//! ```ignore
//! name = optional_modifier { expression }
//! ```
//!
//! The name of the rule is formed from alphanumeric characters or `_` with the condition that the
//! first character is not a digit and is used to create token pairs. When the rule starts being
//! parsed, the starting part of the token is being produced, with the ending part being produced
//! when the rule finishes parsing.
//!
//! The following token pair notation `a(b(), c())` denotes the tokens: start `a`, start `b`, end
//! `b`, start `c`, end `c`, end `a`.
//!
//! #### Modifiers
//!
//! Modifiers are optional and can be one of `_`, `@`, `$`, or `!`. These modifiers change the
//! behavior of the rules.
//!
//! 1. Silent (`_`)
//!
//!     Silent rules do not create token pairs during parsing, nor are they error-reported.
//!
//!     ```ignore
//!     a = _{ "a" }
//!     b =  { a ~ "b" }
//!     ```
//!
//!     Parsing `"ab"` produces the token pair `b()`.
//!
//! 2. Atomic (`@`)
//!
//!     Atomic rules do not accept whitespace or comments within their expressions and have a
//!     cascading effect on any rule they call. I.e. rules that are not atomic but are called by atomic
//!     rules behave atomically.
//!
//!     Any rules called by atomic rules do not generate token pairs.
//!
//!     ```ignore
//!     a =  { "a" }
//!     b = @{ a ~ "b" }
//!
//!     whitespace = _{ " " }
//!     ```
//!
//!     Parsing `"ab"` produces the token pair `b()`, while `"a   b"` produces an error.
//!
//! 3. Compound-atomic (`$`)
//!
//!     Compound-atomic are identical to atomic rules with the exception that rules called by them are
//!     not forbidden from generating token pairs.
//!
//!     ```ignore
//!     a =  { "a" }
//!     b = ${ a ~ "b" }
//!
//!     whitespace = _{ " " }
//!     ```
//!
//!     Parsing `"ab"` produces the token pairs `b(a())`, while `"a   b"` produces an error.
//!
//! 4. Non-atomic (`!`)
//!
//!     Non-atomic are identical to normal rules with the exception that they stop the cascading effect
//!     of atomic and compound-atomic rules.
//!
//!     ```ignore
//!     a =  { "a" }
//!     b = !{ a ~ "b" }
//!     c = @{ b }
//!
//!     whitespace = _{ " " }
//!     ```
//!
//!     Parsing both `"ab"` and `"a   b"` produce the token pairs `c(a())`.
//!
//! #### Expressions
//!
//! Expressions can be either terminals or non-terminals.
//!
//! 1. Terminals
//!
//!     | Terminal   | Usage                                                          |
//!     |------------|----------------------------------------------------------------|
//!     | `"a"`      | matches the exact string `"a"`                                 |
//!     | `^"a"`     | matches the exact string `"a"` case insensitively (ASCII only) |
//!     | `'a'..'z'` | matches one character between `'a'` and `'z'`                  |
//!     | `a`        | matches rule `a`                                               |
//!
//! 2. Non-terminals
//!
//!     | Non-terminal | Usage                                                      |
//!     |--------------|------------------------------------------------------------|
//!     | `(e)`        | matches `e`                                                |
//!     | `e1 ~ e2`    | matches the sequence `e1` `e2`                             |
//!     | `e1 | e2`    | matches either `e1` or `e1`                                |
//!     | `e*`         | matches `e` zero or more times                             |
//!     | `e+`         | matches `e` one or more times                              |
//!     | `e?`         | optionally matches `e`                                     |
//!     | `&e`         | matches `e` without making progress                        |
//!     | `!e`         | matches if `e` doesn't match without making progress       |
//!     | `push(e)`    | matches `e` and pushes it's captured string down the stack |
//!
//!     where `e`, `e1`, and `e2` are expressions.
//!
//! ## Special rules
//!
//! Special rules can be called within the grammar. They are:
//!
//! * `whitespace` - gets run between rules and sub-rules
//! * `comment` - gets run between rules and sub-rules
//! * `any` - matches exactly one `char`
//! * `soi` - (start-of-input) matches only when a `Parser` is still at the starting position
//! * `eoi` - (end-of-input) matches only when a `Parser` has reached its end
//! * `pop` - pops a string from the stack and matches it
//! * `peek` - peeks a string from the stack and matches it
//!
//! `whitespace` and `comment` should be defined manually if needed. All other rules cannot be
//! overridden.
//!
//! ## `Rule`
//!
//! All rules defined or used in the grammar populate a generated `enum` called `Rule`. This
//! implements `pest`'s `RuleType` and can be used throughout the API.

#![doc(html_root_url = "https://docs.rs/pest_derive")]
#![recursion_limit="256"]

#[macro_use]
extern crate pest;
extern crate proc_macro;
#[macro_use]
extern crate quote;
extern crate syn;

use std::env;
use std::path::Path;
use std::rc::Rc;

use pest::inputs::FileInput;
use pest::Parser;
use proc_macro::TokenStream;
use quote::Ident;
use syn::{Attribute, Lit, MetaItem};

mod ast;
mod generator;
mod optimizer;
mod parser;
mod validator;

use parser::{GrammarParser, GrammarRule};

#[proc_macro_derive(Parser, attributes(grammar))]
pub fn derive_parser(input: TokenStream) -> TokenStream {
    let source = input.to_string();

    let (name, path) = parse_derive(source);

    let root = env::var("CARGO_MANIFEST_DIR").unwrap_or(".".into());
    let path = Path::new(&root).join("src/").join(&path);
    let file_name = match path.file_name() {
        Some(file_name) => file_name,
        None => panic!("grammar attribute should point to a file")
    };

    let input = match FileInput::new(&path) {
        Ok(input) => Rc::new(input),
        Err(error) => panic!("error opening {:?}: {}", file_name, error)
    };
    let pairs = match GrammarParser::parse(GrammarRule::grammar_rules, input) {
        Ok(pairs) => pairs,
        Err(error) => panic!("error parsing {:?}\n\n{}", file_name, error.renamed_rules(|rule| {
            match *rule {
                GrammarRule::grammar_rule => "rule".to_owned(),
                GrammarRule::eoi => "end-of-input".to_owned(),
                GrammarRule::assignment_operator => "`=`".to_owned(),
                GrammarRule::silent_modifier => "`_`".to_owned(),
                GrammarRule::atomic_modifier => "`@`".to_owned(),
                GrammarRule::compound_atomic_modifier => "`$`".to_owned(),
                GrammarRule::non_atomic_modifier => "`!`".to_owned(),
                GrammarRule::opening_brace => "`{`".to_owned(),
                GrammarRule::closing_brace => "`}`".to_owned(),
                GrammarRule::opening_paren => "`(`".to_owned(),
                GrammarRule::positive_predicate_operator => "`&`".to_owned(),
                GrammarRule::negative_predicate_operator => "`!`".to_owned(),
                GrammarRule::sequence_operator => "`&`".to_owned(),
                GrammarRule::choice_operator => "`|`".to_owned(),
                GrammarRule::optional_operator => "`?`".to_owned(),
                GrammarRule::repeat_operator => "`*`".to_owned(),
                GrammarRule::repeat_once_operator => "`+`".to_owned(),
                GrammarRule::closing_paren => "`)`".to_owned(),
                GrammarRule::quote => "`\"`".to_owned(),
                GrammarRule::insensitive_string => "`^`".to_owned(),
                GrammarRule::range_operator => "`..`".to_owned(),
                GrammarRule::single_quote => "`'`".to_owned(),
                other_rule => format!("{:?}", other_rule)
            }
        }))
    };

    let (ast, defaults) = parser::consume_rules(pairs);
    let optimized = optimizer::optimize(ast);
    let generated = generator::generate(name, optimized, defaults);

    generated.as_ref().parse().unwrap()
}

fn parse_derive(source: String) -> (Ident, String) {
    let ast = syn::parse_macro_input(&source).unwrap();
    let name = Ident::new(ast.ident.as_ref());

    let grammar: Vec<_> = ast.attrs.iter().filter(|attr| {
        match attr.value {
            MetaItem::NameValue(ref ident, _) => format!("{}", ident) == "grammar",
            _ => false
        }
    }).collect();

    let filename = match grammar.len() {
        0 => panic!("a grammar file needs to be provided with the #[grammar(\"...\")] attribute"),
        1 => get_filename(grammar[0]),
        _ => panic!("only 1 grammar file can be provided")
    };

    (name, filename)
}

fn get_filename(attr: &Attribute) -> String {
    if let MetaItem::NameValue(_, ref lit) = attr.value {
        if let &Lit::Str(ref string, _) = lit {
            string.clone()
        } else {
            panic!("grammar attribute must be a string")
        }
    } else {
        unreachable!();
    }
}

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

    #[test]
    fn derive_ok() {
        let (_, filename) = parse_derive("
            #[other_attr]
            #[grammar = \"myfile.pest\"]
            pub struct MyParser<'a, T>;
        ".to_owned());

        assert_eq!(filename, "myfile.pest");
    }

    #[test]
    #[should_panic(expected = "only 1 grammar file can be provided")]
    fn derive_multiple_grammars() {
        parse_derive("
            #[other_attr]
            #[grammar = \"myfile1.pest\"]
            #[grammar = \"myfile2.pest\"]
            pub struct MyParser<'a, T>;
        ".to_owned());
    }

    #[test]
    #[should_panic(expected = "grammar attribute must be a string")]
    fn derive_wrong_arg() {
        parse_derive("
            #[other_attr]
            #[grammar = 1]
            pub struct MyParser<'a, T>;
        ".to_owned());
    }
}
<|endoftext|>


<commit_before>use std::ascii::*;

/// Converts a `String` to `SCREAMING_SNAKE_CASE` `String`
///
/// #Examples
/// ```
///     use inflector::cases::screamingsnakecase::to_screaming_snake_case;
///     let mock_string: String = "foo_bar".to_string();
///     let expected_string: String = "FOO_BAR".to_string();
///     let asserted_string: String = to_screaming_snake_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::to_screaming_snake_case;
///     let mock_string: String = "HTTP Foo bar".to_string();
///     let expected_string: String = "HTTP_FOO_BAR".to_string();
///     let asserted_string: String = to_screaming_snake_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::to_screaming_snake_case;
///     let mock_string: String = "Foo bar".to_string();
///     let expected_string: String = "FOO_BAR".to_string();
///     let asserted_string: String = to_screaming_snake_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::to_screaming_snake_case;
///     let mock_string: String = "Foo Bar".to_string();
///     let expected_string: String = "FOO_BAR".to_string();
///     let asserted_string: String = to_screaming_snake_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::to_screaming_snake_case;
///     let mock_string: String = "FooBar".to_string();
///     let expected_string: String = "FOO_BAR".to_string();
///     let asserted_string: String = to_screaming_snake_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::to_screaming_snake_case;
///     let mock_string: String = "fooBar".to_string();
///     let expected_string: String = "FOO_BAR".to_string();
///     let asserted_string: String = to_screaming_snake_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::to_screaming_snake_case;
///     let mock_string: String = "fooBar3".to_string();
///     let expected_string: String = "FOO_BAR_3".to_string();
///     let asserted_string: String = to_screaming_snake_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
pub fn to_screaming_snake_case(non_snake_case_string: String) -> String {
    if non_snake_case_string.contains(' ') || non_snake_case_string.contains('_') ||
       non_snake_case_string.contains('-') {
        to_snake_from_sentence_or_kebab(non_snake_case_string)
    } else {
        to_snake_from_camel_or_class(non_snake_case_string)
    }
}
fn to_snake_from_camel_or_class(non_snake_case_string: String) -> String {
    let mut result: String = "".to_string();
    let mut first_character: bool = true;
    for character in non_snake_case_string.chars() {
        if character == character.to_ascii_uppercase() && !first_character {
            result = format!("{}_{}", result, character.to_ascii_uppercase());
        } else {
            result = format!("{}{}", result, character.to_ascii_uppercase());
            first_character = false;
        }
    }
    result
}

fn to_snake_from_sentence_or_kebab(non_snake_case_string: String) -> String {
    non_snake_case_string.replace(" ", "_").replace("-", "_").to_uppercase()
}

/// Determines of a `String` is `SCREAMING_SNAKE_CASE`
///
/// #Examples
/// ```
///     use inflector::cases::screamingsnakecase::is_screaming_snake_case;
///     let mock_string: String = "Foo bar string that is really really long".to_string();
///     let asserted_bool: bool = is_screaming_snake_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::is_screaming_snake_case;
///     let mock_string: String = "foo-bar-string-that-is-really-really-long".to_string();
///     let asserted_bool: bool = is_screaming_snake_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::is_screaming_snake_case;
///     let mock_string: String = "FooBarIsAReallyReallyLongString".to_string();
///     let asserted_bool: bool = is_screaming_snake_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::is_screaming_snake_case;
///     let mock_string: String = "Foo Bar Is A Really Really Long String".to_string();
///     let asserted_bool: bool = is_screaming_snake_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::is_screaming_snake_case;
///     let mock_string: String = "fooBarIsAReallyReallyLongString".to_string();
///     let asserted_bool: bool = is_screaming_snake_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::is_screaming_snake_case;
///     let mock_string: String = "FOO_BAR_STRING_THAT_IS_REALLY_REALLY_LONG".to_string();
///     let asserted_bool: bool = is_screaming_snake_case(mock_string);
///     assert!(asserted_bool == true);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::is_screaming_snake_case;
///     let mock_string: String = "FOO_BAR1_STRING_THAT_IS_REALLY_REALLY_LONG".to_string();
///     let asserted_bool: bool = is_screaming_snake_case(mock_string);
///     assert!(asserted_bool == true);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::is_screaming_snake_case;
///     let mock_string: String = "FOO_BAR_1_STRING_THAT_IS_REALLY_REALLY_LONG".to_string();
///     let asserted_bool: bool = is_screaming_snake_case(mock_string);
///     assert!(asserted_bool == true);
///
/// ```
pub fn is_screaming_snake_case(test_string: String) -> bool {
    test_string == to_screaming_snake_case(test_string.clone())
}

#[cfg(test)]
mod tests {
    extern crate test;
    use self::test::Bencher;

    #[bench]
    fn bench_screaming_snake(b: &mut Bencher) {
        b.iter(|| super::to_screaming_snake_case("Foo bar".to_string()));
    }

    #[bench]
    fn bench_is_screaming_snake(b: &mut Bencher) {
        b.iter(|| super::is_screaming_snake_case("Foo bar".to_string()));
    }

    #[bench]
    fn bench_screaming_snake_from_kebab(b: &mut Bencher) {
        b.iter(|| super::to_snake_from_sentence_or_kebab("test-test-test".to_string()));
    }

    #[bench]
    fn bench_screaming_snake_from_upper_kebab(b: &mut Bencher) {
        b.iter(|| super::to_snake_from_sentence_or_kebab("TEST-TEST-TEST".to_string()));
    }

    #[bench]
    fn bench_screaming_snake_from_screaming_snake(b: &mut Bencher) {
        b.iter(|| super::to_snake_from_sentence_or_kebab("test_case".to_string()));
    }

    #[bench]
    fn bench_screaming_snake_from_sentence(b: &mut Bencher) {
        b.iter(|| super::to_snake_from_sentence_or_kebab("The quick brown fox".to_string()));
    }

    #[bench]
    fn bench_screaming_snake_from_camel(b: &mut Bencher) {
        b.iter(|| super::to_snake_from_camel_or_class("testCase".to_string()));
    }

    #[bench]
    fn bench_screaming_snake_from_class(b: &mut Bencher) {
        b.iter(|| super::to_snake_from_camel_or_class("TestCase".to_string()));
    }
}
<commit_msg>Cleaned up screaming snake<commit_after>use std::ascii::*;

use cases::snakecase::to_snake_case;
/// Converts a `String` to `SCREAMING_SNAKE_CASE` `String`
///
/// #Examples
/// ```
///     use inflector::cases::screamingsnakecase::to_screaming_snake_case;
///     let mock_string: String = "foo_bar".to_string();
///     let expected_string: String = "FOO_BAR".to_string();
///     let asserted_string: String = to_screaming_snake_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::to_screaming_snake_case;
///     let mock_string: String = "HTTP Foo bar".to_string();
///     let expected_string: String = "HTTP_FOO_BAR".to_string();
///     let asserted_string: String = to_screaming_snake_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::to_screaming_snake_case;
///     let mock_string: String = "Foo bar".to_string();
///     let expected_string: String = "FOO_BAR".to_string();
///     let asserted_string: String = to_screaming_snake_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::to_screaming_snake_case;
///     let mock_string: String = "Foo Bar".to_string();
///     let expected_string: String = "FOO_BAR".to_string();
///     let asserted_string: String = to_screaming_snake_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::to_screaming_snake_case;
///     let mock_string: String = "FooBar".to_string();
///     let expected_string: String = "FOO_BAR".to_string();
///     let asserted_string: String = to_screaming_snake_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::to_screaming_snake_case;
///     let mock_string: String = "fooBar".to_string();
///     let expected_string: String = "FOO_BAR".to_string();
///     let asserted_string: String = to_screaming_snake_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::to_screaming_snake_case;
///     let mock_string: String = "fooBar3".to_string();
///     let expected_string: String = "FOO_BAR_3".to_string();
///     let asserted_string: String = to_screaming_snake_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
pub fn to_screaming_snake_case(non_snake_case_string: String) -> String {
    to_snake_case(non_snake_case_string).to_uppercase()
}

/// Determines of a `String` is `SCREAMING_SNAKE_CASE`
///
/// #Examples
/// ```
///     use inflector::cases::screamingsnakecase::is_screaming_snake_case;
///     let mock_string: String = "Foo bar string that is really really long".to_string();
///     let asserted_bool: bool = is_screaming_snake_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::is_screaming_snake_case;
///     let mock_string: String = "foo-bar-string-that-is-really-really-long".to_string();
///     let asserted_bool: bool = is_screaming_snake_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::is_screaming_snake_case;
///     let mock_string: String = "FooBarIsAReallyReallyLongString".to_string();
///     let asserted_bool: bool = is_screaming_snake_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::is_screaming_snake_case;
///     let mock_string: String = "Foo Bar Is A Really Really Long String".to_string();
///     let asserted_bool: bool = is_screaming_snake_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::is_screaming_snake_case;
///     let mock_string: String = "fooBarIsAReallyReallyLongString".to_string();
///     let asserted_bool: bool = is_screaming_snake_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::is_screaming_snake_case;
///     let mock_string: String = "FOO_BAR_STRING_THAT_IS_REALLY_REALLY_LONG".to_string();
///     let asserted_bool: bool = is_screaming_snake_case(mock_string);
///     assert!(asserted_bool == true);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::is_screaming_snake_case;
///     let mock_string: String = "FOO_BAR1_STRING_THAT_IS_REALLY_REALLY_LONG".to_string();
///     let asserted_bool: bool = is_screaming_snake_case(mock_string);
///     assert!(asserted_bool == true);
///
/// ```
/// ```
///     use inflector::cases::screamingsnakecase::is_screaming_snake_case;
///     let mock_string: String = "FOO_BAR_1_STRING_THAT_IS_REALLY_REALLY_LONG".to_string();
///     let asserted_bool: bool = is_screaming_snake_case(mock_string);
///     assert!(asserted_bool == true);
///
/// ```
pub fn is_screaming_snake_case(test_string: String) -> bool {
    test_string == to_screaming_snake_case(test_string.clone())
}

#[cfg(test)]
mod tests {
    extern crate test;
    use self::test::Bencher;

    #[bench]
    fn bench_screaming_snake(b: &mut Bencher) {
        b.iter(|| super::to_screaming_snake_case("Foo bar".to_string()));
    }

    #[bench]
    fn bench_is_screaming_snake(b: &mut Bencher) {
        b.iter(|| super::is_screaming_snake_case("Foo bar".to_string()));
    }
}
<|endoftext|>


<commit_before>#![allow(unused_imports)]
#![allow(non_snake_case)]

use procon::*;
use std::cmp::{max, min};
use std::collections::*;
use std::ops::*;
use std::*;

pub fn main() {
    return;
}

pub mod procon {
    use std;
    use std::cmp::*;
    use std::collections::*;
    use std::io;
    use std::mem;
    use std::str::FromStr;

    pub fn read_line() -> String {
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        buf.trim_right().to_owned()
    }

    pub fn read_words<T>() -> Vec<T>
    where
        T: std::str::FromStr,
        T::Err: std::fmt::Debug,
    {
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        buf.split_whitespace()
            .map(|word| T::from_str(word).unwrap())
            .collect()
    }

    // Polyfill
    #[derive(PartialEq, Eq, Clone, Debug)]
    pub struct Rev<T>(pub T);

    impl<T: PartialOrd> PartialOrd for Rev<T> {
        fn partial_cmp(&self, other: &Rev<T>) -> Option<Ordering> {
            other.0.partial_cmp(&self.0)
        }
    }

    impl<T: Ord> Ord for Rev<T> {
        fn cmp(&self, other: &Rev<T>) -> Ordering {
            other.0.cmp(&self.0)
        }
    }
}

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

    #[test]
    pub fn test_ok() {
        assert_eq!(7, 1 + 2 * 3);
    }
}
<commit_msg>Rename read_line to rl, read_words to rw<commit_after>#![allow(unused_imports)]
#![allow(non_snake_case)]

use procon::*;
use std::cmp::{max, min};
use std::collections::*;
use std::ops::*;
use std::*;

pub fn main() {
    return;
}

pub mod procon {
    use std;
    use std::cmp::*;
    use std::collections::*;
    use std::io;
    use std::mem;
    use std::str::FromStr;

    pub fn rl() -> String {
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        buf.trim_right().to_owned()
    }

    pub fn rw<T>() -> Vec<T>
    where
        T: std::str::FromStr,
        T::Err: std::fmt::Debug,
    {
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        buf.split_whitespace()
            .map(|word| T::from_str(word).unwrap())
            .collect()
    }

    // Polyfill
    #[derive(PartialEq, Eq, Clone, Debug)]
    pub struct Rev<T>(pub T);

    impl<T: PartialOrd> PartialOrd for Rev<T> {
        fn partial_cmp(&self, other: &Rev<T>) -> Option<Ordering> {
            other.0.partial_cmp(&self.0)
        }
    }

    impl<T: Ord> Ord for Rev<T> {
        fn cmp(&self, other: &Rev<T>) -> Ordering {
            other.0.cmp(&self.0)
        }
    }
}

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

    #[test]
    pub fn test_ok() {
        assert_eq!(7, 1 + 2 * 3);
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use std::rc::Rc;
use std::rc::Weak;
use std::cell::RefCell;
use std::ptr;

use drawing_ctx::RsvgDrawingCtx;

use handle::RsvgHandle;

use property_bag::RsvgPropertyBag;

use state::RsvgState;

/* A *const RsvgNode is just a pointer for the C code's benefit: it
 * points to an  Rc<Node>, which is our refcounted Rust representation
 * of nodes.
 */
pub type RsvgNode = Rc<Node>;

/* A *const RsvgCNodeImpl is just an opaque pointer to the C code's
 * struct for a particular node type.
 */
pub enum RsvgCNodeImpl {}

pub trait NodeTrait {
    fn set_atts (&self, node: &RsvgNode, handle: *const RsvgHandle, pbag: *const RsvgPropertyBag);
    fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32);
    fn get_c_impl (&self) -> *const RsvgCNodeImpl;
}

pub struct Node {
    node_type: NodeType,
    parent:    Option<Weak<Node>>,       // optional; weak ref to parent
    children:  RefCell<Vec<Rc<Node>>>,   // strong references to children
    state:     *mut RsvgState,
    node_impl: Box<NodeTrait>
}

/* Keep this in sync with rsvg-private.h:RsvgNodeType */
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum NodeType {
    Invalid = 0,

    Chars,
    Circle,
    ClipPath,
    ComponentTransferFunction,
    Defs,
    Ellipse,
    Filter,
    Group,
    Image,
    LightSource,
    Line,
    LinearGradient,
    Marker,
    Mask,
    Path,
    Pattern,
    Polygon,
    Polyline,
    RadialGradient,
    Rect,
    Stop,
    Svg,
    Switch,
    Symbol,
    Text,
    TRef,
    TSpan,
    Use,

    /* Filter primitives */
    FilterPrimitiveFirst,              /* just a marker; not a valid type */
    FilterPrimitiveBlend,
    FilterPrimitiveColorMatrix,
    FilterPrimitiveComponentTransfer,
    FilterPrimitiveComposite,
    FilterPrimitiveConvolveMatrix,
    FilterPrimitiveDiffuseLighting,
    FilterPrimitiveDisplacementMap,
    FilterPrimitiveErode,
    FilterPrimitiveFlood,
    FilterPrimitiveGaussianBlur,
    FilterPrimitiveImage,
    FilterPrimitiveMerge,
    FilterPrimitiveMergeNode,
    FilterPrimitiveOffset,
    FilterPrimitiveSpecularLighting,
    FilterPrimitiveTile,
    FilterPrimitiveTurbulence,
    FilterPrimitiveLast                /* just a marker; not a valid type */
}

impl Node {
    pub fn new (node_type: NodeType,
                parent:    Option<Weak<Node>>,
                state:     *mut RsvgState,
                node_impl: Box<NodeTrait>) -> Node {
        Node {
            node_type: node_type,
            parent:    parent,
            children:  RefCell::new (Vec::new ()),
            state:     state,
            node_impl: node_impl
        }
    }

    pub fn get_type (&self) -> NodeType {
        self.node_type
    }

    pub fn get_state (&self) -> *mut RsvgState {
        self.state
    }

    pub fn add_child (&self, child: &Rc<Node>) {
        self.children.borrow_mut ().push (child.clone ());
    }

    pub fn set_atts (&self, node: &RsvgNode, handle: *const RsvgHandle, pbag: *const RsvgPropertyBag) {
        self.node_impl.set_atts (node, handle, pbag);
    }

    pub fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
        self.node_impl.draw (node, draw_ctx, dominate);
    }

    pub fn get_c_impl (&self) -> *const RsvgCNodeImpl {
        self.node_impl.get_c_impl ()
    }
}

extern "C" {
    fn rsvg_state_free (state: *mut RsvgState);
}

impl Drop for Node {
    fn drop (&mut self) {
//        unsafe { rsvg_state_free (self.state); }
    }
}

#[no_mangle]
pub extern fn rsvg_node_get_type (raw_node: *const RsvgNode) -> NodeType {
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    node.get_type ()
}

pub fn box_node (node: RsvgNode) -> *mut RsvgNode {
    Box::into_raw (Box::new (node))
}

#[no_mangle]
pub extern fn rsvg_node_get_parent (raw_node: *const RsvgNode) -> *const RsvgNode {
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    match node.parent {
        None => { ptr::null () }

        Some (ref weak_node) => {
            let strong_node = weak_node.upgrade ().unwrap ();
            box_node (strong_node)
        }
    }
}

#[no_mangle]
pub extern fn rsvg_node_ref (raw_node: *mut RsvgNode) -> *mut RsvgNode {
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    box_node (node.clone ())
}

#[no_mangle]
pub extern fn rsvg_node_unref (raw_node: *mut RsvgNode) -> *mut RsvgNode {
    if !raw_node.is_null () {
        let _ = unsafe { Box::from_raw (raw_node) };
    }

    ptr::null_mut () // so the caller can do "node = rsvg_node_unref (node);" and lose access to the node
}

// See https://github.com/rust-lang/rust/issues/36497 - this is what
// added Rc::ptr_eq(), but we don't want to depend on unstable Rust
// just yet.

fn rc_node_ptr_eq<T: ?Sized> (this: &Rc<T>, other: &Rc<T>) -> bool {
    let this_ptr: *const T = &**this;
    let other_ptr: *const T = &**other;
    this_ptr == other_ptr
}

#[no_mangle]
pub extern fn rsvg_node_is_same (raw_node1: *const RsvgNode, raw_node2: *const RsvgNode) -> bool {
    if raw_node1.is_null () && raw_node2.is_null () {
        true
    } else if !raw_node1.is_null () && !raw_node2.is_null () {
        let node1: &RsvgNode = unsafe { & *raw_node1 };
        let node2: &RsvgNode = unsafe { & *raw_node2 };

        rc_node_ptr_eq (node1, node2)
    } else {
        false
    }
}

#[no_mangle]
pub extern fn rsvg_node_get_state (raw_node: *const RsvgNode) -> *mut RsvgState {
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    node.get_state ()
}

#[no_mangle]
pub extern fn rsvg_node_add_child (raw_node: *mut RsvgNode, raw_child: *const RsvgNode) {
    assert! (!raw_node.is_null ());
    assert! (!raw_child.is_null ());
    let node: &mut RsvgNode = unsafe { &mut *raw_node };
    let child: &RsvgNode = unsafe { & *raw_child };

    node.add_child (child);
}

#[no_mangle]
pub extern fn rsvg_node_set_atts (raw_node: *mut RsvgNode, handle: *const RsvgHandle, pbag: *const RsvgPropertyBag) {
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    node.set_atts (node, handle, pbag);
}

#[no_mangle]
pub extern fn rsvg_node_draw (raw_node: *const RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    node.draw (node, draw_ctx, dominate);
}

type NodeForeachChild = unsafe extern "C" fn (node: *const RsvgNode, data: *const libc::c_void) -> bool;

#[no_mangle]
pub extern fn rsvg_node_foreach_child (raw_node: *const RsvgNode, func: NodeForeachChild, data: *const libc::c_void)
{
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    for child in &*node.children.borrow () {
        let mut boxed_child = box_node (child.clone ());

        let next = unsafe { func (boxed_child, data) };

        boxed_child = rsvg_node_unref (boxed_child);

        if !next {
            break;
        }
    }
}

#[cfg(test)]
mod tests {
    use std::rc::Rc;
    use drawing_ctx::RsvgDrawingCtx;
    use handle::RsvgHandle;
    use property_bag::RsvgPropertyBag;
    use state::RsvgState;
    use super::*;
    use std::ptr;
    use std::mem;

    struct TestNodeImpl {}

    impl NodeTrait for TestNodeImpl {
        fn set_atts (&self, node: &RsvgNode, handle: *const RsvgHandle, pbag: *const RsvgPropertyBag) {
        }

        fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
        }

        fn get_c_impl (&self) -> *const RsvgCNodeImpl {
            return ptr::null ();
        }
    }

    #[test]
    fn node_refs_and_unrefs () {
        let node = Rc::new (Node::new (NodeType::Path,
                                       None,
                                       ptr::null_mut (),
                                       Box::new (TestNodeImpl {})));

        let mut ref1 = box_node (node);

        let new_node: &mut RsvgNode = unsafe { &mut *ref1 };
        let weak = Rc::downgrade (new_node);

        let mut ref2 = unsafe { rsvg_node_ref (new_node) };
        assert! (weak.upgrade ().is_some ());

        ref2 = unsafe { rsvg_node_unref (ref2) };
        assert! (weak.upgrade ().is_some ());

        ref1 = unsafe { rsvg_node_unref (ref1) };
        assert! (weak.upgrade ().is_none ());
    }

    #[test]
    fn reffed_node_is_same_as_original_node () {
        let node = Rc::new (Node::new (NodeType::Path,
                                       None,
                                       ptr::null_mut (),
                                       Box::new (TestNodeImpl {})));

        let mut ref1 = box_node (node);

        let mut ref2 = unsafe { rsvg_node_ref (ref1) };

        unsafe { assert! (rsvg_node_is_same (ref1, ref2)); }

        ref1 = rsvg_node_unref (ref1);
        ref2 = rsvg_node_unref (ref2);
    }

    #[test]
    fn different_nodes_have_different_pointers () {
        let node1 = Rc::new (Node::new (NodeType::Path,
                                       None,
                                       ptr::null_mut (),
                                       Box::new (TestNodeImpl {})));

        let mut ref1 = box_node (node1);

        let node2 = Rc::new (Node::new (NodeType::Path,
                                       None,
                                       ptr::null_mut (),
                                       Box::new (TestNodeImpl {})));

        let mut ref2 = box_node (node2);

        unsafe { assert! (!rsvg_node_is_same (ref1, ref2)); }

        ref1 = rsvg_node_unref (ref1);
        ref2 = rsvg_node_unref (ref2);
    }
}
<commit_msg>node.rs: Remove unused mut<commit_after>extern crate libc;

use std::rc::Rc;
use std::rc::Weak;
use std::cell::RefCell;
use std::ptr;

use drawing_ctx::RsvgDrawingCtx;

use handle::RsvgHandle;

use property_bag::RsvgPropertyBag;

use state::RsvgState;

/* A *const RsvgNode is just a pointer for the C code's benefit: it
 * points to an  Rc<Node>, which is our refcounted Rust representation
 * of nodes.
 */
pub type RsvgNode = Rc<Node>;

/* A *const RsvgCNodeImpl is just an opaque pointer to the C code's
 * struct for a particular node type.
 */
pub enum RsvgCNodeImpl {}

pub trait NodeTrait {
    fn set_atts (&self, node: &RsvgNode, handle: *const RsvgHandle, pbag: *const RsvgPropertyBag);
    fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32);
    fn get_c_impl (&self) -> *const RsvgCNodeImpl;
}

pub struct Node {
    node_type: NodeType,
    parent:    Option<Weak<Node>>,       // optional; weak ref to parent
    children:  RefCell<Vec<Rc<Node>>>,   // strong references to children
    state:     *mut RsvgState,
    node_impl: Box<NodeTrait>
}

/* Keep this in sync with rsvg-private.h:RsvgNodeType */
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum NodeType {
    Invalid = 0,

    Chars,
    Circle,
    ClipPath,
    ComponentTransferFunction,
    Defs,
    Ellipse,
    Filter,
    Group,
    Image,
    LightSource,
    Line,
    LinearGradient,
    Marker,
    Mask,
    Path,
    Pattern,
    Polygon,
    Polyline,
    RadialGradient,
    Rect,
    Stop,
    Svg,
    Switch,
    Symbol,
    Text,
    TRef,
    TSpan,
    Use,

    /* Filter primitives */
    FilterPrimitiveFirst,              /* just a marker; not a valid type */
    FilterPrimitiveBlend,
    FilterPrimitiveColorMatrix,
    FilterPrimitiveComponentTransfer,
    FilterPrimitiveComposite,
    FilterPrimitiveConvolveMatrix,
    FilterPrimitiveDiffuseLighting,
    FilterPrimitiveDisplacementMap,
    FilterPrimitiveErode,
    FilterPrimitiveFlood,
    FilterPrimitiveGaussianBlur,
    FilterPrimitiveImage,
    FilterPrimitiveMerge,
    FilterPrimitiveMergeNode,
    FilterPrimitiveOffset,
    FilterPrimitiveSpecularLighting,
    FilterPrimitiveTile,
    FilterPrimitiveTurbulence,
    FilterPrimitiveLast                /* just a marker; not a valid type */
}

impl Node {
    pub fn new (node_type: NodeType,
                parent:    Option<Weak<Node>>,
                state:     *mut RsvgState,
                node_impl: Box<NodeTrait>) -> Node {
        Node {
            node_type: node_type,
            parent:    parent,
            children:  RefCell::new (Vec::new ()),
            state:     state,
            node_impl: node_impl
        }
    }

    pub fn get_type (&self) -> NodeType {
        self.node_type
    }

    pub fn get_state (&self) -> *mut RsvgState {
        self.state
    }

    pub fn add_child (&self, child: &Rc<Node>) {
        self.children.borrow_mut ().push (child.clone ());
    }

    pub fn set_atts (&self, node: &RsvgNode, handle: *const RsvgHandle, pbag: *const RsvgPropertyBag) {
        self.node_impl.set_atts (node, handle, pbag);
    }

    pub fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
        self.node_impl.draw (node, draw_ctx, dominate);
    }

    pub fn get_c_impl (&self) -> *const RsvgCNodeImpl {
        self.node_impl.get_c_impl ()
    }
}

extern "C" {
    fn rsvg_state_free (state: *mut RsvgState);
}

impl Drop for Node {
    fn drop (&mut self) {
//        unsafe { rsvg_state_free (self.state); }
    }
}

#[no_mangle]
pub extern fn rsvg_node_get_type (raw_node: *const RsvgNode) -> NodeType {
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    node.get_type ()
}

pub fn box_node (node: RsvgNode) -> *mut RsvgNode {
    Box::into_raw (Box::new (node))
}

#[no_mangle]
pub extern fn rsvg_node_get_parent (raw_node: *const RsvgNode) -> *const RsvgNode {
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    match node.parent {
        None => { ptr::null () }

        Some (ref weak_node) => {
            let strong_node = weak_node.upgrade ().unwrap ();
            box_node (strong_node)
        }
    }
}

#[no_mangle]
pub extern fn rsvg_node_ref (raw_node: *mut RsvgNode) -> *mut RsvgNode {
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    box_node (node.clone ())
}

#[no_mangle]
pub extern fn rsvg_node_unref (raw_node: *mut RsvgNode) -> *mut RsvgNode {
    if !raw_node.is_null () {
        let _ = unsafe { Box::from_raw (raw_node) };
    }

    ptr::null_mut () // so the caller can do "node = rsvg_node_unref (node);" and lose access to the node
}

// See https://github.com/rust-lang/rust/issues/36497 - this is what
// added Rc::ptr_eq(), but we don't want to depend on unstable Rust
// just yet.

fn rc_node_ptr_eq<T: ?Sized> (this: &Rc<T>, other: &Rc<T>) -> bool {
    let this_ptr: *const T = &**this;
    let other_ptr: *const T = &**other;
    this_ptr == other_ptr
}

#[no_mangle]
pub extern fn rsvg_node_is_same (raw_node1: *const RsvgNode, raw_node2: *const RsvgNode) -> bool {
    if raw_node1.is_null () && raw_node2.is_null () {
        true
    } else if !raw_node1.is_null () && !raw_node2.is_null () {
        let node1: &RsvgNode = unsafe { & *raw_node1 };
        let node2: &RsvgNode = unsafe { & *raw_node2 };

        rc_node_ptr_eq (node1, node2)
    } else {
        false
    }
}

#[no_mangle]
pub extern fn rsvg_node_get_state (raw_node: *const RsvgNode) -> *mut RsvgState {
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    node.get_state ()
}

#[no_mangle]
pub extern fn rsvg_node_add_child (raw_node: *mut RsvgNode, raw_child: *const RsvgNode) {
    assert! (!raw_node.is_null ());
    assert! (!raw_child.is_null ());
    let node: &mut RsvgNode = unsafe { &mut *raw_node };
    let child: &RsvgNode = unsafe { & *raw_child };

    node.add_child (child);
}

#[no_mangle]
pub extern fn rsvg_node_set_atts (raw_node: *mut RsvgNode, handle: *const RsvgHandle, pbag: *const RsvgPropertyBag) {
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    node.set_atts (node, handle, pbag);
}

#[no_mangle]
pub extern fn rsvg_node_draw (raw_node: *const RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    node.draw (node, draw_ctx, dominate);
}

type NodeForeachChild = unsafe extern "C" fn (node: *const RsvgNode, data: *const libc::c_void) -> bool;

#[no_mangle]
pub extern fn rsvg_node_foreach_child (raw_node: *const RsvgNode, func: NodeForeachChild, data: *const libc::c_void)
{
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    for child in &*node.children.borrow () {
        let boxed_child = box_node (child.clone ());

        let next = unsafe { func (boxed_child, data) };

        rsvg_node_unref (boxed_child);

        if !next {
            break;
        }
    }
}

#[cfg(test)]
mod tests {
    use std::rc::Rc;
    use drawing_ctx::RsvgDrawingCtx;
    use handle::RsvgHandle;
    use property_bag::RsvgPropertyBag;
    use state::RsvgState;
    use super::*;
    use std::ptr;
    use std::mem;

    struct TestNodeImpl {}

    impl NodeTrait for TestNodeImpl {
        fn set_atts (&self, node: &RsvgNode, handle: *const RsvgHandle, pbag: *const RsvgPropertyBag) {
        }

        fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
        }

        fn get_c_impl (&self) -> *const RsvgCNodeImpl {
            return ptr::null ();
        }
    }

    #[test]
    fn node_refs_and_unrefs () {
        let node = Rc::new (Node::new (NodeType::Path,
                                       None,
                                       ptr::null_mut (),
                                       Box::new (TestNodeImpl {})));

        let mut ref1 = box_node (node);

        let new_node: &mut RsvgNode = unsafe { &mut *ref1 };
        let weak = Rc::downgrade (new_node);

        let mut ref2 = unsafe { rsvg_node_ref (new_node) };
        assert! (weak.upgrade ().is_some ());

        ref2 = unsafe { rsvg_node_unref (ref2) };
        assert! (weak.upgrade ().is_some ());

        ref1 = unsafe { rsvg_node_unref (ref1) };
        assert! (weak.upgrade ().is_none ());
    }

    #[test]
    fn reffed_node_is_same_as_original_node () {
        let node = Rc::new (Node::new (NodeType::Path,
                                       None,
                                       ptr::null_mut (),
                                       Box::new (TestNodeImpl {})));

        let mut ref1 = box_node (node);

        let mut ref2 = unsafe { rsvg_node_ref (ref1) };

        unsafe { assert! (rsvg_node_is_same (ref1, ref2)); }

        ref1 = rsvg_node_unref (ref1);
        ref2 = rsvg_node_unref (ref2);
    }

    #[test]
    fn different_nodes_have_different_pointers () {
        let node1 = Rc::new (Node::new (NodeType::Path,
                                       None,
                                       ptr::null_mut (),
                                       Box::new (TestNodeImpl {})));

        let mut ref1 = box_node (node1);

        let node2 = Rc::new (Node::new (NodeType::Path,
                                       None,
                                       ptr::null_mut (),
                                       Box::new (TestNodeImpl {})));

        let mut ref2 = box_node (node2);

        unsafe { assert! (!rsvg_node_is_same (ref1, ref2)); }

        ref1 = rsvg_node_unref (ref1);
        ref2 = rsvg_node_unref (ref2);
    }
}
<|endoftext|>


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

//! A task that takes a URL and streams back the binary data.

use file_loader;
use http_loader;

use std::cell::Cell;
use std::comm::{Chan, Port, SharedChan};
use extra::url::Url;
use util::spawn_listener;

pub enum ControlMsg {
    /// Request the data associated with a particular URL
    Load(Url, Chan<ProgressMsg>),
    Exit
}

/// Messages sent in response to a `Load` message
#[deriving(Eq)]
pub enum ProgressMsg {
    /// Binary data - there may be multiple of these
    Payload(~[u8]),
    /// Indicates loading is complete, either successfully or not
    Done(Result<(), ()>)
}

/// Handle to a resource task
pub type ResourceTask = SharedChan<ControlMsg>;

/**
Creates a task to load a specific resource

The ResourceManager delegates loading to a different type of loader task for
each URL scheme
*/
type LoaderTaskFactory = ~fn() -> ~fn(url: Url, Chan<ProgressMsg>);

pub type LoaderTask = ~fn(url: Url, Chan<ProgressMsg>);

/// Create a ResourceTask with the default loaders
pub fn ResourceTask() -> ResourceTask {
    let file_loader_factory: LoaderTaskFactory = file_loader::factory;
    let http_loader_factory: LoaderTaskFactory = http_loader::factory;
    let loaders = ~[
        (~"file", file_loader_factory),
        (~"http", http_loader_factory)
    ];
    create_resource_task_with_loaders(loaders)
}

fn create_resource_task_with_loaders(loaders: ~[(~str, LoaderTaskFactory)]) -> ResourceTask {
    let loaders_cell = Cell::new(loaders);
    let chan = do spawn_listener |from_client| {
        // TODO: change copy to move once we can move out of closures
        ResourceManager(from_client, loaders_cell.take()).start()
    };
    SharedChan::new(chan)
}

pub struct ResourceManager {
    from_client: Port<ControlMsg>,
    /// Per-scheme resource loaders
    loaders: ~[(~str, LoaderTaskFactory)],
}

pub fn ResourceManager(from_client: Port<ControlMsg>,
                       loaders: ~[(~str, LoaderTaskFactory)]) -> ResourceManager {
    ResourceManager {
        from_client : from_client,
        loaders : loaders,
    }
}

impl ResourceManager {
    fn start(&self) {
        loop {
            match self.from_client.recv() {
              Load(url, progress_chan) => {
                self.load(url.clone(), progress_chan)
              }
              Exit => {
                break
              }
            }
        }
    }

    fn load(&self, url: Url, progress_chan: Chan<ProgressMsg>) {

        match self.get_loader_factory(&url) {
            Some(loader_factory) => {
                debug!("resource_task: loading url: %s", url.to_str());
                loader_factory(url, progress_chan);
            }
            None => {
                debug!("resource_task: no loader for scheme %s", url.scheme);
                progress_chan.send(Done(Err(())));
            }
        }
    }

    fn get_loader_factory(&self, url: &Url) -> Option<LoaderTask> {
        for scheme_loader in self.loaders.iter() {
            match *scheme_loader {
                (ref scheme, ref loader_factory) => {
	            if (*scheme) == url.scheme {
                        return Some((*loader_factory)());
                    }
	        }
            }
        }
        return None;
    }
}

#[test]
fn test_exit() {
    let resource_task = ResourceTask();
    resource_task.send(Exit);
}

#[test]
#[allow(non_implicitly_copyable_typarams)]
fn test_bad_scheme() {
    let resource_task = ResourceTask();
    let progress = Port();
    resource_task.send(Load(url::from_str(~"bogus://whatever").get(), progress.chan()));
    match progress.recv() {
      Done(result) => { assert!(result.is_err()) }
      _ => fail
    }
    resource_task.send(Exit);
}

#[test]
#[allow(non_implicitly_copyable_typarams)]
fn should_delegate_to_scheme_loader() {
    let payload = ~[1, 2, 3];
    let loader_factory = |_url: Url, progress_chan: Chan<ProgressMsg>| {
        progress_chan.send(Payload(payload.clone()));
        progress_chan.send(Done(Ok(())));
    };
    let loader_factories = ~[(~"snicklefritz", loader_factory)];
    let resource_task = create_resource_task_with_loaders(loader_factories);
    let progress = Port();
    resource_task.send(Load(url::from_str(~"snicklefritz://heya").get(), progress.chan()));
    assert!(progress.recv() == Payload(payload));
    assert!(progress.recv() == Done(Ok(())));
    resource_task.send(Exit);
}
<commit_msg>auto merge of #897 : metajack/servo/non-ic-typarams, r=pcwalton<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/. */

//! A task that takes a URL and streams back the binary data.

use file_loader;
use http_loader;

use std::cell::Cell;
use std::comm::{Chan, Port, SharedChan};
use extra::url::Url;
use util::spawn_listener;

pub enum ControlMsg {
    /// Request the data associated with a particular URL
    Load(Url, Chan<ProgressMsg>),
    Exit
}

/// Messages sent in response to a `Load` message
#[deriving(Eq)]
pub enum ProgressMsg {
    /// Binary data - there may be multiple of these
    Payload(~[u8]),
    /// Indicates loading is complete, either successfully or not
    Done(Result<(), ()>)
}

/// Handle to a resource task
pub type ResourceTask = SharedChan<ControlMsg>;

/**
Creates a task to load a specific resource

The ResourceManager delegates loading to a different type of loader task for
each URL scheme
*/
type LoaderTaskFactory = ~fn() -> ~fn(url: Url, Chan<ProgressMsg>);

pub type LoaderTask = ~fn(url: Url, Chan<ProgressMsg>);

/// Create a ResourceTask with the default loaders
pub fn ResourceTask() -> ResourceTask {
    let file_loader_factory: LoaderTaskFactory = file_loader::factory;
    let http_loader_factory: LoaderTaskFactory = http_loader::factory;
    let loaders = ~[
        (~"file", file_loader_factory),
        (~"http", http_loader_factory)
    ];
    create_resource_task_with_loaders(loaders)
}

fn create_resource_task_with_loaders(loaders: ~[(~str, LoaderTaskFactory)]) -> ResourceTask {
    let loaders_cell = Cell::new(loaders);
    let chan = do spawn_listener |from_client| {
        // TODO: change copy to move once we can move out of closures
        ResourceManager(from_client, loaders_cell.take()).start()
    };
    SharedChan::new(chan)
}

pub struct ResourceManager {
    from_client: Port<ControlMsg>,
    /// Per-scheme resource loaders
    loaders: ~[(~str, LoaderTaskFactory)],
}

pub fn ResourceManager(from_client: Port<ControlMsg>,
                       loaders: ~[(~str, LoaderTaskFactory)]) -> ResourceManager {
    ResourceManager {
        from_client : from_client,
        loaders : loaders,
    }
}

impl ResourceManager {
    fn start(&self) {
        loop {
            match self.from_client.recv() {
              Load(url, progress_chan) => {
                self.load(url.clone(), progress_chan)
              }
              Exit => {
                break
              }
            }
        }
    }

    fn load(&self, url: Url, progress_chan: Chan<ProgressMsg>) {

        match self.get_loader_factory(&url) {
            Some(loader_factory) => {
                debug!("resource_task: loading url: %s", url.to_str());
                loader_factory(url, progress_chan);
            }
            None => {
                debug!("resource_task: no loader for scheme %s", url.scheme);
                progress_chan.send(Done(Err(())));
            }
        }
    }

    fn get_loader_factory(&self, url: &Url) -> Option<LoaderTask> {
        for scheme_loader in self.loaders.iter() {
            match *scheme_loader {
                (ref scheme, ref loader_factory) => {
	            if (*scheme) == url.scheme {
                        return Some((*loader_factory)());
                    }
	        }
            }
        }
        return None;
    }
}

#[test]
fn test_exit() {
    let resource_task = ResourceTask();
    resource_task.send(Exit);
}

#[test]
fn test_bad_scheme() {
    let resource_task = ResourceTask();
    let progress = Port();
    resource_task.send(Load(url::from_str(~"bogus://whatever").get(), progress.chan()));
    match progress.recv() {
      Done(result) => { assert!(result.is_err()) }
      _ => fail
    }
    resource_task.send(Exit);
}

#[test]
fn should_delegate_to_scheme_loader() {
    let payload = ~[1, 2, 3];
    let loader_factory = |_url: Url, progress_chan: Chan<ProgressMsg>| {
        progress_chan.send(Payload(payload.clone()));
        progress_chan.send(Done(Ok(())));
    };
    let loader_factories = ~[(~"snicklefritz", loader_factory)];
    let resource_task = create_resource_task_with_loaders(loader_factories);
    let progress = Port();
    resource_task.send(Load(url::from_str(~"snicklefritz://heya").get(), progress.chan()));
    assert!(progress.recv() == Payload(payload));
    assert!(progress.recv() == Done(Ok(())));
    resource_task.send(Exit);
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs 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.

#[macro_use]
extern crate gfx;
extern crate gfx_window_glutin;
extern crate glutin;

extern crate image;

use std::io::Cursor;
use gfx::traits::{Factory, Stream, FactoryExt};

gfx_vertex!( Vertex {
    a_Pos@ pos: [f32; 2],
    a_Uv@ uv: [f32; 2],
});

impl Vertex {
    fn new(p: [f32; 2], u: [f32; 2]) -> Vertex {
        Vertex {
            pos: p,
            uv: u,
        }
    }
}

gfx_parameters!( Params {
    t_Color@ color: gfx::shade::TextureParam<R>,
    t_Flow@ flow: gfx::shade::TextureParam<R>,
    t_Noise@ noise: gfx::shade::TextureParam<R>,
    f_Offset0@ offset0: f32,
    f_Offset1@ offset1: f32,
});

fn load_texture<R, F>(factory: &mut F, data: &[u8]) -> Result<gfx::handle::Texture<R>, String>
        where R: gfx::Resources, F: gfx::device::Factory<R> {
    let img = image::load(Cursor::new(data), image::PNG).unwrap();

    let img = match img {
        image::DynamicImage::ImageRgba8(img) => img,
        img => img.to_rgba()
    };
    let (width, height) = img.dimensions();
    let tex_info = gfx::tex::TextureInfo {
        width: width as u16,
        height: height as u16,
        depth: 1,
        levels: 1,
        kind: gfx::tex::Kind::D2,
        format: gfx::tex::RGBA8
    };

    Ok(factory.create_texture_static(tex_info, &img).unwrap())
}

pub fn main() {
    let (mut stream, mut device, mut factory) = gfx_window_glutin::init(
        glutin::WindowBuilder::new()
            .with_title("Flowmap example".to_string())
            .with_dimensions(800, 600).build().unwrap()
    );

    let vertex_data = [
        Vertex::new([-1.0, -1.0], [0.0, 0.0]),
        Vertex::new([ 1.0, -1.0], [1.0, 0.0]),
        Vertex::new([ 1.0,  1.0], [1.0, 1.0]),

        Vertex::new([-1.0, -1.0], [0.0, 0.0]),
        Vertex::new([ 1.0,  1.0], [1.0, 1.0]),
        Vertex::new([-1.0,  1.0], [0.0, 1.0]),
    ];

    let mesh = factory.create_mesh(&vertex_data);

    let water_texture = load_texture(&mut factory, &include_bytes!("image/water.png")[..]).unwrap();
    let flow_texture  = load_texture(&mut factory, &include_bytes!("image/flow.png")[..]).unwrap();
    let noise_texture = load_texture(&mut factory, &include_bytes!("image/noise.png")[..]).unwrap();

    let program = {
        let vs = gfx::ShaderSource {
            glsl_120: Some(include_bytes!("shader/flowmap_120.glslv")),
            glsl_150: Some(include_bytes!("shader/flowmap_150.glslv")),
            .. gfx::ShaderSource::empty()
        };
        let fs = gfx::ShaderSource {
            glsl_120: Some(include_bytes!("shader/flowmap_120.glslf")),
            glsl_150: Some(include_bytes!("shader/flowmap_150.glslf")),
            .. gfx::ShaderSource::empty()
        };
        factory.link_program_source(vs, fs).unwrap()
    };

    let uniforms = Params {
        color: (water_texture, None),
        flow: (flow_texture, None),
        noise: (noise_texture, None),
        offset0: 0f32,
        offset1: 0.5f32,
        _r: std::marker::PhantomData,
    };
    let mut batch = gfx::batch::Full::new(mesh, program, uniforms).unwrap();

    let mut cycle0 = 0.0f32;
    let mut cycle1 = 0.5f32;

    'main: loop {
        // quit when Esc is pressed.
        for event in stream.out.window.poll_events() {
            match event {
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) => break 'main,
                glutin::Event::Closed => break 'main,
                _ => {},
            }
        }

        // since we sample our diffuse texture twice we need to lerp between
        // them to get a smooth transition (shouldn't even be noticable).

        // they start half a cycle apart (0.5) and is later used to calculate
        // the interpolation amount via `2.0 * abs(cycle0 - .5f)`
        cycle0 += 0.0025f32;
        if cycle0 > 1f32 {
            cycle0 -= 1f32;
        }

        cycle1 += 0.0025f32;
        if cycle1 > 1f32 {
            cycle1 -= 1f32;
        }

        batch.params.offset0 = cycle0;
        batch.params.offset1 = cycle1;

        stream.clear(gfx::ClearData {
            color: [0.3, 0.3, 0.3, 1.0],
            depth: 1.0,
            stencil: 0,
        });

        stream.draw(&batch).unwrap();
        stream.present(&mut device);
    }
}
<commit_msg>Auto merge of #783 - fkaa:flowmap-delta, r=fkaa<commit_after>// Copyright 2014 The Gfx-rs 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.

extern crate time;

#[macro_use]
extern crate gfx;
extern crate gfx_window_glutin;
extern crate glutin;

extern crate image;

use std::io::Cursor;
use gfx::traits::{Factory, Stream, FactoryExt};

gfx_vertex!( Vertex {
    a_Pos@ pos: [f32; 2],
    a_Uv@ uv: [f32; 2],
});

impl Vertex {
    fn new(p: [f32; 2], u: [f32; 2]) -> Vertex {
        Vertex {
            pos: p,
            uv: u,
        }
    }
}

gfx_parameters!( Params {
    t_Color@ color: gfx::shade::TextureParam<R>,
    t_Flow@ flow: gfx::shade::TextureParam<R>,
    t_Noise@ noise: gfx::shade::TextureParam<R>,
    f_Offset0@ offset0: f32,
    f_Offset1@ offset1: f32,
});

fn load_texture<R, F>(factory: &mut F, data: &[u8]) -> Result<gfx::handle::Texture<R>, String>
        where R: gfx::Resources, F: gfx::device::Factory<R> {
    let img = image::load(Cursor::new(data), image::PNG).unwrap();

    let img = match img {
        image::DynamicImage::ImageRgba8(img) => img,
        img => img.to_rgba()
    };
    let (width, height) = img.dimensions();
    let tex_info = gfx::tex::TextureInfo {
        width: width as u16,
        height: height as u16,
        depth: 1,
        levels: 1,
        kind: gfx::tex::Kind::D2,
        format: gfx::tex::RGBA8
    };

    Ok(factory.create_texture_static(tex_info, &img).unwrap())
}

pub fn main() {
    use time::precise_time_s;

    let (mut stream, mut device, mut factory) = gfx_window_glutin::init(
        glutin::WindowBuilder::new()
            .with_title("Flowmap example".to_string())
            .with_dimensions(800, 600).build().unwrap()
    );

    let vertex_data = [
        Vertex::new([-1.0, -1.0], [0.0, 0.0]),
        Vertex::new([ 1.0, -1.0], [1.0, 0.0]),
        Vertex::new([ 1.0,  1.0], [1.0, 1.0]),

        Vertex::new([-1.0, -1.0], [0.0, 0.0]),
        Vertex::new([ 1.0,  1.0], [1.0, 1.0]),
        Vertex::new([-1.0,  1.0], [0.0, 1.0]),
    ];

    let mesh = factory.create_mesh(&vertex_data);

    let water_texture = load_texture(&mut factory, &include_bytes!("image/water.png")[..]).unwrap();
    let flow_texture  = load_texture(&mut factory, &include_bytes!("image/flow.png")[..]).unwrap();
    let noise_texture = load_texture(&mut factory, &include_bytes!("image/noise.png")[..]).unwrap();

    let program = {
        let vs = gfx::ShaderSource {
            glsl_120: Some(include_bytes!("shader/flowmap_120.glslv")),
            glsl_150: Some(include_bytes!("shader/flowmap_150.glslv")),
            .. gfx::ShaderSource::empty()
        };
        let fs = gfx::ShaderSource {
            glsl_120: Some(include_bytes!("shader/flowmap_120.glslf")),
            glsl_150: Some(include_bytes!("shader/flowmap_150.glslf")),
            .. gfx::ShaderSource::empty()
        };
        factory.link_program_source(vs, fs).unwrap()
    };

    let uniforms = Params {
        color: (water_texture, None),
        flow: (flow_texture, None),
        noise: (noise_texture, None),
        offset0: 0f32,
        offset1: 0.5f32,
        _r: std::marker::PhantomData,
    };
    let mut batch = gfx::batch::Full::new(mesh, program, uniforms).unwrap();

    let mut cycle0 = 0.0f32;
    let mut cycle1 = 0.5f32;

    let mut time_start = precise_time_s();
    let mut time_end;
    'main: loop {
        time_end = time_start;
        time_start = precise_time_s();

        let delta = (time_start - time_end) as f32;

        // quit when Esc is pressed.
        for event in stream.out.window.poll_events() {
            match event {
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) => break 'main,
                glutin::Event::Closed => break 'main,
                _ => {},
            }
        }

        // since we sample our diffuse texture twice we need to lerp between
        // them to get a smooth transition (shouldn't even be noticable).

        // they start half a cycle apart (0.5) and is later used to calculate
        // the interpolation amount via `2.0 * abs(cycle0 - .5f)`
        cycle0 += 0.25f32 * delta;
        if cycle0 > 1f32 {
            cycle0 -= 1f32;
        }

        cycle1 += 0.25f32 * delta;
        if cycle1 > 1f32 {
            cycle1 -= 1f32;
        }

        batch.params.offset0 = cycle0;
        batch.params.offset1 = cycle1;

        stream.clear(gfx::ClearData {
            color: [0.3, 0.3, 0.3, 1.0],
            depth: 1.0,
            stencil: 0,
        });

        stream.draw(&batch).unwrap();
        stream.present(&mut device);
    }
}
<|endoftext|>


<commit_before>extern crate session_types;
extern crate rand;

use session_types::*;
use std::sync::mpsc::{channel, Receiver};
use std::thread::spawn;
use rand::random;

type Server = Recv<u8, Choose<Send<u8, Eps>, Eps>>;
type Client = <Server as HasDual>::Dual;

fn handler(c: Chan<(), Server>) {
    let (c, n) = c.recv();
    match n.checked_add(42) {
        Some(n) => c.sel1().send(n).close(),
        None => c.sel2().close(),
    }
}

fn server(rx: Receiver<Chan<(), Server>>) {
    let mut count = 0;
    loop {
        match borrow_request(&rx) {
            Some(c) => {
                spawn(move || handler(c));
                count += 1;
            },
            None => break,
        }
    }
    println!("Handled {} connections", count);
}

fn client(c: Chan<(), Client>) {
    let n = random();
    match c.send(n).offer() {
        Ok(c) => {
            let (c, n2) = c.recv();
            c.close();
            println!("{} + 42 = {}", n, n2);
        },
        Err(c) => {
            c.close();
            println!("{} + 42 is an overflow :(", n);
        }
    }
}

fn main() {
    let (tx, rx) = channel();
    let mut buf = Vec::new();

    let n: u8 = random();
    println!("Spawning {} clients", n);
    for _ in 0..n {
        let tmp = tx.clone();
        buf.push(spawn(move || client(accept(tmp).unwrap())));
    }
    drop(tx);

    server(rx);
}
<commit_msg>rename stuff to _handler<commit_after>extern crate session_types;
extern crate rand;

use session_types::*;
use std::sync::mpsc::{channel, Receiver};
use std::thread::spawn;
use rand::random;

type Server = Recv<u8, Choose<Send<u8, Eps>, Eps>>;
type Client = <Server as HasDual>::Dual;

fn server_handler(c: Chan<(), Server>) {
    let (c, n) = c.recv();
    match n.checked_add(42) {
        Some(n) => c.sel1().send(n).close(),
        None => c.sel2().close(),
    }
}

fn server(rx: Receiver<Chan<(), Server>>) {
    let mut count = 0;
    loop {
        match borrow_request(&rx) {
            Some(c) => {
                spawn(move || handler(c));
                count += 1;
            },
            None => break,
        }
    }
    println!("Handled {} connections", count);
}

fn client_handler(c: Chan<(), Client>) {
    let n = random();
    match c.send(n).offer() {
        Ok(c) => {
            let (c, n2) = c.recv();
            c.close();
            println!("{} + 42 = {}", n, n2);
        },
        Err(c) => {
            c.close();
            println!("{} + 42 is an overflow :(", n);
        }
    }
}

fn main() {
    let (tx, rx) = channel();
    let mut buf = Vec::new();

    let n: u8 = random();
    println!("Spawning {} clients", n);
    for _ in 0..n {
        let tmp = tx.clone();
        buf.push(spawn(move || client(accept(tmp).unwrap())));
    }
    drop(tx);

    server(rx);
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate variadic_generics;

pub trait OptionTuple {
    type Values;
    fn collect(self) -> Option<Self::Values>;
}

va_expand!{ ($va_len:tt) ($($va_idents:ident),+) ($($va_indices:tt),+)
    impl<$($va_idents),+> OptionTuple for ($(Option<$va_idents>,)+) {
        type Values = ($($va_idents,)+);
        fn collect(self) -> Option<Self::Values> {
            Some((
                $(match self.$va_indices { Some(r) => r, None => return None },)+
            ))
        }
    }
}

fn main() {
    let options = (Some("foo"), Some(42), Some(vec![2, 3, 4]));
    let values = options.clone().collect().unwrap();
    println!("options: {:?}", options);
    println!("values: {:?}", values);
}

// OUTPUT
//
// options: (Some("foo"), Some(42), Some([2, 3, 4]))
// values: ("foo", 42, [2, 3, 4])

<commit_msg>Rename `collect()` to `tuplewrap()`<commit_after>#[macro_use]
extern crate variadic_generics;

pub trait OptionTuple {
    type Values;
    fn tuplewrap(self) -> Option<Self::Values>;
}

va_expand!{ ($va_len:tt) ($($va_idents:ident),+) ($($va_indices:tt),+)
    impl<$($va_idents),+> OptionTuple for ($(Option<$va_idents>,)+) {
        type Values = ($($va_idents,)+);
        fn tuplewrap(self) -> Option<Self::Values> {
            Some((
                $(match self.$va_indices { Some(r) => r, None => return None },)+
            ))
        }
    }
}

fn main() {
    let options = (Some("foo"), Some(42), Some(vec![2, 3, 4]));
    let values = options.clone().tuplewrap().unwrap();
    println!("options: {:?}", options);
    println!("values: {:?}", values);
}

// OUTPUT
//
// options: (Some("foo"), Some(42), Some([2, 3, 4]))
// values: ("foo", 42, [2, 3, 4])

<|endoftext|>