<commit_before>//! Requires the 'framework' feature flag be enabled in your project's
//! `Cargo.toml`.
//!
//! This can be enabled by specifying the feature in the dependency section:
//!
//! ```toml
//! [dependencies.serenity]
//! git = "https://github.com/serenity-rs/serenity.git"
//! features = ["framework", "standard_framework"]
//! ```

#[macro_use]
extern crate serenity;
extern crate typemap;

use serenity::client::bridge::gateway::{ShardId, ShardManager};
use serenity::framework::standard::{Args, DispatchError, StandardFramework, HelpBehaviour, CommandOptions, help_commands};
use serenity::model::channel::Message;
use serenity::model::gateway::Ready;
use serenity::model::Permissions;
use serenity::prelude::Mutex;
use serenity::prelude::*;
use std::collections::HashMap;
use std::env;
use std::fmt::Write;
use std::sync::Arc;
use typemap::Key;

// A container type is created for inserting into the Client's `data`, which
// allows for data to be accessible across all events and framework commands, or
// anywhere else that has a copy of the `data` Arc.
struct ShardManagerContainer;

impl Key for ShardManagerContainer {
    type Value = Arc<Mutex<ShardManager>>;
}

struct CommandCounter;

impl Key for CommandCounter {
    type Value = HashMap<String, u64>;
}

struct Handler;

impl EventHandler for Handler {
    fn ready(&self, _: Context, ready: Ready) {
        println!("{} is connected!", ready.user.name);
    }
}

fn main() {
    // Configure the client with your Discord bot token in the environment.
    let token = env::var("DISCORD_TOKEN").expect(
        "Expected a token in the environment",
    );
    let mut client = Client::new(&token, Handler).expect("Err creating client");

    {
        let mut data = client.data.lock();
        data.insert::<CommandCounter>(HashMap::default());
        data.insert::<ShardManagerContainer>(Arc::clone(&client.shard_manager));
    }

    // Commands are equivalent to:
    // "~about"
    // "~emoji cat"
    // "~emoji dog"
    // "~multiply"
    // "~ping"
    // "~some long command"
    client.with_framework(
        // Configures the client, allowing for options to mutate how the
        // framework functions.
        //
        // Refer to the documentation for
        // `serenity::ext::framework::Configuration` for all available
        // configurations.
        StandardFramework::new()
        .configure(|c| c
            .allow_whitespace(true)
            .on_mention(true)
            .prefix("~")
            // You can set multiple delimiters via delimiters()
            // or just one via delimiter(",")
            // If you set multiple delimiters, the order you list them
            // decides their priority (from first to last).
            //
            // In this case, if "," would be first, a message would never
            // be delimited at ", ", forcing you to trim your arguments if you
            // want to avoid whitespaces at the start of each.
            .delimiters(vec![", ", ","]))

        // Set a function to be called prior to each command execution. This
        // provides the context of the command, the message that was received,
        // and the full name of the command that will be called.
        //
        // You can not use this to determine whether a command should be
        // executed. Instead, `set_check` is provided to give you this
        // functionality.
        .before(|ctx, msg, command_name| {
            println!("Got command '{}' by user '{}'",
                     command_name,
                     msg.author.name);

            // Increment the number of times this command has been run once. If
            // the command's name does not exist in the counter, add a default
            // value of 0.
            let mut data = ctx.data.lock();
            let counter = data.get_mut::<CommandCounter>().unwrap();
            let entry = counter.entry(command_name.to_string()).or_insert(0);
            *entry += 1;

            true // if `before` returns false, command processing doesn't happen.
        })
        // Similar to `before`, except will be called directly _after_
        // command execution.
        .after(|_, _, command_name, error| {
            match error {
                Ok(()) => println!("Processed command '{}'", command_name),
                Err(why) => println!("Command '{}' returned error {:?}", command_name, why),
            }
        })
        // Set a function that's called whenever an attempted command-call's
        // command could not be found.
        .unrecognised_command(|_, _, unknown_command_name| {
            println!("Could not find command named '{}'", unknown_command_name);
        })
        // Set a function that's called whenever a command's execution didn't complete for one
        // reason or another. For example, when a user has exceeded a rate-limit or a command
        // can only be performed by the bot owner.
        .on_dispatch_error(|_ctx, msg, error| {
            if let DispatchError::RateLimited(seconds) = error {
                let _ = msg.channel_id.say(&format!("Try this again in {} seconds.", seconds));
            }
        })
        // Can't be used more than once per 5 seconds:
        .simple_bucket("emoji", 5)
        // Can't be used more than 2 times per 30 seconds, with a 5 second delay:
        .bucket("complicated", 5, 30, 2)
        .command("about", |c| c.cmd(about))
        // You can use the simple `help(help_commands::with_embeds)` or
        // customise your help-menu via `customised_help()`.
        .customised_help(help_commands::with_embeds, |c| {
                // This replaces the information that a user can pass
                // a command-name as argument to gain specific information about it.
                c.individual_command_tip("Hello! こんにちは！Hola! Bonjour! 您好!\n\
                If you want more information about a specific command, just pass the command as argument.")
                // Some arguments require a `{}` in order to replace it with contextual information.
                // In this case our `{}` refers to a command's name.
                .command_not_found_text("Could not find: `{}`.")
                // On another note, you can set up the help-menu-filter-behaviour.
                // Here are all possible settings shown on all possible options.
                // First case is if a user lacks permissions for a command, we can hide the command.
                .lacking_permissions(HelpBehaviour::Hide)
                // If the user is nothing but lacking a certain role, we just display it hence our variant is `Nothing`.
                .lacking_role(HelpBehaviour::Nothing)
                // The last `enum`-variant is `Strike`, which ~~strikes~~ a command.
                .wrong_channel(HelpBehaviour::Strike)
                // Serenity will automatically analyse and generate a hint/tip explaining the possible
                // cases of ~~strikethrough-commands~~, but only if
                // `striked_commands_tip(Some(""))` keeps `Some()` wrapping an empty `String`, which is the default value.
                // If the `String` is not empty, your given `String` will be used instead.
                // If you pass in a `None`, no hint will be displayed at all.
                 })
        .command("commands", |c| c
            // Make this command use the "complicated" bucket.
            .bucket("complicated")
            .cmd(commands))
        .group("Emoji", |g| g
            // Sets a single prefix for a group:
            .prefix("emoji")
            // Sets a command that will be executed if only a group-prefix was passed.
            .default_cmd(dog)
            .command("cat", |c| c
                .desc("Sends an emoji with a cat.")
                .batch_known_as(vec!["kitty", "neko"]) // Adds multiple aliases
                .bucket("emoji") // Make this command use the "emoji" bucket.
                .cmd(cat)
                 // Allow only administrators to call this:
                .required_permissions(Permissions::ADMINISTRATOR))
            .command("dog", |c| c
                .desc("Sends an emoji with a dog.")
                .bucket("emoji")
                .cmd(dog)))
        .group("Math", |g| g
            // Sets multiple prefixes for a group.
            // This requires us to call commands in this group
            // via `~math` (or `~m`) instead of just `~`.
            .prefixes(vec!["m", "math"])
            .command("multiply", |c| c
                .known_as("*") // Lets us also call `~math *` instead of just `~math multiply`.
                .cmd(multiply)))
        .command("latency", |c| c
            .cmd(latency))
        .command("ping", |c| c
            .check(owner_check) // User needs to pass this test to run command
            .cmd(ping))
        .command("role", |c| c
            .cmd(about_role)
            // Limits the usage of this command to roles named:
            .allowed_roles(vec!["mods", "ultimate neko"]))
        .command("some long command", |c| c.cmd(some_long_command))
        .group("Owner", |g| g
            // This check applies to every command on this group.
            // User needs to pass the test for the command to execute.
            .check(admin_check)
            .command("am i admin", |c| c
                .cmd(am_i_admin))
                .guild_only(true)
        ),
    );

    if let Err(why) = client.start() {
        println!("Client error: {:?}", why);
    }
}

// Commands can be created via the `command!` macro, to avoid manually typing
// type annotations.
//
// This may bring more features available for commands in the future. See the
// "multiply" command below for some of the power that the `command!` macro can
// bring.
command!(commands(ctx, msg, _args) {
    let mut contents = "Commands used:\n".to_string();

    let data = ctx.data.lock();
    let counter = data.get::<CommandCounter>().unwrap();

    for (k, v) in counter {
        let _ = write!(contents, "- {name}: {amount}\n", name=k, amount=v);
    }

    if let Err(why) = msg.channel_id.say(&contents) {
        println!("Error sending message: {:?}", why);
    }
});

// A function which acts as a "check", to determine whether to call a command.
//
// In this case, this command checks to ensure you are the owner of the message
// in order for the command to be executed. If the check fails, the command is
// not called.
fn owner_check(_: &mut Context, msg: &Message, _: &mut Args, _: &CommandOptions) -> bool {
    // Replace 7 with your ID
    msg.author.id == 7
}

// A function which acts as a "check", to determine whether to call a command.
//
// This check analyses whether a guild member permissions has
// administrator-permissions.
fn admin_check(_: &mut Context, msg: &Message, _: &mut Args, _: &CommandOptions) -> bool {
    if let Some(member) = msg.member() {

        if let Ok(permissions) = member.permissions() {
            return permissions.administrator();
        }
    }

    false
}

command!(some_long_command(_ctx, msg, args) {
    if let Err(why) = msg.channel_id.say(&format!("Arguments: {:?}", args)) {
        println!("Error sending message: {:?}", why);
    }
});

command!(about_role(_ctx, msg, args) {
    let potential_role_name = args.full();

    if let Some(guild) = msg.guild() {
        // `role_by_name()` allows us to attempt attaining a reference to a role
        // via its name.
        if let Some(role) = guild.read().role_by_name(&potential_role_name) {
            if let Err(why) = msg.channel_id.say(&format!("Role-ID: {}", role.id)) {
                println!("Error sending message: {:?}", why);
            }

            return Ok(());
        }
    }

    if let Err(why) = msg.channel_id.say(
                      &format!("Could not find role named: {:?}", potential_role_name)) {
        println!("Error sending message: {:?}", why);
    }
});

