<commit_before>use image::{ImageBuffer, RgbImage};
use bitreader::BitReader;

#[derive(Debug)]
pub struct CoverImage {
    message: &'static str,
    output_image_path: &'static str,
    cover_image: RgbImage,
    message_as_bits: Vec<u8>
}

impl CoverImage {
    pub fn new() -> CoverImage {
        CoverImage {
            message: "",
            output_image_path: "",
            cover_image: ImageBuffer::new(0, 0),
            message_as_bits: vec![]
        }
    }

    pub fn set_cover_image(mut self, input_path: &'static str) -> Self {
        self.cover_image = image::open(input_path).unwrap().as_rgb8().unwrap().clone();

        self.cover_image.get_pixel_mut(0, 0);

        self
    }

    pub fn set_message(mut self, message: &'static str) -> Self {
        self.message = message;

        self
    }

    pub fn set_output_image_path(mut self, output_path: &'static str) -> Self {
        self.output_image_path = output_path;

        self
    }

    fn get_message_as_bits(&mut self) {
        let mut reader = BitReader::new(&self.message.as_bytes());

        for _ in 0..self.message.len() * 8 {
            self.message_as_bits.push(reader.read_u8(1).unwrap());
        }
    }

    fn tile_image(&mut self) -> Vec<u8> {
        let (width, height) = self.cover_image.dimensions();

        let mut tiles = Vec::new();
        let mut count = 0;

        for row_index in 0..(height / 8) as u32 {
            for col_index in 0..(width / 8) as u32 {
                for channel in 0..3 {
                    if count == self.message_as_bits.len() {
                        break
                    }

                    for row in 0..8 {
                        for column in 0..8 {
                            let pixel = self.cover_image.get_pixel(column + (col_index * 8),
                                                                      row + (row_index * 8));

                            tiles.push(pixel.data[channel]);
                        }
                    }
                    count += 1;
                }
            }
        }

        tiles
    }
}

#[test]
fn get_message_as_bits_test() {
    let test_bits = vec![0, 1, 1, 0, 1, 0, 0, 0];
    let mut cover_image = CoverImage::new().set_message("h");

    cover_image.get_message_as_bits();

    assert_eq!(cover_image.message_as_bits, test_bits);
}

#[test]
fn tile_image_length_test() {
    let mut cover_image = CoverImage::new().set_message("h")
        .set_cover_image("src/testing.jpg");

    // 64 = length of 1 tile, message.len() * 8 = number of tiles needed; 1 tile per bit
    let length = 64 * cover_image.message.len() * 8;

    cover_image.get_message_as_bits();

    let tile_vec_length = cover_image.tile_image().len();

    assert_eq!(length, tile_vec_length);
}

#[test]
fn test_random_pixel_in_tile() {
    let mut cover_image = CoverImage::new().set_message("h")
        .set_cover_image("src/testing.jpg");

    cover_image.get_message_as_bits();

    let tile_vec = cover_image.tile_image();

    let pixel = cover_image.cover_image.get_pixel(8, 8);

    let r_pixel = pixel.data[0];
    let g_pixel = pixel.data[1];
    let b_pixel = pixel.data[2];

    let r_pixel_from_tile = tile_vec[63];
    let g_pixel_from_tile = tile_vec[127];
    let b_pixel_from_tile = tile_vec[191];

    assert_eq!(r_pixel, r_pixel_from_tile);
    assert_eq!(g_pixel, g_pixel_from_tile);
    assert_eq!(b_pixel, b_pixel_from_tile);
}<commit_msg>Remove get_pixel_mut from set_cover_image, not sure how or why it was in there anyway...<commit_after>use image::{ImageBuffer, RgbImage};
use bitreader::BitReader;

#[derive(Debug)]
pub struct CoverImage {
    message: &'static str,
    output_image_path: &'static str,
    cover_image: RgbImage,
    message_as_bits: Vec<u8>
}

impl CoverImage {
    pub fn new() -> CoverImage {
        CoverImage {
            message: "",
            output_image_path: "",
            cover_image: ImageBuffer::new(0, 0),
            message_as_bits: vec![]
        }
    }

    pub fn set_cover_image(mut self, input_path: &'static str) -> Self {
        self.cover_image = image::open(input_path).unwrap().as_rgb8().unwrap().clone();

        self
    }

    pub fn set_message(mut self, message: &'static str) -> Self {
        self.message = message;

        self
    }

    pub fn set_output_image_path(mut self, output_path: &'static str) -> Self {
        self.output_image_path = output_path;

        self
    }

    fn get_message_as_bits(&mut self) {
        let mut reader = BitReader::new(&self.message.as_bytes());

        for _ in 0..self.message.len() * 8 {
            self.message_as_bits.push(reader.read_u8(1).unwrap());
        }
    }

    fn tile_image(&mut self) -> Vec<u8> {
        let (width, height) = self.cover_image.dimensions();

        let mut tiles = Vec::new();
        let mut count = 0;

        for row_index in 0..(height / 8) as u32 {
            for col_index in 0..(width / 8) as u32 {
                for channel in 0..3 {
                    if count == self.message_as_bits.len() {
                        break
                    }

                    for row in 0..8 {
                        for column in 0..8 {
                            let pixel = self.cover_image.get_pixel(column + (col_index * 8),
                                                                      row + (row_index * 8));

                            tiles.push(pixel.data[channel]);
                        }
                    }
                    count += 1;
                }
            }
        }

        tiles
    }
}

#[test]
fn get_message_as_bits_test() {
    let test_bits = vec![0, 1, 1, 0, 1, 0, 0, 0];
    let mut cover_image = CoverImage::new().set_message("h");

    cover_image.get_message_as_bits();

    assert_eq!(cover_image.message_as_bits, test_bits);
}

#[test]
fn tile_image_length_test() {
    let mut cover_image = CoverImage::new().set_message("h")
        .set_cover_image("src/testing.jpg");

    // 64 = length of 1 tile, message.len() * 8 = number of tiles needed; 1 tile per bit
    let length = 64 * cover_image.message.len() * 8;

    cover_image.get_message_as_bits();

    let tile_vec_length = cover_image.tile_image().len();

    assert_eq!(length, tile_vec_length);
}

#[test]
fn test_random_pixel_in_tile() {
    let mut cover_image = CoverImage::new().set_message("h")
        .set_cover_image("src/testing.jpg");

    cover_image.get_message_as_bits();

    let tile_vec = cover_image.tile_image();

    let pixel = cover_image.cover_image.get_pixel(8, 8);

    let r_pixel = pixel.data[0];
    let g_pixel = pixel.data[1];
    let b_pixel = pixel.data[2];

    let r_pixel_from_tile = tile_vec[63];
    let g_pixel_from_tile = tile_vec[127];
    let b_pixel_from_tile = tile_vec[191];

    assert_eq!(r_pixel, r_pixel_from_tile);
    assert_eq!(g_pixel, g_pixel_from_tile);
    assert_eq!(b_pixel, b_pixel_from_tile);
}<|endoftext|>


<commit_before>//! A collection of default help commands for the framework.
//!
//! # Example
//!
//! Using the [`with_embeds`] function to have the framework's help message use
//! embeds:
//!
//! ```rs,no_run
//! use serenity::framework::standard::help_commands;
//! use serenity::Client;
//! use std::env;
//!
//! let mut client = Client::new(&env::var("DISCORD_TOKEN").unwrap());
//! use serenity::framework::StandardFramework;
//!
//! client.with_framework(StandardFramework::new()
//!     .command("help", |c| c.exec_help(help_commands::with_embeds)));
//! ```
//!
//! The same can be accomplished with no embeds by substituting `with_embeds`
//! with the [`plain`] function.
//!
//! [`plain`]: fn.plain.html
//! [`with_embeds`]: fn.with_embeds.html

use std::collections::HashMap;
use std::sync::Arc;
use std::fmt::Write;
use super::command::InternalCommand;
use super::{Args, Command, CommandGroup, CommandOrAlias, CommandError};
use client::Context;
use model::{ChannelId, Guild, Member, Message};
use utils::Colour;
use framework::standard::{has_correct_roles, has_correct_permissions};

fn error_embed(channel_id: &ChannelId, input: &str) {
    let _ = channel_id.send_message(|m| {
        m.embed(|e| e.colour(Colour::dark_red()).description(input))
    });
}

fn remove_aliases(cmds: &HashMap<String, CommandOrAlias>) -> HashMap<&String, &InternalCommand> {
    let mut result = HashMap::new();

    for (n, v) in cmds {
        if let CommandOrAlias::Command(ref cmd) = *v {
            result.insert(n, cmd);
        }
    }

    result
}

/// Checks whether a user is member of required roles
/// and given the required permissions.
pub fn has_all_requirements(cmd: &Command, guild: &Guild, member: &Member, msg: &Message) -> bool {
    if cmd.allowed_roles.is_empty() {
        has_correct_permissions(cmd, msg)
    } else {
        has_correct_roles(cmd, guild, member) && has_correct_permissions(cmd, msg)
    }
}

