<commit_before>
use diamond::*;

#[test]
fn test_a() {
    assert_eq!(get_diamond('A'), vec!["A"]);
}

#[test]
#[ignore]
fn test_b() {
    assert_eq!(get_diamond('B'), vec![" A ", "B B", " A "]);
}

#[test]
#[ignore]
fn test_c() {
    assert_eq!(
        get_diamond('C'),
        vec!["  A  ", " B B ", "C   C", " B B ", "  A  "]
    );
}

#[test]
#[ignore]
fn test_d() {
    assert_eq!(
        get_diamond('D'),
        vec![
            "   A   ",
            "  B B  ",
            " C   C ",
            "D     D",
            " C   C ",
            "  B B  ",
            "   A   ",
        ]
    );
}

#[test]
#[ignore]
fn test_e() {
    assert_eq!(
        get_diamond('Z'),
        vec![
            "                         A                         ",
            "                        B B                        ",
            "                       C   C                       ",
            "                      D     D                      ",
            "                     E       E                     ",
            "                    F         F                    ",
            "                   G           G                   ",
            "                  H             H                  ",
            "                 I               I                 ",
            "                J                 J                ",
            "               K                   K               ",
            "              L                     L              ",
            "             M                       M             ",
            "            N                         N            ",
            "           O                           O           ",
            "          P                             P          ",
            "         Q                               Q         ",
            "        R                                 R        ",
            "       S                                   S       ",
            "      T                                     T      ",
            "     U                                       U     ",
            "    V                                         V    ",
            "   W                                           W   ",
            "  X                                             X  ",
            " Y                                               Y ",
            "Z                                                 Z",
            " Y                                               Y ",
            "  X                                             X  ",
            "   W                                           W   ",
            "    V                                         V    ",
            "     U                                       U     ",
            "      T                                     T      ",
            "       S                                   S       ",
            "        R                                 R        ",
            "         Q                               Q         ",
            "          P                             P          ",
            "           O                           O           ",
            "            N                         N            ",
            "             M                       M             ",
            "              L                     L              ",
            "               K                   K               ",
            "                J                 J                ",
            "                 I               I                 ",
            "                  H             H                  ",
            "                   G           G                   ",
            "                    F         F                    ",
            "                     E       E                     ",
            "                      D     D                      ",
            "                       C   C                       ",
            "                        B B                        ",
            "                         A                         ",
        ]
    );
}
<commit_msg>diamond: format, with skips<commit_after>use diamond::*;

#[test]
fn test_a() {
    assert_eq!(get_diamond('A'), vec!["A"]);
}

#[test]
#[ignore]
fn test_b() {
    #[rustfmt::skip]
    assert_eq!(
        get_diamond('B'),
        vec![
            " A ",
            "B B",
            " A ",
        ]
    );
}

#[test]
#[ignore]
fn test_c() {
    #[rustfmt::skip]
    assert_eq!(
        get_diamond('C'),
        vec![
            "  A  ",
            " B B ",
            "C   C",
            " B B ",
            "  A  ",
        ]
    );
}

#[test]
#[ignore]
fn test_d() {
    #[rustfmt::skip]
    assert_eq!(
        get_diamond('D'),
        vec![
            "   A   ",
            "  B B  ",
            " C   C ",
            "D     D",
            " C   C ",
            "  B B  ",
            "   A   ",
        ]
    );
}

#[test]
#[ignore]
fn test_e() {
    assert_eq!(
        get_diamond('Z'),
        vec![
            "                         A                         ",
            "                        B B                        ",
            "                       C   C                       ",
            "                      D     D                      ",
            "                     E       E                     ",
            "                    F         F                    ",
            "                   G           G                   ",
            "                  H             H                  ",
            "                 I               I                 ",
            "                J                 J                ",
            "               K                   K               ",
            "              L                     L              ",
            "             M                       M             ",
            "            N                         N            ",
            "           O                           O           ",
            "          P                             P          ",
            "         Q                               Q         ",
            "        R                                 R        ",
            "       S                                   S       ",
            "      T                                     T      ",
            "     U                                       U     ",
            "    V                                         V    ",
            "   W                                           W   ",
            "  X                                             X  ",
            " Y                                               Y ",
            "Z                                                 Z",
            " Y                                               Y ",
            "  X                                             X  ",
            "   W                                           W   ",
            "    V                                         V    ",
            "     U                                       U     ",
            "      T                                     T      ",
            "       S                                   S       ",
            "        R                                 R        ",
            "         Q                               Q         ",
            "          P                             P          ",
            "           O                           O           ",
            "            N                         N            ",
            "             M                       M             ",
            "              L                     L              ",
            "               K                   K               ",
            "                J                 J                ",
            "                 I               I                 ",
            "                  H             H                  ",
            "                   G           G                   ",
            "                    F         F                    ",
            "                     E       E                     ",
            "                      D     D                      ",
            "                       C   C                       ",
            "                        B B                        ",
            "                         A                         ",
        ]
    );
}
<|endoftext|>


<commit_before>extern mod std;

use std::run;
use std::str;
use std::option::*;
use std::trie::*;

fn session_is_attached(line: &str) -> bool {
    line.ends_with("(attached)")
}

fn session_number(line: &str) -> Option<uint> {
    line.split_iter(':').next().and_then(|s| from_str(s))
}

fn detached_sessions(output: ~str) -> TrieSet {
    let mut set = TrieSet::new();
    for line in output.line_iter(){
        if !session_is_attached(line) {
            match session_number(line) {
                Some(n) => { set.insert(n); }
                None => ()
            }
        }
    }
    set
}

fn main() {
    let proc = run::process_output("/usr/local/bin/tmux", &[~"list-sessions"]);
    if proc.status != 0 {
        fail!(fmt!("Tmux exited with an error status: %d", proc.status));
    }
    let output = str::from_utf8(proc.output);
    let sessions = detached_sessions(output);
    match sessions.iter().next() {
        Some(n) => { println(fmt!("Can attach to %u", n)); }
        _ => { println("Have no sessions to attach to"); }
    }
}

#[test]
fn test_session_is_attached() {
    assert!(session_is_attached("11: 1 windows (created Sat Sep 14 17:11:29 2013) [130x65] (attached)"));
    assert!(!session_is_attached("20: 1 windows (created Sat Sep 14 17:11:29 2013) [130x65]"));
}

#[test]
fn test_session_number_with_numbers(){
    match(session_number("11: 1 windows (created Sat Sep 14 17:11:29 2013) [130x65] (attached)")) {
        Some(11) => (),
        Some(n) => fail!(fmt!("Should have returned 11, got %u!", n)),
        None => fail!("Should have returned something, got nothing"),
    }
}

#[test]
fn test_session_number_with_strings(){
    match(session_number("oink: 1 windows (created Sat Sep 14 17:11:29 2013) [130x65] (attached)")) {
        Some(n) => fail!(fmt!("Should have returned None, got %u!", n)),
        None => ()
    }
}

#[test]
fn test_detached_sessions() {
    let set = detached_sessions(~"3: foo (attached)\n2: bar\n4: abz (attached)\nfoo: baz");
    assert!(!set.contains(&2));
    assert!(set.contains(&3));
    assert!(set.contains(&4));
    assert!(!set.contains(&1));
}
<commit_msg>Use the tmux that's on $PATH<commit_after>extern mod std;

use std::run;
use std::str;
use std::option::*;
use std::trie::*;

fn session_is_attached(line: &str) -> bool {
    line.ends_with("(attached)")
}

fn session_number(line: &str) -> Option<uint> {
    line.split_iter(':').next().and_then(|s| from_str(s))
}

fn detached_sessions(output: ~str) -> TrieSet {
    let mut set = TrieSet::new();
    for line in output.line_iter(){
        if !session_is_attached(line) {
            match session_number(line) {
                Some(n) => { set.insert(n); }
                None => ()
            }
        }
    }
    set
}

fn main() {
    let proc = run::process_output("tmux", &[~"list-sessions"]);
    if proc.status != 0 {
        fail!(fmt!("Tmux exited with an error status: %d", proc.status));
    }
    let output = str::from_utf8(proc.output);
    let sessions = detached_sessions(output);
    match sessions.iter().next() {
        Some(n) => { println(fmt!("Can attach to %u", n)); }
        _ => { println("Have no sessions to attach to"); }
    }
}

#[test]
fn test_session_is_attached() {
    assert!(session_is_attached("11: 1 windows (created Sat Sep 14 17:11:29 2013) [130x65] (attached)"));
    assert!(!session_is_attached("20: 1 windows (created Sat Sep 14 17:11:29 2013) [130x65]"));
}

#[test]
fn test_session_number_with_numbers(){
    match(session_number("11: 1 windows (created Sat Sep 14 17:11:29 2013) [130x65] (attached)")) {
        Some(11) => (),
        Some(n) => fail!(fmt!("Should have returned 11, got %u!", n)),
        None => fail!("Should have returned something, got nothing"),
    }
}

#[test]
fn test_session_number_with_strings(){
    match(session_number("oink: 1 windows (created Sat Sep 14 17:11:29 2013) [130x65] (attached)")) {
        Some(n) => fail!(fmt!("Should have returned None, got %u!", n)),
        None => ()
    }
}

