<commit_before>#![deny(warnings)]

extern crate extra;

use std::cell::Cell; // Provide mutable fields in immutable structs
use std::env;
use std::error::Error;
use std::fs::{self, File};
use std::io::{self, BufReader, Read, Stderr, StdinLock, StdoutLock, Write};
use std::process::exit;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{cat} */ r#"NAME
    cat - concatenate files and print on the standard output

SYNOPSIS
    cat [-h | --help] [-A | --show-all] [-b | --number-nonblank] [-e] [-E | --show-ends]
        [-n | --number] [-s | --squeeze-blank] [-t] [-T] FILES...

DESCRIPTION
    Concatenates all files to the standard output.

    If no file is given, or if FILE is '-', read from standard input.

OPTIONS
    -A
    --show-all
        equivalent to -v -E -T

    -b
    --number-nonblank
        number nonempty output lines, overriding -n

    -e
        equivalent to -v -E

    -E
    --show-ends
        display $ at the end of each line

    -n
    --number
        number all output lines

    -s
    --squeeze-blank
        supress repeated empty output lines

    -t
        equivalent to -v -T

    -T
    --show_tabs
        display TAB characters as ^I

    -v
    --show-nonprinting
        use caret (^) and M- notation, except for LFD and TAB.

    -h
    --help
        display this help and exit

AUTHOR
    Written by Michael Murphy.
"#; /* @MANEND */

struct Program {
    exit_status:      Cell<i32>,
    number:           bool,
    number_nonblank:  bool,
    show_ends:        bool,
    show_tabs:        bool,
    show_nonprinting: bool,
    squeeze_blank:    bool,
    paths:            Vec<String>,
}

impl Program {
    /// Initialize the program's arguments and flags.
    fn initialize(stdout: &mut StdoutLock, stderr: &mut Stderr) -> Program {
        let mut cat = Program {
            exit_status:      Cell::new(0i32),
            number:           false,
            number_nonblank:  false,
            show_ends:        false,
            show_tabs:        false,
            show_nonprinting: false,
            squeeze_blank:    false,
            paths:            Vec::new()
        };
        for arg in env::args().skip(1) {
            if arg.starts_with('-') && &arg != "-" {
                match arg.as_str() {
                    "-h" | "--help" => {
                        stdout.write(MAN_PAGE.as_bytes()).try(stderr);
                        stdout.flush().try(stderr);
                        exit(0);
                    }
                    "-A" | "--show-all" => {
                        cat.show_nonprinting = true;
                        cat.show_ends = true;
                        cat.show_tabs = true;
                    },
                    "-b" | "--number-nonblank" => {
                        cat.number_nonblank = true;
                        cat.number = false;
                    },
                    "-e" => {
                        cat.show_nonprinting = true;
                        cat.show_ends = true;
                    },
                    "-E" | "--show-ends" => cat.show_ends = true,
                    "-n" | "--number" => {
                        cat.number = true;
                        cat.number_nonblank = false;
                    },
                    "-s" | "--squeeze-blank" => cat.squeeze_blank = true,
                    "-t" => {
                        cat.show_nonprinting = true;
                        cat.show_tabs = true;
                    },
                    "-T" => cat.show_tabs = true,
                    "-v" | "--show-nonprinting" => {
                        cat.show_nonprinting = true;
                    },
                    _ => {
                        stderr.write(b"invalid option -- '").try(stderr);
                        stderr.write(arg.as_bytes()).try(stderr);
                        stderr.write(b"'\nTry 'cat --help' for more information.\n").try(stderr);
                        stderr.flush().try(stderr);
                        exit(1);
                    }
                }
            } else {
                cat.paths.push(arg);
            }
        }
        cat
    }

    /// Execute the parameters given to the program.
    fn and_execute(&self, stdout: &mut StdoutLock, stderr: &mut Stderr) -> i32 {
        let stdin = io::stdin();
        let stdin = &mut stdin.lock();
        let line_count = &mut 0usize;
        let flags_enabled = self.number || self.number_nonblank || self.show_ends || self.show_tabs ||
                            self.squeeze_blank || self.show_nonprinting;

        if self.paths.is_empty() && flags_enabled {
            self.cat_stdin(line_count, stdin, stdout, stderr);
        } else if self.paths.is_empty() {
            io::copy(stdin, stdout).try(stderr);
        } else {
            for path in &self.paths {
                if flags_enabled && path == "-" {
                    self.cat_stdin(line_count, stdin, stdout, stderr);
                } else if flags_enabled {
                    let file = match fs::File::open(&path) {
                        Ok(file) => file,
                        Err(message) => {
                            stderr.write(&path.as_bytes()).try(stderr);
                            stderr.write(b": ").try(stderr);
                            stderr.write(message.description().as_bytes()).try(stderr);
                            stderr.write(b"\n").try(stderr);
                            stderr.flush().try(stderr);
                            self.exit_status.set(1i32);;
                            continue
                        }
                    };

                    self.cat_file(&file, line_count, stdout, stderr);
                } else if path == "-" {
                    io::copy(stdin, stdout).try(stderr);
                } else {
                    let file = &mut match fs::File::open(&path) {
                        Ok(file) => file,
                        Err(message) => {
                            stderr.write(&path.as_bytes()).try(stderr);
                            stderr.write(b": ").try(stderr);
                            stderr.write(message.description().as_bytes()).try(stderr);
                            stderr.write(b"\n").try(stderr);
                            stderr.flush().try(stderr);
                            self.exit_status.set(1i32);;
                            continue
                        }
                    };

                    io::copy(file, stdout).try(stderr);
                }
            }
        }
        self.exit_status.get()
    }