/// Posts an embed showing each individual command group and its commands.
///
/// # Examples
///
/// Use the command with `exec_help`:
///
/// ```rust
/// # use serenity::prelude::*;
/// # struct Handler;
/// #
/// # impl EventHandler for Handler {}
/// # let mut client = Client::new("token", Handler);
/// #
/// use serenity::framework::standard::{StandardFramework, help_commands};
///
/// client.with_framework(StandardFramework::new()
///     .command("help", |c| c.exec_help(help_commands::with_embeds)));
/// ```
pub fn with_embeds(_: &mut Context,
                   msg: &Message,
                   groups: HashMap<String, Arc<CommandGroup>>,
                   args: Args)
                   -> Result<(), CommandError> {
    if !args.is_empty() {
        let name = args.full();

        for (group_name, group) in groups {
            let mut found: Option<(&String, &InternalCommand)> = None;

            for (command_name, command) in &group.commands {
                let with_prefix = if let Some(ref prefix) = group.prefix {
                    format!("{} {}", prefix, command_name)
                } else {
                    command_name.to_string()
                };

                if name == with_prefix || name == *command_name {
                    match *command {
                        CommandOrAlias::Command(ref cmd) => {
                            if !cmd.allowed_roles.is_empty() {
                                if let Some(guild) = msg.guild() {
                                    let guild = guild.read().unwrap();
                                    if let Some(member) = guild.members.get(&msg.author.id) {
                                        if let Ok(permissions) = member.permissions() {
                                            if !permissions.administrator() &&
                                               !has_all_requirements(cmd, &guild, member, msg) {
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                            found = Some((command_name, cmd));
                        },
                        CommandOrAlias::Alias(ref name) => {
                            error_embed(&msg.channel_id, &format!("Did you mean \"{}\"?", name));

                            return Ok(());
                        },
                    }
                }
            }

            if let Some((command_name, command)) = found {
                if !command.help_available {
                    error_embed(&msg.channel_id, "**Error**: No help available.");

                    return Ok(());
                }

                let _ = msg.channel_id.send_message(|m| {
                    m.embed(|e| {
                        let mut embed = e.colour(Colour::rosewater()).title(command_name);
                        if let Some(ref desc) = command.desc {
                            embed = embed.description(desc);
                        }

                        if let Some(ref usage) = command.usage {
                            embed = embed.field(|f| {
                                f.name("Usage")
                                    .value(&format!("`{} {}`", command_name, usage))
                            });
                        }

                        if let Some(ref example) = command.example {
                            embed = embed.field(|f| {
                                f.name("Sample usage")
                                    .value(&format!("`{} {}`", command_name, example))
                            });
                        }

                        if group_name != "Ungrouped" {
                            embed = embed.field(|f| f.name("Group").value(&group_name));
                        }

                        let available = if command.dm_only {
                            "Only in DM"
                        } else if command.guild_only {
                            "Only in guilds"
                        } else {
                            "In DM and guilds"
                        };

                        embed = embed.field(|f| f.name("Available").value(available));

                        embed
                    })
                });

                return Ok(());
            }
        }

        let error_msg = format!("**Error**: Command `{}` not found.", name);
        error_embed(&msg.channel_id, &error_msg);

        return Ok(());
    }

    let _ = msg.channel_id.send_message(|m| {
        m.embed(|mut e| {
            e = e.colour(Colour::rosewater()).description(
                "To get help with an individual command, pass its \
                 name as an argument to this command.",
            );

            let mut group_names = groups.keys().collect::<Vec<_>>();
            group_names.sort();

            for group_name in group_names {
                let group = &groups[group_name];
                let mut desc = String::new();

                if let Some(ref x) = group.prefix {
                    let _ = write!(desc, "Prefix: {}\n", x);
                }

                let mut has_commands = false;

                let commands = remove_aliases(&group.commands);
                let mut command_names = commands.keys().collect::<Vec<_>>();
                command_names.sort();

                for name in command_names {
                    let cmd = &commands[name];

                    if cmd.help_available {
                        if let Some(guild) = msg.guild() {
                            let guild = guild.read().unwrap();
                            if let Some(member) = guild.members.get(&msg.author.id) {
                                if let Ok(permissions) = member.permissions() {
                                    if cmd.help_available &&
                                       (has_all_requirements(cmd, &guild, member, msg) ||
                                        permissions.administrator()) {
                                        let _ = write!(desc, "`{}`\n", name);
                                        has_commands = true;
                                    }
                                }
                            }
                        }
                    }
                }
                if has_commands {
                    e = e.field(|f| f.name(group_name).value(&desc));
                }
            }
            e
        })
    });

    Ok(())
}

/// Posts formatted text displaying each individual command group and its commands.
///
/// # Examples
///
/// Use the command with `exec_help`:
///
/// ```rust
/// # use serenity::prelude::*;
/// # struct Handler;
/// #
/// # impl EventHandler for Handler {}
/// # let mut client = Client::new("token", Handler);
/// #
/// use serenity::framework::standard::{StandardFramework, help_commands};
///
/// client.with_framework(StandardFramework::new()
///     .command("help", |c| c.exec_help(help_commands::plain)));
/// ```
#[cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity))]
pub fn plain(_: &mut Context,
             msg: &Message,
             groups: HashMap<String, Arc<CommandGroup>>,
             args: Args)
             -> Result<(), CommandError> {
    if !args.is_empty() {
        let name = args.full();

        for (group_name, group) in groups {
            let mut found: Option<(&String, &Command)> = None;

            for (command_name, command) in &group.commands {
                let with_prefix = if let Some(ref prefix) = group.prefix {
                    format!("{} {}", prefix, command_name)
                } else {
                    command_name.to_string()
                };

                if name == with_prefix || name == *command_name {
                    match *command {
                        CommandOrAlias::Command(ref cmd) => {
                            if !cmd.allowed_roles.is_empty() {
                                if let Some(guild) = msg.guild() {
                                    let guild = guild.read().unwrap();
                                    if let Some(member) = guild.members.get(&msg.author.id) {
                                        if let Ok(permissions) = member.permissions() {
                                            if !permissions.administrator() &&
                                               !has_all_requirements(cmd, &guild, member, msg) {
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                            found = Some((command_name, cmd));
                        },
                        CommandOrAlias::Alias(ref name) => {
                            let _ = msg.channel_id.say(&format!("Did you mean {:?}?", name));
                            return Ok(());
                        },
                    }
                }
            }

            if let Some((command_name, command)) = found {
                if !command.help_available {
                    let _ = msg.channel_id.say("**Error**: No help available.");
                    return Ok(());
                }

                let mut result = format!("**{}**\n", command_name);

                if let Some(ref desc) = command.desc {
                    let _ = write!(result, "**Description:** {}\n", desc);
                }

                if let Some(ref usage) = command.usage {
                    let _ = write!(result, "**Usage:** `{} {}`\n", command_name, usage);
                }

                if let Some(ref example) = command.example {
                    let _ = write!(result, "**Sample usage:** `{} {}`\n", command_name, example);
                }

                if group_name != "Ungrouped" {
                    let _ = write!(result, "**Group:** {}\n", group_name);
                }

                let only = if command.dm_only {
                    "Only in DM"
                } else if command.guild_only {
                    "Only in guilds"
                } else {
                    "In DM and guilds"
                };

                result.push_str("**Available:** ");
                result.push_str(only);
                result.push_str("\n");

                let _ = msg.channel_id.say(&result);

                return Ok(());
            }
        }

        let _ = msg.channel_id
            .say(&format!("**Error**: Command `{}` not found.", name));

        return Ok(());
    }

    let mut result = "**Commands**\nTo get help with an individual command, pass its \
                      name as an argument to this command.\n\n"
        .to_string();

    let mut group_names = groups.keys().collect::<Vec<_>>();
    group_names.sort();

    for group_name in group_names {
        let group = &groups[group_name];
        let mut group_help = String::new();

        let commands = remove_aliases(&group.commands);
        let mut command_names = commands.keys().collect::<Vec<_>>();
        command_names.sort();

        for name in command_names {
            let cmd = &commands[name];
            if let Some(guild) = msg.guild() {
                let guild = guild.read().unwrap();
                if let Some(member) = guild.members.get(&msg.author.id) {
                    if let Ok(permissions) = member.permissions() {
                        if cmd.help_available &&
                           (permissions.administrator() || has_all_requirements(cmd, &guild, member, msg)) {
                            let _ = write!(group_help, "`{}` ", name);
                        }
                    }
                }
            }
        }

        if !group_help.is_empty() {
            let _ = write!(result, "**{}:** ", group_name);

            if let Some(ref x) = group.prefix {
                let _ = write!(result, "(prefix: `{}`): ", x);
            }

            result.push_str(&group_help);
            result.push('\n');
        }
    }

    let _ = msg.channel_id.say(&result);

    Ok(())
}
<commit_msg>Help-features display `Aliases` and list information for `Aliases`. (#190)<commit_after>//! A collection of default help commands for the framework.
//!
//! # Example
//!
//! Using the [`with_embeds`] function to have the framework's help message use
//! embeds:
//!
//! ```rs,no_run
//! use serenity::framework::standard::help_commands;
//! use serenity::Client;
//! use std::env;
//!
//! let mut client = Client::new(&env::var("DISCORD_TOKEN").unwrap());
//! use serenity::framework::StandardFramework;
//!
//! client.with_framework(StandardFramework::new()
//!     .command("help", |c| c.exec_help(help_commands::with_embeds)));
//! ```
//!
//! The same can be accomplished with no embeds by substituting `with_embeds`
//! with the [`plain`] function.
//!
//! [`plain`]: fn.plain.html
//! [`with_embeds`]: fn.with_embeds.html

use std::collections::HashMap;
use std::sync::Arc;
use std::fmt::Write;
use super::command::InternalCommand;
use super::{Args, Command, CommandGroup, CommandOrAlias, CommandError};
use client::Context;
use model::{ChannelId, Message};
use utils::Colour;
use framework::standard::{has_correct_roles, has_correct_permissions};

fn error_embed(channel_id: &ChannelId, input: &str) {
    let _ = channel_id.send_message(|m| {
        m.embed(|e| e.colour(Colour::dark_red()).description(input))
    });
}

fn remove_aliases(cmds: &HashMap<String, CommandOrAlias>) -> HashMap<&String, &InternalCommand> {
    let mut result = HashMap::new();

    for (n, v) in cmds {
        if let CommandOrAlias::Command(ref cmd) = *v {
            result.insert(n, cmd);
        }
    }

    result
}

/// Checks whether a user is member of required roles
/// and given the required permissions.
pub fn has_all_requirements(cmd: &Command, msg: &Message) -> bool {
    if let Some(guild) = msg.guild() {
        let guild = guild.read().unwrap();

        if let Some(member) = guild.members.get(&msg.author.id) {

            if let Ok(permissions) = member.permissions() {

                if cmd.allowed_roles.is_empty() {
                    return permissions.administrator() || has_correct_permissions(&cmd, &msg);
                } else {
                    return permissions.administrator() || (has_correct_roles(&cmd, &guild, &member) && has_correct_permissions(cmd, msg));
                }
            }
        }
    }
    false
}

/// Posts an embed showing each individual command group and its commands.
///
/// # Examples
///
/// Use the command with `exec_help`:
///
/// ```rust
/// # use serenity::prelude::*;
/// # struct Handler;
/// #
/// # impl EventHandler for Handler {}
/// # let mut client = Client::new("token", Handler);
/// #
/// use serenity::framework::standard::{StandardFramework, help_commands};
///
/// client.with_framework(StandardFramework::new()
///     .command("help", |c| c.exec_help(help_commands::with_embeds)));
/// ```
pub fn with_embeds(_: &mut Context,
                   msg: &Message,
                   groups: HashMap<String, Arc<CommandGroup>>,
                   args: Args)
                   -> Result<(), CommandError> {
    if !args.is_empty() {
        let name = args.full();

        for (group_name, group) in groups {
            let mut found: Option<(&String, &InternalCommand)> = None;

            for (command_name, command) in &group.commands {
                let with_prefix = if let Some(ref prefix) = group.prefix {
                    format!("{} {}", prefix, command_name)
                } else {
                    command_name.to_string()
                };

                if name == with_prefix || name == *command_name {
                    match *command {
                        CommandOrAlias::Command(ref cmd) => {
                            if has_all_requirements(&cmd, &msg) {
                                found = Some((command_name, cmd));
                            }
                            else {
                                break;
                            }
                        },
                        CommandOrAlias::Alias(ref name) => {
                            let actual_command = group.commands.get(name).unwrap();

                            match *actual_command {
                                CommandOrAlias::Command(ref cmd) => {
                                    if has_all_requirements(&cmd, &msg) {
                                        found = Some((name, cmd));
                                    }
                                    else {
                                        break;
                                    }
                                },

                                CommandOrAlias::Alias(ref name) => {
                                    let _ = msg.channel_id.say(&format!("Did you mean {:?}?", name));
                                    return Ok(());
                                },
                            }
                        },
                    }
                }
            }

            if let Some((command_name, command)) = found {
                if !command.help_available {
                    error_embed(&msg.channel_id, "**Error**: No help available.");

                    return Ok(());
                }

                let _ = msg.channel_id.send_message(|m| {
                    m.embed(|e| {
                        let mut embed = e.colour(Colour::rosewater()).title(command_name);

                        if let Some(ref desc) = command.desc {
                            embed = embed.description(desc);
                        }

                        if let Some(ref usage) = command.usage {
                            embed = embed.field(|f| {
                                f.name("Usage")
                                    .value(&format!("`{} {}`", command_name, usage))
                            });
                        }

                        if let Some(ref example) = command.example {
                            embed = embed.field(|f| {
                                f.name("Sample usage")
                                    .value(&format!("`{} {}`", command_name, example))
                            });
                        }

                        if group_name != "Ungrouped" {
                            embed = embed.field(|f| f.name("Group").value(&group_name));
                        }

                        if !command.aliases.is_empty() {
                            let aliases = command.aliases.join(", ");
                            embed = embed.field(|f| f.name("Aliases").value(&aliases));
                        }

                        let available = if command.dm_only {
                            "Only in DM"
                        } else if command.guild_only {
                            "Only in guilds"
                        } else {
                            "In DM and guilds"
                        };

                        embed = embed.field(|f| f.name("Available").value(available));

                        embed
                    })
                });

                return Ok(());
            }
        }

        let error_msg = format!("**Error**: Command `{}` not found.", name);
        error_embed(&msg.channel_id, &error_msg);

        return Ok(());
    }

    let _ = msg.channel_id.send_message(|m| {
        m.embed(|mut e| {
            e = e.colour(Colour::rosewater()).description(
                "To get help with an individual command, pass its \
                 name as an argument to this command.",
            );

            let mut group_names = groups.keys().collect::<Vec<_>>();
            group_names.sort();

            for group_name in group_names {
                let group = &groups[group_name];
                let mut desc = String::new();

                if let Some(ref x) = group.prefix {
                    let _ = write!(desc, "Prefix: {}\n", x);
                }

                let mut has_commands = false;

                let commands = remove_aliases(&group.commands);
                let mut command_names = commands.keys().collect::<Vec<_>>();
                command_names.sort();

                for name in command_names {
                    let cmd = &commands[name];

                    if cmd.help_available {

                        if cmd.help_available && has_all_requirements(&cmd, &msg) {
                            let _ = write!(desc, "`{}`\n", name);
                            has_commands = true;
                        }
                    }
                }

                if has_commands {
                    e = e.field(|f| f.name(group_name).value(&desc));
                }
            }
            e
        })
    });

    Ok(())
}

/// Posts formatted text displaying each individual command group and its commands.
///
/// # Examples
///
/// Use the command with `exec_help`:
///
/// ```rust
/// # use serenity::prelude::*;
/// # struct Handler;
/// #
/// # impl EventHandler for Handler {}
/// # let mut client = Client::new("token", Handler);
/// #
/// use serenity::framework::standard::{StandardFramework, help_commands};
///
/// client.with_framework(StandardFramework::new()
///     .command("help", |c| c.exec_help(help_commands::plain)));
/// ```
pub fn plain(_: &mut Context,
             msg: &Message,
             groups: HashMap<String, Arc<CommandGroup>>,
             args: Args)
             -> Result<(), CommandError> {
    if !args.is_empty() {
        let name = args.full();

        for (group_name, group) in groups {
            let mut found: Option<(&String, &Command)> = None;

            for (command_name, command) in &group.commands {
                let with_prefix = if let Some(ref prefix) = group.prefix {
                    format!("{} {}", prefix, command_name)
                } else {
                    command_name.to_string()
                };

                if name == with_prefix || name == *command_name {
                    match *command {
                        CommandOrAlias::Command(ref cmd) => {
                            if has_all_requirements(&cmd, &msg) {
                                found = Some((command_name, cmd));
                            }
                            else {
                                break;
                            }
                        },
                        CommandOrAlias::Alias(ref name) => {
                            let actual_command = group.commands.get(name).unwrap();

                            match *actual_command {
                                CommandOrAlias::Command(ref cmd) => {
                                    if has_all_requirements(&cmd, &msg) {
                                        found = Some((name, cmd));
                                    }
                                    else {
                                        break;
                                    }
                                },

                                CommandOrAlias::Alias(ref name) => {
                                    let _ = msg.channel_id.say(&format!("Did you mean {:?}?", name));
                                    return Ok(());
                                },
                            }
                        },
                    }
                }
            }

            if let Some((command_name, command)) = found {
                if !command.help_available {
                    let _ = msg.channel_id.say("**Error**: No help available.");
                    return Ok(());
                }

                let mut result = format!("**{}**\n", command_name);

                if !command.aliases.is_empty() {
                    let aliases = command.aliases.join("`, `");
                    let _ = write!(result, "**Aliases:** `{}`\n", aliases);
                }

                if let Some(ref desc) = command.desc {
                    let _ = write!(result, "**Description:** {}\n", desc);
                }

                if let Some(ref usage) = command.usage {
                    let _ = write!(result, "**Usage:** `{} {}`\n", command_name, usage);
                }

                if let Some(ref example) = command.example {
                    let _ = write!(result, "**Sample usage:** `{} {}`\n", command_name, example);
                }

                if group_name != "Ungrouped" {
                    let _ = write!(result, "**Group:** {}\n", group_name);
                }

                let only = if command.dm_only {
                    "Only in DM"
                } else if command.guild_only {
                    "Only in guilds"
                } else {
                    "In DM and guilds"
                };

                result.push_str("**Available:** ");
                result.push_str(only);
                result.push_str("\n");

                let _ = msg.channel_id.say(&result);

                return Ok(());
            }
        }

        let _ = msg.channel_id
            .say(&format!("**Error**: Command `{}` not found.", name));

        return Ok(());
    }

    let mut result = "**Commands**\nTo get help with an individual command, pass its \
                      name as an argument to this command.\n\n"
        .to_string();

    let mut group_names = groups.keys().collect::<Vec<_>>();
    group_names.sort();

    for group_name in group_names {
        let group = &groups[group_name];
        let mut group_help = String::new();

        let commands = remove_aliases(&group.commands);
        let mut command_names = commands.keys().collect::<Vec<_>>();
        command_names.sort();

        for name in command_names {
            let cmd = &commands[name];

            if cmd.help_available && has_all_requirements(&cmd, &msg) {
                let _ = write!(group_help, "`{}` ", name);
            }
        }

        if !group_help.is_empty() {
            let _ = write!(result, "**{}:** ", group_name);

            if let Some(ref x) = group.prefix {
                let _ = write!(result, "(prefix: `{}`): ", x);
            }

            result.push_str(&group_help);
            result.push('\n');
        }
    }

    let _ = msg.channel_id.say(&result);

    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2016 `multipart` Crate Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! Boundary parsing for `multipart` requests.

use ::safemem;

use super::buf_redux::BufReader;
use super::buf_redux::strategy::{LessThan, AtEndLessThan};
use super::twoway;

use log::LogLevel;

use std::cmp;
use std::borrow::Borrow;

use std::io;
use std::io::prelude::*;

use self::State::*;

pub const MIN_BUF_SIZE: usize = 1024;

#[derive(Debug, PartialEq, Eq)]
enum State {
    Searching,
    BoundaryRead,
    AtEnd
}

/// A struct implementing `Read` and `BufRead` that will yield bytes until it sees a given sequence.
#[derive(Debug)]
pub struct BoundaryReader<R> {
    source: BufReader<R, LessThan, AtEndLessThan>,
    boundary: Vec<u8>,
    search_idx: usize,
    state: State,
}

impl<R> BoundaryReader<R> where R: Read {
    #[doc(hidden)]
    pub fn from_reader<B: Into<Vec<u8>>>(reader: R, boundary: B) -> BoundaryReader<R> {
        let mut boundary = boundary.into();
        safemem::prepend(b"--", &mut boundary);

        BoundaryReader {
            source: BufReader::with_strategies(
                reader,
                LessThan(MIN_BUF_SIZE),
                AtEndLessThan(MIN_BUF_SIZE),
            ),
            boundary,
            search_idx: 0,
            state: Searching,
        }
    }

    fn read_to_boundary(&mut self) -> io::Result<&[u8]> {
        let buf = self.source.fill_buf()?;

        trace!("Buf: {:?}", String::from_utf8_lossy(buf));

        debug!("Before-loop Buf len: {} Search idx: {} State: {:?}",
               buf.len(), self.search_idx, self.state);

        if self.state == Searching && self.search_idx < buf.len() {
            let lookahead = &buf[self.search_idx..];

            debug!("Find boundary loop! Lookahead len: {}", lookahead.len());

            // Look for the boundary, or if it isn't found, stop near the end.
            match twoway::find_bytes(lookahead, &self.boundary) {
                Some(found_idx) => {
                    self.search_idx += found_idx;
                    self.state = BoundaryRead;
                },
                None => {
                    self.search_idx += lookahead.len().saturating_sub(self.boundary.len() + 2);
                }
            }
        }

        debug!("After-loop Buf len: {} Search idx: {} State: {:?}",
               buf.len(), self.search_idx, self.state);

        // don't modify search_idx so it always points to the start of the boundary
        let mut buf_len = self.search_idx;

        // back up the cursor to before the boundary's preceding CRLF
        if self.state != Searching && buf_len >= 2 {
            let two_bytes_before = &buf[buf_len - 2 .. buf_len];

            trace!("Two bytes before: {:?} ({:?}) (\"\\r\\n\": {:?})",
                   String::from_utf8_lossy(two_bytes_before), two_bytes_before, b"\r\n");

            if two_bytes_before == &*b"\r\n" {
                debug!("Subtract two!");
                buf_len -= 2;
            }
        }

        let ret_buf = &buf[..buf_len];

        trace!("Returning buf: {:?}", String::from_utf8_lossy(ret_buf));

        Ok(ret_buf)
    }

    pub fn set_min_buf_size(&mut self, min_buf_size: usize) {
        let min_buf_size = cmp::min(self.boundary.len() * 2, min_buf_size);

        self.source.read_strategy_mut().0 = min_buf_size;
        self.source.move_strategy_mut().0 = min_buf_size;
    }

    #[doc(hidden)]
    pub fn consume_boundary(&mut self) -> io::Result<bool> {
        if self.state == AtEnd {
            return Ok(true);
        }

        while self.state == Searching {
            debug!("Boundary not found yet");

            let buf_len = self.read_to_boundary()?.len();

            debug!("Discarding {} bytes", buf_len);

            self.consume(buf_len);
        }

        let consume_amt = {
            let min_len = self.boundary.len() + 4;

            let buf = self.source.fill_buf()?;

            if buf.len() < min_len {
                return Err(io::Error::new(io::ErrorKind::UnexpectedEof,
                                          "not enough bytes to verify boundary"));
            }

            // we have enough bytes to verify
            self.state = Searching;

            let mut consume_amt = self.search_idx + self.boundary.len();

            let last_two = &buf[consume_amt .. consume_amt + 2];

            match last_two {
                b"\r\n" => consume_amt += 2,
                b"--" => { consume_amt += 2; self.state = AtEnd },
                _ => debug!("Unexpected bytes following boundary: {:?}",
                            String::from_utf8_lossy(&last_two)),
            }

            consume_amt
        };

        trace!("Consuming {} bytes, remaining buf: {:?}",
               consume_amt,
               String::from_utf8_lossy(self.source.get_buf()));

        self.source.consume(consume_amt);
        self.search_idx = 0;

        trace!("Consumed boundary (state: {:?}), remaining buf: {:?}", self.state,
               String::from_utf8_lossy(self.source.get_buf()));

        Ok(self.state == AtEnd)
    }
}

#[cfg(feature = "bench")]
impl<'a> BoundaryReader<io::Cursor<&'a [u8]>> {
    fn new_with_bytes(bytes: &'a [u8], boundary: &str) -> Self {
        Self::from_reader(io::Cursor::new(bytes), boundary)
    }

    fn reset(&mut self) {
        // Dump buffer and reset cursor
        self.source.seek(io::SeekFrom::Start(0));
        self.state = Searching;
        self.search_idx = 0;
    }
}

impl<R> Borrow<R> for BoundaryReader<R> {
    fn borrow(&self) -> &R {
        self.source.get_ref()
    }
}

impl<R> Read for BoundaryReader<R> where R: Read {
    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
        let read = {
            let mut buf = self.read_to_boundary()?;
            // This shouldn't ever be an error so unwrapping is fine.
            buf.read(out).unwrap()
        };

        self.consume(read);
        Ok(read)
    }
}

impl<R> BufRead for BoundaryReader<R> where R: Read {
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        self.read_to_boundary()
    }

    fn consume(&mut self, amt: usize) {
        let true_amt = cmp::min(amt, self.search_idx);

        debug!("Consume! amt: {} true amt: {}", amt, true_amt);

        self.source.consume(true_amt);
        self.search_idx -= true_amt;
    }
}

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

    use std::io;
    use std::io::prelude::*;
    use std::slice;

    const BOUNDARY: &'static str = "boundary";
    const TEST_VAL: &'static str = "--boundary\r\n\
                                    dashed-value-1\r\n\
                                    --boundary\r\n\
                                    dashed-value-2\r\n\
                                    --boundary--";

    #[test]
    fn test_boundary() {
        let _ = ::env_logger::init();
        debug!("Testing boundary (no split)");

        let src = &mut TEST_VAL.as_bytes();
        let mut reader = BoundaryReader::from_reader(src, BOUNDARY);

        let mut buf = String::new();

        test_boundary_reader(&mut reader, &mut buf);
    }

    struct SplitReader<'a> {
        left: &'a [u8],
        right: &'a [u8],
    }

    impl<'a> SplitReader<'a> {
        fn split(data: &'a [u8], at: usize) -> SplitReader<'a> {
            let (left, right) = data.split_at(at);

            SplitReader {
                left: left,
                right: right,
            }
        }
    }

    impl<'a> Read for SplitReader<'a> {
        fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
            fn copy_bytes_partial(src: &mut &[u8], dst: &mut [u8]) -> usize {
                src.read(dst).unwrap()
            }

            let mut copy_amt = copy_bytes_partial(&mut self.left, dst);

            if copy_amt == 0 {
                copy_amt = copy_bytes_partial(&mut self.right, dst)
            };

            Ok(copy_amt)
        }
    }

    #[test]
    fn test_split_boundary() {
        let _ = ::env_logger::init();
        debug!("Testing boundary (split)");

        let mut buf = String::new();

        // Substitute for `.step_by()` being unstable.
        for split_at in 0 .. TEST_VAL.len(){
            debug!("Testing split at: {}", split_at);

            let src = SplitReader::split(TEST_VAL.as_bytes(), split_at);
            let mut reader = BoundaryReader::from_reader(src, BOUNDARY);
            test_boundary_reader(&mut reader, &mut buf);
        }

    }

    fn test_boundary_reader<R: Read>(reader: &mut BoundaryReader<R>, buf: &mut String) {
        buf.clear();

        debug!("Read 1");
        let _ = reader.read_to_string(buf).unwrap();
        assert!(buf.is_empty(), "Buffer not empty: {:?}", buf);
        buf.clear();

        debug!("Consume 1");
        reader.consume_boundary().unwrap();

        debug!("Read 2");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "dashed-value-1");
        buf.clear();

        debug!("Consume 2");
        reader.consume_boundary().unwrap();

        debug!("Read 3");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "dashed-value-2");
        buf.clear();

        debug!("Consume 3");
        reader.consume_boundary().unwrap();

        debug!("Read 4");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "");
    }

    #[test]
    fn test_leading_crlf() {
        let mut body: &[u8] = b"\r\n\r\n--boundary\r\n\
                         asdf1234\
                         \r\n\r\n--boundary--";

        let ref mut buf = String::new();
        let mut reader = BoundaryReader::from_reader(&mut body, BOUNDARY);

        debug!("Consume 1");
        reader.consume_boundary().unwrap();

        debug!("Read 1");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "asdf1234\r\n");
        buf.clear();

        debug!("Consume 2");
        reader.consume_boundary().unwrap();

        debug!("Read 2 (empty)");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "");
    }

    #[test]
    fn test_trailing_crlf() {
        let mut body: &[u8] = b"--boundary\r\n\
                         asdf1234\
                         \r\n\r\n--boundary\r\n\
                         hjkl5678\r\n--boundary--";

        let ref mut buf = String::new();
        let mut reader = BoundaryReader::from_reader(&mut body, BOUNDARY);

        debug!("Consume 1");
        reader.consume_boundary().unwrap();

        debug!("Read 1");

        // Repro for https://github.com/abonander/multipart/issues/93
        // These two reads should produce the same buffer
        let buf1 = reader.read_to_boundary().unwrap().to_owned();
        let buf2 = reader.read_to_boundary().unwrap().to_owned();
        assert_eq!(buf1, buf2);

        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "asdf1234\r\n");
        buf.clear();

        debug!("Consume 2");
        reader.consume_boundary().unwrap();

        debug!("Read 2");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "hjkl5678");
        buf.clear();

        debug!("Consume 3");
        reader.consume_boundary().unwrap();

        debug!("Read 3 (empty)");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "");
    }

    // https://github.com/abonander/multipart/issues/93#issuecomment-343610587
    #[test]
    fn test_trailing_lflf() {
        let mut body: &[u8] = b"--boundary\r\n\
                         asdf1234\
                         \n\n\r\n--boundary\r\n\
                         hjkl5678\r\n--boundary--";

        let ref mut buf = String::new();
        let mut reader = BoundaryReader::from_reader(&mut body, BOUNDARY);

        debug!("Consume 1");
        reader.consume_boundary().unwrap();

        debug!("Read 1");

        // same as above
        let buf1 = reader.read_to_boundary().unwrap().to_owned();
        let buf2 = reader.read_to_boundary().unwrap().to_owned();
        assert_eq!(buf1, buf2);

        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "asdf1234\n\n");
        buf.clear();

        debug!("Consume 2");
        reader.consume_boundary().unwrap();

        debug!("Read 2");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "hjkl5678");
        buf.clear();

        debug!("Consume 3");
        reader.consume_boundary().unwrap();

        debug!("Read 3 (empty)");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "");
    }

    #[cfg(feature = "bench")]
    mod bench {
        extern crate test;
        use self::test::Bencher;

        use super::*;

        #[bench]
        fn bench_boundary_reader(b: &mut Bencher) {
            let mut reader = BoundaryReader::new_with_bytes(TEST_VAL.as_bytes(), BOUNDARY);
            let mut buf = String::with_capacity(256);

            b.iter(|| {
                reader.reset();
                test_boundary_reader(&mut reader, &mut buf);
            });
        }
    }
}
<commit_msg>fix `BoundaryReader::set_min_buf_size`<commit_after>// Copyright 2016 `multipart` Crate Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! Boundary parsing for `multipart` requests.