// Using the `command!` macro, commands can be created with a certain type of
// "dynamic" type checking. This is a method of requiring that the arguments
// given match the required type, and maps those arguments to the specified
// bindings.
//
// For example, the following will be correctly parsed by the macro:
//
// `~multiply 3.7 4.3`
//
// However, the following will not, as the second argument can not be an f64:
//
// `~multiply 3.7 four`
//
// Since the argument can't be converted, the command returns early.
//
// Additionally, if not enough arguments are given (e.g. `~multiply 3`), then
// the command will return early. If additional arguments are provided, they
// will be ignored.
//
// Argument type overloading is currently not supported.
command!(multiply(_ctx, msg, args) {
    let first = args.single::<f64>().unwrap();
    let second = args.single::<f64>().unwrap();

    let res = first * second;

    if let Err(why) = msg.channel_id.say(&res.to_string()) {
        println!("Err sending product of {} and {}: {:?}", first, second, why);
    }
});

command!(about(_ctx, msg, _args) {
    if let Err(why) = msg.channel_id.say("This is a small test-bot! : )") {
        println!("Error sending message: {:?}", why);
    }
});

command!(latency(ctx, msg, _args) {
    // The shard manager is an interface for mutating, stopping, restarting, and
    // retrieving information about shards.
    let data = ctx.data.lock();

    let shard_manager = match data.get::<ShardManagerContainer>() {
        Some(v) => v,
        None => {
            let _ = msg.reply("There was a problem getting the shard manager");

            return Ok(());
        },
    };

    let manager = shard_manager.lock();
    let runners = manager.runners.lock();

    // Shards are backed by a "shard runner" responsible for processing events
    // over the shard, so we'll get the information about the shard runner for
    // the shard this command was sent over.
    let runner = match runners.get(&ShardId(ctx.shard_id)) {
        Some(runner) => runner,
        None => {
            let _ = msg.reply("No shard found");

            return Ok(());
        },
    };

    let _ = msg.reply(&format!("The shard latency is {:?}", runner.latency));
});

command!(ping(_ctx, msg, _args) {
    if let Err(why) = msg.channel_id.say("Pong! : )") {
        println!("Error sending message: {:?}", why);
    }
});

command!(am_i_admin(_ctx, msg, _args) {
    if let Err(why) = msg.channel_id.say("Yes you are.") {
        println!("Error sending message: {:?}", why);
    }
});

command!(dog(_ctx, msg, _args) {
    if let Err(why) = msg.channel_id.say(":dog:") {
        println!("Error sending message: {:?}", why);
    }
});

command!(cat(_ctx, msg, _args) {
    if let Err(why) = msg.channel_id.say(":cat:") {
        println!("Error sending message: {:?}", why);
    }
});
<commit_msg>Use `Args::full` in the framework example<commit_after>//! Requires the 'framework' feature flag be enabled in your project's
//! `Cargo.toml`.
//!
//! This can be enabled by specifying the feature in the dependency section:
//!
//! ```toml
//! [dependencies.serenity]
//! git = "https://github.com/serenity-rs/serenity.git"
//! features = ["framework", "standard_framework"]
//! ```

#[macro_use]
extern crate serenity;
extern crate typemap;

use serenity::client::bridge::gateway::{ShardId, ShardManager};
use serenity::framework::standard::{Args, DispatchError, StandardFramework, HelpBehaviour, CommandOptions, help_commands};
use serenity::model::channel::Message;
use serenity::model::gateway::Ready;
use serenity::model::Permissions;
use serenity::prelude::Mutex;
use serenity::prelude::*;
use std::collections::HashMap;
use std::env;
use std::fmt::Write;
use std::sync::Arc;
use typemap::Key;

// A container type is created for inserting into the Client's `data`, which
// allows for data to be accessible across all events and framework commands, or
// anywhere else that has a copy of the `data` Arc.
struct ShardManagerContainer;

impl Key for ShardManagerContainer {
    type Value = Arc<Mutex<ShardManager>>;
}

struct CommandCounter;

impl Key for CommandCounter {
    type Value = HashMap<String, u64>;
}

struct Handler;

impl EventHandler for Handler {
    fn ready(&self, _: Context, ready: Ready) {
        println!("{} is connected!", ready.user.name);
    }
}

fn main() {
    // Configure the client with your Discord bot token in the environment.
    let token = env::var("DISCORD_TOKEN").expect(
        "Expected a token in the environment",
    );
    let mut client = Client::new(&token, Handler).expect("Err creating client");

    {
        let mut data = client.data.lock();
        data.insert::<CommandCounter>(HashMap::default());
        data.insert::<ShardManagerContainer>(Arc::clone(&client.shard_manager));
    }

    // Commands are equivalent to:
    // "~about"
    // "~emoji cat"
    // "~emoji dog"
    // "~multiply"
    // "~ping"
    // "~some long command"
    client.with_framework(
        // Configures the client, allowing for options to mutate how the
        // framework functions.
        //
        // Refer to the documentation for
        // `serenity::ext::framework::Configuration` for all available
        // configurations.
        StandardFramework::new()
        .configure(|c| c
            .allow_whitespace(true)
            .on_mention(true)
            .prefix("~")
            // You can set multiple delimiters via delimiters()
            // or just one via delimiter(",")
            // If you set multiple delimiters, the order you list them
            // decides their priority (from first to last).
            //
            // In this case, if "," would be first, a message would never
            // be delimited at ", ", forcing you to trim your arguments if you
            // want to avoid whitespaces at the start of each.
            .delimiters(vec![", ", ","]))

        // Set a function to be called prior to each command execution. This
        // provides the context of the command, the message that was received,
        // and the full name of the command that will be called.
        //
        // You can not use this to determine whether a command should be
        // executed. Instead, `set_check` is provided to give you this
        // functionality.
        .before(|ctx, msg, command_name| {
            println!("Got command '{}' by user '{}'",
                     command_name,
                     msg.author.name);

            // Increment the number of times this command has been run once. If
            // the command's name does not exist in the counter, add a default
            // value of 0.
            let mut data = ctx.data.lock();
            let counter = data.get_mut::<CommandCounter>().unwrap();
            let entry = counter.entry(command_name.to_string()).or_insert(0);
            *entry += 1;

            true // if `before` returns false, command processing doesn't happen.
        })
        // Similar to `before`, except will be called directly _after_
        // command execution.
        .after(|_, _, command_name, error| {
            match error {
                Ok(()) => println!("Processed command '{}'", command_name),
                Err(why) => println!("Command '{}' returned error {:?}", command_name, why),
            }
        })
        // Set a function that's called whenever an attempted command-call's
        // command could not be found.
        .unrecognised_command(|_, _, unknown_command_name| {
            println!("Could not find command named '{}'", unknown_command_name);
        })
        // Set a function that's called whenever a command's execution didn't complete for one
        // reason or another. For example, when a user has exceeded a rate-limit or a command
        // can only be performed by the bot owner.
        .on_dispatch_error(|_ctx, msg, error| {
            if let DispatchError::RateLimited(seconds) = error {
                let _ = msg.channel_id.say(&format!("Try this again in {} seconds.", seconds));
            }
        })
        // Can't be used more than once per 5 seconds:
        .simple_bucket("emoji", 5)
        // Can't be used more than 2 times per 30 seconds, with a 5 second delay:
        .bucket("complicated", 5, 30, 2)
        .command("about", |c| c.cmd(about))
        // You can use the simple `help(help_commands::with_embeds)` or
        // customise your help-menu via `customised_help()`.
        .customised_help(help_commands::with_embeds, |c| {
                // This replaces the information that a user can pass
                // a command-name as argument to gain specific information about it.
                c.individual_command_tip("Hello! こんにちは！Hola! Bonjour! 您好!\n\
                If you want more information about a specific command, just pass the command as argument.")
                // Some arguments require a `{}` in order to replace it with contextual information.
                // In this case our `{}` refers to a command's name.
                .command_not_found_text("Could not find: `{}`.")
                // On another note, you can set up the help-menu-filter-behaviour.
                // Here are all possible settings shown on all possible options.
                // First case is if a user lacks permissions for a command, we can hide the command.
                .lacking_permissions(HelpBehaviour::Hide)
                // If the user is nothing but lacking a certain role, we just display it hence our variant is `Nothing`.
                .lacking_role(HelpBehaviour::Nothing)
                // The last `enum`-variant is `Strike`, which ~~strikes~~ a command.
                .wrong_channel(HelpBehaviour::Strike)
                // Serenity will automatically analyse and generate a hint/tip explaining the possible
                // cases of ~~strikethrough-commands~~, but only if
                // `striked_commands_tip(Some(""))` keeps `Some()` wrapping an empty `String`, which is the default value.
                // If the `String` is not empty, your given `String` will be used instead.
                // If you pass in a `None`, no hint will be displayed at all.
                 })
        .command("commands", |c| c
            // Make this command use the "complicated" bucket.
            .bucket("complicated")
            .cmd(commands))
        .group("Emoji", |g| g
            // Sets a single prefix for a group:
            .prefix("emoji")
            // Sets a command that will be executed if only a group-prefix was passed.
            .default_cmd(dog)
            .command("cat", |c| c
                .desc("Sends an emoji with a cat.")
                .batch_known_as(vec!["kitty", "neko"]) // Adds multiple aliases
                .bucket("emoji") // Make this command use the "emoji" bucket.
                .cmd(cat)
                 // Allow only administrators to call this:
                .required_permissions(Permissions::ADMINISTRATOR))
            .command("dog", |c| c
                .desc("Sends an emoji with a dog.")
                .bucket("emoji")
                .cmd(dog)))
        .group("Math", |g| g
            // Sets multiple prefixes for a group.
            // This requires us to call commands in this group
            // via `~math` (or `~m`) instead of just `~`.
            .prefixes(vec!["m", "math"])
            .command("multiply", |c| c
                .known_as("*") // Lets us also call `~math *` instead of just `~math multiply`.
                .cmd(multiply)))
        .command("latency", |c| c
            .cmd(latency))
        .command("ping", |c| c
            .check(owner_check) // User needs to pass this test to run command
            .cmd(ping))
        .command("role", |c| c
            .cmd(about_role)
            // Limits the usage of this command to roles named:
            .allowed_roles(vec!["mods", "ultimate neko"]))
        .command("some long command", |c| c.cmd(some_long_command))
        .group("Owner", |g| g
            // This check applies to every command on this group.
            // User needs to pass the test for the command to execute.
            .check(admin_check)
            .command("am i admin", |c| c
                .cmd(am_i_admin))
                .guild_only(true)
        ),
    );

    if let Err(why) = client.start() {
        println!("Client error: {:?}", why);
    }
}