#[test]
fn test_detached_sessions() {
    let set = detached_sessions(~"3: foo (attached)\n2: bar\n4: abz (attached)\nfoo: baz");
    assert!(!set.contains(&2));
    assert!(set.contains(&3));
    assert!(set.contains(&4));
    assert!(!set.contains(&1));
}
<|endoftext|>


<commit_before>static LANGUAGE: &'static str = "Rust";
static THRESHOLD: int = 10;

fn is_big(n: int) -> bool {
    // access constant in some function
    n > THRESHOLD
}

fn main() {
    let n = 16;

    // access constant in the main loop
    println!("This is {}", LANGUAGE);
    println!("The threshold is {}", THRESHOLD);
    println!("{} is {}", n, if is_big(n) { "big" } else { "small" });

    // Error: cannot modify static item
    //THRESHOLD = 5;

    if true {
        // string literals are references to read-only memory
        let static_string: &'static str = "In read-only memory";

        // when static_string goes out of scope, we can no longer refer to the
        // underlying data, but the string remains in the read-only memory
    }
}
<commit_msg>constants: fix style, add FIXME<commit_after>static LANGUAGE: &'static str = "Rust";
static THRESHOLD: int = 10;

fn is_big(n: int) -> bool {
    // Access constant in some function
    n > THRESHOLD
}

fn main() {
    let n = 16;

    // Access constant in the main task
    println!("This is {}", LANGUAGE);
    println!("The threshold is {}", THRESHOLD);
    println!("{} is {}", n, if is_big(n) { "big" } else { "small" });

    // Error! Cannot modify an static item
    THRESHOLD = 5;
    // FIXME ^ Comment out this line

    {
        // String literals are references to read-only memory
        let _static_string: &'static str = "In read-only memory";

        // When `_static_string` goes out of scope, we can no longer refer to
        // the underlying data, but the string remains in the read-only memory
    }
}
<|endoftext|>


<commit_before>//! The framework is a customizable method of separating commands, used in
//! combination with [`Client::with_framework`].
//!
//! The framework has a number of configurations, and can have any number of
//! commands bound to it. The primary purpose of it is to offer the utility of
//! not needing to manually match message content strings to determine if a
//! message is a command.
//!
//! Additionally, "checks" can be added to commands, to ensure that a certain
//! condition is met prior to calling a command; this could be a check that the
//! user who posted a message owns the bot, for example.
//!
//! Each command has a given named, and an associated function/closure. For
//! example, you might have two commands: `"ping"` and `"weather"`. These each
//! have an associated function that are called if the framework determines
//! that a message is of that command.
//!
//! Assuming a command prefix of `"~"`, then the following would occur with the
//! two previous commands:
//!
//! ```ignore
//! ~ping // calls the ping command's function
//! ~pin // does not
//! ~ ping // _does_ call it _if_ the `allow_whitespace` option is enabled
//! ~~ping // does not
//! ```
//!
//! # Examples
//!
//! Configuring a Client with a framework, which has a prefix of `"~"` and a
//! ping and about command:
//!
//! ```rust,no_run
//! use serenity::client::{Client, Context};
//! use serenity::model::Message;
//! use std::env;
//!
//! let mut client = Client::login_bot(&env::var("DISCORD_BOT_TOKEN").unwrap());
//!
//! client.with_framework(|f| f
//!     .configure(|c| c.prefix("~"))
//!     .on("about", about)
//!     .on("ping", ping));
//!
//! fn about(context: &Context, _message: &Message, _args: Vec<String>) {
//!     let _ = context.say("A simple test bot");
//! }
//!
//! fn ping(context: &Context, _message: &Message, _args: Vec<String>) {
//!     let _ = context.say("Pong!");
//! }
//! ```
//!
//! [`Client::with_framework`]: ../../client/struct.Client.html#method.with_framework

mod command;
mod configuration;

pub use self::command::Command;
pub use self::configuration::Configuration;

use self::command::InternalCommand;
use std::collections::HashMap;
use std::sync::Arc;
use std::thread;
use ::client::Context;
use ::model::Message;

/// A macro to generate "named parameters". This is useful to avoid manually
/// using the "arguments" parameter and manually parsing types.
///
/// This is meant for use with the command [`Framework`].
///
/// # Examples
///
/// Create a regular `ping` command which takes no arguments:
///
/// ```rust,ignore
/// command!(ping(_context, message, _args) {
///     if let Err(why) = message.reply("Pong!") {
///         println!("Error sending pong: {:?}", why);
///     }
/// });
/// ```
///
/// Create a command named `multiply` which accepts 2 floats and multiplies
/// them, sending the product as a reply:
///
/// ```rust,ignore
/// command!(multiply(_context, message, _args, first: f64, second: f64) {
///     let product = first * second;
///
///     if let Err(why) = message.reply(&product.to_string()) {
///         println!("Error sending product: {:?}", why);
///     }
/// });
/// ```
///
/// [`Framework`]: ext/framework/index.html
#[macro_export]
macro_rules! command {
    ($fname:ident($c:ident, $m:ident, $a:ident) $b:block) => {
        fn $fname($c: &Context, $m: &Message, $a: Vec<String>) {
            $b
        }
    };
    ($fname:ident($c:ident, $m:ident, $a:ident, $($name:ident: $t:ty),*) $b:block) => {
        fn $fname($c: &Context, $m: &Message, $a: Vec<String>) {
            let mut i = $a.iter();

            $(
                let $name = match i.next() {
                    Some(v) => match v.parse::<$t>() {
                        Ok(v) => v,
                        Err(_why) => return,
                    },
                    None => return,
                };
            )*

            drop(i);

            $b
        }
    };
}

/// A utility for easily managing dispatches to commands.
///
/// Refer to the [module-level documentation] for more information.
///
/// [module-level documentation]: index.html
#[allow(type_complexity)]
#[derive(Default)]
pub struct Framework {
    configuration: Configuration,
    commands: HashMap<String, InternalCommand>,
    before: Option<Arc<Fn(&Context, &Message, &String) + Send + Sync + 'static>>,
    after: Option<Arc<Fn(&Context, &Message, &String) + Send + Sync + 'static>>,
    checks: HashMap<String, Arc<Fn(&Context, &Message) -> bool + Send + Sync + 'static>>,
    /// Whether the framework has been "initialized".
    ///
    /// The framework is initialized once one of the following occurs:
    ///
    /// - configuration has been set;
    /// - a command handler has been set;
    /// - a command check has been set.
    ///
    /// This is used internally to determine whether or not - in addition to
    /// dispatching to the [`Client::on_message`] handler - to have the
    /// framework check if a [`Event::MessageCreate`] should be processed by
    /// itself.
    ///
    /// [`Client::on_message`]: ../../client/struct.Client.html#method.on_message
    /// [`Event::MessageCreate`]: ../../model/event/enum.Event.html#variant.MessageCreate
    pub initialized: bool,
}

impl Framework {
    /// Configures the framework, setting non-default values. All fields are
    /// optional. Refer to [`Configuration::default`] for more information on
    /// the default values.
    ///
    /// # Examples
    ///
    /// Configuring the framework for a [`Client`], setting the [`depth`] to 3,
    /// [allowing whitespace], and setting the [`prefix`] to `"~"`:
    ///
    /// ```rust,no_run
    /// use serenity::Client;
    /// use std::env;
    ///
    /// let mut client = Client::login_bot(&env::var("DISCORD_TOKEN").unwrap());
    /// client.with_framework(|f| f
    ///     .configure(|c| c
    ///         .depth(3)
    ///         .allow_whitespace(true)
    ///         .prefix("~")));
    /// ```
    ///
    /// [`Client`]: ../../client/struct.Client.html
    /// [`Configuration::default`]: struct.Configuration.html#method.default
    /// [`depth`]: struct.Configuration.html#method.depth
    /// [`prefix`]: struct.Configuration.html#method.prefix
    /// [allowing whitespace]: struct.Configuration.html#method.allow_whitespace
    pub fn configure<F>(mut self, f: F) -> Self
        where F: FnOnce(Configuration) -> Configuration {
        self.configuration = f(self.configuration);

        self
    }

    #[doc(hidden)]
    pub fn dispatch(&mut self, context: Context, message: Message) {
        let res = command::positions(&message.content, &self.configuration);

        let positions = match res {
            Some(positions) => positions,
            None => return,
        };

        // Ensure that the message length is at least longer than a prefix
        // length. There's no point in checking further ahead if there's nothing
        // _to_ check.
        if positions.iter().all(|p| message.content.len() <= *p) {
            return;
        }

        for position in positions {
            let mut built = String::new();

            for i in 0..self.configuration.depth {
                if i != 0 {
                    built.push(' ');
                }

                built.push_str(match {
                    message.content
                        .split_at(position)
                        .1
                        .trim()
                        .split_whitespace()
                        .collect::<Vec<&str>>()
                        .get(i)
                } {
                    Some(piece) => piece,
                    None => continue,
                });

                if let Some(command) = self.commands.get(&built) {
                    if let Some(check) = self.checks.get(&built) {
                        if !(check)(&context, &message) {
                            continue;
                        }
                    }

                    let before = self.before.clone();
                    let command = command.clone();
                    let after = self.after.clone();

                    thread::spawn(move || {
                        if let Some(before) = before {
                            (before)(&context, &message, &built);
                        }

                        let args = message.content[position + built.len()..]
                            .split_whitespace()
                            .map(|arg| arg.to_owned())
                            .collect::<Vec<String>>();

                        (command)(&context, &message, args);

                        if let Some(after) = after {
                            (after)(&context, &message, &built);
                        }
                    });

                    return;
                }
            }
        }
    }