use ::safemem;

use super::buf_redux::BufReader;
use super::buf_redux::strategy::{LessThan, AtEndLessThan};
use super::twoway;

use log::LogLevel;

use std::cmp;
use std::borrow::Borrow;

use std::io;
use std::io::prelude::*;

use self::State::*;

pub const MIN_BUF_SIZE: usize = 1024;

#[derive(Debug, PartialEq, Eq)]
enum State {
    Searching,
    BoundaryRead,
    AtEnd
}

/// A struct implementing `Read` and `BufRead` that will yield bytes until it sees a given sequence.
#[derive(Debug)]
pub struct BoundaryReader<R> {
    source: BufReader<R, LessThan, AtEndLessThan>,
    boundary: Vec<u8>,
    search_idx: usize,
    state: State,
}

impl<R> BoundaryReader<R> where R: Read {
    #[doc(hidden)]
    pub fn from_reader<B: Into<Vec<u8>>>(reader: R, boundary: B) -> BoundaryReader<R> {
        let mut boundary = boundary.into();
        safemem::prepend(b"--", &mut boundary);

        BoundaryReader {
            source: BufReader::with_strategies(
                reader,
                LessThan(MIN_BUF_SIZE),
                AtEndLessThan(MIN_BUF_SIZE),
            ),
            boundary,
            search_idx: 0,
            state: Searching,
        }
    }