// Commands can be created via the `command!` macro, to avoid manually typing
// type annotations.
//
// This may bring more features available for commands in the future. See the
// "multiply" command below for some of the power that the `command!` macro can
// bring.
command!(commands(ctx, msg, _args) {
    let mut contents = "Commands used:\n".to_string();

    let data = ctx.data.lock();
    let counter = data.get::<CommandCounter>().unwrap();

    for (k, v) in counter {
        let _ = write!(contents, "- {name}: {amount}\n", name=k, amount=v);
    }

    if let Err(why) = msg.channel_id.say(&contents) {
        println!("Error sending message: {:?}", why);
    }
});

// A function which acts as a "check", to determine whether to call a command.
//
// In this case, this command checks to ensure you are the owner of the message
// in order for the command to be executed. If the check fails, the command is
// not called.
fn owner_check(_: &mut Context, msg: &Message, _: &mut Args, _: &CommandOptions) -> bool {
    // Replace 7 with your ID
    msg.author.id == 7
}

// A function which acts as a "check", to determine whether to call a command.
//
// This check analyses whether a guild member permissions has
// administrator-permissions.
fn admin_check(_: &mut Context, msg: &Message, _: &mut Args, _: &CommandOptions) -> bool {
    if let Some(member) = msg.member() {

        if let Ok(permissions) = member.permissions() {
            return permissions.administrator();
        }
    }

    false
}

command!(some_long_command(_ctx, msg, args) {
    if let Err(why) = msg.channel_id.say(&format!("Arguments: {}", args.full())) {
        println!("Error sending message: {:?}", why);
    }
});

command!(about_role(_ctx, msg, args) {
    let potential_role_name = args.full();

    if let Some(guild) = msg.guild() {
        // `role_by_name()` allows us to attempt attaining a reference to a role
        // via its name.
        if let Some(role) = guild.read().role_by_name(&potential_role_name) {
            if let Err(why) = msg.channel_id.say(&format!("Role-ID: {}", role.id)) {
                println!("Error sending message: {:?}", why);
            }

            return Ok(());
        }
    }

    if let Err(why) = msg.channel_id.say(
                      &format!("Could not find role named: {:?}", potential_role_name)) {
        println!("Error sending message: {:?}", why);
    }
});

// Using the `command!` macro, commands can be created with a certain type of
// "dynamic" type checking. This is a method of requiring that the arguments
// given match the required type, and maps those arguments to the specified
// bindings.
//
// For example, the following will be correctly parsed by the macro:
//
// `~multiply 3.7 4.3`
//
// However, the following will not, as the second argument can not be an f64:
//
// `~multiply 3.7 four`
//
// Since the argument can't be converted, the command returns early.
//
// Additionally, if not enough arguments are given (e.g. `~multiply 3`), then
// the command will return early. If additional arguments are provided, they
// will be ignored.
//
// Argument type overloading is currently not supported.
command!(multiply(_ctx, msg, args) {
    let first = args.single::<f64>().unwrap();
    let second = args.single::<f64>().unwrap();

    let res = first * second;

    if let Err(why) = msg.channel_id.say(&res.to_string()) {
        println!("Err sending product of {} and {}: {:?}", first, second, why);
    }
});

command!(about(_ctx, msg, _args) {
    if let Err(why) = msg.channel_id.say("This is a small test-bot! : )") {
        println!("Error sending message: {:?}", why);
    }
});

command!(latency(ctx, msg, _args) {
    // The shard manager is an interface for mutating, stopping, restarting, and
    // retrieving information about shards.
    let data = ctx.data.lock();

    let shard_manager = match data.get::<ShardManagerContainer>() {
        Some(v) => v,
        None => {
            let _ = msg.reply("There was a problem getting the shard manager");

            return Ok(());
        },
    };

    let manager = shard_manager.lock();
    let runners = manager.runners.lock();

    // Shards are backed by a "shard runner" responsible for processing events
    // over the shard, so we'll get the information about the shard runner for
    // the shard this command was sent over.
    let runner = match runners.get(&ShardId(ctx.shard_id)) {
        Some(runner) => runner,
        None => {
            let _ = msg.reply("No shard found");

            return Ok(());
        },
    };

    let _ = msg.reply(&format!("The shard latency is {:?}", runner.latency));
});

command!(ping(_ctx, msg, _args) {
    if let Err(why) = msg.channel_id.say("Pong! : )") {
        println!("Error sending message: {:?}", why);
    }
});

command!(am_i_admin(_ctx, msg, _args) {
    if let Err(why) = msg.channel_id.say("Yes you are.") {
        println!("Error sending message: {:?}", why);
    }
});

command!(dog(_ctx, msg, _args) {
    if let Err(why) = msg.channel_id.say(":dog:") {
        println!("Error sending message: {:?}", why);
    }
});

command!(cat(_ctx, msg, _args) {
    if let Err(why) = msg.channel_id.say(":cat:") {
        println!("Error sending message: {:?}", why);
    }
});
<|endoftext|>


<commit_before>// Copyright 2017 The Exonum Team
//
// 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.

use std::ffi::OsString;
use std::collections::HashMap;

use clap;

use super::{Context, ArgumentType};
use super::internal::{Feedback, CollectedCommand};
use super::CommandName;

pub struct ClapBackend;

impl ClapBackend {
    // TODO: remove code duplication (ECR-164)
    #[doc(hidden)]
    pub fn execute_cmd_string<I, T>(
        commands: &HashMap<CommandName, CollectedCommand>,
        line: I,
    ) -> Feedback
    where
        I: IntoIterator<Item = T>,
        T: Into<OsString> + Clone,
    {
        let subcommands: Vec<_> = commands
            .values()
            .map(|command| ClapBackend::command_into_subcommand(command))
            .collect();
        let matches = clap::App::new("Exonum application based on fabric configuration.")
            .setting(clap::AppSettings::ArgRequiredElseHelp)
            .version(crate_version!())
            .author(crate_authors!("\n"))
            .about(
                "It contain basic set of command, to deploy network on exonum.",
            )
            .subcommands(subcommands.into_iter())
            .get_matches_from_safe(line)
            .unwrap();

        let subcommand = matches.subcommand();
        let command = commands.get(subcommand.0).expect("Subcommand not found.");
        command.execute(
            commands,
            Context::new_from_args(command.args(), subcommand.1.expect("Arguments not found.")),
        )
    }

    pub fn execute(commands: &HashMap<CommandName, CollectedCommand>) -> Feedback {
        let subcommands: Vec<_> = commands
            .values()
            .map(|command| ClapBackend::command_into_subcommand(command))
            .collect();

        let matches = clap::App::new("Exonum application based on fabric configuration.")
            .setting(clap::AppSettings::ArgRequiredElseHelp)
            .version(crate_version!())
            .author(crate_authors!("\n"))
            .about("Exonum application based on fabric configuration.")
            .subcommands(subcommands.into_iter())
            .get_matches();

        let subcommand = matches.subcommand();
        let command = commands.get(subcommand.0).expect("Subcommand not found.");
        command.execute(
            commands,
            Context::new_from_args(command.args(), subcommand.1.expect("Arguments not found.")),
        )
    }

    fn command_into_subcommand(command: &CollectedCommand) -> clap::App {
        let command_args: Vec<_> = command
            .args()
            .iter()
            .zip(1..)
            .map(|(arg, index)| {
                let clap_arg = clap::Arg::with_name(arg.name);
                let clap_arg = match arg.argument_type {
                    ArgumentType::Positional => clap_arg.index(index),
                    ArgumentType::Named(detail) => {
                        let mut clap_arg = clap_arg.long(detail.long_name);
                        if let Some(short) = detail.short_name {
                            clap_arg = clap_arg.short(short);
                        }
                        clap_arg.multiple(detail.multiple).takes_value(true)
                    }
                };
                clap_arg.help(arg.help).required(arg.required)
            })
            .collect();

        let mut subcommand = clap::SubCommand::with_name(command.name()).about(command.about());

        subcommand = subcommand.args(&command_args);

        subcommand
    }
}
<commit_msg>Revert correct positional arguments indexing<commit_after>// Copyright 2017 The Exonum Team
//
// 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.

use std::ffi::OsString;
use std::collections::HashMap;

use clap;

use super::{Context, ArgumentType};
use super::internal::{Feedback, CollectedCommand};
use super::CommandName;

pub struct ClapBackend;

impl ClapBackend {
    // TODO: remove code duplication (ECR-164)
    #[doc(hidden)]
    pub fn execute_cmd_string<I, T>(
        commands: &HashMap<CommandName, CollectedCommand>,
        line: I,
    ) -> Feedback
    where
        I: IntoIterator<Item = T>,
        T: Into<OsString> + Clone,
    {
        let subcommands: Vec<_> = commands
            .values()
            .map(|command| ClapBackend::command_into_subcommand(command))
            .collect();
        let matches = clap::App::new("Exonum application based on fabric configuration.")
            .setting(clap::AppSettings::ArgRequiredElseHelp)
            .version(crate_version!())
            .author(crate_authors!("\n"))
            .about(
                "It contain basic set of command, to deploy network on exonum.",
            )
            .subcommands(subcommands.into_iter())
            .get_matches_from_safe(line)
            .unwrap();

        let subcommand = matches.subcommand();
        let command = commands.get(subcommand.0).expect("Subcommand not found.");
        command.execute(
            commands,
            Context::new_from_args(command.args(), subcommand.1.expect("Arguments not found.")),
        )
    }

    pub fn execute(commands: &HashMap<CommandName, CollectedCommand>) -> Feedback {
        let subcommands: Vec<_> = commands
            .values()
            .map(|command| ClapBackend::command_into_subcommand(command))
            .collect();

        let matches = clap::App::new("Exonum application based on fabric configuration.")
            .setting(clap::AppSettings::ArgRequiredElseHelp)
            .version(crate_version!())
            .author(crate_authors!("\n"))
            .about("Exonum application based on fabric configuration.")
            .subcommands(subcommands.into_iter())
            .get_matches();

        let subcommand = matches.subcommand();
        let command = commands.get(subcommand.0).expect("Subcommand not found.");
        command.execute(
            commands,
            Context::new_from_args(command.args(), subcommand.1.expect("Arguments not found.")),
        )
    }