    /// Adds a function to be associated with a command, which will be called
    /// when a command is used in a message.
    ///
    /// This requires that a check - if one exists - passes, prior to being
    /// called.
    ///
    /// Refer to the [module-level documentation] for more information and
    /// usage.
    ///
    /// [module-level documentation]: index.html
    pub fn on<F, S>(mut self, command_name: S, f: F) -> Self
        where F: Fn(&Context, &Message, Vec<String>) + Send + Sync + 'static,
              S: Into<String> {
        self.commands.insert(command_name.into(), Arc::new(f));
        self.initialized = true;

        self
    }

    /// This will call given closure before every command's execution
    pub fn before<F>(mut self, f: F) -> Self
        where F: Fn(&Context, &Message, &String) + Send + Sync + 'static {
        self.before = Some(Arc::new(f));

        self
    }

    /// This will call given closure after every command's execution
    pub fn after<F>(mut self, f: F) -> Self
        where F: Fn(&Context, &Message, &String) + Send + Sync + 'static {
        self.after = Some(Arc::new(f));

        self
    }

    /// Adds a "check" to a command, which checks whether or not the command's
    /// associated function should be called.
    ///
    /// # Examples
    ///
    /// Ensure that the user who created a message, calling a "ping" command,
    /// is the owner.
    ///
    /// ```rust,no_run
    /// use serenity::client::{Client, Context};
    /// use serenity::model::Message;
    /// use std::env;
    ///
    /// let mut client = Client::login_bot(&env::var("DISCORD_TOKEN").unwrap());
    ///
    /// client.with_framework(|f| f
    ///     .configure(|c| c.prefix("~"))
    ///     .on("ping", ping)
    ///     .set_check("ping", owner_check));
    ///
    /// fn ping(context: &Context, _message: &Message, _args: Vec<String>) {
    ///     context.say("Pong!");
    /// }
    ///
    /// fn owner_check(_context: &Context, message: &Message) -> bool {
    ///     // replace with your user ID
    ///     message.author.id == 7
    /// }
    /// ```
    pub fn set_check<F, S>(mut self, command: S, check: F) -> Self
        where F: Fn(&Context, &Message) -> bool + Send + Sync + 'static,
              S: Into<String> {
        self.checks.insert(command.into(), Arc::new(check));

        self
    }
}
<commit_msg>Make command macro functions public<commit_after>//! The framework is a customizable method of separating commands, used in
//! combination with [`Client::with_framework`].
//!
//! The framework has a number of configurations, and can have any number of
//! commands bound to it. The primary purpose of it is to offer the utility of
//! not needing to manually match message content strings to determine if a
//! message is a command.
//!
//! Additionally, "checks" can be added to commands, to ensure that a certain
//! condition is met prior to calling a command; this could be a check that the
//! user who posted a message owns the bot, for example.
//!
//! Each command has a given named, and an associated function/closure. For
//! example, you might have two commands: `"ping"` and `"weather"`. These each
//! have an associated function that are called if the framework determines
//! that a message is of that command.
//!
//! Assuming a command prefix of `"~"`, then the following would occur with the
//! two previous commands:
//!
//! ```ignore
//! ~ping // calls the ping command's function
//! ~pin // does not
//! ~ ping // _does_ call it _if_ the `allow_whitespace` option is enabled
//! ~~ping // does not
//! ```
//!
//! # Examples
//!
//! Configuring a Client with a framework, which has a prefix of `"~"` and a
//! ping and about command:
//!
//! ```rust,no_run
//! use serenity::client::{Client, Context};
//! use serenity::model::Message;
//! use std::env;
//!
//! let mut client = Client::login_bot(&env::var("DISCORD_BOT_TOKEN").unwrap());
//!
//! client.with_framework(|f| f
//!     .configure(|c| c.prefix("~"))
//!     .on("about", about)
//!     .on("ping", ping));
//!
//! fn about(context: &Context, _message: &Message, _args: Vec<String>) {
//!     let _ = context.say("A simple test bot");
//! }
//!
//! fn ping(context: &Context, _message: &Message, _args: Vec<String>) {
//!     let _ = context.say("Pong!");
//! }
//! ```
//!
//! [`Client::with_framework`]: ../../client/struct.Client.html#method.with_framework

mod command;
mod configuration;

pub use self::command::Command;
pub use self::configuration::Configuration;

use self::command::InternalCommand;
use std::collections::HashMap;
use std::sync::Arc;
use std::thread;
use ::client::Context;
use ::model::Message;

/// A macro to generate "named parameters". This is useful to avoid manually
/// using the "arguments" parameter and manually parsing types.
///
/// This is meant for use with the command [`Framework`].
///
/// # Examples
///
/// Create a regular `ping` command which takes no arguments:
///
/// ```rust,ignore
/// command!(ping(_context, message, _args) {
///     if let Err(why) = message.reply("Pong!") {
///         println!("Error sending pong: {:?}", why);
///     }
/// });
/// ```
///
/// Create a command named `multiply` which accepts 2 floats and multiplies
/// them, sending the product as a reply:
///
/// ```rust,ignore
/// command!(multiply(_context, message, _args, first: f64, second: f64) {
///     let product = first * second;
///
///     if let Err(why) = message.reply(&product.to_string()) {
///         println!("Error sending product: {:?}", why);
///     }
/// });
/// ```
///
/// [`Framework`]: ext/framework/index.html
#[macro_export]
macro_rules! command {
    ($fname:ident($c:ident, $m:ident, $a:ident) $b:block) => {
        pub fn $fname($c: &Context, $m: &Message, $a: Vec<String>) {
            $b
        }
    };
    ($fname:ident($c:ident, $m:ident, $a:ident, $($name:ident: $t:ty),*) $b:block) => {
        pub fn $fname($c: &Context, $m: &Message, $a: Vec<String>) {
            let mut i = $a.iter();

            $(
                let $name = match i.next() {
                    Some(v) => match v.parse::<$t>() {
                        Ok(v) => v,
                        Err(_why) => return,
                    },
                    None => return,
                };
            )*

            drop(i);

            $b
        }
    };
}

/// A utility for easily managing dispatches to commands.
///
/// Refer to the [module-level documentation] for more information.
///
/// [module-level documentation]: index.html
#[allow(type_complexity)]
#[derive(Default)]
pub struct Framework {
    configuration: Configuration,
    commands: HashMap<String, InternalCommand>,
    before: Option<Arc<Fn(&Context, &Message, &String) + Send + Sync + 'static>>,
    after: Option<Arc<Fn(&Context, &Message, &String) + Send + Sync + 'static>>,
    checks: HashMap<String, Arc<Fn(&Context, &Message) -> bool + Send + Sync + 'static>>,
    /// Whether the framework has been "initialized".
    ///
    /// The framework is initialized once one of the following occurs:
    ///
    /// - configuration has been set;
    /// - a command handler has been set;
    /// - a command check has been set.
    ///
    /// This is used internally to determine whether or not - in addition to
    /// dispatching to the [`Client::on_message`] handler - to have the
    /// framework check if a [`Event::MessageCreate`] should be processed by
    /// itself.
    ///
    /// [`Client::on_message`]: ../../client/struct.Client.html#method.on_message
    /// [`Event::MessageCreate`]: ../../model/event/enum.Event.html#variant.MessageCreate
    pub initialized: bool,
}

impl Framework {
    /// Configures the framework, setting non-default values. All fields are
    /// optional. Refer to [`Configuration::default`] for more information on
    /// the default values.
    ///
    /// # Examples
    ///
    /// Configuring the framework for a [`Client`], setting the [`depth`] to 3,
    /// [allowing whitespace], and setting the [`prefix`] to `"~"`:
    ///
    /// ```rust,no_run
    /// use serenity::Client;
    /// use std::env;
    ///
    /// let mut client = Client::login_bot(&env::var("DISCORD_TOKEN").unwrap());
    /// client.with_framework(|f| f
    ///     .configure(|c| c
    ///         .depth(3)
    ///         .allow_whitespace(true)
    ///         .prefix("~")));
    /// ```
    ///
    /// [`Client`]: ../../client/struct.Client.html
    /// [`Configuration::default`]: struct.Configuration.html#method.default
    /// [`depth`]: struct.Configuration.html#method.depth
    /// [`prefix`]: struct.Configuration.html#method.prefix
    /// [allowing whitespace]: struct.Configuration.html#method.allow_whitespace
    pub fn configure<F>(mut self, f: F) -> Self
        where F: FnOnce(Configuration) -> Configuration {
        self.configuration = f(self.configuration);

        self
    }