    fn read_to_boundary(&mut self) -> io::Result<&[u8]> {
        let buf = self.source.fill_buf()?;

        trace!("Buf: {:?}", String::from_utf8_lossy(buf));

        debug!("Before-loop Buf len: {} Search idx: {} State: {:?}",
               buf.len(), self.search_idx, self.state);

        if self.state == Searching && self.search_idx < buf.len() {
            let lookahead = &buf[self.search_idx..];

            debug!("Find boundary loop! Lookahead len: {}", lookahead.len());

            // Look for the boundary, or if it isn't found, stop near the end.
            match twoway::find_bytes(lookahead, &self.boundary) {
                Some(found_idx) => {
                    self.search_idx += found_idx;
                    self.state = BoundaryRead;
                },
                None => {
                    self.search_idx += lookahead.len().saturating_sub(self.boundary.len() + 2);
                }
            }
        }

        debug!("After-loop Buf len: {} Search idx: {} State: {:?}",
               buf.len(), self.search_idx, self.state);

        // don't modify search_idx so it always points to the start of the boundary
        let mut buf_len = self.search_idx;

        // back up the cursor to before the boundary's preceding CRLF
        if self.state != Searching && buf_len >= 2 {
            let two_bytes_before = &buf[buf_len - 2 .. buf_len];

            trace!("Two bytes before: {:?} ({:?}) (\"\\r\\n\": {:?})",
                   String::from_utf8_lossy(two_bytes_before), two_bytes_before, b"\r\n");

            if two_bytes_before == &*b"\r\n" {
                debug!("Subtract two!");
                buf_len -= 2;
            }
        }

        let ret_buf = &buf[..buf_len];

        trace!("Returning buf: {:?}", String::from_utf8_lossy(ret_buf));

        Ok(ret_buf)
    }