    fn command_into_subcommand(command: &CollectedCommand) -> clap::App {
        let mut index = 1;
        let command_args: Vec<_> = command
            .args()
            .iter()
            .map(|arg| {
                let clap_arg = clap::Arg::with_name(arg.name);
                let clap_arg = match arg.argument_type {
                    ArgumentType::Positional => {
                        let arg = clap_arg.index(index);
                        index += 1;
                        arg
                    }
                    ArgumentType::Named(detail) => {
                        let mut clap_arg = clap_arg.long(detail.long_name);
                        if let Some(short) = detail.short_name {
                            clap_arg = clap_arg.short(short);
                        }
                        clap_arg.multiple(detail.multiple).takes_value(true)
                    }
                };
                clap_arg.help(arg.help).required(arg.required)
            })
            .collect();

        let mut subcommand = clap::SubCommand::with_name(command.name()).about(command.about());

        subcommand = subcommand.args(&command_args);

        subcommand
    }
}
<|endoftext|>


<commit_before>use std::num::{Zero, One};
use vec::{Vec2, Vec3, Vec2MulRhs, Vec3MulRhs};
use mat::{Mat1, Mat2, Mat3, Inv, Row, Col, Mat3MulRhs, Mat2MulRhs};
use mat;

// some specializations:
impl<N: Num + Clone>
Inv for Mat1<N> {
    #[inline]
    fn inverse(&self) -> Option<Mat1<N>> {
        let mut res : Mat1<N> = self.clone();

        if res.inplace_inverse() {
            Some(res)
        }
        else {
            None
        }
    }

    #[inline]
    fn inplace_inverse(&mut self) -> bool {
        if self.m11.is_zero() {
            false
        }
        else {
            let _1: N = One::one();
            self.m11 = _1 / self.m11;
            true
        }
    }
}

impl<N: Num + Clone>
Inv for Mat2<N> {
    #[inline]
    fn inverse(&self) -> Option<Mat2<N>> {
        let mut res : Mat2<N> = self.clone();

        if res.inplace_inverse() {
            Some(res)
        }
        else {
            None
        }
    }

    #[inline]
    fn inplace_inverse(&mut self) -> bool {
        let det = self.m11 * self.m22 - self.m21 * self.m12;

        if det.is_zero() {
            false
        }
        else {
            *self = Mat2::new(
                self.m22 / det , -self.m12 / det,
                -self.m21 / det, self.m11 / det);

            true
        }
    }
}

impl<N: Num + Clone>
Inv for Mat3<N> {
    #[inline]
    fn inverse(&self) -> Option<Mat3<N>> {
        let mut res = self.clone();

        if res.inplace_inverse() {
            Some(res)
        }
        else {
            None
        }
    }

    #[inline]
    fn inplace_inverse(&mut self) -> bool {
        let minor_m12_m23 = self.m22 * self.m33 - self.m32 * self.m23;
        let minor_m11_m23 = self.m21 * self.m33 - self.m31 * self.m23;
        let minor_m11_m22 = self.m21 * self.m32 - self.m31 * self.m22;

        let det = self.m11 * minor_m12_m23
                  - self.m12 * minor_m11_m23
                  + self.m13 * minor_m11_m22;

        if det.is_zero() {
            false
        }
        else {
            *self = Mat3::new(
                (minor_m12_m23 / det),
                ((self.m13 * self.m32 - self.m33 * self.m12) / det),
                ((self.m12 * self.m23 - self.m22 * self.m13) / det),

                (-minor_m11_m23 / det),
                ((self.m11 * self.m33 - self.m31 * self.m13) / det),
                ((self.m13 * self.m21 - self.m23 * self.m11) / det),

                (minor_m11_m22  / det),
                ((self.m12 * self.m31 - self.m32 * self.m11) / det),
                ((self.m11 * self.m22 - self.m21 * self.m12) / det)
                );

            true
        }
    }
}

impl<N: Clone> Row<Vec3<N>> for Mat3<N> {
    #[inline]
    fn num_rows(&self) -> uint {
        3
    }

    #[inline]
    fn row(&self, i: uint) -> Vec3<N> {
        match i {
            0 => Vec3::new(self.m11.clone(), self.m12.clone(), self.m13.clone()),
            1 => Vec3::new(self.m21.clone(), self.m22.clone(), self.m23.clone()),
            2 => Vec3::new(self.m31.clone(), self.m32.clone(), self.m33.clone()),
            _ => fail!("Index out of range: 3d matrices do not have " + i.to_str() + " rows.")
        }
    }

    #[inline]
    fn set_row(&mut self, i: uint, r: Vec3<N>) {
        match i {
            0 => {
                self.m11 = r.x.clone();
                self.m12 = r.y.clone();
                self.m13 = r.z;
            },
            1 => {
                self.m21 = r.x.clone();
                self.m22 = r.y.clone();
                self.m23 = r.z;
            },
            2 => {
                self.m31 = r.x.clone();
                self.m32 = r.y.clone();
                self.m33 = r.z;
            },
            _ => fail!("Index out of range: 3d matrices do not have " + i.to_str() + " rows.")

        }
    }
}

impl<N: Clone> Col<Vec3<N>> for Mat3<N> {
    #[inline]
    fn num_cols(&self) -> uint {
        3
    }

    #[inline]
    fn col(&self, i: uint) -> Vec3<N> {
        match i {
            0 => Vec3::new(self.m11.clone(), self.m21.clone(), self.m31.clone()),
            1 => Vec3::new(self.m12.clone(), self.m22.clone(), self.m32.clone()),
            2 => Vec3::new(self.m13.clone(), self.m23.clone(), self.m33.clone()),
            _ => fail!("Index out of range: 3d matrices do not have " + i.to_str() + " cols.")
        }
    }

    #[inline]
    fn set_col(&mut self, i: uint, r: Vec3<N>) {
        match i {
            0 => {
                self.m11 = r.x.clone();
                self.m21 = r.y.clone();
                self.m31 = r.z;
            },
            1 => {
                self.m12 = r.x.clone();
                self.m22 = r.y.clone();
                self.m32 = r.z;
            },
            2 => {
                self.m13 = r.x.clone();
                self.m23 = r.y.clone();
                self.m33 = r.z;
            },
            _ => fail!("Index out of range: 3d matrices do not have " + i.to_str() + " cols.")

        }
    }
}

impl<N: Mul<N, N> + Add<N, N>> Mat3MulRhs<N, Mat3<N>> for Mat3<N> {
    #[inline]
    fn binop(left: &Mat3<N>, right: &Mat3<N>) -> Mat3<N> {
        Mat3::new(
            left.m11 * right.m11 + left.m12 * right.m21 + left.m13 * right.m31,
            left.m11 * right.m12 + left.m12 * right.m22 + left.m13 * right.m32,
            left.m11 * right.m13 + left.m12 * right.m23 + left.m13 * right.m33,

            left.m21 * right.m11 + left.m22 * right.m21 + left.m23 * right.m31,
            left.m21 * right.m12 + left.m22 * right.m22 + left.m23 * right.m32,
            left.m21 * right.m13 + left.m22 * right.m23 + left.m23 * right.m33,

            left.m31 * right.m11 + left.m32 * right.m21 + left.m33 * right.m31,
            left.m31 * right.m12 + left.m32 * right.m22 + left.m33 * right.m32,
            left.m31 * right.m13 + left.m32 * right.m23 + left.m33 * right.m33
        )
    }
}

impl<N: Mul<N, N> + Add<N, N>> Mat2MulRhs<N, Mat2<N>> for Mat2<N> {
    #[inline(always)]
    fn binop(left: &Mat2<N>, right: &Mat2<N>) -> Mat2<N> {
        Mat2::new(
            left.m11 * right.m11 + left.m12 * right.m21,
            left.m11 * right.m12 + left.m12 * right.m22,

            left.m21 * right.m11 + left.m22 * right.m21,
            left.m21 * right.m12 + left.m22 * right.m22
        )
    }
}

impl<N: Mul<N, N> + Add<N, N>> Mat3MulRhs<N, Vec3<N>> for Vec3<N> {
    #[inline(always)]
    fn binop(left: &Mat3<N>, right: &Vec3<N>) -> Vec3<N> {
        Vec3::new(
            left.m11 * right.x + left.m12 * right.y + left.m13 * right.z,
            left.m21 * right.x + left.m22 * right.y + left.m23 * right.z,
            left.m31 * right.x + left.m32 * right.y + left.m33 * right.z
        )
    }
}

impl<N: Mul<N, N> + Add<N, N>> Vec3MulRhs<N, Vec3<N>> for Mat3<N> {
    #[inline(always)]
    fn binop(left: &Vec3<N>, right: &Mat3<N>) -> Vec3<N> {
        Vec3::new(
            left.x * right.m11 + left.y * right.m21 + left.z * right.m31,
            left.x * right.m12 + left.y * right.m22 + left.z * right.m32,
            left.x * right.m13 + left.y * right.m23 + left.z * right.m33
        )
    }
}

impl<N: Mul<N, N> + Add<N, N>> Vec2MulRhs<N, Vec2<N>> for Mat2<N> {
    #[inline(always)]
    fn binop(left: &Vec2<N>, right: &Mat2<N>) -> Vec2<N> {
        Vec2::new(
            left.x * right.m11 + left.y * right.m21,
            left.x * right.m12 + left.y * right.m22
        )
    }
}

impl<N: Mul<N, N> + Add<N, N>> Mat2MulRhs<N, Vec2<N>> for Vec2<N> {
    #[inline(always)]
    fn binop(left: &Mat2<N>, right: &Vec2<N>) -> Vec2<N> {
        Vec2::new(
            left.m11 * right.x + left.m21 * right.y,
            left.m12 * right.x + left.m22 * right.y
        )
    }
}

// FIXME: move this to another file?
impl<N: Real + NumCast + Zero + One> mat::Mat4<N> {
    /// Computes a projection matrix given the frustrum near plane width, height, the field of
    /// view, and the distance to the clipping planes (`znear` and `zfar`).
    pub fn new_perspective(width: N, height: N, fov: N, znear: N, zfar: N) -> mat::Mat4<N> {
        let aspect = width / height;

        let _1: N = One::one();
        let sy    = _1 / (fov * NumCast::from(0.5)).tan();
        let sx    = -sy / aspect;
        let sz    = -(zfar + znear) / (znear - zfar);
        let tz    = zfar * znear * NumCast::from(2.0) / (znear - zfar);

        mat::Mat4::new(
            sx,           Zero::zero(), Zero::zero(), Zero::zero(),
            Zero::zero(), sy,           Zero::zero(), Zero::zero(),
            Zero::zero(), Zero::zero(), sz,           tz,
            Zero::zero(), Zero::zero(), One::one(),   Zero::zero()
            )
    }
}
<commit_msg>Fix broken 2d rotation.<commit_after>use std::num::{Zero, One};
use vec::{Vec2, Vec3, Vec2MulRhs, Vec3MulRhs};
use mat::{Mat1, Mat2, Mat3, Inv, Row, Col, Mat3MulRhs, Mat2MulRhs};
use mat;