    /// Cats a file based on the flag arguments given to the program.
    fn cat_file(&self, file: &File, line_count: &mut usize, stdout: &mut StdoutLock, stderr: &mut Stderr) {
        let mut character_count = 0;
        let mut last_line_was_blank = false;

        for byte in BufReader::new(file).bytes().map(|x| x.unwrap()) {
            if (self.number && character_count == 0) || (character_count == 0 && self.number_nonblank && byte != b'\n') {
                stdout.write(b"     ").try(stderr);
                stdout.write(line_count.to_string().as_bytes()).try(stderr);
                stdout.write(b"  ").try(stderr);
                *line_count += 1;
            }
            match byte {
                0...8 | 11...31 => if self.show_nonprinting {
                    push_caret(stdout, stderr, byte+64);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
                9 => {
                    if self.show_tabs {
                        push_caret(stdout, stderr, b'I');
                    } else {
                        stdout.write(&[byte]).try(stderr);
                    }
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                }
                10 => {
                    if character_count == 0 {
                        if self.squeeze_blank && last_line_was_blank {
                            continue
                        } else if !last_line_was_blank {
                            last_line_was_blank = true;
                        }
                    } else {
                        last_line_was_blank = false;
                        character_count = 0;
                    }
                    if self.show_ends {
                        stdout.write(b"$\n").try(stderr);
                    } else {
                        stdout.write(b"\n").try(stderr);
                    }
                    stdout.flush().try(stderr);
                },
                32...126 => {
                    stdout.write(&[byte]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
                127 => if self.show_nonprinting {
                    push_caret(stdout, stderr, b'?');
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
                128...159 => if self.show_nonprinting {
                    stdout.write(b"M-^").try(stderr);
                    stdout.write(&[byte-64]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                } else {
                    stdout.write(&[byte]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
                _ => if self.show_nonprinting {
                    stdout.write(b"M-").try(stderr);
                    stdout.write(&[byte-128]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                } else {
                    stdout.write(&[byte]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
            }
        }
    }

    /// Cats stdin based on the flag arguments given to the program.
    fn cat_stdin(&self, line_count: &mut usize, stdin: &mut StdinLock, stdout: &mut StdoutLock, stderr: &mut Stderr) {
        let mut character_count = 0;
        let mut last_line_was_blank = false;

        for byte in stdin.bytes().map(|x| x.unwrap()) {
            if (self.number && character_count == 0) || (character_count == 0 && self.number_nonblank && byte != b'\n') {
                stdout.write(b"     ").try(stderr);
                stdout.write(line_count.to_string().as_bytes()).try(stderr);
                stdout.write(b"  ").try(stderr);
                *line_count += 1;
            }
            match byte {
                0...8 | 11...31 => if self.show_nonprinting {
                    push_caret(stdout, stderr, byte+64);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
                9 => {
                    if self.show_tabs {
                        push_caret(stdout, stderr, b'I');
                    } else {
                        stdout.write(&[byte]).try(stderr);
                    }
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                }
                10 => {
                    if character_count == 0 {
                        if self.squeeze_blank && last_line_was_blank {
                            continue
                        } else if !last_line_was_blank {
                            last_line_was_blank = true;
                        }
                    } else {
                        last_line_was_blank = false;
                        character_count = 0;
                    }
                    if self.show_ends {
                        stdout.write(b"$\n").try(stderr);
                    } else {
                        stdout.write(b"\n").try(stderr);
                    }
                    stdout.flush().try(stderr);
                },
                32...126 => {
                    stdout.write(&[byte]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
                127 => if self.show_nonprinting {
                    push_caret(stdout, stderr, b'?');
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
                128...159 => if self.show_nonprinting {
                    stdout.write(b"M-^").try(stderr);
                    stdout.write(&[byte-64]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                } else {
                    stdout.write(&[byte]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
                _ => if self.show_nonprinting {
                    stdout.write(b"M-").try(stderr);
                    stdout.write(&[byte-128]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                } else {
                    stdout.write(&[byte]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
            }
        }
    }
}

/// Increase the character count by one if number printing is enabled.
fn count_character(character_count: &mut usize, number: &bool, number_nonblank: &bool) {
    if *number || *number_nonblank {
        *character_count += 1;
    }
}

/// Print a caret notation to stdout.
fn push_caret(stdout: &mut StdoutLock, stderr: &mut Stderr, notation: u8) {
    stdout.write(&[b'^']).try(stderr);
    stdout.write(&[notation]).try(stderr);
}

fn main() {
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    let mut stderr = io::stderr();
    exit(Program::initialize(&mut stdout, &mut stderr).and_execute(&mut stdout, &mut stderr));
}
<commit_msg>Fix build on redox<commit_after>#![deny(warnings)]

extern crate extra;

use std::cell::Cell; // Provide mutable fields in immutable structs
use std::env;
use std::error::Error;
use std::fs::{self, File};
use std::io::{self, BufReader, Read, Stderr, StdinLock, StdoutLock, Write};
use std::process::exit;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{cat} */ r#"NAME
    cat - concatenate files and print on the standard output

SYNOPSIS
    cat [-h | --help] [-A | --show-all] [-b | --number-nonblank] [-e] [-E | --show-ends]
        [-n | --number] [-s | --squeeze-blank] [-t] [-T] FILES...

DESCRIPTION
    Concatenates all files to the standard output.

    If no file is given, or if FILE is '-', read from standard input.

OPTIONS
    -A
    --show-all
        equivalent to -v -E -T

    -b
    --number-nonblank
        number nonempty output lines, overriding -n

    -e
        equivalent to -v -E

    -E
    --show-ends
        display $ at the end of each line

    -n
    --number
        number all output lines

    -s
    --squeeze-blank
        supress repeated empty output lines

    -t
        equivalent to -v -T

    -T
    --show_tabs
        display TAB characters as ^I

    -v
    --show-nonprinting
        use caret (^) and M- notation, except for LFD and TAB.

    -h
    --help
        display this help and exit

AUTHOR
    Written by Michael Murphy.
"#; /* @MANEND */

struct Program {
    exit_status:      Cell<i32>,
    number:           bool,
    number_nonblank:  bool,
    show_ends:        bool,
    show_tabs:        bool,
    show_nonprinting: bool,
    squeeze_blank:    bool,
    paths:            Vec<String>,
}

impl Program {
    /// Initialize the program's arguments and flags.
    fn initialize(stdout: &mut StdoutLock, stderr: &mut Stderr) -> Program {
        let mut cat = Program {
            exit_status:      Cell::new(0i32),
            number:           false,
            number_nonblank:  false,
            show_ends:        false,
            show_tabs:        false,
            show_nonprinting: false,
            squeeze_blank:    false,
            paths:            Vec::new()
        };
        for arg in env::args().skip(1) {
            if arg.starts_with('-') && &arg != "-" {
                match arg.as_str() {
                    "-h" | "--help" => {
                        stdout.write(MAN_PAGE.as_bytes()).try(stderr);
                        stdout.flush().try(stderr);
                        exit(0);
                    }
                    "-A" | "--show-all" => {
                        cat.show_nonprinting = true;
                        cat.show_ends = true;
                        cat.show_tabs = true;
                    },
                    "-b" | "--number-nonblank" => {
                        cat.number_nonblank = true;
                        cat.number = false;
                    },
                    "-e" => {
                        cat.show_nonprinting = true;
                        cat.show_ends = true;
                    },
                    "-E" | "--show-ends" => cat.show_ends = true,
                    "-n" | "--number" => {
                        cat.number = true;
                        cat.number_nonblank = false;
                    },
                    "-s" | "--squeeze-blank" => cat.squeeze_blank = true,
                    "-t" => {
                        cat.show_nonprinting = true;
                        cat.show_tabs = true;
                    },
                    "-T" => cat.show_tabs = true,
                    "-v" | "--show-nonprinting" => {
                        cat.show_nonprinting = true;
                    },
                    _ => {
                        stderr.write(b"invalid option -- '").try(stderr);
                        stderr.write(arg.as_bytes()).try(stderr);
                        stderr.write(b"'\nTry 'cat --help' for more information.\n").try(stderr);
                        stderr.flush().try(stderr);
                        exit(1);
                    }
                }
            } else {
                cat.paths.push(arg);
            }
        }
        cat
    }

    /// Execute the parameters given to the program.
    fn and_execute(&self, stdout: &mut StdoutLock, stderr: &mut Stderr) -> i32 {
        let stdin = io::stdin();
        let stdin = &mut stdin.lock();
        let line_count = &mut 0usize;
        let flags_enabled = self.number || self.number_nonblank || self.show_ends || self.show_tabs ||
                            self.squeeze_blank || self.show_nonprinting;

        if self.paths.is_empty() && flags_enabled {
            self.cat_stdin(line_count, stdin, stdout, stderr);
        } else if self.paths.is_empty() {
            io::copy(stdin, stdout).try(stderr);
        } else {
            for path in &self.paths {
                if flags_enabled && path == "-" {
                    self.cat_stdin(line_count, stdin, stdout, stderr);
                } else if flags_enabled {
                    let file = match fs::File::open(&path) {
                        Ok(file) => file,
                        Err(message) => {
                            stderr.write(&path.as_bytes()).try(stderr);
                            stderr.write(b": ").try(stderr);
                            stderr.write(message.description().as_bytes()).try(stderr);
                            stderr.write(b"\n").try(stderr);
                            stderr.flush().try(stderr);
                            self.exit_status.set(1i32);;
                            continue
                        }
                    };

                    self.cat_file(file, line_count, stdout, stderr);
                } else if path == "-" {
                    io::copy(stdin, stdout).try(stderr);
                } else {
                    let file = &mut match fs::File::open(&path) {
                        Ok(file) => file,
                        Err(message) => {
                            stderr.write(&path.as_bytes()).try(stderr);
                            stderr.write(b": ").try(stderr);
                            stderr.write(message.description().as_bytes()).try(stderr);
                            stderr.write(b"\n").try(stderr);
                            stderr.flush().try(stderr);
                            self.exit_status.set(1i32);;
                            continue
                        }
                    };

                    io::copy(file, stdout).try(stderr);
                }
            }
        }
        self.exit_status.get()
    }

    /// Cats a file based on the flag arguments given to the program.
    fn cat_file(&self, file: File, line_count: &mut usize, stdout: &mut StdoutLock, stderr: &mut Stderr) {
        let mut character_count = 0;
        let mut last_line_was_blank = false;

        for byte in BufReader::new(file).bytes().map(|x| x.unwrap()) {
            if (self.number && character_count == 0) || (character_count == 0 && self.number_nonblank && byte != b'\n') {
                stdout.write(b"     ").try(stderr);
                stdout.write(line_count.to_string().as_bytes()).try(stderr);
                stdout.write(b"  ").try(stderr);
                *line_count += 1;
            }
            match byte {
                0...8 | 11...31 => if self.show_nonprinting {
                    push_caret(stdout, stderr, byte+64);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
                9 => {
                    if self.show_tabs {
                        push_caret(stdout, stderr, b'I');
                    } else {
                        stdout.write(&[byte]).try(stderr);
                    }
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                }
                10 => {
                    if character_count == 0 {
                        if self.squeeze_blank && last_line_was_blank {
                            continue
                        } else if !last_line_was_blank {
                            last_line_was_blank = true;
                        }
                    } else {
                        last_line_was_blank = false;
                        character_count = 0;
                    }
                    if self.show_ends {
                        stdout.write(b"$\n").try(stderr);
                    } else {
                        stdout.write(b"\n").try(stderr);
                    }
                    stdout.flush().try(stderr);
                },
                32...126 => {
                    stdout.write(&[byte]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
                127 => if self.show_nonprinting {
                    push_caret(stdout, stderr, b'?');
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
                128...159 => if self.show_nonprinting {
                    stdout.write(b"M-^").try(stderr);
                    stdout.write(&[byte-64]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                } else {
                    stdout.write(&[byte]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
                _ => if self.show_nonprinting {
                    stdout.write(b"M-").try(stderr);
                    stdout.write(&[byte-128]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                } else {
                    stdout.write(&[byte]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
            }
        }
    }

    /// Cats stdin based on the flag arguments given to the program.
    fn cat_stdin(&self, line_count: &mut usize, stdin: &mut StdinLock, stdout: &mut StdoutLock, stderr: &mut Stderr) {
        let mut character_count = 0;
        let mut last_line_was_blank = false;

        for byte in stdin.bytes().map(|x| x.unwrap()) {
            if (self.number && character_count == 0) || (character_count == 0 && self.number_nonblank && byte != b'\n') {
                stdout.write(b"     ").try(stderr);
                stdout.write(line_count.to_string().as_bytes()).try(stderr);
                stdout.write(b"  ").try(stderr);
                *line_count += 1;
            }
            match byte {
                0...8 | 11...31 => if self.show_nonprinting {
                    push_caret(stdout, stderr, byte+64);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
                9 => {
                    if self.show_tabs {
                        push_caret(stdout, stderr, b'I');
                    } else {
                        stdout.write(&[byte]).try(stderr);
                    }
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                }
                10 => {
                    if character_count == 0 {
                        if self.squeeze_blank && last_line_was_blank {
                            continue
                        } else if !last_line_was_blank {
                            last_line_was_blank = true;
                        }
                    } else {
                        last_line_was_blank = false;
                        character_count = 0;
                    }
                    if self.show_ends {
                        stdout.write(b"$\n").try(stderr);
                    } else {
                        stdout.write(b"\n").try(stderr);
                    }
                    stdout.flush().try(stderr);
                },
                32...126 => {
                    stdout.write(&[byte]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
                127 => if self.show_nonprinting {
                    push_caret(stdout, stderr, b'?');
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
                128...159 => if self.show_nonprinting {
                    stdout.write(b"M-^").try(stderr);
                    stdout.write(&[byte-64]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                } else {
                    stdout.write(&[byte]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
                _ => if self.show_nonprinting {
                    stdout.write(b"M-").try(stderr);
                    stdout.write(&[byte-128]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                } else {
                    stdout.write(&[byte]).try(stderr);
                    count_character(&mut character_count, &self.number, &self.number_nonblank);
                },
            }
        }
    }
}

/// Increase the character count by one if number printing is enabled.
fn count_character(character_count: &mut usize, number: &bool, number_nonblank: &bool) {
    if *number || *number_nonblank {
        *character_count += 1;
    }
}

/// Print a caret notation to stdout.
fn push_caret(stdout: &mut StdoutLock, stderr: &mut Stderr, notation: u8) {
    stdout.write(&[b'^']).try(stderr);
    stdout.write(&[notation]).try(stderr);
}

fn main() {
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    let mut stderr = io::stderr();
    exit(Program::initialize(&mut stdout, &mut stderr).and_execute(&mut stdout, &mut stderr));
}
<|endoftext|>


<commit_before>use std::{
    collections::HashSet,
    fmt,
};
use crate::client::Context;
use crate::model::{
    channel::Message,
    permissions::Permissions,
    id::UserId,
};
use crate::utils::Colour;
use super::Args;

mod check;
pub mod buckets;

pub use self::check::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OnlyIn {
    Dm,
    Guild,
    None,
    #[doc(hidden)]
    __Nonexhaustive,
}

impl Default for OnlyIn {
    fn default() -> Self { Self::None }
}

#[derive(Debug, Default, PartialEq)]
pub struct CommandOptions {
    /// A set of checks to be called prior to executing the command. The checks
    /// will short-circuit on the first check that returns `false`.
    pub checks: &'static [&'static Check],
    /// Ratelimit bucket.
    pub bucket: Option<&'static str>,
    /// Names that the command can be referred to.
    pub names: &'static [&'static str],
    /// Command description, used by other commands.
    pub desc: Option<&'static str>,
    /// Delimiters used to split the arguments of the command by.
    /// If empty, the [global delimiters](struct.Configuration.html#method.delimiters) are used.
    pub delimiters: &'static [&'static str],
    /// Command usage schema, used by other commands.
    pub usage: Option<&'static str>,
    /// Example arguments, used by other commands.
    pub examples: &'static [&'static str],
    /// Minimum amount of arguments that should be passed.
    pub min_args: Option<u16>,
    /// Maximum amount of arguments that can be passed.
    pub max_args: Option<u16>,
    /// Roles allowed to use this command.
    pub allowed_roles: &'static [&'static str],
    /// Permissions required to use this command.
    pub required_permissions: Permissions,
    /// Whether the command should be displayed in help list or not, used by other commands.
    pub help_available: bool,
    /// Whether the command can only be used in dms or guilds; or both.
    pub only_in: OnlyIn,
    /// Whether the command can only be used by owners or not.
    pub owners_only: bool,
    /// Whether the command treats owners as normal users.
    pub owner_privilege: bool,
    /// Other commands belonging to this command.
    pub sub_commands: &'static [&'static Command],
}

#[derive(Debug, Clone)]
pub struct CommandError(pub String);

impl<T: fmt::Display> From<T> for CommandError {
    #[inline]
    fn from(d: T) -> Self {
        CommandError(d.to_string())
    }
}

pub type CommandResult = ::std::result::Result<(), CommandError>;

pub type CommandFn = fn(&Context, &Message, Args) -> CommandResult;

pub struct Command {
    pub fun: CommandFn,
    pub options: &'static CommandOptions,
}

impl fmt::Debug for Command {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Command")
            .field("options", &self.options)
            .finish()
    }
}

impl PartialEq for Command {
    #[inline]
    fn eq(&self, other: &Command) -> bool {
        (self.fun as usize == other.fun as usize) && (self.options == other.options)
    }
}

pub type HelpCommandFn = fn(
    &Context,
    &Message,
    Args,
    &'static HelpOptions,
    &[&'static CommandGroup],
    HashSet<UserId>,
) -> CommandResult;

pub struct HelpCommand {
    pub fun: HelpCommandFn,
    pub options: &'static HelpOptions,
}

impl fmt::Debug for HelpCommand {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("HelpCommand")
            .field("fun", &"<function>")
            .field("options", &self.options)
            .finish()
    }
}

impl PartialEq for HelpCommand {
    #[inline]
    fn eq(&self, other: &HelpCommand) -> bool {
        (self.fun as usize == other.fun as usize) && (self.options == other.options)
    }
}

/// Describes the behaviour the help-command shall execute once it encounters
/// a command which the user or command fails to meet following criteria :
/// Lacking required permissions to execute the command.
/// Lacking required roles to execute the command.
/// The command can't be used in the current channel (as in `DM only` or `guild only`).
#[derive(Copy, Clone, Debug, PartialOrd, Ord, Eq, PartialEq)]
pub enum HelpBehaviour {
    /// The command will be displayed, hence nothing will be done.
    Nothing,
    /// Strikes a command by applying `~~{command_name}~~`.
    Strike,
    /// Does not list a command in the help-menu.
    Hide,
    #[doc(hidden)]
    __Nonexhaustive,
}

#[derive(Clone, Debug, PartialEq)]
pub struct HelpOptions {
    /// Which names should the help command use for dispatching.
    /// Defaults to `["help"]`
    pub names: &'static [&'static str],
    /// Suggests a command's name.
    pub suggestion_text: &'static str,
    /// If no help is available, this text will be displayed.
    pub no_help_available_text: &'static str,
    /// How to use a command, `{usage_label}: {command_name} {args}`
    pub usage_label: &'static str,
    /// Actual sample label, `{usage_sample_label}: {command_name} {args}`
    pub usage_sample_label: &'static str,
    /// Text labeling ungrouped commands, `{ungrouped_label}: ...`
    pub ungrouped_label: &'static str,
    /// Text labeling the start of the description.
    pub description_label: &'static str,
    /// Text labeling grouped commands, `{grouped_label} {group_name}: ...`
    pub grouped_label: &'static str,
    /// Text labeling a command's alternative names (aliases).
    pub aliases_label: &'static str,
    /// Text specifying that a command is only usable in a guild.
    pub guild_only_text: &'static str,
    /// Text labeling a command's names of checks.
    pub checks_label: &'static str,
    /// Text specifying that a command is only usable in via DM.
    pub dm_only_text: &'static str,
    /// Text specifying that a command can be used via DM and in guilds.
    pub dm_and_guild_text: &'static str,
    /// Text expressing that a command is available.
    pub available_text: &'static str,
    /// Error-message once a command could not be found.
    /// Output-example (without whitespace between both substitutions: `{command_not_found_text}{command_name}`
    /// `{command_name}` describes user's input as in: `{prefix}help {command_name}`.
    pub command_not_found_text: &'static str,
    /// Explains the user on how to use access a single command's details.
    pub individual_command_tip: &'static str,
    /// Explains reasoning behind strikethrough-commands, see fields requiring `HelpBehaviour` for further information.
    /// If `HelpBehaviour::Strike` is unused, this field will evaluate to `None` during creation
    /// inside of the help macro.
    ///
    /// **Note**: Text is only used in direct messages.
    pub strikethrough_commands_tip_in_dm: Option<&'static str>,
    /// Explains reasoning behind strikethrough-commands, see fields requiring `HelpBehaviour` for further information.
    /// If `HelpBehaviour::Strike` is unused, this field will evaluate to `None` during creation
    /// inside of the help macro.
    ///
    /// **Note**: Text is only used in guilds.
    pub strikethrough_commands_tip_in_guild: Option<&'static str>,
    /// Announcing a group's prefix as in: {group_prefix} {prefix}.
    pub group_prefix: &'static str,
    /// If a user lacks required roles, this will treat how these commands will be displayed.
    pub lacking_role: HelpBehaviour,
    /// If a user lacks permissions, this will treat how these commands will be displayed.
    pub lacking_permissions: HelpBehaviour,
    /// If a user lacks ownership, this will treat how these commands will be displayed.
    pub lacking_ownership: HelpBehaviour,
    /// If conditions (of a check) may be lacking by the user, this will treat how these commands will be displayed.
    pub lacking_conditions: HelpBehaviour,
    /// If a user is using the help-command in a channel where a command is not available,
    /// this behaviour will be executed.
    pub wrong_channel: HelpBehaviour,
    /// Colour help-embed will use upon encountering an error.
    pub embed_error_colour: Colour,
    /// Colour help-embed will use if no error occurred.
    pub embed_success_colour: Colour,
    /// If not 0, help will check whether a command is similar to searched named.
    pub max_levenshtein_distance: usize,
    /// Help will use this as prefix to express how deeply nested a command or
    /// group is.
    pub indention_prefix: &'static str,
}

#[derive(Debug, Default, PartialEq)]
pub struct GroupOptions {
    pub prefixes: &'static [&'static str],
    pub only_in: OnlyIn,
    pub owners_only: bool,
    pub owner_privilege: bool,
    pub help_available: bool,
    pub allowed_roles: &'static [&'static str],
    pub required_permissions: Permissions,
    pub checks: &'static [&'static Check],
    pub default_command: Option<&'static Command>,
    pub description: Option<&'static str>,
    pub commands: &'static [&'static Command],
    pub sub_groups: &'static [&'static CommandGroup],
}

#[derive(Debug, PartialEq)]
pub struct CommandGroup {
    pub name: &'static str,
    pub options: &'static GroupOptions,
}

#[cfg(test)]
#[cfg(all(feature = "cache", feature = "http"))]
mod levenshtein_tests {
    use super::HelpBehaviour;

    #[test]
    fn help_behaviour_eq() {
        assert_eq!(HelpBehaviour::Hide, std::cmp::max(HelpBehaviour::Hide, HelpBehaviour::Hide));
        assert_eq!(HelpBehaviour::Strike, std::cmp::max(HelpBehaviour::Strike, HelpBehaviour::Strike));
        assert_eq!(HelpBehaviour::Nothing, std::cmp::max(HelpBehaviour::Nothing, HelpBehaviour::Nothing));
    }

    #[test]
    fn help_behaviour_hide() {
        assert_eq!(HelpBehaviour::Hide, std::cmp::max(HelpBehaviour::Hide, HelpBehaviour::Nothing));
        assert_eq!(HelpBehaviour::Hide, std::cmp::max(HelpBehaviour::Hide, HelpBehaviour::Strike));
    }

    #[test]
    fn help_behaviour_strike() {
        assert_eq!(HelpBehaviour::Strike, std::cmp::max(HelpBehaviour::Strike, HelpBehaviour::Nothing));
        assert_eq!(HelpBehaviour::Hide, std::cmp::max(HelpBehaviour::Strike, HelpBehaviour::Hide));
    }

    #[test]
    fn help_behaviour_nothing() {
        assert_eq!(HelpBehaviour::Strike, std::cmp::max(HelpBehaviour::Nothing, HelpBehaviour::Strike));
        assert_eq!(HelpBehaviour::Hide, std::cmp::max(HelpBehaviour::Nothing, HelpBehaviour::Hide));
    }
}
<commit_msg>Replace `CommandError` with an alias to `Box<dyn Error>` (#873)<commit_after>use std::{
    collections::HashSet,
    fmt,
    error::Error as StdError,
};
use crate::client::Context;
use crate::model::{
    channel::Message,
    permissions::Permissions,
    id::UserId,
};
use crate::utils::Colour;
use super::Args;

mod check;
pub mod buckets;

pub use self::check::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OnlyIn {
    Dm,
    Guild,
    None,
    #[doc(hidden)]
    __Nonexhaustive,
}

impl Default for OnlyIn {
    fn default() -> Self { Self::None }
}

#[derive(Debug, Default, PartialEq)]
pub struct CommandOptions {
    /// A set of checks to be called prior to executing the command. The checks
    /// will short-circuit on the first check that returns `false`.
    pub checks: &'static [&'static Check],
    /// Ratelimit bucket.
    pub bucket: Option<&'static str>,
    /// Names that the command can be referred to.
    pub names: &'static [&'static str],
    /// Command description, used by other commands.
    pub desc: Option<&'static str>,
    /// Delimiters used to split the arguments of the command by.
    /// If empty, the [global delimiters](struct.Configuration.html#method.delimiters) are used.
    pub delimiters: &'static [&'static str],
    /// Command usage schema, used by other commands.
    pub usage: Option<&'static str>,
    /// Example arguments, used by other commands.
    pub examples: &'static [&'static str],
    /// Minimum amount of arguments that should be passed.
    pub min_args: Option<u16>,
    /// Maximum amount of arguments that can be passed.
    pub max_args: Option<u16>,
    /// Roles allowed to use this command.
    pub allowed_roles: &'static [&'static str],
    /// Permissions required to use this command.
    pub required_permissions: Permissions,
    /// Whether the command should be displayed in help list or not, used by other commands.
    pub help_available: bool,
    /// Whether the command can only be used in dms or guilds; or both.
    pub only_in: OnlyIn,
    /// Whether the command can only be used by owners or not.
    pub owners_only: bool,
    /// Whether the command treats owners as normal users.
    pub owner_privilege: bool,
    /// Other commands belonging to this command.
    pub sub_commands: &'static [&'static Command],
}

pub type CommandError = Box<dyn StdError>;
pub type CommandResult = ::std::result::Result<(), CommandError>;

pub type CommandFn = fn(&Context, &Message, Args) -> CommandResult;

pub struct Command {
    pub fun: CommandFn,
    pub options: &'static CommandOptions,
}

impl fmt::Debug for Command {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Command")
            .field("options", &self.options)
            .finish()
    }
}

impl PartialEq for Command {
    #[inline]
    fn eq(&self, other: &Command) -> bool {
        (self.fun as usize == other.fun as usize) && (self.options == other.options)
    }
}

pub type HelpCommandFn = fn(
    &Context,
    &Message,
    Args,
    &'static HelpOptions,
    &[&'static CommandGroup],
    HashSet<UserId>,
) -> CommandResult;

pub struct HelpCommand {
    pub fun: HelpCommandFn,
    pub options: &'static HelpOptions,
}

impl fmt::Debug for HelpCommand {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("HelpCommand")
            .field("fun", &"<function>")
            .field("options", &self.options)
            .finish()
    }
}

impl PartialEq for HelpCommand {
    #[inline]
    fn eq(&self, other: &HelpCommand) -> bool {
        (self.fun as usize == other.fun as usize) && (self.options == other.options)
    }
}

/// Describes the behaviour the help-command shall execute once it encounters
/// a command which the user or command fails to meet following criteria :
/// Lacking required permissions to execute the command.
/// Lacking required roles to execute the command.
/// The command can't be used in the current channel (as in `DM only` or `guild only`).
#[derive(Copy, Clone, Debug, PartialOrd, Ord, Eq, PartialEq)]
pub enum HelpBehaviour {
    /// The command will be displayed, hence nothing will be done.
    Nothing,
    /// Strikes a command by applying `~~{command_name}~~`.
    Strike,
    /// Does not list a command in the help-menu.
    Hide,
    #[doc(hidden)]
    __Nonexhaustive,
}

#[derive(Clone, Debug, PartialEq)]
pub struct HelpOptions {
    /// Which names should the help command use for dispatching.
    /// Defaults to `["help"]`
    pub names: &'static [&'static str],
    /// Suggests a command's name.
    pub suggestion_text: &'static str,
    /// If no help is available, this text will be displayed.
    pub no_help_available_text: &'static str,
    /// How to use a command, `{usage_label}: {command_name} {args}`
    pub usage_label: &'static str,
    /// Actual sample label, `{usage_sample_label}: {command_name} {args}`
    pub usage_sample_label: &'static str,
    /// Text labeling ungrouped commands, `{ungrouped_label}: ...`
    pub ungrouped_label: &'static str,
    /// Text labeling the start of the description.
    pub description_label: &'static str,
    /// Text labeling grouped commands, `{grouped_label} {group_name}: ...`
    pub grouped_label: &'static str,
    /// Text labeling a command's alternative names (aliases).
    pub aliases_label: &'static str,
    /// Text specifying that a command is only usable in a guild.
    pub guild_only_text: &'static str,
    /// Text labeling a command's names of checks.
    pub checks_label: &'static str,
    /// Text specifying that a command is only usable in via DM.
    pub dm_only_text: &'static str,
    /// Text specifying that a command can be used via DM and in guilds.
    pub dm_and_guild_text: &'static str,
    /// Text expressing that a command is available.
    pub available_text: &'static str,
    /// Error-message once a command could not be found.
    /// Output-example (without whitespace between both substitutions: `{command_not_found_text}{command_name}`
    /// `{command_name}` describes user's input as in: `{prefix}help {command_name}`.
    pub command_not_found_text: &'static str,
    /// Explains the user on how to use access a single command's details.
    pub individual_command_tip: &'static str,
    /// Explains reasoning behind strikethrough-commands, see fields requiring `HelpBehaviour` for further information.
    /// If `HelpBehaviour::Strike` is unused, this field will evaluate to `None` during creation
    /// inside of the help macro.
    ///
    /// **Note**: Text is only used in direct messages.
    pub strikethrough_commands_tip_in_dm: Option<&'static str>,
    /// Explains reasoning behind strikethrough-commands, see fields requiring `HelpBehaviour` for further information.
    /// If `HelpBehaviour::Strike` is unused, this field will evaluate to `None` during creation
    /// inside of the help macro.
    ///
    /// **Note**: Text is only used in guilds.
    pub strikethrough_commands_tip_in_guild: Option<&'static str>,
    /// Announcing a group's prefix as in: {group_prefix} {prefix}.
    pub group_prefix: &'static str,
    /// If a user lacks required roles, this will treat how these commands will be displayed.
    pub lacking_role: HelpBehaviour,
    /// If a user lacks permissions, this will treat how these commands will be displayed.
    pub lacking_permissions: HelpBehaviour,
    /// If a user lacks ownership, this will treat how these commands will be displayed.
    pub lacking_ownership: HelpBehaviour,
    /// If conditions (of a check) may be lacking by the user, this will treat how these commands will be displayed.
    pub lacking_conditions: HelpBehaviour,
    /// If a user is using the help-command in a channel where a command is not available,
    /// this behaviour will be executed.
    pub wrong_channel: HelpBehaviour,
    /// Colour help-embed will use upon encountering an error.
    pub embed_error_colour: Colour,
    /// Colour help-embed will use if no error occurred.
    pub embed_success_colour: Colour,
    /// If not 0, help will check whether a command is similar to searched named.
    pub max_levenshtein_distance: usize,
    /// Help will use this as prefix to express how deeply nested a command or
    /// group is.
    pub indention_prefix: &'static str,
}

#[derive(Debug, Default, PartialEq)]
pub struct GroupOptions {
    pub prefixes: &'static [&'static str],
    pub only_in: OnlyIn,
    pub owners_only: bool,
    pub owner_privilege: bool,
    pub help_available: bool,
    pub allowed_roles: &'static [&'static str],
    pub required_permissions: Permissions,
    pub checks: &'static [&'static Check],
    pub default_command: Option<&'static Command>,
    pub description: Option<&'static str>,
    pub commands: &'static [&'static Command],
    pub sub_groups: &'static [&'static CommandGroup],
}

#[derive(Debug, PartialEq)]
pub struct CommandGroup {
    pub name: &'static str,
    pub options: &'static GroupOptions,
}

#[cfg(test)]
#[cfg(all(feature = "cache", feature = "http"))]
mod levenshtein_tests {
    use super::HelpBehaviour;

    #[test]
    fn help_behaviour_eq() {
        assert_eq!(HelpBehaviour::Hide, std::cmp::max(HelpBehaviour::Hide, HelpBehaviour::Hide));
        assert_eq!(HelpBehaviour::Strike, std::cmp::max(HelpBehaviour::Strike, HelpBehaviour::Strike));
        assert_eq!(HelpBehaviour::Nothing, std::cmp::max(HelpBehaviour::Nothing, HelpBehaviour::Nothing));
    }

    #[test]
    fn help_behaviour_hide() {
        assert_eq!(HelpBehaviour::Hide, std::cmp::max(HelpBehaviour::Hide, HelpBehaviour::Nothing));
        assert_eq!(HelpBehaviour::Hide, std::cmp::max(HelpBehaviour::Hide, HelpBehaviour::Strike));
    }

    #[test]
    fn help_behaviour_strike() {
        assert_eq!(HelpBehaviour::Strike, std::cmp::max(HelpBehaviour::Strike, HelpBehaviour::Nothing));
        assert_eq!(HelpBehaviour::Hide, std::cmp::max(HelpBehaviour::Strike, HelpBehaviour::Hide));
    }

    #[test]
    fn help_behaviour_nothing() {
        assert_eq!(HelpBehaviour::Strike, std::cmp::max(HelpBehaviour::Nothing, HelpBehaviour::Strike));
        assert_eq!(HelpBehaviour::Hide, std::cmp::max(HelpBehaviour::Nothing, HelpBehaviour::Hide));
    }
}
<|endoftext|>


<commit_before>use ffi;
use libc::{c_uint, c_int, c_void};
use num::complex::Complex64;

use plan::RawPlan;

/// How much effort FFTW should put into computing the best strategy
/// to use.
///
/// The `FFTW_WISDOM_ONLY` rigor level is replaced by the
pub enum Rigor {
    Estimate,
    Measure,
    Patient,
    Exhaustive,
}
impl Rigor {
    fn flags(self) -> c_uint {
        match self {
            Estimate => ffi::FFTW_ESTIMATE,
            Measure => ffi::FFTW_MEASURE,
            Patient => ffi::FFTW_PATIENT,
            Exhaustive => ffi::FFTW_EXHAUSTIVE,
        }
    }
}

/// The direction of the transform to perform..
pub enum Direction {
    Forward, Backward
}

/// Control the basic properties of a set of transforms.
pub struct Planner {
    rigor: Rigor,
    wisdom_restriction: bool,
    direction: Direction,
}

impl Planner {
    /// Construct a new planner with default values.
    ///
    /// This defaults to a forward transform with estimate rigor.
    pub fn new() -> Planner {
        Planner {
            rigor: Estimate,
            wisdom_restriction: false,
            direction: Forward,
        }
    }

    /// Set the rigor to use for this plan.
    pub fn rigor(&mut self, r: Rigor) -> &mut Planner {
        self.rigor = r;
        self
    }
    /// Set whether the planner should only be successfully created if
    /// there exists wisdom created with at least the rigor level set.
    pub fn wisdom_restriction(&mut self, wisdom_only: bool) -> &mut Planner {
        self.wisdom_restriction = wisdom_only;
        self
    }

    /// Set the direction of the transform to perform.
    pub fn direction(&mut self, direction: Direction) -> &mut Planner {
        self.direction = direction;
        self
    }

    fn flags(&self) -> c_uint {
        self.rigor.flags() | if self.wisdom_restriction {
            ffi::FFTW_WISDOM_ONLY
        } else {
            0
        }
    }
    fn dir(&self) -> c_int {
        match self.direction {
            Forward => ffi::FFTW_FORWARD,
            Backward => ffi::FFTW_BACKWARD,
        }
    }

    pub fn inplace(&self) -> InPlacePlanner {
        InPlacePlanner { plan: *self }
    }

    pub fn c2c<I, O>(&self, in_: I, out: O) -> PlanMem<I, O>
        where I: DerefMut<[Complex64]>, O: DerefMut<[Complex64]>
    {
        assert!(in_.len() <= 0x7F_FF_FF_FF);
        assert!(in_.len() <= out.len());
        let dims = Detailed(vec![Dim { n: in_.len(), in_stride: 1, out_stride: 1 }]);
        PlanMem {
            plan: *self,
            in_: in_,
            out: Some(out),
            planner: c2c,

            dims: dims,
            how_many: Contiguous(vec![1]),
        }
    }
    pub fn c2r<I, O>(&self, in_: I, out: O) -> PlanMem<I, O>
        where I: DerefMut<[Complex64]>, O: DerefMut<[f64]>
    {
        assert!(in_.len() <= 0x7F_FF_FF_FF);
        assert!(in_.len() <= out.len() / 2 + 1);
        let dims = Detailed(vec![Dim { n: 2 * (in_.len() - 1),
                                       in_stride: 1, out_stride: 1 }]);
        PlanMem {
            plan: *self,
            in_: in_,
            out: Some(out),
            planner: c2r,

            dims: dims,
            how_many: Contiguous(vec![1]),
        }
    }
    pub fn r2c<I, O>(&self, in_: I, out: O) -> PlanMem<I, O>
        where I: DerefMut<[f64]>, O: DerefMut<[Complex64]>
    {
        assert!(in_.len() <= 0x7F_FF_FF_FF);
        assert!(in_.len() / 2 + 1 <= out.len());
        let dims = Detailed(vec![Dim { n: in_.len(), in_stride: 1, out_stride: 1 }]);
        PlanMem {
            plan: *self,
            in_: in_,
            out: Some(out),
            planner: r2c,

            dims: dims,
            how_many: Contiguous(vec![1]),
        }
    }
    #[cfg(r2r_is_hard)]
    pub fn r2r<I, O>(&self, in_: I, out: O) -> PlanMem<I, O>
        where I: DerefMut<[f64]>, O: DerefMut<[f64]>
    {
        assert!(in_.len() <= 0x7F_FF_FF_FF);
        assert!(in_.len() <= out.len());
        let dims = Detailed(vec![Dim { n: in_.len(), in_stride: 1, out_stride: 1 }]);
        PlanMem {
            plan: *self,
            in_: in_,
            out: Some(out),
            planner: r2r,

            dims: dims,
            how_many: Contiguous(vec![1]),
        }
    }
}

pub struct InPlacePlanner {
    plan: Planner
}

impl InPlacePlanner {
    pub fn c2c<I>(&self, in_: I) -> PlanMem<I, I>
        where I: DerefMut<[Complex64]>
    {
        assert!(in_.len() <= 0x7F_FF_FF_FF);
        let dims = Detailed(vec![Dim { n: in_.len(), in_stride: 1, out_stride: 1 }]);
        PlanMem {
            plan: self.plan,
            in_: in_,
            out: None,
            planner: c2c,

            dims: dims,
            how_many: Contiguous(vec![1]),
        }
    }
}

type GuruPlanner =
    unsafe fn(rank: c_int, dims: *const ffi::fftw_iodim64,
              howmany_rank: c_int, howmany_dims: *const ffi::fftw_iodim64,
              in_: *mut c_void, out: *mut c_void,
              sign: c_int, flags: c_uint) -> ffi::fftw_plan;

unsafe fn c2c(rank: c_int, dims: *const ffi::fftw_iodim64,
              howmany_rank: c_int, howmany_dims: *const ffi::fftw_iodim64,
              in_: *mut c_void, out: *mut c_void,
              sign: c_int, flags: c_uint) -> ffi::fftw_plan {
    ffi::fftw_plan_guru64_dft(rank, dims,
                            howmany_rank, howmany_dims,
                            in_ as *mut _, out as *mut _,
                            sign, flags)
}

unsafe fn r2c(rank: c_int, dims: *const ffi::fftw_iodim64,
              howmany_rank: c_int, howmany_dims: *const ffi::fftw_iodim64,
              in_: *mut c_void, out: *mut c_void,
              _sign: c_int, flags: c_uint) -> ffi::fftw_plan {
    ffi::fftw_plan_guru64_dft_r2c(rank, dims,
                                howmany_rank, howmany_dims,
                                in_ as *mut _, out as *mut _,
                                flags)
}
unsafe fn c2r(rank: c_int, dims: *const ffi::fftw_iodim64,
              howmany_rank: c_int, howmany_dims: *const ffi::fftw_iodim64,
              in_: *mut c_void, out: *mut c_void,
              _sign: c_int, flags: c_uint) -> ffi::fftw_plan {
    ffi::fftw_plan_guru64_dft_c2r(rank, dims,
                                howmany_rank, howmany_dims,
                                in_ as *mut _, out as *mut _,
                                flags)
}
#[cfg(r2r_is_hard)]
unsafe fn r2r(n: c_int, in_: *mut c_void, out: *mut c_void,
              sign: c_int, flags: c_uint) -> ffi::fftw_plan {
    ffi::fftw_plan_r2r_1d(n,
                          in_ as *mut f64, out as *mut f64,
                          sign, flags)
}

#[repr(C)]
pub struct Dim {
    pub n: uint,
    pub in_stride: uint,
    pub out_stride: uint,
}

enum Dims {
    Contiguous(Vec<uint>),
    Detailed(Vec<Dim>),
}

pub struct PlanMem<I, O> {
    plan: Planner,
    dims: Dims,
    how_many: Dims,
    in_: I,
    out: Option<O>,
    planner: GuruPlanner
}

impl<X, Y, I: DerefMut<[X]>, O: DerefMut<[Y]>> PlanMem<I, O> {
    pub fn dimensions(mut self, dims: Vec<uint>) -> PlanMem<I, O> {
        unimplemented!()
        self.dims = Contiguous(dims);
        self
    }
    pub fn multiples(mut self, number: uint) -> PlanMem<I, O> {
        unimplemented!()
        self.how_many = Contiguous(vec![number]);
        self
    }
    pub fn plan(mut self) -> Result<Planned<I, O>, PlanMem<I, O>> {
        let plan;
        {
            let in_ptr = self.in_.as_mut_ptr() as *mut c_void;
            let out_ptr = match self.out {
                None => in_ptr,
                Some(ref mut o) => o.as_mut_ptr() as *mut c_void,
            };
            let dims = match self.dims {
                Contiguous(_) => unimplemented!(),
                Detailed(ref v) => v.as_slice()
            };
            assert!(dims.len() == 1);

            plan = RawPlan::new(|| unsafe {
                (self.planner)(
                    dims.len() as c_int, dims.as_ptr() as *const ffi::fftw_iodim64,
                    0, [].as_ptr(),
                    in_ptr,
                    out_ptr,
                    self.plan.dir(),
                    self.plan.flags())
            });
        }
        match plan {
            None => Err(self),
            Some(p) => Ok(Planned { mem: self, plan: p })
        }
    }
}

pub struct Planned<I, O> {
    mem: PlanMem<I, O>,
    plan: RawPlan,
}

impl<X, Y, I: DerefMut<[X]>, O: DerefMut<[Y]>> Planned<I, O> {
    pub fn input(&mut self) -> &mut [X] {
        &mut *self.mem.in_
    }
    pub fn output(&mut self) -> Option<&mut [Y]> {
        self.mem.out.as_mut().map(|o| &mut **o)
    }

    pub fn execute(&mut self) {
        unsafe {
            self.plan.execute()
        }
    }
}
<commit_msg>Add test for iodim FFI.<commit_after>use ffi;
use libc::{c_uint, c_int, c_void};
use num::complex::Complex64;

use plan::RawPlan;

/// How much effort FFTW should put into computing the best strategy
/// to use.
///
/// The `FFTW_WISDOM_ONLY` rigor level is replaced by the
pub enum Rigor {
    Estimate,
    Measure,
    Patient,
    Exhaustive,
}
impl Rigor {
    fn flags(self) -> c_uint {
        match self {
            Estimate => ffi::FFTW_ESTIMATE,
            Measure => ffi::FFTW_MEASURE,
            Patient => ffi::FFTW_PATIENT,
            Exhaustive => ffi::FFTW_EXHAUSTIVE,
        }
    }
}

/// The direction of the transform to perform..
pub enum Direction {
    Forward, Backward
}

/// Control the basic properties of a set of transforms.
pub struct Planner {
    rigor: Rigor,
    wisdom_restriction: bool,
    direction: Direction,
}

impl Planner {
    /// Construct a new planner with default values.
    ///
    /// This defaults to a forward transform with estimate rigor.
    pub fn new() -> Planner {
        Planner {
            rigor: Estimate,
            wisdom_restriction: false,
            direction: Forward,
        }
    }

    /// Set the rigor to use for this plan.
    pub fn rigor(&mut self, r: Rigor) -> &mut Planner {
        self.rigor = r;
        self
    }
    /// Set whether the planner should only be successfully created if
    /// there exists wisdom created with at least the rigor level set.
    pub fn wisdom_restriction(&mut self, wisdom_only: bool) -> &mut Planner {
        self.wisdom_restriction = wisdom_only;
        self
    }

    /// Set the direction of the transform to perform.
    pub fn direction(&mut self, direction: Direction) -> &mut Planner {
        self.direction = direction;
        self
    }

    fn flags(&self) -> c_uint {
        self.rigor.flags() | if self.wisdom_restriction {
            ffi::FFTW_WISDOM_ONLY
        } else {
            0
        }
    }
    fn dir(&self) -> c_int {
        match self.direction {
            Forward => ffi::FFTW_FORWARD,
            Backward => ffi::FFTW_BACKWARD,
        }
    }

    pub fn inplace(&self) -> InPlacePlanner {
        InPlacePlanner { plan: *self }
    }

    pub fn c2c<I, O>(&self, in_: I, out: O) -> PlanMem<I, O>
        where I: DerefMut<[Complex64]>, O: DerefMut<[Complex64]>
    {
        assert!(in_.len() <= 0x7F_FF_FF_FF);
        assert!(in_.len() <= out.len());
        let dims = Detailed(vec![Dim { n: in_.len(), in_stride: 1, out_stride: 1 }]);
        PlanMem {
            plan: *self,
            in_: in_,
            out: Some(out),
            planner: c2c,

            dims: dims,
            how_many: Contiguous(vec![1]),
        }
    }
    pub fn c2r<I, O>(&self, in_: I, out: O) -> PlanMem<I, O>
        where I: DerefMut<[Complex64]>, O: DerefMut<[f64]>
    {
        assert!(in_.len() <= 0x7F_FF_FF_FF);
        assert!(in_.len() <= out.len() / 2 + 1);
        let dims = Detailed(vec![Dim { n: 2 * (in_.len() - 1),
                                       in_stride: 1, out_stride: 1 }]);
        PlanMem {
            plan: *self,
            in_: in_,
            out: Some(out),
            planner: c2r,

            dims: dims,
            how_many: Contiguous(vec![1]),
        }
    }
    pub fn r2c<I, O>(&self, in_: I, out: O) -> PlanMem<I, O>
        where I: DerefMut<[f64]>, O: DerefMut<[Complex64]>
    {
        assert!(in_.len() <= 0x7F_FF_FF_FF);
        assert!(in_.len() / 2 + 1 <= out.len());
        let dims = Detailed(vec![Dim { n: in_.len(), in_stride: 1, out_stride: 1 }]);
        PlanMem {
            plan: *self,
            in_: in_,
            out: Some(out),
            planner: r2c,

            dims: dims,
            how_many: Contiguous(vec![1]),
        }
    }
    #[cfg(r2r_is_hard)]
    pub fn r2r<I, O>(&self, in_: I, out: O) -> PlanMem<I, O>
        where I: DerefMut<[f64]>, O: DerefMut<[f64]>
    {
        assert!(in_.len() <= 0x7F_FF_FF_FF);
        assert!(in_.len() <= out.len());
        let dims = Detailed(vec![Dim { n: in_.len(), in_stride: 1, out_stride: 1 }]);
        PlanMem {
            plan: *self,
            in_: in_,
            out: Some(out),
            planner: r2r,

            dims: dims,
            how_many: Contiguous(vec![1]),
        }
    }
}

pub struct InPlacePlanner {
    plan: Planner
}

impl InPlacePlanner {
    pub fn c2c<I>(&self, in_: I) -> PlanMem<I, I>
        where I: DerefMut<[Complex64]>
    {
        assert!(in_.len() <= 0x7F_FF_FF_FF);
        let dims = Detailed(vec![Dim { n: in_.len(), in_stride: 1, out_stride: 1 }]);
        PlanMem {
            plan: self.plan,
            in_: in_,
            out: None,
            planner: c2c,

            dims: dims,
            how_many: Contiguous(vec![1]),
        }
    }
}

type GuruPlanner =
    unsafe fn(rank: c_int, dims: *const ffi::fftw_iodim64,
              howmany_rank: c_int, howmany_dims: *const ffi::fftw_iodim64,
              in_: *mut c_void, out: *mut c_void,
              sign: c_int, flags: c_uint) -> ffi::fftw_plan;

unsafe fn c2c(rank: c_int, dims: *const ffi::fftw_iodim64,
              howmany_rank: c_int, howmany_dims: *const ffi::fftw_iodim64,
              in_: *mut c_void, out: *mut c_void,
              sign: c_int, flags: c_uint) -> ffi::fftw_plan {
    ffi::fftw_plan_guru64_dft(rank, dims,
                            howmany_rank, howmany_dims,
                            in_ as *mut _, out as *mut _,
                            sign, flags)
}

unsafe fn r2c(rank: c_int, dims: *const ffi::fftw_iodim64,
              howmany_rank: c_int, howmany_dims: *const ffi::fftw_iodim64,
              in_: *mut c_void, out: *mut c_void,
              _sign: c_int, flags: c_uint) -> ffi::fftw_plan {
    ffi::fftw_plan_guru64_dft_r2c(rank, dims,
                                howmany_rank, howmany_dims,
                                in_ as *mut _, out as *mut _,
                                flags)
}
unsafe fn c2r(rank: c_int, dims: *const ffi::fftw_iodim64,
              howmany_rank: c_int, howmany_dims: *const ffi::fftw_iodim64,
              in_: *mut c_void, out: *mut c_void,
              _sign: c_int, flags: c_uint) -> ffi::fftw_plan {
    ffi::fftw_plan_guru64_dft_c2r(rank, dims,
                                howmany_rank, howmany_dims,
                                in_ as *mut _, out as *mut _,
                                flags)
}
#[cfg(r2r_is_hard)]
unsafe fn r2r(n: c_int, in_: *mut c_void, out: *mut c_void,
              sign: c_int, flags: c_uint) -> ffi::fftw_plan {
    ffi::fftw_plan_r2r_1d(n,
                          in_ as *mut f64, out as *mut f64,
                          sign, flags)
}

#[repr(C)]
pub struct Dim {
    pub n: uint,
    pub in_stride: uint,
    pub out_stride: uint,
}

enum Dims {
    Contiguous(Vec<uint>),
    Detailed(Vec<Dim>),
}

pub struct PlanMem<I, O> {
    plan: Planner,
    dims: Dims,
    how_many: Dims,
    in_: I,
    out: Option<O>,
    planner: GuruPlanner
}

impl<X, Y, I: DerefMut<[X]>, O: DerefMut<[Y]>> PlanMem<I, O> {
    pub fn dimensions(mut self, dims: Vec<uint>) -> PlanMem<I, O> {
        unimplemented!()
        self.dims = Contiguous(dims);
        self
    }
    pub fn multiples(mut self, number: uint) -> PlanMem<I, O> {
        unimplemented!()
        self.how_many = Contiguous(vec![number]);
        self
    }
    pub fn plan(mut self) -> Result<Planned<I, O>, PlanMem<I, O>> {
        let plan;
        {
            let in_ptr = self.in_.as_mut_ptr() as *mut c_void;
            let out_ptr = match self.out {
                None => in_ptr,
                Some(ref mut o) => o.as_mut_ptr() as *mut c_void,
            };
            let dims = match self.dims {
                Contiguous(_) => unimplemented!(),
                Detailed(ref v) => v.as_slice()
            };
            assert!(dims.len() == 1);

            plan = RawPlan::new(|| unsafe {
                (self.planner)(
                    dims.len() as c_int, dims.as_ptr() as *const ffi::fftw_iodim64,
                    0, [].as_ptr(),
                    in_ptr,
                    out_ptr,
                    self.plan.dir(),
                    self.plan.flags())
            });
        }
        match plan {
            None => Err(self),
            Some(p) => Ok(Planned { mem: self, plan: p })
        }
    }
}

pub struct Planned<I, O> {
    mem: PlanMem<I, O>,
    plan: RawPlan,
}

impl<X, Y, I: DerefMut<[X]>, O: DerefMut<[Y]>> Planned<I, O> {
    pub fn input(&mut self) -> &mut [X] {
        &mut *self.mem.in_
    }
    pub fn output(&mut self) -> Option<&mut [Y]> {
        self.mem.out.as_mut().map(|o| &mut **o)
    }

    pub fn execute(&mut self) {
        unsafe {
            self.plan.execute()
        }
    }
}

#[cfg(test)]
mod tests {
    use std::mem;
    use libc::ptrdiff_t;
    use ffi::Struct_fftw_iodim64_do_not_use_me;
    use super::Dim;

    #[test]
    fn iodims_are_compatible() {
        // handle 32-bit and 64-bit platforms properly
        let n = 0x0102_0304_0506_0708u64 as uint;
        let is = 0x090A_0B0C_0D0E_0F00u64 as uint;
        let os = 0x1122_3344_5566_7788u64 as uint;

        let d = Dim { n: n, in_stride: is, out_stride: os };
        let f = Struct_fftw_iodim64_do_not_use_me {
            n: n as ptrdiff_t, is: is as ptrdiff_t, os: os as ptrdiff_t
        };
        type T = (uint, uint, uint);
        unsafe {
            assert_eq!(mem::transmute::<_, T>(d), mem::transmute::<_, T>(f));
        }
    }
}
<|endoftext|>


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

extern crate test;
extern crate ndarray;

use ndarray::{Array, S, Si};
use ndarray::{arr0, arr1, arr2};

use test::black_box;

#[bench]
fn bench_std_add(bench: &mut test::Bencher)
{
    let mut a = arr2::<f32, _>(&[[1., 2., 2.],
                              [3., 4., 4.],
                              [3., 4., 4.],
                              [3., 4., 4.],
                              [5., 6., 6.]]);
    let b = a.clone();
    bench.iter(|| a.iadd(&b));
}

#[bench]
fn bench_std_iter_1d(bench: &mut test::Bencher)
{
    let a = arr1::<f32>(&[1., 2., 2.,
                         3., 4., 4.,
                         3., 4., 4.,
                         3., 4., 4.,
                         5., 6., 6.]);
    bench.iter(|| for &elt in a.iter() { black_box(elt) })
}

#[bench]
fn bench_std_iter_1d_raw(bench: &mut test::Bencher)
{
    let a = arr1::<f32>(&[1., 2., 2.,
                         3., 4., 4.,
                         3., 4., 4.,
                         3., 4., 4.,
                         5., 6., 6.]);
    bench.iter(|| for &elt in a.raw_data().iter() { black_box(elt) })
}

#[bench]
fn bench_std_iter_2d(bench: &mut test::Bencher)
{
    let a = arr2::<f32, _>(&[[1., 2., 2.],
                          [3., 4., 4.],
                          [3., 4., 4.],
                          [3., 4., 4.],
                          [5., 6., 6.]]);
    bench.iter(|| for &elt in a.iter() { black_box(elt) })
}

#[bench]
fn bench_std_iter_1d_large(bench: &mut test::Bencher)
{
    let a = Array::<f32, _>::zeros((1024));
    bench.iter(|| for &elt in a.iter() { black_box(elt) })
}

#[bench]
fn bench_std_iter_1d_raw_large(bench: &mut test::Bencher)
{
    let a = Array::<f32, _>::zeros((1024));
    bench.iter(|| for &elt in a.raw_data().iter() { black_box(elt) })
}

#[bench]
fn bench_std_iter_2d_large(bench: &mut test::Bencher)
{
    let a = Array::<f32, _>::zeros((16, 64));
    bench.iter(|| for &elt in a.iter() { black_box(elt) })
}

#[bench]
fn assign_scalar_2d(bench: &mut test::Bencher)
{
    let mut a = arr2::<f32, _>(&[[1., 2., 2.],
                              [3., 4., 4.],
                              [3., 4., 4.],
                              [3., 4., 4.],
                              [5., 6., 6.]]);
    a.swap_axes(0, 1);
    bench.iter(|| a.assign_scalar(&3.))
}

#[bench]
fn bench_iter_diag(bench: &mut test::Bencher)
{
    let a = Array::<f32, _>::zeros((1024, 1024));
    bench.iter(|| for elt in a.diag_iter() { black_box(elt) })
}

#[bench]
fn bench_row_iter(bench: &mut test::Bencher)
{
    let a = Array::<f32, _>::zeros((1024, 1024));
    let it = a.row_iter(17);
    bench.iter(|| for elt in it.clone() { black_box(elt) })
}

#[bench]
fn bench_col_iter(bench: &mut test::Bencher)
{
    let a = Array::<f32, _>::zeros((1024, 1024));
    bench.iter(|| for elt in a.col_iter(17) { black_box(elt) })
}

#[bench]
fn bench_mat_mul(bench: &mut test::Bencher)
{
    let a = arr2::<f32, _>(&[[1., 2., 2.],
                          [3., 4., 4.],
                          [3., 4., 4.],
                          [3., 4., 4.],
                          [5., 6., 6.]]);
    let mut at = a.clone();
    at.swap_axes(0, 1);
    bench.iter(|| at.mat_mul(&a));
}

#[bench]
fn lst_squares(bench: &mut test::Bencher)
{
    let xs = arr2::<f32, _>(&[[ 2.,  3.],
                           [-2., -1.],
                           [ 1.,  5.],
                           [-1.,  2.]]);
    let b = arr1(&[1., -1., 2., 1.]);
    bench.iter(|| ndarray::linalg::least_squares(&xs, &b));
}
<commit_msg>Fix compilation of benches after black_box change.<commit_after>#![allow(uppercase_variables)]
#![allow(unused_imports)]

extern crate test;
extern crate ndarray;

use ndarray::{Array, S, Si};
use ndarray::{arr0, arr1, arr2};

use test::black_box;

#[bench]
fn bench_std_add(bench: &mut test::Bencher)
{
    let mut a = arr2::<f32, _>(&[[1., 2., 2.],
                              [3., 4., 4.],
                              [3., 4., 4.],
                              [3., 4., 4.],
                              [5., 6., 6.]]);
    let b = a.clone();
    bench.iter(|| a.iadd(&b));
}

#[bench]
fn bench_std_iter_1d(bench: &mut test::Bencher)
{
    let a = arr1::<f32>(&[1., 2., 2.,
                         3., 4., 4.,
                         3., 4., 4.,
                         3., 4., 4.,
                         5., 6., 6.]);
    bench.iter(|| for &elt in a.iter() { black_box(elt); })
}

#[bench]
fn bench_std_iter_1d_raw(bench: &mut test::Bencher)
{
    let a = arr1::<f32>(&[1., 2., 2.,
                         3., 4., 4.,
                         3., 4., 4.,
                         3., 4., 4.,
                         5., 6., 6.]);
    bench.iter(|| for &elt in a.raw_data().iter() { black_box(elt); })
}

#[bench]
fn bench_std_iter_2d(bench: &mut test::Bencher)
{
    let a = arr2::<f32, _>(&[[1., 2., 2.],
                          [3., 4., 4.],
                          [3., 4., 4.],
                          [3., 4., 4.],
                          [5., 6., 6.]]);
    bench.iter(|| for &elt in a.iter() { black_box(elt); })
}

#[bench]
fn bench_std_iter_1d_large(bench: &mut test::Bencher)
{
    let a = Array::<f32, _>::zeros((1024));
    bench.iter(|| for &elt in a.iter() { black_box(elt); })
}

#[bench]
fn bench_std_iter_1d_raw_large(bench: &mut test::Bencher)
{
    let a = Array::<f32, _>::zeros((1024));
    bench.iter(|| for &elt in a.raw_data().iter() { black_box(elt); })
}

#[bench]
fn bench_std_iter_2d_large(bench: &mut test::Bencher)
{
    let a = Array::<f32, _>::zeros((16, 64));
    bench.iter(|| for &elt in a.iter() { black_box(elt); })
}

#[bench]
fn assign_scalar_2d(bench: &mut test::Bencher)
{
    let mut a = arr2::<f32, _>(&[[1., 2., 2.],
                              [3., 4., 4.],
                              [3., 4., 4.],
                              [3., 4., 4.],
                              [5., 6., 6.]]);
    a.swap_axes(0, 1);
    bench.iter(|| a.assign_scalar(&3.))
}

#[bench]
fn bench_iter_diag(bench: &mut test::Bencher)
{
    let a = Array::<f32, _>::zeros((1024, 1024));
    bench.iter(|| for elt in a.diag_iter() { black_box(elt); })
}

#[bench]
fn bench_row_iter(bench: &mut test::Bencher)
{
    let a = Array::<f32, _>::zeros((1024, 1024));
    let it = a.row_iter(17);
    bench.iter(|| for elt in it.clone() { black_box(elt); })
}

#[bench]
fn bench_col_iter(bench: &mut test::Bencher)
{
    let a = Array::<f32, _>::zeros((1024, 1024));
    bench.iter(|| for elt in a.col_iter(17) { black_box(elt); })
}

#[bench]
fn bench_mat_mul(bench: &mut test::Bencher)
{
    let a = arr2::<f32, _>(&[[1., 2., 2.],
                          [3., 4., 4.],
                          [3., 4., 4.],
                          [3., 4., 4.],
                          [5., 6., 6.]]);
    let mut at = a.clone();
    at.swap_axes(0, 1);
    bench.iter(|| at.mat_mul(&a));
}

#[bench]
fn lst_squares(bench: &mut test::Bencher)
{
    let xs = arr2::<f32, _>(&[[ 2.,  3.],
                           [-2., -1.],
                           [ 1.,  5.],
                           [-1.,  2.]]);
    let b = arr1(&[1., -1., 2., 1.]);
    bench.iter(|| ndarray::linalg::least_squares(&xs, &b));
}
<|endoftext|>


<commit_before>extern crate rs_logic;

use rs_logic::element::*;

// NOT X = X NAND X
fn init_not() -> Element {
    // init hardcoded NAND component
    let nand = Element::init_nand();
    // init user NOT component (composit)
    let mut not = Element::init("NOT", 1, 1);
    // push NAND component into NOT
    let nand_id = not.push_element(nand);
    // connect all wires
    not.connect_wire(Wire::InputSelf(0), Wire::Input(nand_id, 0));
    not.connect_wire(Wire::InputSelf(0), Wire::Input(nand_id, 1));
    not.connect_wire(Wire::Output(nand_id, 0), Wire::OutputSelf(0));
    not
}

//              A     B     C
// X AND Y = (NOT X) NOR (NOT Y)
fn init_and() -> Element {
    let not_a = init_not();
    let not_b = init_not();
    let nor = Element::init_nor();
    // init user AND component
    let mut and = Element::init("AND", 2, 1);
    // push all components
    let b = and.push_element(nor);
    let a = and.push_element(not_a);
    let c = and.push_element(not_b);
    // connect A
    and.connect_wire(Wire::InputSelf(0), Wire::Input(a, 0));
    // connect C
    and.connect_wire(Wire::InputSelf(1), Wire::Input(c, 0));
    // connect B
    and.connect_wire(Wire::Output(a, 0), Wire::Input(b, 0));
    and.connect_wire(Wire::Output(c, 0), Wire::Input(b, 1));
    // result to output
    and.connect_wire(Wire::Output(b, 0), Wire::OutputSelf(0));
    and
}

//             A     B      C
// X OR Y = (NOT X) NAND (NOT Y)
fn init_or() -> Element {
    let not_a = init_not();
    let not_b = init_not();
    let nand = Element::init_nand();
    // init user OR component
    let mut or = Element::init("OR", 2, 1);
    // push all components
    let b = or.push_element(nand);
    let a = or.push_element(not_a);
    let c = or.push_element(not_b);
    // connect A
    or.connect_wire(Wire::InputSelf(0), Wire::Input(a, 0));
    // connect C
    or.connect_wire(Wire::InputSelf(1), Wire::Input(c, 0));
    // connect B
    or.connect_wire(Wire::Output(a, 0), Wire::Input(b, 0));
    or.connect_wire(Wire::Output(c, 0), Wire::Input(b, 1));
    // result to output
    or.connect_wire(Wire::Output(b, 0), Wire::OutputSelf(0));
    or
}

// SOMETHING WENT WRONG!
//               A       B     C
// X XOR Y = (X NAND Y) AND (X OR Y)
fn init_xor() -> Element {
    let nand = Element::init_nand();
    let or = init_or();
    let and = init_and();
    // init user XOR component
    let mut xor = Element::init("XOR", 2, 1);
    // push all components
    let a = xor.push_element(nand);
    let b = xor.push_element(and);
    let c = xor.push_element(or);
    // connect A
    xor.connect_wire(Wire::InputSelf(0), Wire::Input(a, 0));
    xor.connect_wire(Wire::InputSelf(1), Wire::Input(a, 1));
    // connect C
    xor.connect_wire(Wire::InputSelf(0), Wire::Input(c, 0));
    xor.connect_wire(Wire::InputSelf(1), Wire::Input(c, 1));
    // connect B
    xor.connect_wire(Wire::Output(a, 0), Wire::Input(b, 0));
    xor.connect_wire(Wire::Output(c, 0), Wire::Input(b, 1));
    // result to output
    xor.connect_wire(Wire::Output(b, 0), Wire::OutputSelf(0));
    xor
}

fn main() {
    let mut not = init_not();
    println!("NOT component:");
    for v1 in vec![0, 1] {
        not.set_input_wire(0, v1);
        not.execute();
        println!("  [{}] -> {:?}", v1, not.get_output());
    }
    let mut and = init_and();
    let mut and_result = String::new();
    let mut or = init_or();
    let mut or_result = String::new();
    let mut xor = init_xor();
    let mut xor_result = String::new();
    for (v1, v2) in vec![(0, 0), (0, 1), (1, 0), (1, 1)] {
        and.set_input(vec![v1, v2]);
        and.execute();
        or.set_input(vec![v1, v2]);
        or.execute();
        xor.set_input(vec![v1, v2]);
        xor.execute();
        and_result.push_str(&format!("\n  {:?} -> {:?}", &[v1, v2], and.get_output()));
        or_result.push_str(&format!("\n  {:?} -> {:?}", &[v1, v2], or.get_output()));
        xor_result.push_str(&format!("\n  {:?} -> {:?}", &[v1, v2], xor.get_output()));
    }
    println!("AND component:{}", and_result);
    println!("OR component:{}", or_result);
    println!("XOR component:{}", xor_result);
}<commit_msg>[upd] clean example code<commit_after>extern crate rs_logic;

use rs_logic::element::*;

// NOT X = X NAND X
pub fn init_not() -> Element {
    // init user NOT component (composit)
    let mut not = Element::init("NOT", 1, 1);
    // push NAND component into NOT
    let nand_id = not.push_element(Element::init_nand());
    // connect all wires
    not.connect_wire(Wire::InputSelf(0), Wire::Input(nand_id, 0));
    not.connect_wire(Wire::InputSelf(0), Wire::Input(nand_id, 1));
    not.connect_wire(Wire::Output(nand_id, 0), Wire::OutputSelf(0));
    not
}

//              A     B     C
// X AND Y = (NOT X) NOR (NOT Y)
pub fn init_and() -> Element {
    // init user AND component
    let mut and = Element::init("AND", 2, 1);
    // push all components
    let b = and.push_element(Element::init_nor());
    let a = and.push_element(init_not());
    let c = and.push_element(init_not());
    // connect A
    and.connect_wire(Wire::InputSelf(0), Wire::Input(a, 0));
    // connect C
    and.connect_wire(Wire::InputSelf(1), Wire::Input(c, 0));
    // connect B
    and.connect_wire(Wire::Output(a, 0), Wire::Input(b, 0));
    and.connect_wire(Wire::Output(c, 0), Wire::Input(b, 1));
    // result to output
    and.connect_wire(Wire::Output(b, 0), Wire::OutputSelf(0));
    and
}

//             A     B      C
// X OR Y = (NOT X) NAND (NOT Y)
pub fn init_or() -> Element {
    // init user OR component
    let mut or = Element::init("OR", 2, 1);
    // push all components
    let b = or.push_element(Element::init_nand());
    let a = or.push_element(init_not());
    let c = or.push_element(init_not());
    // connect A
    or.connect_wire(Wire::InputSelf(0), Wire::Input(a, 0));
    // connect C
    or.connect_wire(Wire::InputSelf(1), Wire::Input(c, 0));
    // connect B
    or.connect_wire(Wire::Output(a, 0), Wire::Input(b, 0));
    or.connect_wire(Wire::Output(c, 0), Wire::Input(b, 1));
    // result to output
    or.connect_wire(Wire::Output(b, 0), Wire::OutputSelf(0));
    or
}

//               A       B     C
// X XOR Y = (X NAND Y) AND (X OR Y)
pub fn init_xor() -> Element {
    // init user XOR component
    let mut xor = Element::init("XOR", 2, 1);
    // push all components
    let a = xor.push_element(Element::init_nand());
    let b = xor.push_element(init_and());
    let c = xor.push_element(init_or());
    // connect A
    xor.connect_wire(Wire::InputSelf(0), Wire::Input(a, 0));
    xor.connect_wire(Wire::InputSelf(1), Wire::Input(a, 1));
    // connect C
    xor.connect_wire(Wire::InputSelf(0), Wire::Input(c, 0));
    xor.connect_wire(Wire::InputSelf(1), Wire::Input(c, 1));
    // connect B
    xor.connect_wire(Wire::Output(a, 0), Wire::Input(b, 0));
    xor.connect_wire(Wire::Output(c, 0), Wire::Input(b, 1));
    // result to output
    xor.connect_wire(Wire::Output(b, 0), Wire::OutputSelf(0));
    xor
}

fn main() {
    let mut not = init_not();
    println!("NOT component:");
    for v1 in vec![0, 1] {
        not.set_input_wire(0, v1);
        not.execute();
        println!("  [{}] -> {:?}", v1, not.get_output());
    }
    let mut and = init_and();
    let mut and_result = String::new();
    let mut or = init_or();
    let mut or_result = String::new();
    let mut xor = init_xor();
    let mut xor_result = String::new();
    for (v1, v2) in vec![(0, 0), (0, 1), (1, 0), (1, 1)] {
        and.set_input(vec![v1, v2]);
        and.execute();
        or.set_input(vec![v1, v2]);
        or.execute();
        xor.set_input(vec![v1, v2]);
        xor.execute();
        and_result.push_str(&format!("\n  {:?} -> {:?}", &[v1, v2], and.get_output()));
        or_result.push_str(&format!("\n  {:?} -> {:?}", &[v1, v2], or.get_output()));
        xor_result.push_str(&format!("\n  {:?} -> {:?}", &[v1, v2], xor.get_output()));
    }
    println!("AND component:{}", and_result);
    println!("OR component:{}", or_result);
    println!("XOR component:{}", xor_result);
}<|endoftext|>


<commit_before>use std::{
    any::{Any, TypeId},
    collections::{BTreeMap, HashMap},
    marker::PhantomData,
    sync::{mpsc, Arc, Mutex},
};

use crate::shell::WindowRequest;

use dces::entity::Entity;

/// Internal wrapper that stores a message inside a box.
#[derive(Debug)]
pub struct MessageBox {
    message: Box<dyn Any + Send>,
    message_type: TypeId,
    target: Entity,
}

impl MessageBox {
    /// Creates a new `MessageBox`.
    pub fn new<M: Any + Send>(message: M, target: Entity) -> Self {
        MessageBox {
            message: Box::new(message),
            target,
            message_type: TypeId::of::<M>(),
        }
    }

    /// Check if the given type is the type of the message.
    pub fn is_type<M: Any>(&self) -> bool {
        self.message_type == TypeId::of::<M>()
    }

    /// Returns the type of the event.
    pub fn message_type(&self) -> TypeId {
        self.message_type
    }

    /// Downcasts the box to an concrete message.
    pub fn downcast<M: Any>(self) -> Result<M, String> {
        if self.message_type == TypeId::of::<M>() {
            return Ok(*self.message.downcast::<M>().unwrap());
        }

        Err("Wrong message type".to_string())
    }

    /// Downcasts the box as reference of an concrete message.
    pub fn downcast_ref<M: Any>(&self) -> Result<&M, String> {
        if self.message_type == TypeId::of::<M>() {
            return Ok(&*self.message.downcast_ref::<M>().unwrap());
        }

        Err("Wrong message type".to_string())
    }
}

/// The `MessageAdapter` provides a thread save entry point to sent
/// and read messages inside widget entities. They are processed inside the
/// method `message` defined in each widgets `State` code.
///
/// # Example
///
/// ```rust
/// // State
/// fn say_hello(entity: Entity, message_adapter: MessageAdapter) {
///     message_adapter.send_message(String::from("Hello rustician"), entity);
///     message_adapter.send_message(String::from("Did you recieve my message?"), entity);
/// }
///
/// impl MyState {}
///
/// // implementation for the State
/// impl State for MyState {
///     fn message(&mut self, mut messages: MessageReader, _registry: &mut Registry, _ctx: &mut Context) {
///         for message in messages.read::<String>() {
///             println!("{}", message);
///         }
///     }
/// }
/// ```
///
/// The example code snippet above will print two lines to stdout:
///
/// ```text
/// $ Hello rustician,
/// $  Did you receive my message?
/// ```
#[derive(Clone, Debug)]
pub struct MessageAdapter {
    messages: Arc<Mutex<BTreeMap<Entity, HashMap<TypeId, Vec<MessageBox>>>>>,
    window_sender: mpsc::Sender<WindowRequest>,
}

impl MessageAdapter {
    /// Creates a new message adapter
    pub fn new(window_sender: mpsc::Sender<WindowRequest>) -> Self {
        MessageAdapter {
            messages: Arc::new(Mutex::new(BTreeMap::new())),
            window_sender,
        }
    }

    /// Send a new message to the message pipeline.
    pub fn send_message<M: Any + Send>(&self, message: M, target: Entity) {
        if !self.messages.lock().unwrap().contains_key(&target) {
            self.messages
                .lock()
                .expect("MessageAdapter::send_message: Cannot lock messages.")
                .insert(target, HashMap::new());
        }

        let type_id = TypeId::of::<M>();

        if !self
            .messages
            .lock()
            .expect("MessageAdapter::send_message: Cannot lock messages.")
            .get(&target)
            .unwrap()
            .contains_key(&type_id)
        {
            self.messages
                .lock()
                .expect("MessageAdapter::send_message: Cannot lock messages.")
                .get_mut(&target)
                .unwrap()
                .insert(type_id, vec![]);
        }

        self.messages
            .lock()
            .expect("MessageAdapter::send_message: Cannot lock messages.")
            .get_mut(&target)
            .unwrap()
            .get_mut(&type_id)
            .unwrap()
            .push(MessageBox::new(message, target));

        self.window_sender
            .send(WindowRequest::Redraw)
            .expect("MessageAdapter::send_message: Cannot send redraw request.");
    }

    /// Returns a list of entities that has messages.
    pub(crate) fn entities(&self) -> Vec<Entity> {
        self.messages
            .lock()
            .expect("MessageAdapter::entities: Cannot lock messages.")
            .keys()
            .cloned()
            .collect()
    }

    /// Removes all messages for the given target entity. This is used
    /// to remove messages for entities that does not have a `State`
    /// to read the messages.
    pub(crate) fn remove_message_for_entity(&self, target: Entity) {
        self.messages
            .lock()
            .expect("MessageAdapter::remove_message_for_entity: Cannot lock messages.")
            .remove(&target);
    }

    /// Returns the number of messages in the queue.
    pub fn len(&self) -> usize {
        self.messages
            .lock()
            .expect("MessageAdapter::len: Cannot lock messages.")
            .len()
    }

    /// Returns `true` if the event message contains no events.
    pub fn is_empty(&self) -> bool {
        self.messages
            .lock()
            .expect("MessageAdapter::is_empty: Cannot lock messages.")
            .is_empty()
    }

    /// Returns a message reader for the given entity. Moves all
    /// messages for the entity from the adapter to the reader.
    pub(crate) fn message_reader(&self, entity: Entity) -> MessageReader {
        let messages = if let Some(messages) = self
            .messages
            .lock()
            .expect("MessageAdapter::message_reader: Cannot lock messages.")
            .remove(&entity)
        {
            messages
        } else {
            HashMap::new()
        };

        MessageReader::new(messages, entity)
    }
}

/// The `MessageReader` is used to access the messages of a widget.
pub struct MessageReader {
    messages: HashMap<TypeId, Vec<MessageBox>>,
    target: Entity,
}

impl MessageReader {
    /// Creates a new message reader.
    pub fn new(messages: HashMap<TypeId, Vec<MessageBox>>, target: Entity) -> Self {
        MessageReader { messages, target }
    }

    /// Returns the target entity of the reader.
    pub fn entity(&self) -> Entity {
        self.target
    }

    /// Returns `true` if the reader contains message for the specified type.
    pub fn contains_type<M: Any>(&self) -> bool {
        self.messages.contains_key(&TypeId::of::<M>())
    }

    /// Returns `true` if the reader contains no messages.
    pub fn is_empty(&self) -> bool {
        self.messages.is_empty()
    }

    /// Returns a message iterator for the given message type.
    pub fn read<M: Any + Send>(&mut self) -> MessageIterator<M> {
        let messages = if let Some(messages) = self.messages.remove(&TypeId::of::<M>()) {
            messages
        } else {
            vec![]
        };

        MessageIterator::new(messages)
    }
}

/// Iterator of messages.
#[derive(Debug)]
pub struct MessageIterator<M>
where
    M: Any + Send,
{
    messages: Vec<MessageBox>,
    _phantom: PhantomData<M>,
}

impl<M> MessageIterator<M>
where
    M: Any + Send,
{
    pub(crate) fn new(messages: Vec<MessageBox>) -> Self {
        MessageIterator {
            messages,
            _phantom: PhantomData::default(),
        }
    }
}

impl<M> Iterator for MessageIterator<M>
where
    M: Any + Send,
{
    type Item = M;

    fn next(&mut self) -> Option<Self::Item> {
        if self.messages.is_empty() {
            return None;
        }

        // unwrap is ok because only messages of the same type should
        // be stored in the vec
        Some(self.messages.remove(0).downcast::<M>().unwrap())
    }
}
<commit_msg>Implementation of the method MessageAdapter.send_message is not thread safe. Make it thread safe.<commit_after>use std::{
    any::{Any, TypeId},
    collections::{BTreeMap, HashMap},
    marker::PhantomData,
    sync::{mpsc, Arc, Mutex},
};

use crate::shell::WindowRequest;

use dces::entity::Entity;

/// Internal wrapper that stores a message inside a box.
#[derive(Debug)]
pub struct MessageBox {
    message: Box<dyn Any + Send>,
    message_type: TypeId,
    target: Entity,
}

impl MessageBox {
    /// Creates a new `MessageBox`.
    pub fn new<M: Any + Send>(message: M, target: Entity) -> Self {
        MessageBox {
            message: Box::new(message),
            target,
            message_type: TypeId::of::<M>(),
        }
    }

    /// Check if the given type is the type of the message.
    pub fn is_type<M: Any>(&self) -> bool {
        self.message_type == TypeId::of::<M>()
    }

    /// Returns the type of the event.
    pub fn message_type(&self) -> TypeId {
        self.message_type
    }

    /// Downcasts the box to an concrete message.
    pub fn downcast<M: Any>(self) -> Result<M, String> {
        if self.message_type == TypeId::of::<M>() {
            return Ok(*self.message.downcast::<M>().unwrap());
        }

        Err("Wrong message type".to_string())
    }

    /// Downcasts the box as reference of an concrete message.
    pub fn downcast_ref<M: Any>(&self) -> Result<&M, String> {
        if self.message_type == TypeId::of::<M>() {
            return Ok(&*self.message.downcast_ref::<M>().unwrap());
        }

        Err("Wrong message type".to_string())
    }
}

/// The `MessageAdapter` provides a thread save entry point to sent
/// and read messages inside widget entities. They are processed inside the
/// method `message` defined in each widgets `State` code.
///
/// # Example
///
/// ```rust
/// // State
/// fn say_hello(entity: Entity, message_adapter: MessageAdapter) {
///     message_adapter.send_message(String::from("Hello rustician"), entity);
///     message_adapter.send_message(String::from("Did you recieve my message?"), entity);
/// }
///
/// impl MyState {}
///
/// // implementation for the State
/// impl State for MyState {
///     fn message(&mut self, mut messages: MessageReader, _registry: &mut Registry, _ctx: &mut Context) {
///         for message in messages.read::<String>() {
///             println!("{}", message);
///         }
///     }
/// }
/// ```
///
/// The example code snippet above will print two lines to stdout:
///
/// ```text
/// $ Hello rustician,
/// $  Did you receive my message?
/// ```
#[derive(Clone, Debug)]
pub struct MessageAdapter {
    messages: Arc<Mutex<BTreeMap<Entity, HashMap<TypeId, Vec<MessageBox>>>>>,
    window_sender: mpsc::Sender<WindowRequest>,
}

impl MessageAdapter {
    /// Creates a new message adapter
    pub fn new(window_sender: mpsc::Sender<WindowRequest>) -> Self {
        MessageAdapter {
            messages: Arc::new(Mutex::new(BTreeMap::new())),
            window_sender,
        }
    }

    /// Send a new message to the message pipeline.
    pub fn send_message<M: Any + Send>(&self, message: M, target: Entity) {
        // Docs say this method must be thread safe
        // to ensure thread safety,
        // do not release this lock until this method execution ends
        let mut locked_messages = self
            .messages
            .lock()
            .expect("MessageAdapter::send_message: Cannot lock messages.");
        locked_messages
            .entry(target)
            .or_insert_with(|| HashMap::new())
            .entry(TypeId::of::<M>())
            .or_insert_with(|| vec![])
            .push(MessageBox::new(message, target));

        self.window_sender
            .send(WindowRequest::Redraw)
            .expect("MessageAdapter::send_message: Cannot send redraw request.");
    }

    /// Returns a list of entities that has messages.
    pub(crate) fn entities(&self) -> Vec<Entity> {
        self.messages
            .lock()
            .expect("MessageAdapter::entities: Cannot lock messages.")
            .keys()
            .cloned()
            .collect()
    }

    /// Removes all messages for the given target entity. This is used
    /// to remove messages for entities that does not have a `State`
    /// to read the messages.
    pub(crate) fn remove_message_for_entity(&self, target: Entity) {
        self.messages
            .lock()
            .expect("MessageAdapter::remove_message_for_entity: Cannot lock messages.")
            .remove(&target);
    }

    /// Returns the number of messages in the queue.
    pub fn len(&self) -> usize {
        self.messages
            .lock()
            .expect("MessageAdapter::len: Cannot lock messages.")
            .len()
    }

    /// Returns `true` if the event message contains no events.
    pub fn is_empty(&self) -> bool {
        self.messages
            .lock()
            .expect("MessageAdapter::is_empty: Cannot lock messages.")
            .is_empty()
    }

    /// Returns a message reader for the given entity. Moves all
    /// messages for the entity from the adapter to the reader.
    pub(crate) fn message_reader(&self, entity: Entity) -> MessageReader {
        let messages = if let Some(messages) = self
            .messages
            .lock()
            .expect("MessageAdapter::message_reader: Cannot lock messages.")
            .remove(&entity)
        {
            messages
        } else {
            HashMap::new()
        };

        MessageReader::new(messages, entity)
    }
}

/// The `MessageReader` is used to access the messages of a widget.
pub struct MessageReader {
    messages: HashMap<TypeId, Vec<MessageBox>>,
    target: Entity,
}

impl MessageReader {
    /// Creates a new message reader.
    pub fn new(messages: HashMap<TypeId, Vec<MessageBox>>, target: Entity) -> Self {
        MessageReader { messages, target }
    }

    /// Returns the target entity of the reader.
    pub fn entity(&self) -> Entity {
        self.target
    }

    /// Returns `true` if the reader contains message for the specified type.
    pub fn contains_type<M: Any>(&self) -> bool {
        self.messages.contains_key(&TypeId::of::<M>())
    }

    /// Returns `true` if the reader contains no messages.
    pub fn is_empty(&self) -> bool {
        self.messages.is_empty()
    }

    /// Returns a message iterator for the given message type.
    pub fn read<M: Any + Send>(&mut self) -> MessageIterator<M> {
        let messages = if let Some(messages) = self.messages.remove(&TypeId::of::<M>()) {
            messages
        } else {
            vec![]
        };

        MessageIterator::new(messages)
    }
}

/// Iterator of messages.
#[derive(Debug)]
pub struct MessageIterator<M>
where
    M: Any + Send,
{
    messages: Vec<MessageBox>,
    _phantom: PhantomData<M>,
}

impl<M> MessageIterator<M>
where
    M: Any + Send,
{
    pub(crate) fn new(messages: Vec<MessageBox>) -> Self {
        MessageIterator {
            messages,
            _phantom: PhantomData::default(),
        }
    }
}

impl<M> Iterator for MessageIterator<M>
where
    M: Any + Send,
{
    type Item = M;

    fn next(&mut self) -> Option<Self::Item> {
        if self.messages.is_empty() {
            return None;
        }

        // unwrap is ok because only messages of the same type should
        // be stored in the vec
        Some(self.messages.remove(0).downcast::<M>().unwrap())
    }
}
<|endoftext|>