    pub fn set_min_buf_size(&mut self, min_buf_size: usize) {
        // ensure the minimum buf size is at least enough to find a boundary with some extra
        let min_buf_size = cmp::max(self.boundary.len() * 2, min_buf_size);

        self.source.read_strategy_mut().0 = min_buf_size;
        self.source.move_strategy_mut().0 = min_buf_size;
    }

    #[doc(hidden)]
    pub fn consume_boundary(&mut self) -> io::Result<bool> {
        if self.state == AtEnd {
            return Ok(true);
        }

        while self.state == Searching {
            debug!("Boundary not found yet");

            let buf_len = self.read_to_boundary()?.len();

            debug!("Discarding {} bytes", buf_len);

            self.consume(buf_len);
        }

        let consume_amt = {
            let min_len = self.boundary.len() + 4;

            let buf = self.source.fill_buf()?;

            if buf.len() < min_len {
                return Err(io::Error::new(io::ErrorKind::UnexpectedEof,
                                          "not enough bytes to verify boundary"));
            }

            // we have enough bytes to verify
            self.state = Searching;

            let mut consume_amt = self.search_idx + self.boundary.len();

            let last_two = &buf[consume_amt .. consume_amt + 2];

            match last_two {
                b"\r\n" => consume_amt += 2,
                b"--" => { consume_amt += 2; self.state = AtEnd },
                _ => debug!("Unexpected bytes following boundary: {:?}",
                            String::from_utf8_lossy(&last_two)),
            }

            consume_amt
        };

        trace!("Consuming {} bytes, remaining buf: {:?}",
               consume_amt,
               String::from_utf8_lossy(self.source.get_buf()));

        self.source.consume(consume_amt);
        self.search_idx = 0;

        trace!("Consumed boundary (state: {:?}), remaining buf: {:?}", self.state,
               String::from_utf8_lossy(self.source.get_buf()));

        Ok(self.state == AtEnd)
    }
}

#[cfg(feature = "bench")]
impl<'a> BoundaryReader<io::Cursor<&'a [u8]>> {
    fn new_with_bytes(bytes: &'a [u8], boundary: &str) -> Self {
        Self::from_reader(io::Cursor::new(bytes), boundary)
    }

    fn reset(&mut self) {
        // Dump buffer and reset cursor
        self.source.seek(io::SeekFrom::Start(0));
        self.state = Searching;
        self.search_idx = 0;
    }
}

impl<R> Borrow<R> for BoundaryReader<R> {
    fn borrow(&self) -> &R {
        self.source.get_ref()
    }
}

impl<R> Read for BoundaryReader<R> where R: Read {
    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
        let read = {
            let mut buf = self.read_to_boundary()?;
            // This shouldn't ever be an error so unwrapping is fine.
            buf.read(out).unwrap()
        };