// some specializations:
impl<N: Num + Clone>
Inv for Mat1<N> {
    #[inline]
    fn inverse(&self) -> Option<Mat1<N>> {
        let mut res : Mat1<N> = self.clone();

        if res.inplace_inverse() {
            Some(res)
        }
        else {
            None
        }
    }

    #[inline]
    fn inplace_inverse(&mut self) -> bool {
        if self.m11.is_zero() {
            false
        }
        else {
            let _1: N = One::one();
            self.m11 = _1 / self.m11;
            true
        }
    }
}

impl<N: Num + Clone>
Inv for Mat2<N> {
    #[inline]
    fn inverse(&self) -> Option<Mat2<N>> {
        let mut res : Mat2<N> = self.clone();

        if res.inplace_inverse() {
            Some(res)
        }
        else {
            None
        }
    }

    #[inline]
    fn inplace_inverse(&mut self) -> bool {
        let det = self.m11 * self.m22 - self.m21 * self.m12;

        if det.is_zero() {
            false
        }
        else {
            *self = Mat2::new(
                self.m22 / det , -self.m12 / det,
                -self.m21 / det, self.m11 / det);

            true
        }
    }
}

impl<N: Num + Clone>
Inv for Mat3<N> {
    #[inline]
    fn inverse(&self) -> Option<Mat3<N>> {
        let mut res = self.clone();

        if res.inplace_inverse() {
            Some(res)
        }
        else {
            None
        }
    }

    #[inline]
    fn inplace_inverse(&mut self) -> bool {
        let minor_m12_m23 = self.m22 * self.m33 - self.m32 * self.m23;
        let minor_m11_m23 = self.m21 * self.m33 - self.m31 * self.m23;
        let minor_m11_m22 = self.m21 * self.m32 - self.m31 * self.m22;

        let det = self.m11 * minor_m12_m23
                  - self.m12 * minor_m11_m23
                  + self.m13 * minor_m11_m22;

        if det.is_zero() {
            false
        }
        else {
            *self = Mat3::new(
                (minor_m12_m23 / det),
                ((self.m13 * self.m32 - self.m33 * self.m12) / det),
                ((self.m12 * self.m23 - self.m22 * self.m13) / det),

                (-minor_m11_m23 / det),
                ((self.m11 * self.m33 - self.m31 * self.m13) / det),
                ((self.m13 * self.m21 - self.m23 * self.m11) / det),

                (minor_m11_m22  / det),
                ((self.m12 * self.m31 - self.m32 * self.m11) / det),
                ((self.m11 * self.m22 - self.m21 * self.m12) / det)
                );

            true
        }
    }
}

impl<N: Clone> Row<Vec3<N>> for Mat3<N> {
    #[inline]
    fn num_rows(&self) -> uint {
        3
    }

    #[inline]
    fn row(&self, i: uint) -> Vec3<N> {
        match i {
            0 => Vec3::new(self.m11.clone(), self.m12.clone(), self.m13.clone()),
            1 => Vec3::new(self.m21.clone(), self.m22.clone(), self.m23.clone()),
            2 => Vec3::new(self.m31.clone(), self.m32.clone(), self.m33.clone()),
            _ => fail!("Index out of range: 3d matrices do not have " + i.to_str() + " rows.")
        }
    }

    #[inline]
    fn set_row(&mut self, i: uint, r: Vec3<N>) {
        match i {
            0 => {
                self.m11 = r.x.clone();
                self.m12 = r.y.clone();
                self.m13 = r.z;
            },
            1 => {
                self.m21 = r.x.clone();
                self.m22 = r.y.clone();
                self.m23 = r.z;
            },
            2 => {
                self.m31 = r.x.clone();
                self.m32 = r.y.clone();
                self.m33 = r.z;
            },
            _ => fail!("Index out of range: 3d matrices do not have " + i.to_str() + " rows.")

        }
    }
}

impl<N: Clone> Col<Vec3<N>> for Mat3<N> {
    #[inline]
    fn num_cols(&self) -> uint {
        3
    }

    #[inline]
    fn col(&self, i: uint) -> Vec3<N> {
        match i {
            0 => Vec3::new(self.m11.clone(), self.m21.clone(), self.m31.clone()),
            1 => Vec3::new(self.m12.clone(), self.m22.clone(), self.m32.clone()),
            2 => Vec3::new(self.m13.clone(), self.m23.clone(), self.m33.clone()),
            _ => fail!("Index out of range: 3d matrices do not have " + i.to_str() + " cols.")
        }
    }

    #[inline]
    fn set_col(&mut self, i: uint, r: Vec3<N>) {
        match i {
            0 => {
                self.m11 = r.x.clone();
                self.m21 = r.y.clone();
                self.m31 = r.z;
            },
            1 => {
                self.m12 = r.x.clone();
                self.m22 = r.y.clone();
                self.m32 = r.z;
            },
            2 => {
                self.m13 = r.x.clone();
                self.m23 = r.y.clone();
                self.m33 = r.z;
            },
            _ => fail!("Index out of range: 3d matrices do not have " + i.to_str() + " cols.")

        }
    }
}

impl<N: Mul<N, N> + Add<N, N>> Mat3MulRhs<N, Mat3<N>> for Mat3<N> {
    #[inline]
    fn binop(left: &Mat3<N>, right: &Mat3<N>) -> Mat3<N> {
        Mat3::new(
            left.m11 * right.m11 + left.m12 * right.m21 + left.m13 * right.m31,
            left.m11 * right.m12 + left.m12 * right.m22 + left.m13 * right.m32,
            left.m11 * right.m13 + left.m12 * right.m23 + left.m13 * right.m33,

            left.m21 * right.m11 + left.m22 * right.m21 + left.m23 * right.m31,
            left.m21 * right.m12 + left.m22 * right.m22 + left.m23 * right.m32,
            left.m21 * right.m13 + left.m22 * right.m23 + left.m23 * right.m33,

            left.m31 * right.m11 + left.m32 * right.m21 + left.m33 * right.m31,
            left.m31 * right.m12 + left.m32 * right.m22 + left.m33 * right.m32,
            left.m31 * right.m13 + left.m32 * right.m23 + left.m33 * right.m33
        )
    }
}

impl<N: Mul<N, N> + Add<N, N>> Mat2MulRhs<N, Mat2<N>> for Mat2<N> {
    #[inline(always)]
    fn binop(left: &Mat2<N>, right: &Mat2<N>) -> Mat2<N> {
        Mat2::new(
            left.m11 * right.m11 + left.m12 * right.m21,
            left.m11 * right.m12 + left.m12 * right.m22,

            left.m21 * right.m11 + left.m22 * right.m21,
            left.m21 * right.m12 + left.m22 * right.m22
        )
    }
}

impl<N: Mul<N, N> + Add<N, N>> Mat3MulRhs<N, Vec3<N>> for Vec3<N> {
    #[inline(always)]
    fn binop(left: &Mat3<N>, right: &Vec3<N>) -> Vec3<N> {
        Vec3::new(
            left.m11 * right.x + left.m12 * right.y + left.m13 * right.z,
            left.m21 * right.x + left.m22 * right.y + left.m23 * right.z,
            left.m31 * right.x + left.m32 * right.y + left.m33 * right.z
        )
    }
}

impl<N: Mul<N, N> + Add<N, N>> Vec3MulRhs<N, Vec3<N>> for Mat3<N> {
    #[inline(always)]
    fn binop(left: &Vec3<N>, right: &Mat3<N>) -> Vec3<N> {
        Vec3::new(
            left.x * right.m11 + left.y * right.m21 + left.z * right.m31,
            left.x * right.m12 + left.y * right.m22 + left.z * right.m32,
            left.x * right.m13 + left.y * right.m23 + left.z * right.m33
        )
    }
}

impl<N: Mul<N, N> + Add<N, N>> Vec2MulRhs<N, Vec2<N>> for Mat2<N> {
    #[inline(always)]
    fn binop(left: &Vec2<N>, right: &Mat2<N>) -> Vec2<N> {
        Vec2::new(
            left.x * right.m11 + left.y * right.m21,
            left.x * right.m12 + left.y * right.m22
        )
    }
}

impl<N: Mul<N, N> + Add<N, N>> Mat2MulRhs<N, Vec2<N>> for Vec2<N> {
    #[inline(always)]
    fn binop(left: &Mat2<N>, right: &Vec2<N>) -> Vec2<N> {
        Vec2::new(
            left.m11 * right.x + left.m12 * right.y,
            left.m21 * right.x + left.m22 * right.y
        )
    }
}

// FIXME: move this to another file?
impl<N: Real + NumCast + Zero + One> mat::Mat4<N> {
    /// Computes a projection matrix given the frustrum near plane width, height, the field of
    /// view, and the distance to the clipping planes (`znear` and `zfar`).
    pub fn new_perspective(width: N, height: N, fov: N, znear: N, zfar: N) -> mat::Mat4<N> {
        let aspect = width / height;

        let _1: N = One::one();
        let sy    = _1 / (fov * NumCast::from(0.5)).tan();
        let sx    = -sy / aspect;
        let sz    = -(zfar + znear) / (znear - zfar);
        let tz    = zfar * znear * NumCast::from(2.0) / (znear - zfar);

        mat::Mat4::new(
            sx,           Zero::zero(), Zero::zero(), Zero::zero(),
            Zero::zero(), sy,           Zero::zero(), Zero::zero(),
            Zero::zero(), Zero::zero(), sz,           tz,
            Zero::zero(), Zero::zero(), One::one(),   Zero::zero()
            )
    }
}
<|endoftext|>