    #[doc(hidden)]
    pub fn dispatch(&mut self, context: Context, message: Message) {
        let res = command::positions(&message.content, &self.configuration);

        let positions = match res {
            Some(positions) => positions,
            None => return,
        };

        // Ensure that the message length is at least longer than a prefix
        // length. There's no point in checking further ahead if there's nothing
        // _to_ check.
        if positions.iter().all(|p| message.content.len() <= *p) {
            return;
        }

        for position in positions {
            let mut built = String::new();

            for i in 0..self.configuration.depth {
                if i != 0 {
                    built.push(' ');
                }

                built.push_str(match {
                    message.content
                        .split_at(position)
                        .1
                        .trim()
                        .split_whitespace()
                        .collect::<Vec<&str>>()
                        .get(i)
                } {
                    Some(piece) => piece,
                    None => continue,
                });

                if let Some(command) = self.commands.get(&built) {
                    if let Some(check) = self.checks.get(&built) {
                        if !(check)(&context, &message) {
                            continue;
                        }
                    }

                    let before = self.before.clone();
                    let command = command.clone();
                    let after = self.after.clone();

                    thread::spawn(move || {
                        if let Some(before) = before {
                            (before)(&context, &message, &built);
                        }

                        let args = message.content[position + built.len()..]
                            .split_whitespace()
                            .map(|arg| arg.to_owned())
                            .collect::<Vec<String>>();

                        (command)(&context, &message, args);

                        if let Some(after) = after {
                            (after)(&context, &message, &built);
                        }
                    });

                    return;
                }
            }
        }
    }

    /// Adds a function to be associated with a command, which will be called
    /// when a command is used in a message.
    ///
    /// This requires that a check - if one exists - passes, prior to being
    /// called.
    ///
    /// Refer to the [module-level documentation] for more information and
    /// usage.
    ///
    /// [module-level documentation]: index.html
    pub fn on<F, S>(mut self, command_name: S, f: F) -> Self
        where F: Fn(&Context, &Message, Vec<String>) + Send + Sync + 'static,
              S: Into<String> {
        self.commands.insert(command_name.into(), Arc::new(f));
        self.initialized = true;

        self
    }

    /// This will call given closure before every command's execution
    pub fn before<F>(mut self, f: F) -> Self
        where F: Fn(&Context, &Message, &String) + Send + Sync + 'static {
        self.before = Some(Arc::new(f));

        self
    }

    /// This will call given closure after every command's execution
    pub fn after<F>(mut self, f: F) -> Self
        where F: Fn(&Context, &Message, &String) + Send + Sync + 'static {
        self.after = Some(Arc::new(f));

        self
    }

    /// Adds a "check" to a command, which checks whether or not the command's
    /// associated function should be called.
    ///
    /// # Examples
    ///
    /// Ensure that the user who created a message, calling a "ping" command,
    /// is the owner.
    ///
    /// ```rust,no_run
    /// use serenity::client::{Client, Context};
    /// use serenity::model::Message;
    /// use std::env;
    ///
    /// let mut client = Client::login_bot(&env::var("DISCORD_TOKEN").unwrap());
    ///
    /// client.with_framework(|f| f
    ///     .configure(|c| c.prefix("~"))
    ///     .on("ping", ping)
    ///     .set_check("ping", owner_check));
    ///
    /// fn ping(context: &Context, _message: &Message, _args: Vec<String>) {
    ///     context.say("Pong!");
    /// }
    ///
    /// fn owner_check(_context: &Context, message: &Message) -> bool {
    ///     // replace with your user ID
    ///     message.author.id == 7
    /// }
    /// ```
    pub fn set_check<F, S>(mut self, command: S, check: F) -> Self
        where F: Fn(&Context, &Message) -> bool + Send + Sync + 'static,
              S: Into<String> {
        self.checks.insert(command.into(), Arc::new(check));

        self
    }
}
<|endoftext|>


<commit_before>pub fn init() -> () {
    ()
}
<commit_msg>Code Review Changes<commit_after>pub fn init() -> () {
    println!("bootstrap::init() isn't implemented on linux");
    ()
}
<|endoftext|>


<commit_before>use quote::{Tokens, ToTokens};
use syn;

/// Deprecation notes we want to emit to the user, implementing `quote::ToTokens`.
///
/// Can be expanded at every place that accepts statements and item definitions
/// (e.g. function bodys).
///
/// # Examples
///
/// Will expand to something like the following (depending on settings):
///
/// ```rust
/// # #[macro_use]
/// # extern crate quote;
/// # extern crate derive_builder_core;
/// # use derive_builder_core::DeprecationNotes;
/// # fn main() {
/// #    let mut note = DeprecationNotes::default();
/// #    note.push("Some Warning".to_string());
/// #    assert_eq!(quote!(#note), quote!(
///         {
///             #[deprecated(note="Some Warning")]
///             fn derive_builder_core_deprecation_note() { }
///             derive_builder_core_deprecation_note();
///         }
/// #    ));
/// # }
/// ```
///
/// This will emit a deprecation warning in the downstream crate. Cool stuff. ^^
///
/// Proof of concept:
/// - https://play.rust-lang.org/?gist=8394141c07d1f6d75d314818389eb4d8
#[derive(Debug, Default, Clone)]
pub struct DeprecationNotes(Vec<String>);

impl ToTokens for DeprecationNotes {
    fn to_tokens(&self, tokens: &mut Tokens) {
        for note in &self.0 {
            let fn_ident = syn::Ident::new("derive_builder_core_deprecation_note");
            tokens.append(quote!(
                {
                    #[deprecated(note=#note)]
                    fn #fn_ident() { }
                    #fn_ident();
                }
            ));
        }
    }
}

impl DeprecationNotes {
    /// Appends a note to the collection.
    pub fn push(&mut self, note: String) {
        self.0.push(note)
    }

    /// Extend this collection with all values from another collection.
    pub fn extend(&mut self, other: &DeprecationNotes) {
        for x in &other.0 {
            self.0.push(x.to_owned())
        }
    }

    /// Create a view of these deprecation notes that can annotate a struct.
    pub fn as_item<'a>(&'a self) -> DeprecationNotesAsItem<'a> {
        DeprecationNotesAsItem(&self)
    }
}

/// A view of `DeprecationNotes` that can be used in any context that accept items.
///
/// Expands to a function `__deprecation_notes` which emits the notes.
#[derive(Debug)]
pub struct DeprecationNotesAsItem<'a>(&'a DeprecationNotes);

impl<'a> ToTokens for DeprecationNotesAsItem<'a> {
    fn to_tokens(&self, tokens: &mut Tokens) {
        let deprecation_notes = self.0;

        if !deprecation_notes.0.is_empty() {
            tokens.append(quote!(
                #[doc(hidden)]
                fn derive_builder_core_deprecation_note() {
                    #deprecation_notes
                }
            ))
        }
    }
}

#[test]
fn deprecation_note() {
    let mut note = DeprecationNotes::default();
    note.push("Some Warning".to_string());
    assert_eq!(quote!(#note), quote!(
        {
            #[deprecated(note="Some Warning")]
            fn derive_builder_core_deprecation_note() { }
            derive_builder_core_deprecation_note();
        }
    ));
}
<commit_msg>clippy<commit_after>use quote::{Tokens, ToTokens};
use syn;

/// Deprecation notes we want to emit to the user, implementing `quote::ToTokens`.
///
/// Can be expanded at every place that accepts statements and item definitions
/// (e.g. function bodys).
///
/// # Examples
///
/// Will expand to something like the following (depending on settings):
///
/// ```rust
/// # #[macro_use]
/// # extern crate quote;
/// # extern crate derive_builder_core;
/// # use derive_builder_core::DeprecationNotes;
/// # fn main() {
/// #    let mut note = DeprecationNotes::default();
/// #    note.push("Some Warning".to_string());
/// #    assert_eq!(quote!(#note), quote!(
///         {
///             #[deprecated(note="Some Warning")]
///             fn derive_builder_core_deprecation_note() { }
///             derive_builder_core_deprecation_note();
///         }
/// #    ));
/// # }
/// ```
///
/// This will emit a deprecation warning in the downstream crate. Cool stuff. ^^
///
/// Proof of concept:
/// - https://play.rust-lang.org/?gist=8394141c07d1f6d75d314818389eb4d8
#[derive(Debug, Default, Clone)]
pub struct DeprecationNotes(Vec<String>);

impl ToTokens for DeprecationNotes {
    fn to_tokens(&self, tokens: &mut Tokens) {
        for note in &self.0 {
            let fn_ident = syn::Ident::new("derive_builder_core_deprecation_note");
            tokens.append(quote!(
                {
                    #[deprecated(note=#note)]
                    fn #fn_ident() { }
                    #fn_ident();
                }
            ));
        }
    }
}

impl DeprecationNotes {
    /// Appends a note to the collection.
    pub fn push(&mut self, note: String) {
        self.0.push(note)
    }

    /// Extend this collection with all values from another collection.
    pub fn extend(&mut self, other: &DeprecationNotes) {
        for x in &other.0 {
            self.0.push(x.to_owned())
        }
    }

    /// Create a view of these deprecation notes that can annotate a struct.
    pub fn as_item(&self) -> DeprecationNotesAsItem {
        DeprecationNotesAsItem(self)
    }
}

/// A view of `DeprecationNotes` that can be used in any context that accept items.
///
/// Expands to a function `__deprecation_notes` which emits the notes.
#[derive(Debug)]
pub struct DeprecationNotesAsItem<'a>(&'a DeprecationNotes);