        self.consume(read);
        Ok(read)
    }
}

impl<R> BufRead for BoundaryReader<R> where R: Read {
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        self.read_to_boundary()
    }

    fn consume(&mut self, amt: usize) {
        let true_amt = cmp::min(amt, self.search_idx);

        debug!("Consume! amt: {} true amt: {}", amt, true_amt);

        self.source.consume(true_amt);
        self.search_idx -= true_amt;
    }
}

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

    use std::io;
    use std::io::prelude::*;
    use std::slice;

    const BOUNDARY: &'static str = "boundary";
    const TEST_VAL: &'static str = "--boundary\r\n\
                                    dashed-value-1\r\n\
                                    --boundary\r\n\
                                    dashed-value-2\r\n\
                                    --boundary--";

    #[test]
    fn test_boundary() {
        let _ = ::env_logger::init();
        debug!("Testing boundary (no split)");

        let src = &mut TEST_VAL.as_bytes();
        let mut reader = BoundaryReader::from_reader(src, BOUNDARY);

        let mut buf = String::new();

        test_boundary_reader(&mut reader, &mut buf);
    }

    struct SplitReader<'a> {
        left: &'a [u8],
        right: &'a [u8],
    }

    impl<'a> SplitReader<'a> {
        fn split(data: &'a [u8], at: usize) -> SplitReader<'a> {
            let (left, right) = data.split_at(at);

            SplitReader {
                left: left,
                right: right,
            }
        }
    }

    impl<'a> Read for SplitReader<'a> {
        fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
            fn copy_bytes_partial(src: &mut &[u8], dst: &mut [u8]) -> usize {
                src.read(dst).unwrap()
            }

            let mut copy_amt = copy_bytes_partial(&mut self.left, dst);

            if copy_amt == 0 {
                copy_amt = copy_bytes_partial(&mut self.right, dst)
            };

            Ok(copy_amt)
        }
    }

    #[test]
    fn test_split_boundary() {
        let _ = ::env_logger::init();
        debug!("Testing boundary (split)");

        let mut buf = String::new();

        // Substitute for `.step_by()` being unstable.
        for split_at in 0 .. TEST_VAL.len(){
            debug!("Testing split at: {}", split_at);

            let src = SplitReader::split(TEST_VAL.as_bytes(), split_at);
            let mut reader = BoundaryReader::from_reader(src, BOUNDARY);
            test_boundary_reader(&mut reader, &mut buf);
        }

    }

    fn test_boundary_reader<R: Read>(reader: &mut BoundaryReader<R>, buf: &mut String) {
        buf.clear();

        debug!("Read 1");
        let _ = reader.read_to_string(buf).unwrap();
        assert!(buf.is_empty(), "Buffer not empty: {:?}", buf);
        buf.clear();

        debug!("Consume 1");
        reader.consume_boundary().unwrap();

        debug!("Read 2");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "dashed-value-1");
        buf.clear();

        debug!("Consume 2");
        reader.consume_boundary().unwrap();

        debug!("Read 3");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "dashed-value-2");
        buf.clear();

        debug!("Consume 3");
        reader.consume_boundary().unwrap();

        debug!("Read 4");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "");
    }

    #[test]
    fn test_leading_crlf() {
        let mut body: &[u8] = b"\r\n\r\n--boundary\r\n\
                         asdf1234\
                         \r\n\r\n--boundary--";

        let ref mut buf = String::new();
        let mut reader = BoundaryReader::from_reader(&mut body, BOUNDARY);

        debug!("Consume 1");
        reader.consume_boundary().unwrap();

        debug!("Read 1");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "asdf1234\r\n");
        buf.clear();

        debug!("Consume 2");
        reader.consume_boundary().unwrap();

        debug!("Read 2 (empty)");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "");
    }

    #[test]
    fn test_trailing_crlf() {
        let mut body: &[u8] = b"--boundary\r\n\
                         asdf1234\
                         \r\n\r\n--boundary\r\n\
                         hjkl5678\r\n--boundary--";

        let ref mut buf = String::new();
        let mut reader = BoundaryReader::from_reader(&mut body, BOUNDARY);

        debug!("Consume 1");
        reader.consume_boundary().unwrap();

        debug!("Read 1");

        // Repro for https://github.com/abonander/multipart/issues/93
        // These two reads should produce the same buffer
        let buf1 = reader.read_to_boundary().unwrap().to_owned();
        let buf2 = reader.read_to_boundary().unwrap().to_owned();
        assert_eq!(buf1, buf2);

        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "asdf1234\r\n");
        buf.clear();

        debug!("Consume 2");
        reader.consume_boundary().unwrap();

        debug!("Read 2");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "hjkl5678");
        buf.clear();

        debug!("Consume 3");
        reader.consume_boundary().unwrap();

        debug!("Read 3 (empty)");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "");
    }

    // https://github.com/abonander/multipart/issues/93#issuecomment-343610587
    #[test]
    fn test_trailing_lflf() {
        let mut body: &[u8] = b"--boundary\r\n\
                         asdf1234\
                         \n\n\r\n--boundary\r\n\
                         hjkl5678\r\n--boundary--";

        let ref mut buf = String::new();
        let mut reader = BoundaryReader::from_reader(&mut body, BOUNDARY);

        debug!("Consume 1");
        reader.consume_boundary().unwrap();

        debug!("Read 1");

        // same as above
        let buf1 = reader.read_to_boundary().unwrap().to_owned();
        let buf2 = reader.read_to_boundary().unwrap().to_owned();
        assert_eq!(buf1, buf2);

        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "asdf1234\n\n");
        buf.clear();

        debug!("Consume 2");
        reader.consume_boundary().unwrap();

        debug!("Read 2");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "hjkl5678");
        buf.clear();

        debug!("Consume 3");
        reader.consume_boundary().unwrap();

        debug!("Read 3 (empty)");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "");
    }

    #[cfg(feature = "bench")]
    mod bench {
        extern crate test;
        use self::test::Bencher;

        use super::*;

        #[bench]
        fn bench_boundary_reader(b: &mut Bencher) {
            let mut reader = BoundaryReader::new_with_bytes(TEST_VAL.as_bytes(), BOUNDARY);
            let mut buf = String::with_capacity(256);

            b.iter(|| {
                reader.reset();
                test_boundary_reader(&mut reader, &mut buf);
            });
        }
    }
}
<|endoftext|>


<commit_before>mod markdown {
    use pulldown_cmark::Parser;
    use pulldown_cmark::Event;
    use pulldown_cmark::Tag;

    pub struct MarkdownParser<'a> {
        text: &'a String
    }

    impl<'a> MarkdownParser<'a> {

        pub fn new(s: &'a String) -> MarkdownParser {
            MarkdownParser {
                text: s
            }
        }

        pub fn links(&self) -> Vec<String> {
            self.extract_tag(|tag| {
                match tag {
                    Tag::Link(url, _)   => Some(url.into_owned()),
                    _                   => None
                }
            })
        }

        pub fn codeblocks(&self) -> Vec<String> {
            self.extract_tag(|tag| {
                match tag {
                    Tag::CodeBlock(text)    => Some(text.into_owned()),
                    _                       => None
                }
            })
        }

        fn extract_tag<F>(&self, f: F) -> Vec<String>
            where F: FnMut(Tag) -> Option<String>
        {
            Parser::new(&self.text[..])
                .filter_map(|e| {
                    match e {
                        Event::Start(t) | Event::End(t) => Some(t),
                        _                               => None
                    }
                })
                .filter_map(f)
                .collect::<Vec<String>>()
        }

    }

}
<commit_msg>Make Markdown helper module pub<commit_after>pub mod markdown {
    use pulldown_cmark::Parser;
    use pulldown_cmark::Event;
    use pulldown_cmark::Tag;

    pub struct MarkdownParser<'a> {
        text: &'a String
    }

    impl<'a> MarkdownParser<'a> {

        pub fn new(s: &'a String) -> MarkdownParser {
            MarkdownParser {
                text: s
            }
        }

        pub fn links(&self) -> Vec<String> {
            self.extract_tag(|tag| {
                match tag {
                    Tag::Link(url, _)   => Some(url.into_owned()),
                    _                   => None
                }
            })
        }

        pub fn codeblocks(&self) -> Vec<String> {
            self.extract_tag(|tag| {
                match tag {
                    Tag::CodeBlock(text)    => Some(text.into_owned()),
                    _                       => None
                }
            })
        }

        fn extract_tag<F>(&self, f: F) -> Vec<String>
            where F: FnMut(Tag) -> Option<String>
        {
            Parser::new(&self.text[..])
                .filter_map(|e| {
                    match e {
                        Event::Start(t) | Event::End(t) => Some(t),
                        _                               => None
                    }
                })
                .filter_map(f)
                .collect::<Vec<String>>()
        }

    }

}
<|endoftext|>


<commit_before>use error::Error;

use std::net;
use std::path;
use std::fs;
use std::io::{Read, Write};
use rand;
use ssh2;
use std::mem;

pub struct MasterNode {
    port: u16,
    listener: net::TcpListener,
    session_store: Vec<(net::TcpStream, ssh2::Session)>,
}

impl MasterNode {
    pub fn new(port: u16) -> Result<MasterNode, Error> {
        let listener = try!(net::TcpListener::bind(("0.0.0.0", port)));
        Ok(MasterNode {
            port: port,
            listener: listener,
            session_store: Vec::new(),
        })
    }