<commit_before>fn edit_distance(first: &str, second: &str) -> usize {
    // Initialize a matrix we'll use to track the
    // edit distances as we step through both strings.
    let width = first.chars().count()+1;
    let height = second.chars().count()+1;
    let mut distances: Vec<usize> = Vec::with_capacity(width*height);

    // We want to be able to index values immediately,
    // without having to push data (usizes default to zero).
    unsafe { distances.set_len(width*height); }

    // Initialize first row and column values, when we come
    // across them, which is the distance from nothing to
    // every zero-index substring of the other word.
    // e.g. ("" -> "hou", "" -> "houn", "" -> "hound")
    for row in (0..height) {
        distances[row*width] = row;
    }
    for column in (0..width) {
        distances[column] = column;
    }

    // We need to manage indices manually; strings don't have an
    // index + character iterator, since indexing UTF-8 strings
    // doesn't work beyond the ASCII set. We, however, need to track
    // each substring combination, so they're useful in this scenario.
    let mut row = 1;
    let mut column = 1;
    for row_char in second.chars() {
        for column_char in first.chars() {
            if column_char == row_char {
                // When the strings share a common character, there's
                // no additional cost; we carry forward the optimum edit
                // distance we calculated without having considered it.
                distances[row*width + column] = distances[(row-1)*width + (column-1)];
            } else {
                distances[row*width + column] = *[
                    // Cost of removing a character from the first word.
                    distances[(row-1)*width + column] + 1,

                    // Cost of adding a character to the first word.
                    distances[row*width + (column-1)] + 1,

                    // Cost of substituting the character for another.
                    distances[(row-1)*width + (column-1)] + 1
                ].iter().min().unwrap();
            }
            column += 1;
        }
        row += 1;
        column = 1;
    }

    // The optimal edit distance is always in the
    // lower-right corner of the distance matrix.
    return distances[width*height-1]
}

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

    #[test]
    fn edit_distance_is_correct_for_removing_a_character() {
        assert_eq!(edit_distance("hound", "hounds"), 1);
    }

    #[test]
    fn edit_distance_is_correct_for_adding_a_character() {
        assert_eq!(edit_distance("hounds", "hound"), 1);
    }

    #[test]
    fn edit_distance_is_correct_for_substitutions() {
        assert_eq!(edit_distance("hound", "mound"), 1);
    }
}
<commit_msg>Add doc comments for edit_distance function.<commit_after>/// Determines the minimum number of edits required to transform
/// the first string into the second, using a matrix-driven
/// version of the Levenshtein distance algorithm.
///
/// ```rust
/// let score = edit_distance("hound", "hounds"); // 1
/// ```
fn edit_distance(first: &str, second: &str) -> usize {
    // Initialize a matrix we'll use to track the
    // edit distances as we step through both strings.
    let width = first.chars().count()+1;
    let height = second.chars().count()+1;
    let mut distances: Vec<usize> = Vec::with_capacity(width*height);

    // We want to be able to index values immediately,
    // without having to push data (usizes default to zero).
    unsafe { distances.set_len(width*height); }

    // Initialize first row and column values, when we come
    // across them, which is the distance from nothing to
    // every zero-index substring of the other word.
    // e.g. ("" -> "hou", "" -> "houn", "" -> "hound")
    for row in (0..height) {
        distances[row*width] = row;
    }
    for column in (0..width) {
        distances[column] = column;
    }

    // We need to manage indices manually; strings don't have an
    // index + character iterator, since indexing UTF-8 strings
    // doesn't work beyond the ASCII set. We, however, need to track
    // each substring combination, so they're useful in this scenario.
    let mut row = 1;
    let mut column = 1;
    for row_char in second.chars() {
        for column_char in first.chars() {
            if column_char == row_char {
                // When the strings share a common character, there's
                // no additional cost; we carry forward the optimum edit
                // distance we calculated without having considered it.
                distances[row*width + column] = distances[(row-1)*width + (column-1)];
            } else {
                distances[row*width + column] = *[
                    // Cost of removing a character from the first word.
                    distances[(row-1)*width + column] + 1,

                    // Cost of adding a character to the first word.
                    distances[row*width + (column-1)] + 1,

                    // Cost of substituting the character for another.
                    distances[(row-1)*width + (column-1)] + 1
                ].iter().min().unwrap();
            }
            column += 1;
        }
        row += 1;
        column = 1;
    }

    // The optimal edit distance is always in the
    // lower-right corner of the distance matrix.
    return distances[width*height-1]
}

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

    #[test]
    fn edit_distance_is_correct_for_removing_a_character() {
        assert_eq!(edit_distance("hound", "hounds"), 1);
    }

    #[test]
    fn edit_distance_is_correct_for_adding_a_character() {
        assert_eq!(edit_distance("hounds", "hound"), 1);
    }

    #[test]
    fn edit_distance_is_correct_for_substitutions() {
        assert_eq!(edit_distance("hound", "mound"), 1);
    }
}
<|endoftext|>


<commit_before>
#[link(name = "exempi")]

extern crate libc;
use self::libc::{c_int, c_char, size_t};

pub enum Xmp {}
pub enum XmpFile {}
pub enum XmpString {}
pub enum XmpIterator {}

// the C defined struct.
#[repr(C)]
pub struct XmpDateTime {
    pub year: i32,
    pub month: i32,
    pub day: i32,
    pub hour: i32,
    pub minute: i32,
    pub second: i32,
    pub tz_sign: i32,
    pub tz_hour: i32,
    pub tz_minute: i32,
    pub nano_second: i32,
}

pub const XMP_OPEN_NOOPTION: c_int = 0x00000000;        /**< No open option */
pub const XMP_OPEN_READ: c_int = 0x00000001;            /**< Open for read-only access. */
pub const XMP_OPEN_FORUPDATE: c_int = 0x00000002;       /**< Open for reading and writing. */
pub const XMP_OPEN_ONLYXMP: c_int = 0x00000004;         /**< Only the XMP is wanted, allows space/time optimizations. */
pub const XMP_OPEN_CACHETNAIL: c_int = 0x00000008;      /**< Cache thumbnail if possible, GetThumbnail will be called. */
pub const XMP_OPEN_STRICTLY: c_int = 0x00000010;        /**< Be strict about locating XMP and reconciling with other forms. */
pub const XMP_OPEN_USESMARTHANDLER: c_int = 0x00000020; /**< Require the use of a smart handler. */
pub const XMP_OPEN_USEPACKETSCANNING: c_int = 0x00000040; /**< Force packet scanning, don't use a smart handler. */
pub const XMP_OPEN_LIMITSCANNING: c_int = 0x00000080;     /**< Only packet scan files "known" to need scanning. */
pub const XMP_OPEN_REPAIR_FILE: c_int = 0x00000100; /**< Attempt to repair a file opened for update, default is to not open (throw an exception). */
pub const XMP_OPEN_OPTIMIZEFILELAYOUT: c_int = 0x00000200; /**< Optimize MPEG4 to support stream when updating This can take some time */
pub const XMP_OPEN_INBACKGROUND: c_int = 0x10000000; /**< Set if calling from background thread. */

pub const XMP_CLOSE_NOOPTION: c_int = 0x0000;  /**< No close option */
pub const XMP_CLOSE_SAFEUPDATE: c_int = 0x0001; /**< Write into a temporary file and swap for crash safety. */

extern "C" {
    pub fn xmp_init() -> bool;
    pub fn xmp_terminate();

    pub fn xmp_get_error() -> c_int;

    pub fn xmp_files_new() -> *mut XmpFile;
    pub fn xmp_files_open_new(p: *const c_char, options: c_int) -> *mut XmpFile;
    pub fn xmp_files_open(xf: *mut XmpFile, p:  *const c_char,
                          options: c_int) -> bool;
    pub fn xmp_files_close(xf: *mut XmpFile, options: c_int) -> bool;

    pub fn xmp_files_get_new_xmp(xf: *mut XmpFile) -> *mut Xmp;
    pub fn xmp_files_get_xmp(xf: *mut XmpFile, xmp: *mut Xmp) -> bool;
    pub fn xmp_files_can_put_xmp(xf: *mut XmpFile, xmp: *const Xmp) -> bool;
    pub fn xmp_files_put_xmp(xf: *mut XmpFile, xmp: *const Xmp) -> bool;

    pub fn xmp_files_free(xf: *mut XmpFile) -> bool;

    pub fn xmp_files_get_file_info(xf: *mut XmpFile, fp: *mut XmpString,
                                   options: *mut c_int, format: *mut c_int,
                                   handler_flags: *mut c_int) -> bool;
    pub fn xmp_files_check_file_format(p: *const c_char) -> c_int;

    pub fn xmp_register_namespace(uri: *const c_char, prefix: *const c_char,
                                  reg_prefix: *mut XmpString) -> bool;
    pub fn xmp_namespace_prefix(ns: *const c_char,
                                prefix: *mut XmpString) -> bool;
    pub fn xmp_prefix_namespace_uri(prefix: *const c_char,
                                    ns: *mut XmpString) -> bool;

    pub fn xmp_new_empty() -> *mut Xmp;
    pub fn xmp_new(buffer: *const c_char, len: size_t) -> *mut Xmp;
    pub fn xmp_copy(xmp: *const Xmp) -> *mut Xmp;
    pub fn xmp_free(xmp: *mut Xmp) -> bool;
    pub fn xmp_parse(xmp: *mut Xmp, buffer: *const c_char, len: size_t) -> bool;
    pub fn xmp_serialize(xmp: *const Xmp, buf: *mut XmpString, options: c_int,
                         padding: u32) -> bool;
    pub fn xmp_serialize_and_format(xmp: *const Xmp, buf: *mut XmpString,
                                    options: u32, padding: u32,
                                    newline: *const c_char, tab: *const c_char,
                                    indent: i32) -> bool;

    // get properties
    pub fn xmp_get_property(xmp: *const Xmp, schema: *const c_char,
                            name: *const c_char, property: *mut XmpString,
                            propsbits: *mut u32) -> bool;
    pub fn xmp_get_property_date(xmp: *const Xmp, schema: *const c_char,
                                 name: *const c_char,
                                 property: *mut XmpDateTime,
                                 propsbits: *mut u32) -> bool;
    pub fn xmp_get_property_float(xmp: *const Xmp, schema: *const c_char,
                                  name: *const c_char,
                                  property: *mut f64,
                                  propsbits: *mut u32) -> bool;
    pub fn xmp_get_property_bool(xmp: *const Xmp, schema: *const c_char,
                                  name: *const c_char,
                                  property: *mut bool,
                                  propsbits: *mut u32) -> bool;
    pub fn xmp_get_property_int32(xmp: *const Xmp, schema: *const c_char,
                                  name: *const c_char,
                                  property: *mut i32,
                                  propsbits: *mut u32) -> bool;
    pub fn xmp_get_property_int64(xmp: *const Xmp, schema: *const c_char,
                                  name: *const c_char,
                                  property: *mut i64,
                                  propsbits: *mut u32) -> bool;
    pub fn xmp_get_array_item(xmp: *const Xmp,  schema: *const c_char,
                              name: *const c_char, index: i32,
                              property: *mut XmpString,
                              propsbits: *mut u32) -> bool;

    // set properies
    pub fn xmp_set_property(xmp: *mut Xmp, schema: *const c_char,
                            name: *const c_char, value: *const c_char,
                            optionbits: u32) -> bool;
    pub fn xmp_set_property_date(xmp: *mut Xmp, schema: *const c_char,
                            name: *const c_char, value: *const XmpDateTime,
                            optionbits: u32) -> bool;
    pub fn xmp_set_property_float(xmp: *mut Xmp, schema: *const c_char,
                                  name: *const c_char, value: f64,
                                  optionbits: u32) -> bool;
    pub fn xmp_set_property_bool(xmp: *mut Xmp, schema: *const c_char,
                                  name: *const c_char, value: bool,
                                  optionbits: u32) -> bool;
    pub fn xmp_set_property_int32(xmp: *mut Xmp, schema: *const c_char,
                                  name: *const c_char, value: i32,
                                  optionbits: u32) -> bool;
    pub fn xmp_set_property_int64(xmp: *mut Xmp, schema: *const c_char,
                                  name: *const c_char, value: i64,
                                  optionbits: u32) -> bool;
    pub fn xmp_set_array_item(xmp: *mut Xmp, schema: *const c_char,
                              name: *const c_char, index: i32,
                              value: *const c_char,
                              optionbits: *mut u32) -> bool;

    pub fn xmp_append_array_item(xmp: *mut Xmp, schema: *const c_char,
                                 name: *const c_char, array_options: u32,
                                 value: *const c_char,
                                 optionbits: u32) -> bool;
    pub fn xmp_delete_property(xmp: *mut Xmp, schema: *const c_char,
                               name: *const c_char) -> bool;
    pub fn xmp_has_property(xmp: *const Xmp, schema: *const c_char,
                            name: *const c_char) -> bool;

    pub fn xmp_get_localized_text(xmp: *const Xmp, schema: *const c_char,
                                 name: *const c_char, gen_lang: *const c_char,
                                 spec_lang: *const c_char,
                                 actual_lang: *mut XmpString,
                                 value: *mut XmpString,
                                 propbits: *mut u32) -> bool;
    pub fn xmp_set_localized_text(xmp: *mut Xmp, schema: *const c_char,
                                  name: *const c_char, gen_lang: *const c_char,
                                  spec_lang: *const c_char,
                                  value: *const c_char,
                                  optionbits: u32) -> bool;
    pub fn xmp_delete_localized_text(xmp: *mut Xmp, schema: *const c_char,
                                     name: *const c_char,
                                     gen_lang: *const c_char,
                                     spec_lang: *const c_char) -> bool;

    pub fn xmp_string_new() -> *mut XmpString;
    pub fn xmp_string_free(s: *mut XmpString);
    pub fn xmp_string_cstr(s: *const XmpString) -> *const c_char;

    pub fn xmp_iterator_new() -> *mut XmpIterator;
    pub fn xmp_iterator_free(i: *mut XmpIterator) -> bool;
    pub fn xmp_iterator_next(i: *mut XmpIterator, schema: *mut XmpString,
                             name: *mut XmpString, value: *mut XmpString,
                             option: *mut u32) -> bool;
    pub fn xmp_iterator_skip(i: *mut XmpIterator, option: c_int) -> bool;

    pub fn xmp_datetime_compare(left: *const XmpDateTime,
                                right: *const XmpDateTime) -> c_int;
}