impl<'a> ToTokens for DeprecationNotesAsItem<'a> {
    fn to_tokens(&self, tokens: &mut Tokens) {
        let deprecation_notes = self.0;

        if !deprecation_notes.0.is_empty() {
            tokens.append(quote!(
                #[doc(hidden)]
                fn derive_builder_core_deprecation_note() {
                    #deprecation_notes
                }
            ))
        }
    }
}

#[test]
fn deprecation_note() {
    let mut note = DeprecationNotes::default();
    note.push("Some Warning".to_string());
    assert_eq!(quote!(#note), quote!(
        {
            #[deprecated(note="Some Warning")]
            fn derive_builder_core_deprecation_note() { }
            derive_builder_core_deprecation_note();
        }
    ));
}
<|endoftext|>


<commit_before>pub const MASK_OUT_X_EA: u32 = 0b1111000111000000; // masks out X and Y register bits, plus mode (????xxx???mmmyyy)
pub const MASK_OUT_EA: u32 = 0b1111111111000000;   // masks out Y register bits, plus mode (??????????mmmyyy)

pub const EA_DATA_REGISTER_DIRECT: u16 =      0b1000_0000_0000;
pub const EA_ADDRESS_REGISTER_DIRECT: u16 =   0b0100_0000_0000;
pub const EA_ADDRESS_REGISTER_INDIRECT: u16 = 0b0010_0000_0000;
pub const EA_ARI_POSTINCREMENT: u16 =         0b0001_0000_0000;
pub const EA_ARI_PREDECREMENT: u16 =          0b0000_1000_0000;
pub const EA_ARI_DISPLACEMENT: u16 =          0b0000_0100_0000;
pub const EA_ARI_INDEX: u16 =                 0b0000_0010_0000;
pub const EA_ABSOLUTE_SHORT: u16 =            0b0000_0001_0000;
pub const EA_ABSOLUTE_LONG: u16 =             0b0000_0000_1000;
pub const EA_IMMEDIATE: u16 =                 0b0000_0000_0100;
pub const EA_PC_DISPLACEMENT: u16 =           0b0000_0000_0010;
pub const EA_PC_INDEX: u16 =                  0b0000_0000_0001;

pub const EA_ALL: u16 = 0xfff;
pub const EA_ALL_EXCEPT_AN: u16 = EA_ALL & !EA_ADDRESS_REGISTER_DIRECT;
pub const EA_ALTERABLE: u16 = EA_DATA_REGISTER_DIRECT
                        | EA_ADDRESS_REGISTER_DIRECT
                        | EA_ADDRESS_REGISTER_INDIRECT
                        | EA_ARI_POSTINCREMENT
                        | EA_ARI_PREDECREMENT
                        | EA_ARI_DISPLACEMENT
                        | EA_ARI_INDEX
                        | EA_ABSOLUTE_SHORT
                        | EA_ABSOLUTE_LONG;
pub const EA_CONTROL: u16 = EA_ADDRESS_REGISTER_INDIRECT
                        | EA_ARI_DISPLACEMENT
                        | EA_ARI_INDEX
                        | EA_ABSOLUTE_SHORT
                        | EA_ABSOLUTE_LONG
                        | EA_PC_DISPLACEMENT
                        | EA_PC_INDEX;
pub const EA_CONTROL_ALTERABLE_OR_PD: u16 = EA_CONTROL & EA_ALTERABLE | EA_ARI_PREDECREMENT;
pub const EA_CONTROL_OR_PI: u16 = EA_CONTROL | EA_ARI_POSTINCREMENT;
pub const EA_DATA: u16 = EA_ALL & !(EA_ADDRESS_REGISTER_DIRECT | EA_IMMEDIATE);
pub const EA_DATA_ALTERABLE: u16 = EA_DATA & EA_ALTERABLE;
pub const EA_MEMORY_ALTERABLE: u16 = EA_ALTERABLE & !(EA_DATA_REGISTER_DIRECT | EA_ADDRESS_REGISTER_DIRECT);
pub const EA_NONE: u16 = 0x000;

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

    #[test]
    fn ea_all_except_an() {
        assert_eq!(EA_ALL_EXCEPT_AN & EA_ADDRESS_REGISTER_DIRECT, 0);
    }
    #[test]
    fn ea_alterable() {
        assert_eq!(EA_ALTERABLE & (EA_IMMEDIATE|EA_PC_DISPLACEMENT|EA_PC_INDEX), 0);
    }
    #[test]
    fn ea_control() {
        assert_eq!(EA_CONTROL, 0x27b);
    }
    #[test]
    fn ea_control_alterable_or_pd() {
        assert_eq!(EA_CONTROL_ALTERABLE_OR_PD & EA_ARI_PREDECREMENT, EA_ARI_PREDECREMENT);
    }
    #[test]
    fn ea_control_or_pi() {
        assert_eq!(EA_CONTROL_OR_PI & EA_ARI_POSTINCREMENT, EA_ARI_POSTINCREMENT);
    }
    #[test]
    fn ea_data() {
        assert_eq!(EA_DATA & (EA_ADDRESS_REGISTER_DIRECT | EA_IMMEDIATE), 0);
    }
    #[test]
    fn ea_data_alterable() {
        assert_eq!(EA_DATA_ALTERABLE, EA_DATA & EA_ALTERABLE);
    }
    #[test]
    fn ea_memory_alterable() {
        assert_eq!(EA_MEMORY_ALTERABLE & (EA_DATA_REGISTER_DIRECT | EA_ADDRESS_REGISTER_DIRECT), 0);
    }
}<commit_msg>Fix addressing mode group constants<commit_after>pub const MASK_OUT_X_EA: u32 = 0b1111_0001_1100_0000; // masks out X and Y register bits, plus mode (????xxx???mmmyyy)
pub const MASK_OUT_EA: u32 = 0b1111111111000000;   // masks out Y register bits, plus mode (??????????mmmyyy)
pub const MASK_OUT_EA_EA: u32 = 0b1111_0000_0000_0000;   // masks out destination(reg (x), mode (d)), source(reg(y) and mode(m)) (????xxxdddmmmyyy)

pub const EA_DATA_REGISTER_DIRECT: u16 =      0b1000_0000_0000;
pub const EA_ADDRESS_REGISTER_DIRECT: u16 =   0b0100_0000_0000;
pub const EA_ADDRESS_REGISTER_INDIRECT: u16 = 0b0010_0000_0000;
pub const EA_ARI_POSTINCREMENT: u16 =         0b0001_0000_0000;
pub const EA_ARI_PREDECREMENT: u16 =          0b0000_1000_0000;
pub const EA_ARI_DISPLACEMENT: u16 =          0b0000_0100_0000;
pub const EA_ARI_INDEX: u16 =                 0b0000_0010_0000;
pub const EA_ABSOLUTE_SHORT: u16 =            0b0000_0001_0000;
pub const EA_ABSOLUTE_LONG: u16 =             0b0000_0000_1000;
pub const EA_IMMEDIATE: u16 =                 0b0000_0000_0100;
pub const EA_PC_DISPLACEMENT: u16 =           0b0000_0000_0010;
pub const EA_PC_INDEX: u16 =                  0b0000_0000_0001;

pub const EA_ALL: u16 = 0xfff;
pub const EA_ALL_EXCEPT_AN: u16 = EA_ALL & !EA_ADDRESS_REGISTER_DIRECT;
pub const EA_ALTERABLE: u16 = EA_DATA_REGISTER_DIRECT
                        | EA_ADDRESS_REGISTER_DIRECT
                        | EA_ADDRESS_REGISTER_INDIRECT
                        | EA_ARI_POSTINCREMENT
                        | EA_ARI_PREDECREMENT
                        | EA_ARI_DISPLACEMENT
                        | EA_ARI_INDEX;
pub const EA_CONTROL: u16 = EA_ADDRESS_REGISTER_INDIRECT
                        | EA_ARI_DISPLACEMENT
                        | EA_ARI_INDEX
                        | EA_ABSOLUTE_SHORT
                        | EA_ABSOLUTE_LONG
                        | EA_PC_DISPLACEMENT
                        | EA_PC_INDEX;