    pub fn connect<A: net::ToSocketAddrs, P: AsRef<path::Path>, S: AsRef<str>, S2: AsRef<str>>
                                                                               (self: &mut Self,
                                                                                addr: A,
                                                                                username: S,
                                                                                bin_path: P,
                                                                                hostname: S2)
                                                                                -> Result<(u32, net::TcpStream), Error> {
        let secret: u8 = rand::random();

        // open TCP socket to remote host; create an SSH session and
        // authenticate using given username and password
        let ssh_socket = try!(net::TcpStream::connect(addr));
        let mut ssh_session = ssh2::Session::new().expect("error creating SSH session");
        try!(ssh_session.handshake(&ssh_socket));
        try!(ssh_session.userauth_agent(username.as_ref()));

        // open the local file specified by bin_path
        let mut bin_contents: Vec<u8> = Vec::new();
        let mut bin_file = try!(fs::File::open(bin_path));
        let bin_size = try!(bin_file.read_to_end(&mut bin_contents));

        // send file to remote host at /tmp/dsock_binary
        // TODO: support windows, use a smarter path?
        let worker_id = self.session_store.len() as u32;
        {
            let mut remote_file = try!(ssh_session.scp_send(path::Path::new(format!("/tmp/dsock_binary{}", worker_id)),
                                                            0o700,
                                                            bin_size as u64,
                                                            None));
            try!(remote_file.write_all(&bin_contents[..]));
            try!(remote_file.flush());
        }

        // start a new channel and set environment variables
        {
            // run the binary we copied over earlier
            let mut channel = try!(ssh_session.channel_session());
            try!(channel.exec(&format!("/tmp/dsock_binary{} \"{}\" \"{}\" \"{}\" \"{}\"",
                                       worker_id,
                                       hostname.as_ref(),
                                       self.port,
                                       secret,
                                       worker_id)[..]));
            mem::forget(channel);
        }

        // accept TCP connections until we find one with the secret we sent
        // earlier
        let tcp_socket = try!(self.accept_secret(secret));

        self.session_store.push((ssh_socket, ssh_session));

        Ok((worker_id, tcp_socket))
    }

    fn accept_secret(self: &Self, secret: u8) -> Result<net::TcpStream, Error> {
        loop {
            match self.listener.accept() {
                Ok((mut stream, _)) => {
                    let mut b: [u8; 1] = [0];
                    if !stream.read(&mut b[..]).ok().is_some() {
                        continue;
                    }
                    if b[0] == secret {
                        return Ok(stream);
                    }
                }
                Err(_) => {
                    // keep trying
                }
            }
        }
    }
}
<commit_msg>oops, fixed update<commit_after>use error::Error;

use std::net;
use std::path;
use std::fs;
use std::io::{Read, Write};
use rand;
use ssh2;
use std::mem;

pub struct MasterNode {
    port: u16,
    listener: net::TcpListener,
    session_store: Vec<(net::TcpStream, ssh2::Session)>,
}

impl MasterNode {
    pub fn new(port: u16) -> Result<MasterNode, Error> {
        let listener = try!(net::TcpListener::bind(("0.0.0.0", port)));
        Ok(MasterNode {
            port: port,
            listener: listener,
            session_store: Vec::new(),
        })
    }

    pub fn connect<A: net::ToSocketAddrs, P: AsRef<path::Path>, S: AsRef<str>, S2: AsRef<str>>
                                                                               (self: &mut Self,
                                                                                addr: A,
                                                                                username: S,
                                                                                bin_path: P,
                                                                                hostname: S2)
                                                                                -> Result<(u32, net::TcpStream), Error> {
        let secret: u8 = rand::random();

        // open TCP socket to remote host; create an SSH session and
        // authenticate using given username and password
        let ssh_socket = try!(net::TcpStream::connect(addr));
        let mut ssh_session = ssh2::Session::new().expect("error creating SSH session");
        try!(ssh_session.handshake(&ssh_socket));
        try!(ssh_session.userauth_agent(username.as_ref()));

        // open the local file specified by bin_path
        let mut bin_contents: Vec<u8> = Vec::new();
        let mut bin_file = try!(fs::File::open(bin_path));
        let bin_size = try!(bin_file.read_to_end(&mut bin_contents));

        // send file to remote host at /tmp/dsock_binary
        // TODO: support windows, use a smarter path?
        let worker_id = self.session_store.len() as u32;
        {
            let mut remote_file = try!(ssh_session.scp_send(path::Path::new(&format!("/tmp/dsock_binary{}", worker_id)),
                                                            0o700,
                                                            bin_size as u64,
                                                            None));
            try!(remote_file.write_all(&bin_contents[..]));
            try!(remote_file.flush());
        }

        // start a new channel and set environment variables
        {
            // run the binary we copied over earlier
            let mut channel = try!(ssh_session.channel_session());
            try!(channel.exec(&format!("/tmp/dsock_binary{} \"{}\" \"{}\" \"{}\" \"{}\"",
                                       worker_id,
                                       hostname.as_ref(),
                                       self.port,
                                       secret,
                                       worker_id)[..]));
            mem::forget(channel);
        }

        // accept TCP connections until we find one with the secret we sent
        // earlier
        let tcp_socket = try!(self.accept_secret(secret));

        self.session_store.push((ssh_socket, ssh_session));

        Ok((worker_id, tcp_socket))
    }