#[test]
fn it_works() {
    let inited = unsafe { xmp_init() };

    assert!(inited);

    let xf = unsafe { xmp_files_new() };

    assert!(!xf.is_null());
    assert!(unsafe { xmp_files_free(xf) });
    assert!(unsafe { xmp_get_error() } == 0);

    unsafe { xmp_terminate() };
}
<commit_msg>Native binding tests.<commit_after>
#[link(name = "exempi")]

extern crate libc;
use self::libc::{c_int, c_char, size_t};

pub enum Xmp {}
pub enum XmpFile {}
pub enum XmpString {}
pub enum XmpIterator {}

// the C defined struct.
#[repr(C)]
pub struct XmpDateTime {
    pub year: i32,
    pub month: i32,
    pub day: i32,
    pub hour: i32,
    pub minute: i32,
    pub second: i32,
    pub tz_sign: i32,
    pub tz_hour: i32,
    pub tz_minute: i32,
    pub nano_second: i32,
}

pub const XMP_OPEN_NOOPTION: c_int = 0x00000000;        /**< No open option */
pub const XMP_OPEN_READ: c_int = 0x00000001;            /**< Open for read-only access. */
pub const XMP_OPEN_FORUPDATE: c_int = 0x00000002;       /**< Open for reading and writing. */
pub const XMP_OPEN_ONLYXMP: c_int = 0x00000004;         /**< Only the XMP is wanted, allows space/time optimizations. */
pub const XMP_OPEN_CACHETNAIL: c_int = 0x00000008;      /**< Cache thumbnail if possible, GetThumbnail will be called. */
pub const XMP_OPEN_STRICTLY: c_int = 0x00000010;        /**< Be strict about locating XMP and reconciling with other forms. */
pub const XMP_OPEN_USESMARTHANDLER: c_int = 0x00000020; /**< Require the use of a smart handler. */
pub const XMP_OPEN_USEPACKETSCANNING: c_int = 0x00000040; /**< Force packet scanning, don't use a smart handler. */
pub const XMP_OPEN_LIMITSCANNING: c_int = 0x00000080;     /**< Only packet scan files "known" to need scanning. */
pub const XMP_OPEN_REPAIR_FILE: c_int = 0x00000100; /**< Attempt to repair a file opened for update, default is to not open (throw an exception). */
pub const XMP_OPEN_OPTIMIZEFILELAYOUT: c_int = 0x00000200; /**< Optimize MPEG4 to support stream when updating This can take some time */
pub const XMP_OPEN_INBACKGROUND: c_int = 0x10000000; /**< Set if calling from background thread. */

pub const XMP_CLOSE_NOOPTION: c_int = 0x0000;  /**< No close option */
pub const XMP_CLOSE_SAFEUPDATE: c_int = 0x0001; /**< Write into a temporary file and swap for crash safety. */

extern "C" {
    pub fn xmp_init() -> bool;
    pub fn xmp_terminate();

    pub fn xmp_get_error() -> c_int;

    pub fn xmp_files_new() -> *mut XmpFile;
    pub fn xmp_files_open_new(p: *const c_char, options: c_int) -> *mut XmpFile;
    pub fn xmp_files_open(xf: *mut XmpFile, p:  *const c_char,
                          options: c_int) -> bool;
    pub fn xmp_files_close(xf: *mut XmpFile, options: c_int) -> bool;

    pub fn xmp_files_get_new_xmp(xf: *mut XmpFile) -> *mut Xmp;
    pub fn xmp_files_get_xmp(xf: *mut XmpFile, xmp: *mut Xmp) -> bool;
    pub fn xmp_files_can_put_xmp(xf: *mut XmpFile, xmp: *const Xmp) -> bool;
    pub fn xmp_files_put_xmp(xf: *mut XmpFile, xmp: *const Xmp) -> bool;

    pub fn xmp_files_free(xf: *mut XmpFile) -> bool;

    pub fn xmp_files_get_file_info(xf: *mut XmpFile, fp: *mut XmpString,
                                   options: *mut c_int, format: *mut c_int,
                                   handler_flags: *mut c_int) -> bool;
    pub fn xmp_files_check_file_format(p: *const c_char) -> c_int;

    pub fn xmp_register_namespace(uri: *const c_char, prefix: *const c_char,
                                  reg_prefix: *mut XmpString) -> bool;
    pub fn xmp_namespace_prefix(ns: *const c_char,
                                prefix: *mut XmpString) -> bool;
    pub fn xmp_prefix_namespace_uri(prefix: *const c_char,
                                    ns: *mut XmpString) -> bool;

    pub fn xmp_new_empty() -> *mut Xmp;
    pub fn xmp_new(buffer: *const c_char, len: size_t) -> *mut Xmp;
    pub fn xmp_copy(xmp: *const Xmp) -> *mut Xmp;
    pub fn xmp_free(xmp: *mut Xmp) -> bool;
    pub fn xmp_parse(xmp: *mut Xmp, buffer: *const c_char, len: size_t) -> bool;
    pub fn xmp_serialize(xmp: *const Xmp, buf: *mut XmpString, options: c_int,
                         padding: u32) -> bool;
    pub fn xmp_serialize_and_format(xmp: *const Xmp, buf: *mut XmpString,
                                    options: u32, padding: u32,
                                    newline: *const c_char, tab: *const c_char,
                                    indent: i32) -> bool;

    // get properties
    pub fn xmp_get_property(xmp: *const Xmp, schema: *const c_char,
                            name: *const c_char, property: *mut XmpString,
                            propsbits: *mut u32) -> bool;
    pub fn xmp_get_property_date(xmp: *const Xmp, schema: *const c_char,
                                 name: *const c_char,
                                 property: *mut XmpDateTime,
                                 propsbits: *mut u32) -> bool;
    pub fn xmp_get_property_float(xmp: *const Xmp, schema: *const c_char,
                                  name: *const c_char,
                                  property: *mut f64,
                                  propsbits: *mut u32) -> bool;
    pub fn xmp_get_property_bool(xmp: *const Xmp, schema: *const c_char,
                                  name: *const c_char,
                                  property: *mut bool,
                                  propsbits: *mut u32) -> bool;
    pub fn xmp_get_property_int32(xmp: *const Xmp, schema: *const c_char,
                                  name: *const c_char,
                                  property: *mut i32,
                                  propsbits: *mut u32) -> bool;
    pub fn xmp_get_property_int64(xmp: *const Xmp, schema: *const c_char,
                                  name: *const c_char,
                                  property: *mut i64,
                                  propsbits: *mut u32) -> bool;
    pub fn xmp_get_array_item(xmp: *const Xmp,  schema: *const c_char,
                              name: *const c_char, index: i32,
                              property: *mut XmpString,
                              propsbits: *mut u32) -> bool;

    // set properies
    pub fn xmp_set_property(xmp: *mut Xmp, schema: *const c_char,
                            name: *const c_char, value: *const c_char,
                            optionbits: u32) -> bool;
    pub fn xmp_set_property_date(xmp: *mut Xmp, schema: *const c_char,
                            name: *const c_char, value: *const XmpDateTime,
                            optionbits: u32) -> bool;
    pub fn xmp_set_property_float(xmp: *mut Xmp, schema: *const c_char,
                                  name: *const c_char, value: f64,
                                  optionbits: u32) -> bool;
    pub fn xmp_set_property_bool(xmp: *mut Xmp, schema: *const c_char,
                                  name: *const c_char, value: bool,
                                  optionbits: u32) -> bool;
    pub fn xmp_set_property_int32(xmp: *mut Xmp, schema: *const c_char,
                                  name: *const c_char, value: i32,
                                  optionbits: u32) -> bool;
    pub fn xmp_set_property_int64(xmp: *mut Xmp, schema: *const c_char,
                                  name: *const c_char, value: i64,
                                  optionbits: u32) -> bool;
    pub fn xmp_set_array_item(xmp: *mut Xmp, schema: *const c_char,
                              name: *const c_char, index: i32,
                              value: *const c_char,
                              optionbits: *mut u32) -> bool;

    pub fn xmp_append_array_item(xmp: *mut Xmp, schema: *const c_char,
                                 name: *const c_char, array_options: u32,
                                 value: *const c_char,
                                 optionbits: u32) -> bool;
    pub fn xmp_delete_property(xmp: *mut Xmp, schema: *const c_char,
                               name: *const c_char) -> bool;
    pub fn xmp_has_property(xmp: *const Xmp, schema: *const c_char,
                            name: *const c_char) -> bool;

    pub fn xmp_get_localized_text(xmp: *const Xmp, schema: *const c_char,
                                 name: *const c_char, gen_lang: *const c_char,
                                 spec_lang: *const c_char,
                                 actual_lang: *mut XmpString,
                                 value: *mut XmpString,
                                 propbits: *mut u32) -> bool;
    pub fn xmp_set_localized_text(xmp: *mut Xmp, schema: *const c_char,
                                  name: *const c_char, gen_lang: *const c_char,
                                  spec_lang: *const c_char,
                                  value: *const c_char,
                                  optionbits: u32) -> bool;
    pub fn xmp_delete_localized_text(xmp: *mut Xmp, schema: *const c_char,
                                     name: *const c_char,
                                     gen_lang: *const c_char,
                                     spec_lang: *const c_char) -> bool;

    pub fn xmp_string_new() -> *mut XmpString;
    pub fn xmp_string_free(s: *mut XmpString);
    pub fn xmp_string_cstr(s: *const XmpString) -> *const c_char;

    pub fn xmp_iterator_new() -> *mut XmpIterator;
    pub fn xmp_iterator_free(i: *mut XmpIterator) -> bool;
    pub fn xmp_iterator_next(i: *mut XmpIterator, schema: *mut XmpString,
                             name: *mut XmpString, value: *mut XmpString,
                             option: *mut u32) -> bool;
    pub fn xmp_iterator_skip(i: *mut XmpIterator, option: c_int) -> bool;

    pub fn xmp_datetime_compare(left: *const XmpDateTime,
                                right: *const XmpDateTime) -> c_int;
}