pub const EA_CONTROL_ALTERABLE_OR_PD: u16 = EA_CONTROL & EA_ALTERABLE | EA_ARI_PREDECREMENT;
pub const EA_CONTROL_OR_PI: u16 = EA_CONTROL | EA_ARI_POSTINCREMENT;
pub const EA_DATA: u16 = EA_ALL & !EA_ADDRESS_REGISTER_DIRECT;
pub const EA_DATA_ALTERABLE: u16 = EA_DATA & EA_ALTERABLE;
pub const EA_MEMORY: u16 = EA_ALL & !(EA_DATA_REGISTER_DIRECT | EA_ADDRESS_REGISTER_DIRECT);
pub const EA_MEMORY_ALTERABLE: u16 = EA_MEMORY & EA_ALTERABLE;
pub const EA_NONE: u16 = 0x000;

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

    #[test]
    fn ea_all_except_an() {
        assert_eq!(EA_ALL_EXCEPT_AN & EA_ADDRESS_REGISTER_DIRECT, 0);
    }
    #[test]
    fn ea_alterable() {
        assert_eq!(EA_ALTERABLE & (EA_IMMEDIATE|EA_PC_DISPLACEMENT|EA_PC_INDEX), 0);
    }
    #[test]
    fn ea_control() {
        assert_eq!(EA_CONTROL, 0x27b);
    }
    #[test]
    fn ea_control_alterable_or_pd() {
        assert_eq!(EA_CONTROL_ALTERABLE_OR_PD & EA_ARI_PREDECREMENT, EA_ARI_PREDECREMENT);
    }
    #[test]
    fn ea_control_or_pi() {
        assert_eq!(EA_CONTROL_OR_PI & EA_ARI_POSTINCREMENT, EA_ARI_POSTINCREMENT);
    }
    #[test]
    fn ea_data() {
        assert_eq!(EA_DATA & (EA_ADDRESS_REGISTER_DIRECT | EA_IMMEDIATE), 0);
    }
    #[test]
    fn ea_data_alterable() {
        assert_eq!(EA_DATA_ALTERABLE, EA_DATA & EA_ALTERABLE);
    }
    #[test]
    fn ea_memory_alterable() {
        assert_eq!(EA_MEMORY_ALTERABLE & (EA_DATA_REGISTER_DIRECT | EA_ADDRESS_REGISTER_DIRECT), 0);
    }
}<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::path::Path;

#[derive(Debug)]
pub struct LanguageSpec {
    pub reserved_words: HashMap<String, String>,
    pub hash_comment: bool,
    pub c_style_comments: bool,
    pub backtick_strings: bool,
    pub regexp_literals: bool,
    pub triple_quote_literals: bool,
    pub c_preprocessor: bool,
    // Rust is mostly C-like, with a couple of differences.
    pub rust_tweaks: bool,
}

fn make_reserved(v: &[&str]) -> HashMap<String, String> {
    let mut reserved_words = HashMap::new();
    for word in v {
        reserved_words.insert(word.to_string(), "class=\"syn_reserved\" ".to_string());
    }
    reserved_words
}

lazy_static! {
    static ref RESERVED_WORDS_JS : Vec<&'static str> = vec![
        "abstract", "else", "instanceof", "super",
        "boolean", "enum", "int", "switch",
        "break", "export", "interface", "synchronized",
        "byte", "extends", "let", "this",
        "case", "false", "long", "throw",
        "catch", "final", "native", "throws",
        "char", "finally", "new", "transient",
        "class", "float", "null", "true",
        "const", "for", "package", "try",
        "continue", "function", "private", "typeof",
        "debugger", "goto", "protected", "var",
        "default", "if", "public", "void",
        "delete", "implements", "return", "volatile",
        "do", "import", "short", "while",
        "double", "in", "static", "with",
        "get", "set",
    ];

    static ref RESERVED_WORDS_CPP : Vec<&'static str> = vec![
        "alignas", "alignof", "and", "and_eq", "asm", "atomic_cancel",
        "atomic_commit", "atomic_noexcept", "auto", "bitand", "bitor", "bool", "break",
        "case", "catch", "char", "char16_t", "char32_t", "class", "compl", "concept",
        "const", "constexpr", "const_cast", "continue", "decltype", "default", "delete",
        "do", "double", "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false",
        "float", "for", "friend", "goto", "if", "inline", "int", "import", "long", "module",
        "mutable", "namespace", "new", "noexcept", "not", "not_eq", "nullptr",
        // Don't mark "operator" as a keyword so that people can click
        // on it.
        //"operator",
        "or", "or_eq", "private", "protected", "public", "register", "reinterpret_cast",
        "requires", "return", "short", "signed", "sizeof", "static", "static_assert",
        "static_cast", "struct", "switch", "synchronized", "template", "this", "thread_local",
        "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned",
        "using", "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq",
        "#if", "#ifdef", "#ifndef", "#else", "#elif", "#endif", "#define", "#undef",
        "#include", "#error", "defined",
    ];

    static ref RESERVED_WORDS_IPDL : Vec<&'static str> = vec![
        "answer", "as", "async", "both", "bridges", "call", "child", "class",
        "compress", "compressall", "__delete__", "delete", "from", "goto", "high",
        "include", "intr", "manager", "manages", "namespace", "normal", "nullable",
        "opens", "or", "parent", "prio", "protocol", "recv", "returns", "send",
        "spawns", "start", "state", "struct", "sync", "union", "upto", "urgent",
        "using",
    ];

    static ref RESERVED_WORDS_IDL : Vec<&'static str> = vec![
        "const", "interface", "in", "inout", "out", "attribute", "raises",
        "readonly", "native", "typedef",
        "array", "shared", "iid_is", "size_is", "retval",
        "boolean", "void", "octet", "short", "long", "long",
        "unsigned", "float", "double", "char", "string", "wchar", "wstring",
        "nsid", "domstring", "utf8string", "cstring", "astring", "jsval",
        "uuid", "scriptable", "builtinclass", "function", "noscript", "deprecated",
        "object", "main_process_scriptable_only",
    ];

    static ref RESERVED_WORDS_WEBIDL : Vec<&'static str> = vec![
        "module", "interface", "partial", "dictionary", "exception", "enum", "callback",
        "typedef", "implements", "const", "null", "true", "false", "serializer",
        "stringifier", "jsonifier", "unrestricted", "attribute", "readonly", "inherit",
        "static", "getter", "setter", "creator", "deleter", "legacycaller", "optional",
        "Date", "DOMString", "ByteString", "USVString", "any", "boolean", "byte",
        "double", "float", "long", "object", "octet", "Promise", "required", "sequence",
        "MozMap", "short", "unsigned", "void", "ArrayBuffer", "SharedArrayBuffer", "or",
        "maplike", "setlike", "iterable",
        "Exposed", "ChromeOnly", "ChromeConstructor", "Pref", "Func", "AvailableIn",
        "CheckAnyPermissions", "CheckAllPermissions", "JSImplementation", "HeaderFile",
        "NavigatorProperty", "AvailableIn", "Func", "CheckAnyPermissions", "CheckAllPermissions",
        "Deprecated", "NeedResolve", "OverrideBuiltins", "ChromeOnly", "Unforgeable",
        "UnsafeInPrerendering", "LegacyEventInit", "ProbablyShortLivingObject", "ArrayClass",
        "Clamp", "Constructor", "EnforceRange", "ExceptionClass", "Exposed", "ImplicitThis",
        "Global", "PrimaryGlobal", "LegacyArrayClass", "LegacyUnenumerableNamedProperties",
        "LenientSetter", "LenientThis", "NamedConstructor", "NewObject", "NoInterfaceObject",
        "OverrideBuiltins", "PutForwards", "Replaceable", "SameObject", "SecureContext",
        "Throws", "TreatNonObjectAsNull", "TreatNullAs", "Unforgeable", "Unscopable",
    ];

    static ref RESERVED_WORDS_PYTHON : Vec<&'static str> = vec![
        "and", "del", "from", "not", "while",
        "as", "elif", "global", "or", "with",
        "assert", "else", "if", "pass", "yield",
        "break", "except", "import", "print",
        "class", "exec", "in", "raise", "continue",
        "finally", "is", "return",
        "def", "for", "lambda", "try",
    ];

    // List of Rust reserved words pulled from
    // https://github.com/rust-lang/rust/blob/master/src/libsyntax/symbol.rs
    static ref RESERVED_WORDS_RUST : Vec<&'static str> = vec![
        "as", "box", "break", "const", "continue", "crate",
        "else", "enum", "extern", "false", "fn", "for", "if",
        "impl", "in", "let", "loop", "match", "mod", "move",
        "mut", "pub", "ref", "return", "self", "Self", "static",
        "struct", "super", "trait", "true", "type", "unsafe",
        "use", "where", "while",

        "abstract", "alignof", "become", "do", "final", "macro",
        "offsetof", "override", "priv", "proc", "pure", "sizeof",
        "typeof", "unsized", "virtual", "yield",

        "default", "union",
    ];

    static ref RESERVED_WORDS_JAVA : Vec<&'static str> = vec![
        "abstract", "continue", "for", "new", "switch", "assert", "default",
        "goto", "package", "synchronized", "boolean", "do", "if", "private",
        "this", "break", "double", "implements", "protected", "throw", "byte",
        "else", "import", "public", "throws", "case", "enum", "instanceof",
        "return", "transient", "catch", "extends", "int", "short", "try",
        "char", "final", "interface", "static", "void", "class", "finally",
        "long", "strictfp", "volatile", "const", "float", "native", "super",
        "while", "null", "true", "false",
    ];

    static ref JS_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_JS),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: true,
        regexp_literals: true,
        triple_quote_literals: false,
        c_preprocessor: false,
        rust_tweaks: false,
    };

    static ref CPP_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_CPP),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: true,
        rust_tweaks: false,
    };

    static ref IPDL_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_IPDL),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: false,
        rust_tweaks: false,
    };

    static ref IDL_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_IDL),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: false,
        rust_tweaks: false,
    };

    static ref WEBIDL_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_WEBIDL),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: false,
        rust_tweaks: false,
    };

    static ref PYTHON_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_PYTHON),
        hash_comment: true,
        c_style_comments: false,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: true,
        c_preprocessor: false,
        rust_tweaks: false,
    };

    static ref RUST_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_RUST),
        hash_comment: true, // for now, for attributes
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: false,
        rust_tweaks: true,
    };

    static ref JAVA_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_JAVA),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: false,
        rust_tweaks: false,
    };
}