    fn accept_secret(self: &Self, secret: u8) -> Result<net::TcpStream, Error> {
        loop {
            match self.listener.accept() {
                Ok((mut stream, _)) => {
                    let mut b: [u8; 1] = [0];
                    if !stream.read(&mut b[..]).ok().is_some() {
                        continue;
                    }
                    if b[0] == secret {
                        return Ok(stream);
                    }
                }
                Err(_) => {
                    // keep trying
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate ffmpeg;

use std::path::Path;
use std::ops::{Deref, DerefMut};

use ffmpeg::Rational;
use ffmpeg::format::stream::Disposition;

pub struct Context {
    ffmpeg_context: ffmpeg::format::context::Input,
    pub name: String,
    pub description: String,
    pub video_stream: Option<VideoStream>,
    pub audio_stream: Option<AudioStream>,
}

impl Context {
    pub fn new(path: &Path) -> Result<Context, String> {
        match ffmpeg::format::input(&path) {
            Ok(ffmpeg_context) => {
                // for the moment, let's work on the best streams, if available
                let mut new_ctx = Context{
                    ffmpeg_context: ffmpeg_context,
                    name: String::new(),
                    description: String::new(),
                    video_stream: None,
                    audio_stream: None,
                };

                let stream_count;
                {
                    let format = new_ctx.ffmpeg_context.format();
                    new_ctx.name = String::from(format.name());
                    new_ctx.description = String::from(format.description());

                    let stream_iter = new_ctx.ffmpeg_context.streams();
                    stream_count = stream_iter.size_hint().0;

                    new_ctx.video_stream = VideoStream::new(&stream_iter);
                    new_ctx.audio_stream = AudioStream::new(&stream_iter);
                }

                // TODO: process metadata

                // TODO: see what we should do with subtitles

                println!("Input: {} - {}, {} streams",
                         &new_ctx.name, &new_ctx.description, stream_count
                );

                if stream_count > 0 {
                    // TODO: also check for misdetections (detection score)
                    Ok(new_ctx)
                }
                else {
                    Err("Couldn't find any video or audio stream".to_owned())
                }
            },
            Err(error) => {
                Err(format!("{:?}", error))
            },
        }
    }

}

pub struct Stream {
    pub index: usize,
    pub time_base: Rational,
    pub start_time: i64,
    pub duration: i64,
    pub frames: i64,
    pub disposition: Disposition,
    pub rate: Rational,
    pub avg_frame_rate: Rational,
}

impl Stream {
    pub fn new(stream_iter: &ffmpeg::format::context::common::StreamIter,
               media_type: ffmpeg::media::Type) -> Option<Stream> {
        let stream = stream_iter.best(media_type);
        match stream {
            Some(stream) => {
                Some(Stream {
                    index: stream.index(),
                    time_base: stream.time_base(),
                    start_time: stream.start_time(),
                    duration: stream.duration(),
                    frames: stream.frames(),
                    disposition: stream.disposition(),
                    rate: stream.rate(),
                    avg_frame_rate: stream.avg_frame_rate(),
                })
            },
            None => None,
        }
    }
}

pub struct VideoStream {
    pub stream: Stream,
}

impl VideoStream {
    pub fn new(stream_iter: &ffmpeg::format::context::common::StreamIter) -> Option<VideoStream> {
        let video_stream = Stream::new(stream_iter, ffmpeg::media::Type::Video);

        match video_stream {
            Some(video_stream) => {
                if video_stream.frames > 0 {
                    Some(VideoStream{ stream: video_stream, })
                }
                else {
                    None
                }
            },
            None => None,
        }
    }
}

impl Deref for VideoStream {
	type Target = Stream;

	fn deref(&self) -> &Self::Target {
		&self.stream
	}
}

impl DerefMut for VideoStream {
	fn deref_mut(&mut self) -> &mut Self::Target {
		&mut self.stream
	}
}

pub struct AudioStream {
    pub stream: Stream,
}

impl AudioStream {
    pub fn new(stream_iter: &ffmpeg::format::context::common::StreamIter) -> Option<AudioStream> {
        let audio_stream = Stream::new(stream_iter, ffmpeg::media::Type::Audio);

        match audio_stream {
            Some(audio_stream) => {
                if audio_stream.frames > 0 || audio_stream.duration > 0 {
                    Some(AudioStream{ stream: audio_stream, })
                }
                else {
                    None
                }
            },
            None => None,
        }
   }
}

impl Deref for AudioStream {
	type Target = Stream;

	fn deref(&self) -> &Self::Target {
		&self.stream
	}
}

impl DerefMut for AudioStream {
	fn deref_mut(&mut self) -> &mut Self::Target {
		&mut self.stream
	}
}
<commit_msg>Add more data (#1)<commit_after>extern crate ffmpeg;

use std::path::Path;
use std::ops::{Deref, DerefMut};

use ffmpeg::Rational;
use ffmpeg::format::stream::Disposition;

pub struct Context {
    ffmpeg_context: ffmpeg::format::context::Input,
    pub name: String,
    pub description: String,
    pub video_stream: Option<VideoStream>,
    pub audio_stream: Option<AudioStream>,
}

impl Context {
    pub fn new(path: &Path) -> Result<Context, String> {
        match ffmpeg::format::input(&path) {
            Ok(ffmpeg_context) => {
                // for the moment, let's work on the best streams, if available
                let mut new_ctx = Context{
                    ffmpeg_context: ffmpeg_context,
                    name: String::new(),
                    description: String::new(),
                    video_stream: None,
                    audio_stream: None,
                };

                let stream_count;
                {
                    let format = new_ctx.ffmpeg_context.format();
                    new_ctx.name = String::from(format.name());
                    new_ctx.description = String::from(format.description());

                    let stream_iter = new_ctx.ffmpeg_context.streams();
                    new_ctx.video_stream = VideoStream::new(&stream_iter);
                    new_ctx.audio_stream = AudioStream::new(&stream_iter);
                    stream_count = stream_iter.size_hint().0;
                }

                // TODO: process metadata

                // TODO: see what we should do with subtitles

                println!("Input: {} - {}, {} streams",
                         &new_ctx.name, &new_ctx.description, stream_count
                );

                if stream_count > 0 {
                    // TODO: also check for misdetections (detection score)
                    Ok(new_ctx)
                }
                else {
                    Err("Couldn't find any video or audio stream".to_owned())
                }
            },
            Err(error) => {
                Err(format!("{:?}", error))
            },
        }
    }

}

// TODO: use lifetimes to hold ffmped stream and codec within the structure below
pub struct Stream {
    pub index: usize,
    pub time_base: Rational,
    pub start_time: i64,
    pub duration: i64,
    pub frames: i64,
    pub disposition: Disposition,
    pub rate: Rational,
    pub discard: ffmpeg::Discard,
    pub avg_frame_rate: Rational,
    pub codec_medium: ffmpeg::media::Type,
    pub codec_id: ffmpeg::codec::Id,
}

impl Stream {
    pub fn new(stream: ffmpeg::format::stream::Stream) -> Stream {
        let codec = stream.codec();
        let new_stream = Stream {
            index: stream.index(),
            time_base: stream.time_base(),
            start_time: stream.start_time(),
            duration: stream.duration(),
            frames: stream.frames(),
            disposition: stream.disposition(),
            discard: stream.discard(),
            rate: stream.rate(),
            avg_frame_rate: stream.avg_frame_rate(),
            codec_medium: codec.medium(),
            codec_id: codec.id(),
        };

        println!("stream index {} - {:?}:", new_stream.index, new_stream.codec_medium);
        println!("\ttime_base: {}", new_stream.time_base);
        println!("\tstart_time: {}", new_stream.start_time);
        println!("\tduration (stream timebase): {}", new_stream.duration);
        println!("\tduration (seconds): {:.2}", new_stream.duration as f64 * f64::from(stream.time_base()));
        println!("\tframes: {}", new_stream.frames);
        println!("\tdisposition: {:?}", new_stream.disposition);
        println!("\tdiscard: {:?}", new_stream.discard);
        println!("\trate: {}", new_stream.rate);
        println!("\tcodec_id: {:?}", new_stream.codec_id);

        new_stream
    }
}

pub struct VideoStream {
    pub stream: Stream,
	pub bit_rate: usize,
	pub max_bit_rate: usize,
	pub delay: usize,
    width: u32,
    height: u32,
    format: ffmpeg::format::Pixel,
    has_b_frames: bool,
    aspect_ratio: ffmpeg::Rational,
    color_space: ffmpeg::color::Space,
    color_range: ffmpeg::color::Range,
    color_primaries: ffmpeg::color::Primaries,
    color_transfer_characteristic: ffmpeg::color::TransferCharacteristic,
    chroma_location: ffmpeg::chroma::Location,
    references: usize,
    intra_dc_precision: u8,
}

impl VideoStream {
    pub fn new(stream_iter: &ffmpeg::format::context::common::StreamIter) -> Option<VideoStream> {
        match stream_iter.best(ffmpeg::media::Type::Video) {
            Some(video_stream) => {
                match video_stream.codec().decoder().video() {
                    Ok(video) => {
                        let new_vs = VideoStream{
                            bit_rate: video.bit_rate(),
                            max_bit_rate: video.max_bit_rate(),
                            delay: video.delay(),
                            width: video.width(),
                            height: video.height(),
                            format: video.format(),
                            has_b_frames: video.has_b_frames(),
                            aspect_ratio: video.aspect_ratio(),
                            color_space: video.color_space(),
                            color_range: video.color_range(),
                            color_primaries: video.color_primaries(),
                            color_transfer_characteristic: video.color_transfer_characteristic(),
                            chroma_location: video.chroma_location(),
                            references: video.references(),
                            intra_dc_precision: video.intra_dc_precision(),
                            stream: Stream::new(video_stream),
                        };

                        println!("\tbit_rate: {}", new_vs.bit_rate);
                        println!("\tmax_bit_rate: {}", new_vs.max_bit_rate);
                        println!("\tdelay: {}", new_vs.delay);
					    println!("\twidth: {}", new_vs.width);
					    println!("\theight: {}", new_vs.height);
					    println!("\tformat: {:?}", new_vs.format);
					    println!("\thas_b_frames: {}", new_vs.has_b_frames);
					    println!("\taspect_ratio: {}", new_vs.aspect_ratio);
					    println!("\tcolor_space: {:?}", new_vs.color_space);
					    println!("\tcolor_range: {:?}", new_vs.color_range);
					    println!("\tcolor_primaries: {:?}", new_vs.color_primaries);
					    println!("\tcolor_transfer_characteristic: {:?}", new_vs.color_transfer_characteristic);
					    println!("\tchroma_location: {:?}", new_vs.chroma_location);
					    println!("\treferences: {}", new_vs.references);
                        println!("\tintra_dc_precision: {}", new_vs.intra_dc_precision);

                        Some(new_vs)
                    },
                    Err(error) => {
                        println!("audio stream: {:?}", error);
                        // TODO: should probably panic here
                        None
                    }
                }
            },
            None => None,
        }
    }
}

impl Deref for VideoStream {
	type Target = Stream;

	fn deref(&self) -> &Self::Target {
		&self.stream
	}
}

impl DerefMut for VideoStream {
	fn deref_mut(&mut self) -> &mut Self::Target {
		&mut self.stream
	}
}

pub struct AudioStream {
    pub stream: Stream,
	pub bit_rate: usize,
	pub max_bit_rate: usize,
	pub delay: usize,
	pub rate: u32,
	pub channels: u16,
	pub format: ffmpeg::format::Sample,
	pub frames: usize,
	pub align: usize,
	pub channel_layout: ffmpeg::ChannelLayout,
    pub frame_start: Option<usize>,
}

impl AudioStream {
    pub fn new(stream_iter: &ffmpeg::format::context::common::StreamIter) -> Option<AudioStream> {
        match stream_iter.best(ffmpeg::media::Type::Audio) {
            Some(audio_stream) => {
                match audio_stream.codec().decoder().audio() {
                    Ok(audio) => {
                        let new_as = AudioStream{
                            bit_rate: audio.bit_rate(),
                            max_bit_rate: audio.max_bit_rate(),
                            delay: audio.delay(),
                            rate: audio.rate(),
                            channels: audio.channels(),
                            format: audio.format(),
                            frames: audio.frames(),
                            align: audio.align(),
                            channel_layout: audio.channel_layout(),
                            frame_start: audio.frame_start(),
                            stream: Stream::new(audio_stream),
                        };

                        println!("\tbit_rate: {}", new_as.bit_rate);
                        println!("\tmax_bit_rate: {}", new_as.max_bit_rate);
                        println!("\tdelay: {}", new_as.delay);
                        println!("\trate: {}", new_as.rate);
                        println!("\tchannels: {}", new_as.channels);
                        println!("\tformat: {:?}", new_as.format);
                        println!("\tframes: {}", new_as.frames);
                        println!("\talign: {}", new_as.align);
                        println!("\tchannel_layout: {:?}", new_as.channel_layout);
                        println!("\tframe_start: {:?}", new_as.frame_start);

                        Some(new_as)
                    },
                    Err(error) => {
                        println!("audio stream: {:?}", error);
                        // TODO: should probably panic here
                        None
                    }
                }
            },
            None => None,
        }
   }
}

impl Deref for AudioStream {
	type Target = Stream;

	fn deref(&self) -> &Self::Target {
		&self.stream
	}
}

impl DerefMut for AudioStream {
	fn deref_mut(&mut self) -> &mut Self::Target {
		&mut self.stream
	}
}
<|endoftext|>