#[test]
fn native_call_works() {
    let inited = unsafe { xmp_init() };

    assert!(inited);

    let xf = unsafe { xmp_files_new() };

    assert!(!xf.is_null());
    assert!(unsafe { xmp_files_free(xf) });
    assert!(unsafe { xmp_get_error() } == 0);

    let xs = unsafe { xmp_string_new() };
    assert!(!xs.is_null());
    let s = unsafe { xmp_string_cstr(xs) };
    assert!(!s.is_null());
    unsafe { xmp_string_free(xs); }

    unsafe { xmp_terminate(); }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#![deny(clippy::all)]

mod client;
mod code_action;
mod completion;
mod diagnostic_reporter;
mod explore_schema_for_type;
mod extension_config;
mod goto_definition;
mod graphql_tools;
mod hover;
mod js_language_server;
mod location;
mod lsp_extra_data_provider;
pub mod lsp_process_error;
mod lsp_runtime_error;
mod node_resolution_info;
mod references;
mod resolution_path;
mod resolved_types_at_location;
mod search_schema_items;
mod server;
mod shutdown;
mod status_reporting;
mod status_updater;
mod text_documents;
mod utils;
pub use crate::extension_config::ExtensionConfig;
use common::PerfLogger;
pub use js_language_server::JSLanguageServer;
use js_language_server::NoopJSLanguageServer;
use log::debug;
pub use lsp_extra_data_provider::{FieldDefinitionSourceInfo, LSPExtraDataProvider};
use lsp_process_error::LSPProcessResult;
pub use lsp_runtime_error::{LSPRuntimeError, LSPRuntimeResult};
use lsp_server::Connection;
use relay_compiler::config::Config;
use schema_documentation::{SchemaDocumentation, SchemaDocumentationLoader};
pub use server::LSPNotificationDispatch;
pub use server::LSPRequestDispatch;
pub use server::{LSPState, Schemas};
use std::sync::Arc;
pub use utils::position_to_offset;
#[cfg(test)]
#[macro_use]
extern crate assert_matches;

pub async fn start_language_server<TPerfLogger, TSchemaDocumentation: SchemaDocumentation>(
    config: Config,
    extension_config: ExtensionConfig,
    perf_logger: Arc<TPerfLogger>,
    extra_data_provider: Box<dyn LSPExtraDataProvider + Send + Sync>,
    schema_documentation_loader: Option<Box<dyn SchemaDocumentationLoader<TSchemaDocumentation>>>,
    js_language_server: Option<Box<dyn JSLanguageServer<TPerfLogger, TSchemaDocumentation>>>,
) -> LSPProcessResult<()>
where
    TPerfLogger: PerfLogger + 'static,
{
    let (connection, io_handles) = Connection::stdio();
    debug!("Initialized stdio transport layer");
    let params = server::initialize(&connection)?;
    debug!("JSON-RPC handshake completed");
    server::run(
        connection,
        config,
        extension_config,
        params,
        perf_logger,
        extra_data_provider,
        schema_documentation_loader,
        js_language_server.unwrap_or_else(|| Box::new(NoopJSLanguageServer::default())),
    )
    .await?;
    io_handles.join()?;
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::client;
    use super::lsp_process_error::LSPProcessResult;
    use super::server;
    use lsp_server::Connection;
    use lsp_types::{ClientCapabilities, InitializeParams};
    #[test]
    fn initialize() -> LSPProcessResult<()> {
        // Test with an in-memory connection pair
        let (connection, client) = Connection::memory();
        // Mock set of client parameters. The `root_path` field is deprecated, but
        // still required to construct the params, so we allow deprecated fields here.
        #[allow(deprecated)]
        let init_params = InitializeParams {
            process_id: Some(1),
            root_path: None,
            root_uri: None,
            initialization_options: None,
            capabilities: ClientCapabilities::default(),
            trace: None,
            workspace_folders: None,
            client_info: None,
            locale: None,
        };
        client::initialize(&client, &init_params, 0);
        let params = server::initialize(&connection)?;
        assert_eq!(params, init_params);
        Ok(())
    }
}
<commit_msg>Parse graphql source into ast and resolution path<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#![deny(clippy::all)]

mod client;
mod code_action;
mod completion;
mod diagnostic_reporter;
mod explore_schema_for_type;
mod extension_config;
mod goto_definition;
mod graphql_tools;
mod hover;
mod js_language_server;
mod location;
mod lsp_extra_data_provider;
pub mod lsp_process_error;
pub mod lsp_runtime_error;
mod node_resolution_info;
mod references;
pub mod resolution_path;
mod resolved_types_at_location;
mod search_schema_items;
mod server;
mod shutdown;
mod status_reporting;
mod status_updater;
mod text_documents;
mod utils;
pub use crate::extension_config::ExtensionConfig;
use common::PerfLogger;
pub use js_language_server::JSLanguageServer;
use js_language_server::NoopJSLanguageServer;
use log::debug;
pub use lsp_extra_data_provider::{FieldDefinitionSourceInfo, LSPExtraDataProvider};
use lsp_process_error::LSPProcessResult;
pub use lsp_runtime_error::{LSPRuntimeError, LSPRuntimeResult};
use lsp_server::Connection;
use relay_compiler::config::Config;
use schema_documentation::{SchemaDocumentation, SchemaDocumentationLoader};
pub use server::LSPNotificationDispatch;
pub use server::LSPRequestDispatch;
pub use server::{LSPState, Schemas};
use std::sync::Arc;
pub use utils::position_to_offset;
#[cfg(test)]
#[macro_use]
extern crate assert_matches;

pub async fn start_language_server<TPerfLogger, TSchemaDocumentation: SchemaDocumentation>(
    config: Config,
    extension_config: ExtensionConfig,
    perf_logger: Arc<TPerfLogger>,
    extra_data_provider: Box<dyn LSPExtraDataProvider + Send + Sync>,
    schema_documentation_loader: Option<Box<dyn SchemaDocumentationLoader<TSchemaDocumentation>>>,
    js_language_server: Option<Box<dyn JSLanguageServer<TPerfLogger, TSchemaDocumentation>>>,
) -> LSPProcessResult<()>
where
    TPerfLogger: PerfLogger + 'static,
{
    let (connection, io_handles) = Connection::stdio();
    debug!("Initialized stdio transport layer");
    let params = server::initialize(&connection)?;
    debug!("JSON-RPC handshake completed");
    server::run(
        connection,
        config,
        extension_config,
        params,
        perf_logger,
        extra_data_provider,
        schema_documentation_loader,
        js_language_server.unwrap_or_else(|| Box::new(NoopJSLanguageServer::default())),
    )
    .await?;
    io_handles.join()?;
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::client;
    use super::lsp_process_error::LSPProcessResult;
    use super::server;
    use lsp_server::Connection;
    use lsp_types::{ClientCapabilities, InitializeParams};
    #[test]
    fn initialize() -> LSPProcessResult<()> {
        // Test with an in-memory connection pair
        let (connection, client) = Connection::memory();
        // Mock set of client parameters. The `root_path` field is deprecated, but
        // still required to construct the params, so we allow deprecated fields here.
        #[allow(deprecated)]
        let init_params = InitializeParams {
            process_id: Some(1),
            root_path: None,
            root_uri: None,
            initialization_options: None,
            capabilities: ClientCapabilities::default(),
            trace: None,
            workspace_folders: None,
            client_info: None,
            locale: None,
        };
        client::initialize(&client, &init_params, 0);
        let params = server::initialize(&connection)?;
        assert_eq!(params, init_params);
        Ok(())
    }
}
<|endoftext|>