#[derive(Debug)]
pub enum DocType {
    Markdown,
    ReStructuredText,
}

#[derive(Debug)]
pub enum FormatAs {
    FormatCLike(&'static LanguageSpec),
    FormatTagLike(&'static LanguageSpec),
    Plain,
    Binary,
}

pub fn select_formatting(filename: &str) -> FormatAs {
    let ext = match Path::new(filename).extension() {
        Some(ext) => ext.to_str().unwrap(),
        None => "",
    };
    match ext {
        "c" | "cc" | "cpp" | "h" | "hh" | "mm" => FormatAs::FormatCLike(&*CPP_SPEC),
        "ipdl" | "ipdlh" => FormatAs::FormatCLike(&*IPDL_SPEC),
        "idl" => FormatAs::FormatCLike(&*IDL_SPEC),
        "webidl" => FormatAs::FormatCLike(&*WEBIDL_SPEC),
        "js" | "jsm" | "json" | "sjs" => FormatAs::FormatCLike(&*JS_SPEC),
        "py" | "build" | "configure" => FormatAs::FormatCLike(&*PYTHON_SPEC),
        "rs" => FormatAs::FormatCLike(&*RUST_SPEC),
        "java" => FormatAs::FormatCLike(&*JAVA_SPEC),

        "html" | "htm" | "xhtml" | "xml" | "xul" => FormatAs::FormatTagLike(&*JS_SPEC),

        "ogg" | "ttf" | "xpi" | "png" | "bcmap" |
        "gif" | "ogv" | "jpg" | "jpeg" | "bmp" | "icns" | "ico" |
        "mp4" | "sqlite" | "jar" | "webm" | "woff" |
        "class" | "m4s" | "mgif" | "wav" | "opus" |
        "mp3" | "otf" => FormatAs::Binary,

        _ => FormatAs::Plain,
    }
}
<commit_msg>Bug 1459088 - Treat .xht files as HTML<commit_after>use std::collections::HashMap;
use std::path::Path;

#[derive(Debug)]
pub struct LanguageSpec {
    pub reserved_words: HashMap<String, String>,
    pub hash_comment: bool,
    pub c_style_comments: bool,
    pub backtick_strings: bool,
    pub regexp_literals: bool,
    pub triple_quote_literals: bool,
    pub c_preprocessor: bool,
    // Rust is mostly C-like, with a couple of differences.
    pub rust_tweaks: bool,
}

fn make_reserved(v: &[&str]) -> HashMap<String, String> {
    let mut reserved_words = HashMap::new();
    for word in v {
        reserved_words.insert(word.to_string(), "class=\"syn_reserved\" ".to_string());
    }
    reserved_words
}

lazy_static! {
    static ref RESERVED_WORDS_JS : Vec<&'static str> = vec![
        "abstract", "else", "instanceof", "super",
        "boolean", "enum", "int", "switch",
        "break", "export", "interface", "synchronized",
        "byte", "extends", "let", "this",
        "case", "false", "long", "throw",
        "catch", "final", "native", "throws",
        "char", "finally", "new", "transient",
        "class", "float", "null", "true",
        "const", "for", "package", "try",
        "continue", "function", "private", "typeof",
        "debugger", "goto", "protected", "var",
        "default", "if", "public", "void",
        "delete", "implements", "return", "volatile",
        "do", "import", "short", "while",
        "double", "in", "static", "with",
        "get", "set",
    ];

    static ref RESERVED_WORDS_CPP : Vec<&'static str> = vec![
        "alignas", "alignof", "and", "and_eq", "asm", "atomic_cancel",
        "atomic_commit", "atomic_noexcept", "auto", "bitand", "bitor", "bool", "break",
        "case", "catch", "char", "char16_t", "char32_t", "class", "compl", "concept",
        "const", "constexpr", "const_cast", "continue", "decltype", "default", "delete",
        "do", "double", "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false",
        "float", "for", "friend", "goto", "if", "inline", "int", "import", "long", "module",
        "mutable", "namespace", "new", "noexcept", "not", "not_eq", "nullptr",
        // Don't mark "operator" as a keyword so that people can click
        // on it.
        //"operator",
        "or", "or_eq", "private", "protected", "public", "register", "reinterpret_cast",
        "requires", "return", "short", "signed", "sizeof", "static", "static_assert",
        "static_cast", "struct", "switch", "synchronized", "template", "this", "thread_local",
        "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned",
        "using", "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq",
        "#if", "#ifdef", "#ifndef", "#else", "#elif", "#endif", "#define", "#undef",
        "#include", "#error", "defined",
    ];

    static ref RESERVED_WORDS_IPDL : Vec<&'static str> = vec![
        "answer", "as", "async", "both", "bridges", "call", "child", "class",
        "compress", "compressall", "__delete__", "delete", "from", "goto", "high",
        "include", "intr", "manager", "manages", "namespace", "normal", "nullable",
        "opens", "or", "parent", "prio", "protocol", "recv", "returns", "send",
        "spawns", "start", "state", "struct", "sync", "union", "upto", "urgent",
        "using",
    ];

    static ref RESERVED_WORDS_IDL : Vec<&'static str> = vec![
        "const", "interface", "in", "inout", "out", "attribute", "raises",
        "readonly", "native", "typedef",
        "array", "shared", "iid_is", "size_is", "retval",
        "boolean", "void", "octet", "short", "long", "long",
        "unsigned", "float", "double", "char", "string", "wchar", "wstring",
        "nsid", "domstring", "utf8string", "cstring", "astring", "jsval",
        "uuid", "scriptable", "builtinclass", "function", "noscript", "deprecated",
        "object", "main_process_scriptable_only",
    ];

    static ref RESERVED_WORDS_WEBIDL : Vec<&'static str> = vec![
        "module", "interface", "partial", "dictionary", "exception", "enum", "callback",
        "typedef", "implements", "const", "null", "true", "false", "serializer",
        "stringifier", "jsonifier", "unrestricted", "attribute", "readonly", "inherit",
        "static", "getter", "setter", "creator", "deleter", "legacycaller", "optional",
        "Date", "DOMString", "ByteString", "USVString", "any", "boolean", "byte",
        "double", "float", "long", "object", "octet", "Promise", "required", "sequence",
        "MozMap", "short", "unsigned", "void", "ArrayBuffer", "SharedArrayBuffer", "or",
        "maplike", "setlike", "iterable",
        "Exposed", "ChromeOnly", "ChromeConstructor", "Pref", "Func", "AvailableIn",
        "CheckAnyPermissions", "CheckAllPermissions", "JSImplementation", "HeaderFile",
        "NavigatorProperty", "AvailableIn", "Func", "CheckAnyPermissions", "CheckAllPermissions",
        "Deprecated", "NeedResolve", "OverrideBuiltins", "ChromeOnly", "Unforgeable",
        "UnsafeInPrerendering", "LegacyEventInit", "ProbablyShortLivingObject", "ArrayClass",
        "Clamp", "Constructor", "EnforceRange", "ExceptionClass", "Exposed", "ImplicitThis",
        "Global", "PrimaryGlobal", "LegacyArrayClass", "LegacyUnenumerableNamedProperties",
        "LenientSetter", "LenientThis", "NamedConstructor", "NewObject", "NoInterfaceObject",
        "OverrideBuiltins", "PutForwards", "Replaceable", "SameObject", "SecureContext",
        "Throws", "TreatNonObjectAsNull", "TreatNullAs", "Unforgeable", "Unscopable",
    ];

    static ref RESERVED_WORDS_PYTHON : Vec<&'static str> = vec![
        "and", "del", "from", "not", "while",
        "as", "elif", "global", "or", "with",
        "assert", "else", "if", "pass", "yield",
        "break", "except", "import", "print",
        "class", "exec", "in", "raise", "continue",
        "finally", "is", "return",
        "def", "for", "lambda", "try",
    ];

    // List of Rust reserved words pulled from
    // https://github.com/rust-lang/rust/blob/master/src/libsyntax/symbol.rs
    static ref RESERVED_WORDS_RUST : Vec<&'static str> = vec![
        "as", "box", "break", "const", "continue", "crate",
        "else", "enum", "extern", "false", "fn", "for", "if",
        "impl", "in", "let", "loop", "match", "mod", "move",
        "mut", "pub", "ref", "return", "self", "Self", "static",
        "struct", "super", "trait", "true", "type", "unsafe",
        "use", "where", "while",

        "abstract", "alignof", "become", "do", "final", "macro",
        "offsetof", "override", "priv", "proc", "pure", "sizeof",
        "typeof", "unsized", "virtual", "yield",

        "default", "union",
    ];

    static ref RESERVED_WORDS_JAVA : Vec<&'static str> = vec![
        "abstract", "continue", "for", "new", "switch", "assert", "default",
        "goto", "package", "synchronized", "boolean", "do", "if", "private",
        "this", "break", "double", "implements", "protected", "throw", "byte",
        "else", "import", "public", "throws", "case", "enum", "instanceof",
        "return", "transient", "catch", "extends", "int", "short", "try",
        "char", "final", "interface", "static", "void", "class", "finally",
        "long", "strictfp", "volatile", "const", "float", "native", "super",
        "while", "null", "true", "false",
    ];

    static ref JS_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_JS),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: true,
        regexp_literals: true,
        triple_quote_literals: false,
        c_preprocessor: false,
        rust_tweaks: false,
    };

    static ref CPP_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_CPP),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: true,
        rust_tweaks: false,
    };

    static ref IPDL_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_IPDL),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: false,
        rust_tweaks: false,
    };

    static ref IDL_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_IDL),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: false,
        rust_tweaks: false,
    };

    static ref WEBIDL_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_WEBIDL),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: false,
        rust_tweaks: false,
    };

    static ref PYTHON_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_PYTHON),
        hash_comment: true,
        c_style_comments: false,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: true,
        c_preprocessor: false,
        rust_tweaks: false,
    };

    static ref RUST_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_RUST),
        hash_comment: true, // for now, for attributes
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: false,
        rust_tweaks: true,
    };

    static ref JAVA_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_JAVA),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: false,
        rust_tweaks: false,
    };
}

#[derive(Debug)]
pub enum DocType {
    Markdown,
    ReStructuredText,
}

#[derive(Debug)]
pub enum FormatAs {
    FormatCLike(&'static LanguageSpec),
    FormatTagLike(&'static LanguageSpec),
    Plain,
    Binary,
}

pub fn select_formatting(filename: &str) -> FormatAs {
    let ext = match Path::new(filename).extension() {
        Some(ext) => ext.to_str().unwrap(),
        None => "",
    };
    match ext {
        "c" | "cc" | "cpp" | "h" | "hh" | "mm" => FormatAs::FormatCLike(&*CPP_SPEC),
        "ipdl" | "ipdlh" => FormatAs::FormatCLike(&*IPDL_SPEC),
        "idl" => FormatAs::FormatCLike(&*IDL_SPEC),
        "webidl" => FormatAs::FormatCLike(&*WEBIDL_SPEC),
        "js" | "jsm" | "json" | "sjs" => FormatAs::FormatCLike(&*JS_SPEC),
        "py" | "build" | "configure" => FormatAs::FormatCLike(&*PYTHON_SPEC),
        "rs" => FormatAs::FormatCLike(&*RUST_SPEC),
        "java" => FormatAs::FormatCLike(&*JAVA_SPEC),

        "html" | "htm" | "xhtml" | "xht" | "xml" | "xul" => FormatAs::FormatTagLike(&*JS_SPEC),

        "ogg" | "ttf" | "xpi" | "png" | "bcmap" |
        "gif" | "ogv" | "jpg" | "jpeg" | "bmp" | "icns" | "ico" |
        "mp4" | "sqlite" | "jar" | "webm" | "woff" |
        "class" | "m4s" | "mgif" | "wav" | "opus" |
        "mp3" | "otf" => FormatAs::Binary,

        _ => FormatAs::Plain,
    }
}
<|endoftext|>


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

use dom::attr::Attr;
use dom::bindings::codegen::Bindings::HTMLDetailsElementBinding;
use dom::bindings::codegen::Bindings::HTMLDetailsElementBinding::HTMLDetailsElementMethods;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root;
use dom::bindings::refcounted::Trusted;
use dom::document::Document;
use dom::element::AttributeMutation;
use dom::eventtarget::EventTarget;
use dom::htmlelement::HTMLElement;
use dom::node::{Node, window_from_node};
use dom::virtualmethods::VirtualMethods;
use script_thread::Runnable;
use std::cell::Cell;
use string_cache::Atom;
use task_source::dom_manipulation::DOMManipulationTask;
use util::str::DOMString;

#[dom_struct]
pub struct HTMLDetailsElement {
    htmlelement: HTMLElement,
    toggle_counter: Cell<u32>
}

impl HTMLDetailsElement {
    fn new_inherited(localName: Atom,
                     prefix: Option<DOMString>,
                     document: &Document) -> HTMLDetailsElement {
        HTMLDetailsElement {
            htmlelement:
                HTMLElement::new_inherited(localName, prefix, document),
            toggle_counter: Cell::new(0)
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: Atom,
               prefix: Option<DOMString>,
               document: &Document) -> Root<HTMLDetailsElement> {
        let element = HTMLDetailsElement::new_inherited(localName, prefix, document);
        Node::reflect_node(box element, document, HTMLDetailsElementBinding::Wrap)
    }

    pub fn check_toggle_count(&self, number: u32) -> bool {
        number == self.toggle_counter.get()
    }
}

impl HTMLDetailsElementMethods for HTMLDetailsElement {
    // https://html.spec.whatwg.org/multipage/#dom-details-open
    make_bool_getter!(Open, "open");

    // https://html.spec.whatwg.org/multipage/#dom-details-open
    make_bool_setter!(SetOpen, "open");
}

impl VirtualMethods for HTMLDetailsElement {
    fn super_type(&self) -> Option<&VirtualMethods> {
        Some(self.upcast::<HTMLElement>() as &VirtualMethods)
    }

    fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
        self.super_type().unwrap().attribute_mutated(attr, mutation);

        if attr.local_name() == &atom!("open") {
            let counter = self.toggle_counter.get() + 1;
            self.toggle_counter.set(counter);

            let window = window_from_node(self);
            let window = window.r();
            let task_source = window.dom_manipulation_task_source();
            let details = Trusted::new(self);
            let runnable = box ToggleEventRunnable {
                element: details,
                toggle_number: counter
            };
            let _ = task_source.queue(DOMManipulationTask::FireToggleEvent(runnable));
        }
    }
}

pub struct ToggleEventRunnable {
    element: Trusted<HTMLDetailsElement>,
    toggle_number: u32
}

impl Runnable for ToggleEventRunnable {
    fn handler(self: Box<ToggleEventRunnable>) {
        let target = self.element.root();
        if target.check_toggle_count(self.toggle_number) {
            target.upcast::<EventTarget>().fire_simple_event("toggle");
        }
    }
}
<commit_msg>Rename ToggleEventRunnable to DetailsNotificationRunnable<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 dom::attr::Attr;
use dom::bindings::codegen::Bindings::HTMLDetailsElementBinding;
use dom::bindings::codegen::Bindings::HTMLDetailsElementBinding::HTMLDetailsElementMethods;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root;
use dom::bindings::refcounted::Trusted;
use dom::document::Document;
use dom::element::AttributeMutation;
use dom::eventtarget::EventTarget;
use dom::htmlelement::HTMLElement;
use dom::node::{Node, window_from_node};
use dom::virtualmethods::VirtualMethods;
use script_thread::Runnable;
use std::cell::Cell;
use string_cache::Atom;
use task_source::dom_manipulation::DOMManipulationTask;
use util::str::DOMString;

#[dom_struct]
pub struct HTMLDetailsElement {
    htmlelement: HTMLElement,
    toggle_counter: Cell<u32>
}

impl HTMLDetailsElement {
    fn new_inherited(localName: Atom,
                     prefix: Option<DOMString>,
                     document: &Document) -> HTMLDetailsElement {
        HTMLDetailsElement {
            htmlelement:
                HTMLElement::new_inherited(localName, prefix, document),
            toggle_counter: Cell::new(0)
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: Atom,
               prefix: Option<DOMString>,
               document: &Document) -> Root<HTMLDetailsElement> {
        let element = HTMLDetailsElement::new_inherited(localName, prefix, document);
        Node::reflect_node(box element, document, HTMLDetailsElementBinding::Wrap)
    }

    pub fn check_toggle_count(&self, number: u32) -> bool {
        number == self.toggle_counter.get()
    }
}

impl HTMLDetailsElementMethods for HTMLDetailsElement {
    // https://html.spec.whatwg.org/multipage/#dom-details-open
    make_bool_getter!(Open, "open");

    // https://html.spec.whatwg.org/multipage/#dom-details-open
    make_bool_setter!(SetOpen, "open");
}

impl VirtualMethods for HTMLDetailsElement {
    fn super_type(&self) -> Option<&VirtualMethods> {
        Some(self.upcast::<HTMLElement>() as &VirtualMethods)
    }

    fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
        self.super_type().unwrap().attribute_mutated(attr, mutation);

        if attr.local_name() == &atom!("open") {
            let counter = self.toggle_counter.get() + 1;
            self.toggle_counter.set(counter);

            let window = window_from_node(self);
            let window = window.r();
            let task_source = window.dom_manipulation_task_source();
            let details = Trusted::new(self);
            let runnable = box DetailsNotificationRunnable {
                element: details,
                toggle_number: counter
            };
            let _ = task_source.queue(DOMManipulationTask::FireToggleEvent(runnable));
        }
    }
}

pub struct DetailsNotificationRunnable {
    element: Trusted<HTMLDetailsElement>,
    toggle_number: u32
}

impl Runnable for DetailsNotificationRunnable {
    fn handler(self: Box<DetailsNotificationRunnable>) {
        let target = self.element.root();
        if target.check_toggle_count(self.toggle_number) {
            target.upcast::<EventTarget>().fire_simple_event("toggle");
        }
    }
}
<|endoftext|>