<commit_before>extern crate wtftw;

mod stack {
    use wtftw::core::Stack;
    #[test]
    fn from_element() {
        let stack = Stack::<u32>::from_element(42);
        assert!(stack.focus == 42);
        assert!(stack.up.is_empty());
        assert!(stack.down.is_empty());
    }

    #[test]
    fn add() {
        let stack1 = Stack::<u32>::from_element(42);
        let stack2 = stack1.add(23);

        assert!(stack2.down.head().unwrap() == &stack1.focus);
        assert!(stack2.focus == 23);
    }

    #[test]
    fn integrate() {
        let stack = Stack::<u32>::from_element(42);
        assert!(stack.integrate() == vec!(42));

        let stack2 : Stack<u32> = Stack {
            focus: 1,
            up: vec!(2, 3),
            down: vec!(4, 5)
        };
        assert!(stack2.integrate() == vec!(3, 2, 1, 4, 5));
    }

    #[test]
    fn filter_some() {
        let mut stack = Stack::<u32>::from_element(42);
        for i in range(0, 50) {
            stack = stack.add(2 * i + 1);
        }

        assert!(stack.filter(|&x| x % 2 == 0) == Some(Stack::<u32>::from_element(42)))
    }

    #[test]
    fn filter_none() {
        let mut stack = Stack::<u32>::from_element(43);
        for i in range(0, 50) {
            stack = stack.add(2 * i + 1);
        }

        assert!(stack.filter(|&x| x % 2 == 0) == None)
    }

    #[test]
    fn len() {
        let mut stack = Stack::<u32>::from_element(100);
        for i in range(0, 50) {
            stack = stack.add(i);
        }
        assert!(stack.len() == 51);
    }

    #[test]
    fn contains() {
        let stack = Stack::<u32>::from_element(42);
        assert!( stack.contains(42));
        assert!(!stack.contains(23));
    }
}

mod workspace {
    use wtftw::core::Stack;
    use wtftw::core::Workspace;

    #[test]
    fn new() {
        let stack = Stack::<u64>::from_element(42);
        let workspace = Workspace::new(42, String::from_str("test"), String::from_str("tall"), Some(stack));

        assert!(workspace.id == 42);
    }

    #[test]
    fn windows_some() {
        let stack = Stack::<u64>::from_element(42);
        let workspace = Workspace::new(42, String::from_str("test"), String::from_str("tall"), Some(stack.clone()));

        assert!(workspace.windows() == stack.integrate())
    }

    #[test]
    fn windows_none() {
        let workspace = Workspace::new(42, String::from_str("test"), String::from_str("tall"), None);
        assert!(workspace.windows() == Vec::new())
    }
}

mod screen {
    #[test]
    fn new() {
    }
}
<commit_msg>removed tests from main<commit_after><|endoftext|>


<commit_before>extern crate regex;
extern crate toml;

use self::regex::Error as RegexError;
use self::toml::ParserError as ParseTomlError;

use constant::{self, ME};
use std::num::ParseIntError;
use std::error::Error;
use std::fmt::{Display, Formatter, Result as FmtResult};
use std::io::Error as IoError;

#[derive(Debug)]
pub enum CliError {
    CannotHappen(CannotHappenError),
    Config(ConfigError),
    Cron(CronError),
    Essential(EssentialLack),
    Io(IoError),
    ParseInt(ParseIntError),
    ParseToml(ParseTomlError),
    Regex(RegexError),
    RunningPlace(RunningPlaceError),
    Usage(Usage),
}
impl Display for CliError {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match *self {
            CliError::CannotHappen(ref e) => e.fmt(f),
            CliError::Config(ref e)       => e.fmt(f),
            CliError::Cron(ref e)         => e.fmt(f),
            CliError::Essential(ref e)    => e.fmt(f),
            CliError::Io(ref e)           => e.fmt(f),
            CliError::ParseInt(ref e)     => e.fmt(f),
            CliError::ParseToml(ref e)    => e.fmt(f),
            CliError::Regex(ref e)        => e.fmt(f),
            CliError::RunningPlace(ref e) => e.fmt(f),
            CliError::Usage(ref u)        => u.fmt(f),
        }
    }
}
impl Error for CliError {
    fn cause(&self) -> Option<&Error> {
        match *self {
            CliError::CannotHappen(ref e) => Some(e),
            CliError::Config(ref e)       => Some(e),
            CliError::Cron(ref e)         => Some(e),
            CliError::Essential(ref e)    => Some(e),
            CliError::Io(ref e)           => Some(e),
            CliError::ParseInt(ref e)     => Some(e),
            CliError::ParseToml(ref e)    => Some(e),
            CliError::Regex(ref e)        => Some(e),
            CliError::RunningPlace(ref e) => Some(e),
            CliError::Usage(ref u)        => Some(u),
        }
    }

    fn description(&self) -> &str {
        match *self {
            CliError::CannotHappen(ref e) => e.description(),
            CliError::Config(ref e)       => e.description(),
            CliError::Cron(ref e)         => e.description(),
            CliError::Essential(ref e)    => e.description(),
            CliError::Io(ref e)           => e.description(),
            CliError::ParseInt(ref e)     => e.description(),
            CliError::ParseToml(ref e)    => e.description(),
            CliError::Regex(ref e)        => e.description(),
            CliError::RunningPlace(ref e) => e.description(),
            CliError::Usage(ref u)        => u.description(),
        }
    }
}
impl From<CannotHappenError> for CliError {
    fn from(e: CannotHappenError) -> CliError {
        CliError::CannotHappen(e)
    }
}
impl From<ConfigError> for CliError {
    fn from(e: ConfigError) -> CliError {
        CliError::Config(e)
    }
}
impl From<CronError> for CliError {
    fn from(e: CronError) -> CliError {
        CliError::Cron(e)
    }
}
impl From<EssentialLack> for CliError {
    fn from(e: EssentialLack) -> CliError {
        CliError::Essential(e)
    }
}
impl From<IoError> for CliError {
    fn from(e: IoError) -> CliError {
        CliError::Io(e)
    }
}
impl From<ParseIntError> for CliError {
    fn from(e: ParseIntError) -> CliError {
        CliError::ParseInt(e)
    }
}
impl From<ParseTomlError> for CliError {
    fn from(e: ParseTomlError) -> CliError {
        CliError::ParseToml(e)
    }
}
impl From<RegexError> for CliError {
    fn from(e: RegexError) -> CliError {
        CliError::Regex(e)
    }
}
impl From<RunningPlaceError> for CliError {
    fn from(e: RunningPlaceError) -> CliError {
        CliError::RunningPlace(e)
    }
}
impl From<Usage> for CliError {
    fn from(u: Usage) -> CliError {
        CliError::Usage(u)
    }
}

#[derive(Debug, PartialEq)]
pub struct CannotHappenError;
impl Display for CannotHappenError {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "Cannot happen")
    }
}
impl Error for CannotHappenError {
    fn description(&self) -> &str { "cannot happen" }
}

#[derive(Debug, PartialEq)]
pub enum ConfigErrorKind {
    Something,
    InvalidKey,
    NonStringValue,
    NotFoundBurnAfter,
    BurnAfter,
    SweepPeriod,
    SweepTime,
}
#[derive(Debug, PartialEq)]
pub struct ConfigError {
    kind: ConfigErrorKind,
}
impl ConfigError {
    pub fn new(kind: ConfigErrorKind) -> ConfigError {
        ConfigError { kind: kind }
    }
}
impl Display for ConfigError {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{}", match self.kind {
            ConfigErrorKind::Something         => r#"Something went to wrong"#,
            ConfigErrorKind::InvalidKey        => r#"Cannot set this key"#,
            ConfigErrorKind::NonStringValue    => r#"Please set values as "String""#,
            ConfigErrorKind::NotFoundBurnAfter => r#"Please set [burn]after param"#,
            ConfigErrorKind::BurnAfter         => r#"Please set value like "3days" or "1week" as "[burn]after""#,
            ConfigErrorKind::SweepPeriod       => r#"Please set "daily" or "weekly" as "[sweep]period""#,
            ConfigErrorKind::SweepTime         => r#"Please set value from "00:00" to "23:59" as "[sweep]time""#,
        })
    }
}
impl Error for ConfigError {
    fn description(&self) -> &str { "invalid parameters" }
}

#[derive(Debug, PartialEq)]
pub enum CronErrorKind {
    IncludingInvalidCharacters,
    FailedToWrite,
}
#[derive(Debug, PartialEq)]
pub struct CronError {
    kind: CronErrorKind,
}
impl CronError {
    pub fn new(kind: CronErrorKind) -> Self {
        CronError { kind: kind }
    }
}
impl Display for CronError {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{}", match self.kind {
            CronErrorKind::IncludingInvalidCharacters => "The characters which are not UTF-8 may be mixed in the \"cron\" file",
            CronErrorKind::FailedToWrite              => "Failed to write new \"cron\" file"
        })
    }
}
impl Error for CronError {
    fn description(&self) -> &str { "problems around cron" }
}

#[derive(Debug, PartialEq)]
pub enum EssentialKind {
    WorkingDir,
    StorageDir,
    ConfigFile,
    IgnoreFile,
}
#[derive(Debug, PartialEq)]
pub struct EssentialLack {
    what: EssentialKind,
}
impl EssentialLack {
    pub fn new(what: EssentialKind) -> EssentialLack {
        EssentialLack { what: what }
    }
}
impl Display for EssentialLack {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{} does not exist. Please use \"init\" command", match self.what {
            EssentialKind::WorkingDir => format!("\"{}\" directory", constant::WORKING_DIR_NAME),
            EssentialKind::StorageDir => format!("\"{}\" directory", constant::STORAGE_DIR_NAME),
            EssentialKind::ConfigFile => format!("\"{}\" file"     , constant::CONFIG_FILE_NAME),
            EssentialKind::IgnoreFile => format!("\"{}\" file"     , constant::IGNORE_FILE_NAME),
        })
    }
}
impl Error for EssentialLack {
    fn description(&self) -> &str { "essential file does not exist" }
}

#[derive(Debug, PartialEq)]
pub struct RunningPlaceError {
    dir: String,
}
impl RunningPlaceError {
    pub fn new(dir: String) -> RunningPlaceError {
        RunningPlaceError { dir: dir }
    }
}
impl Display for RunningPlaceError {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "Cannot run in \"{}\" directory", self.dir)
    }
}
impl Error for RunningPlaceError {
    fn description(&self) -> &str { "cannot run in banned directories" }
}

#[derive(Debug, PartialEq)]
pub enum UsageKind {
    Nothing,
    Init,
    Config,
    Ignore,
    Sweep,
    Burn,
    Start,
    End,
    Destroy,
}
impl UsageKind {
    fn command(&self) -> &str {
        match *self {
            UsageKind::Nothing => "<Command>",
            UsageKind::Init    => "init",
            UsageKind::Config  => "config",
            UsageKind::Ignore  => "ignore",
            UsageKind::Sweep   => "sweep",
            UsageKind::Burn    => "burn",
            UsageKind::Start   => "start",
            UsageKind::End     => "end",
            UsageKind::Destroy => "destroy",
        }
    }

    fn common_usage(&self) -> String {
        format!("{} {} [Option]", ME, self.command())
    }

    fn usages(&self) -> Vec<String> {
        match *self {
            UsageKind::Config => {
                vec![
                    format!("{} set <Key> <Value>", self.common_usage()),
                    format!("{} init"             , self.common_usage()),
                ]
            },
            UsageKind::Ignore => {
                vec![
                    format!("{} add <File> ..."   , self.common_usage()),
                    format!("{} remove <File> ...", self.common_usage()),
                    format!("{} current"          , self.common_usage()),
                    format!("{} clear"            , self.common_usage()),
                ]
            },
            _ => vec![self.common_usage()],
        }
    }

    fn description(&self) -> &str {
        match *self {
            UsageKind::Nothing => "Keep your directories clean!",
            UsageKind::Init    => "Register current directory.",
            UsageKind::Config  => "Change parameter.",
            UsageKind::Ignore  => "Change \"non-dust\" file's list.",
            UsageKind::Sweep   => "Sweep \"dust\" files and empty directories in current directory.",
            UsageKind::Burn    => "Burn \"sweeped\" files.",
            UsageKind::Start   => "Register with \"cron\" for autonomous operation.",
            UsageKind::End     => "Unregister from \"cron\".",
            UsageKind::Destroy => "Unregister current directory.",
        }
    }

    fn sub_descriptions(&self) -> Vec<String> {
        match *self {
            UsageKind::Nothing => {
                vec![
                    format!("{}{}", "init    # ", UsageKind::Init   .description()),
                    format!("{}{}", "config  # ", UsageKind::Config .description()),
                    format!("{}{}", "ignore  # ", UsageKind::Ignore .description()),
                    format!("{}{}", "sweep   # ", UsageKind::Sweep  .description()),
                    format!("{}{}", "burn    # ", UsageKind::Burn   .description()),
                    format!("{}{}", "start   # ", UsageKind::Start  .description()),
                    format!("{}{}", "end     # ", UsageKind::End    .description()),
                    format!("{}{}", "destroy # ", UsageKind::Destroy.description()),
                ]
            },
            UsageKind::Config => {
                vec![
                    "set  # Set parameter"       .to_string(),
                    "init # Initialize configure".to_string(),
                ]
            },
            UsageKind::Ignore => {
                let file_expression = "\"non-dust\" file's list";
                vec![
                    format!("add     # Add specified files to {}"        , file_expression),
                    format!("remove  # Remove specified files from {}"   , file_expression),
                    format!("current # Replace {} with current all files", file_expression),
                    format!("clear   # Clear {}"                         , file_expression),
                ]
            },
            _ => Vec::new(),
        }
    }
}

#[derive(Debug, PartialEq)]
pub struct Usage {
    kind: UsageKind,
}
impl Usage {
    pub fn new(kind: UsageKind) -> Usage {
        Usage { kind: kind }
    }

    fn message(&self) -> String {
        let common = format!(
"Option:
    -h|--help    # Display help message.
    -v|--version # Display software version.

Description:
    {}
",
            self.kind.description(),
        );

        let usage = self.kind
            .usages()
            .iter()
            .fold(String::new(), |message, line| {
                message + "    " + line + "\n"
            });

        let main = format!("Usage:\n{}\n{}", usage, common);

        let sub_description = self.kind
            .sub_descriptions()
            .iter()
            .fold(String::new(), |message, line| {
                message + "    " + line + "\n"
            });

        if sub_description.is_empty() {
            main
        } else {
            format!("{}{}{}", main, "\nCommand:\n", sub_description)
        }
    }
}
impl Display for Usage {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{}", self.message())
    }
}
impl Error for Usage {
    fn description(&self) -> &str { "show usage" }
}
<commit_msg>[Remedy] Fix error message for preventing accident<commit_after>extern crate regex;
extern crate toml;

use self::regex::Error as RegexError;
use self::toml::ParserError as ParseTomlError;

use constant::{self, ME};
use std::num::ParseIntError;
use std::error::Error;
use std::fmt::{Display, Formatter, Result as FmtResult};
use std::io::Error as IoError;

#[derive(Debug)]
pub enum CliError {
    CannotHappen(CannotHappenError),
    Config(ConfigError),
    Cron(CronError),
    Essential(EssentialLack),
    Io(IoError),
    ParseInt(ParseIntError),
    ParseToml(ParseTomlError),
    Regex(RegexError),
    RunningPlace(RunningPlaceError),
    Usage(Usage),
}
impl Display for CliError {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match *self {
            CliError::CannotHappen(ref e) => e.fmt(f),
            CliError::Config(ref e)       => e.fmt(f),
            CliError::Cron(ref e)         => e.fmt(f),
            CliError::Essential(ref e)    => e.fmt(f),
            CliError::Io(ref e)           => e.fmt(f),
            CliError::ParseInt(ref e)     => e.fmt(f),
            CliError::ParseToml(ref e)    => e.fmt(f),
            CliError::Regex(ref e)        => e.fmt(f),
            CliError::RunningPlace(ref e) => e.fmt(f),
            CliError::Usage(ref u)        => u.fmt(f),
        }
    }
}
impl Error for CliError {
    fn cause(&self) -> Option<&Error> {
        match *self {
            CliError::CannotHappen(ref e) => Some(e),
            CliError::Config(ref e)       => Some(e),
            CliError::Cron(ref e)         => Some(e),
            CliError::Essential(ref e)    => Some(e),
            CliError::Io(ref e)           => Some(e),
            CliError::ParseInt(ref e)     => Some(e),
            CliError::ParseToml(ref e)    => Some(e),
            CliError::Regex(ref e)        => Some(e),
            CliError::RunningPlace(ref e) => Some(e),
            CliError::Usage(ref u)        => Some(u),
        }
    }

    fn description(&self) -> &str {
        match *self {
            CliError::CannotHappen(ref e) => e.description(),
            CliError::Config(ref e)       => e.description(),
            CliError::Cron(ref e)         => e.description(),
            CliError::Essential(ref e)    => e.description(),
            CliError::Io(ref e)           => e.description(),
            CliError::ParseInt(ref e)     => e.description(),
            CliError::ParseToml(ref e)    => e.description(),
            CliError::Regex(ref e)        => e.description(),
            CliError::RunningPlace(ref e) => e.description(),
            CliError::Usage(ref u)        => u.description(),
        }
    }
}
impl From<CannotHappenError> for CliError {
    fn from(e: CannotHappenError) -> CliError {
        CliError::CannotHappen(e)
    }
}
impl From<ConfigError> for CliError {
    fn from(e: ConfigError) -> CliError {
        CliError::Config(e)
    }
}
impl From<CronError> for CliError {
    fn from(e: CronError) -> CliError {
        CliError::Cron(e)
    }
}
impl From<EssentialLack> for CliError {
    fn from(e: EssentialLack) -> CliError {
        CliError::Essential(e)
    }
}
impl From<IoError> for CliError {
    fn from(e: IoError) -> CliError {
        CliError::Io(e)
    }
}
impl From<ParseIntError> for CliError {
    fn from(e: ParseIntError) -> CliError {
        CliError::ParseInt(e)
    }
}
impl From<ParseTomlError> for CliError {
    fn from(e: ParseTomlError) -> CliError {
        CliError::ParseToml(e)
    }
}
impl From<RegexError> for CliError {
    fn from(e: RegexError) -> CliError {
        CliError::Regex(e)
    }
}
impl From<RunningPlaceError> for CliError {
    fn from(e: RunningPlaceError) -> CliError {
        CliError::RunningPlace(e)
    }
}
impl From<Usage> for CliError {
    fn from(u: Usage) -> CliError {
        CliError::Usage(u)
    }
}

#[derive(Debug, PartialEq)]
pub struct CannotHappenError;
impl Display for CannotHappenError {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "Cannot happen")
    }
}
impl Error for CannotHappenError {
    fn description(&self) -> &str { "cannot happen" }
}

#[derive(Debug, PartialEq)]
pub enum ConfigErrorKind {
    Something,
    InvalidKey,
    NonStringValue,
    NotFoundBurnAfter,
    BurnAfter,
    SweepPeriod,
    SweepTime,
}
#[derive(Debug, PartialEq)]
pub struct ConfigError {
    kind: ConfigErrorKind,
}
impl ConfigError {
    pub fn new(kind: ConfigErrorKind) -> ConfigError {
        ConfigError { kind: kind }
    }
}
impl Display for ConfigError {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{}", match self.kind {
            ConfigErrorKind::Something         => r#"Something went to wrong"#,
            ConfigErrorKind::InvalidKey        => r#"Cannot set this key"#,
            ConfigErrorKind::NonStringValue    => r#"Please set values as "String""#,
            ConfigErrorKind::NotFoundBurnAfter => r#"Please set [burn]after param"#,
            ConfigErrorKind::BurnAfter         => r#"Please set value like "3days" or "1week" as "[burn]after""#,
            ConfigErrorKind::SweepPeriod       => r#"Please set "daily" or "weekly" as "[sweep]period""#,
            ConfigErrorKind::SweepTime         => r#"Please set value from "00:00" to "23:59" as "[sweep]time""#,
        })
    }
}
impl Error for ConfigError {
    fn description(&self) -> &str { "invalid parameters" }
}

#[derive(Debug, PartialEq)]
pub enum CronErrorKind {
    IncludingInvalidCharacters,
    FailedToWrite,
}
#[derive(Debug, PartialEq)]
pub struct CronError {
    kind: CronErrorKind,
}
impl CronError {
    pub fn new(kind: CronErrorKind) -> Self {
        CronError { kind: kind }
    }
}
impl Display for CronError {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{}", match self.kind {
            CronErrorKind::IncludingInvalidCharacters => "The characters which are not UTF-8 may be mixed in the \"cron\" file",
            CronErrorKind::FailedToWrite              => "Failed to write new \"cron\" file"
        })
    }
}
impl Error for CronError {
    fn description(&self) -> &str { "problems around cron" }
}

#[derive(Debug, PartialEq)]
pub enum EssentialKind {
    WorkingDir,
    StorageDir,
    ConfigFile,
    IgnoreFile,
}
#[derive(Debug, PartialEq)]
pub struct EssentialLack {
    what: EssentialKind,
}
impl EssentialLack {
    pub fn new(what: EssentialKind) -> EssentialLack {
        EssentialLack { what: what }
    }
}
impl Display for EssentialLack {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{} does not exist", match self.what {
            EssentialKind::WorkingDir => format!("\"{}\" directory", constant::WORKING_DIR_NAME),
            EssentialKind::StorageDir => format!("\"{}\" directory", constant::STORAGE_DIR_NAME),
            EssentialKind::ConfigFile => format!("\"{}\" file"     , constant::CONFIG_FILE_NAME),
            EssentialKind::IgnoreFile => format!("\"{}\" file"     , constant::IGNORE_FILE_NAME),
        })
    }
}
impl Error for EssentialLack {
    fn description(&self) -> &str { "essential file does not exist" }
}

#[derive(Debug, PartialEq)]
pub struct RunningPlaceError {
    dir: String,
}
impl RunningPlaceError {
    pub fn new(dir: String) -> RunningPlaceError {
        RunningPlaceError { dir: dir }
    }
}
impl Display for RunningPlaceError {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "Cannot run in \"{}\" directory", self.dir)
    }
}
impl Error for RunningPlaceError {
    fn description(&self) -> &str { "cannot run in banned directories" }
}

#[derive(Debug, PartialEq)]
pub enum UsageKind {
    Nothing,
    Init,
    Config,
    Ignore,
    Sweep,
    Burn,
    Start,
    End,
    Destroy,
}
impl UsageKind {
    fn command(&self) -> &str {
        match *self {
            UsageKind::Nothing => "<Command>",
            UsageKind::Init    => "init",
            UsageKind::Config  => "config",
            UsageKind::Ignore  => "ignore",
            UsageKind::Sweep   => "sweep",
            UsageKind::Burn    => "burn",
            UsageKind::Start   => "start",
            UsageKind::End     => "end",
            UsageKind::Destroy => "destroy",
        }
    }

    fn common_usage(&self) -> String {
        format!("{} {} [Option]", ME, self.command())
    }

    fn usages(&self) -> Vec<String> {
        match *self {
            UsageKind::Config => {
                vec![
                    format!("{} set <Key> <Value>", self.common_usage()),
                    format!("{} init"             , self.common_usage()),
                ]
            },
            UsageKind::Ignore => {
                vec![
                    format!("{} add <File> ..."   , self.common_usage()),
                    format!("{} remove <File> ...", self.common_usage()),
                    format!("{} current"          , self.common_usage()),
                    format!("{} clear"            , self.common_usage()),
                ]
            },
            _ => vec![self.common_usage()],
        }
    }

    fn description(&self) -> &str {
        match *self {
            UsageKind::Nothing => "Keep your directories clean!",
            UsageKind::Init    => "Register current directory.",
            UsageKind::Config  => "Change parameter.",
            UsageKind::Ignore  => "Change \"non-dust\" file's list.",
            UsageKind::Sweep   => "Sweep \"dust\" files and empty directories in current directory.",
            UsageKind::Burn    => "Burn \"sweeped\" files.",
            UsageKind::Start   => "Register with \"cron\" for autonomous operation.",
            UsageKind::End     => "Unregister from \"cron\".",
            UsageKind::Destroy => "Unregister current directory.",
        }
    }

    fn sub_descriptions(&self) -> Vec<String> {
        match *self {
            UsageKind::Nothing => {
                vec![
                    format!("{}{}", "init    # ", UsageKind::Init   .description()),
                    format!("{}{}", "config  # ", UsageKind::Config .description()),
                    format!("{}{}", "ignore  # ", UsageKind::Ignore .description()),
                    format!("{}{}", "sweep   # ", UsageKind::Sweep  .description()),
                    format!("{}{}", "burn    # ", UsageKind::Burn   .description()),
                    format!("{}{}", "start   # ", UsageKind::Start  .description()),
                    format!("{}{}", "end     # ", UsageKind::End    .description()),
                    format!("{}{}", "destroy # ", UsageKind::Destroy.description()),
                ]
            },
            UsageKind::Config => {
                vec![
                    "set  # Set parameter"       .to_string(),
                    "init # Initialize configure".to_string(),
                ]
            },
            UsageKind::Ignore => {
                let file_expression = "\"non-dust\" file's list";
                vec![
                    format!("add     # Add specified files to {}"        , file_expression),
                    format!("remove  # Remove specified files from {}"   , file_expression),
                    format!("current # Replace {} with current all files", file_expression),
                    format!("clear   # Clear {}"                         , file_expression),
                ]
            },
            _ => Vec::new(),
        }
    }
}

#[derive(Debug, PartialEq)]
pub struct Usage {
    kind: UsageKind,
}
impl Usage {
    pub fn new(kind: UsageKind) -> Usage {
        Usage { kind: kind }
    }

    fn message(&self) -> String {
        let common = format!(
"Option:
    -h|--help    # Display help message.
    -v|--version # Display software version.

Description:
    {}
",
            self.kind.description(),
        );

        let usage = self.kind
            .usages()
            .iter()
            .fold(String::new(), |message, line| {
                message + "    " + line + "\n"
            });

        let main = format!("Usage:\n{}\n{}", usage, common);

        let sub_description = self.kind
            .sub_descriptions()
            .iter()
            .fold(String::new(), |message, line| {
                message + "    " + line + "\n"
            });

        if sub_description.is_empty() {
            main
        } else {
            format!("{}{}{}", main, "\nCommand:\n", sub_description)
        }
    }
}
impl Display for Usage {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{}", self.message())
    }
}
impl Error for Usage {
    fn description(&self) -> &str { "show usage" }
}
<|endoftext|>


<commit_before>/// Error types

use thiserror::Error;

pub type Result<T> = ::std::result::Result<T, Error>;

#[derive(Debug, Error)]
pub enum Error {
    #[cfg(feature = "typed")]
    #[error("{}", _0)]
    TomlSerialize(#[from] ::toml::ser::Error),

    #[cfg(feature = "typed")]
    #[error("{}", _0)]
    TomlDeserialize(#[from] ::toml::de::Error),

    // Errors for tokenizer
    #[error("Parsing the query '{0}' failed")]
    QueryParsingError(String),

    #[error("The query on the TOML is empty")]
    EmptyQueryError,

    #[error("The passed query has an empty identifier")]
    EmptyIdentifier,

    #[error("The passed query tries to access an array but does not specify the index")]
    ArrayAccessWithoutIndex,

    #[error("The passed query tries to access an array but does not specify a valid index")]
    ArrayAccessWithInvalidIndex,

    // Errors for Resolver
    #[error("The identfier '{0}' is not present in the document")]
    IdentifierNotFoundInDocument(String),

    #[error("Got an index query '[{0}]' but have table")]
    NoIndexInTable(usize),

    #[error("Got an identifier query '{0}' but have array")]
    NoIdentifierInArray(String),

    #[error("Got an identifier query '{0}' but have value")]
    QueryingValueAsTable(String),

    #[error("Got an index query '{0}' but have value")]
    QueryingValueAsArray(usize),

    #[error("Cannot delete table '{0:?}' which is not empty")]
    CannotDeleteNonEmptyTable(Option<String>),

    #[error("Cannot delete array '{0:?}' which is not empty")]
    CannotDeleteNonEmptyArray(Option<String>),

    #[error("Cannot access {0} because expected {1}")]
    CannotAccessBecauseTypeMismatch(&'static str, &'static str),

    #[error("Cannot delete in array at {0}, array has length {1}")]
    ArrayIndexOutOfBounds(usize, usize),

    #[error("Cannot access array at {0}, array has length {1}")]
    IndexOutOfBounds(usize, usize),

    #[error("Type Error. Requested {0}, but got {1}")]
    TypeError(&'static str, &'static str),

    #[error("Value at '{0}' not there")]
    NotAvailable(String),
}
<commit_msg>Fix comment: This is a module comment<commit_after>//! Error types

use thiserror::Error;

pub type Result<T> = ::std::result::Result<T, Error>;

#[derive(Debug, Error)]
pub enum Error {
    #[cfg(feature = "typed")]
    #[error("{}", _0)]
    TomlSerialize(#[from] ::toml::ser::Error),

    #[cfg(feature = "typed")]
    #[error("{}", _0)]
    TomlDeserialize(#[from] ::toml::de::Error),

    // Errors for tokenizer
    #[error("Parsing the query '{0}' failed")]
    QueryParsingError(String),

    #[error("The query on the TOML is empty")]
    EmptyQueryError,

    #[error("The passed query has an empty identifier")]
    EmptyIdentifier,

    #[error("The passed query tries to access an array but does not specify the index")]
    ArrayAccessWithoutIndex,

    #[error("The passed query tries to access an array but does not specify a valid index")]
    ArrayAccessWithInvalidIndex,

    // Errors for Resolver
    #[error("The identfier '{0}' is not present in the document")]
    IdentifierNotFoundInDocument(String),

    #[error("Got an index query '[{0}]' but have table")]
    NoIndexInTable(usize),

    #[error("Got an identifier query '{0}' but have array")]
    NoIdentifierInArray(String),

    #[error("Got an identifier query '{0}' but have value")]
    QueryingValueAsTable(String),

    #[error("Got an index query '{0}' but have value")]
    QueryingValueAsArray(usize),

    #[error("Cannot delete table '{0:?}' which is not empty")]
    CannotDeleteNonEmptyTable(Option<String>),

    #[error("Cannot delete array '{0:?}' which is not empty")]
    CannotDeleteNonEmptyArray(Option<String>),

    #[error("Cannot access {0} because expected {1}")]
    CannotAccessBecauseTypeMismatch(&'static str, &'static str),

    #[error("Cannot delete in array at {0}, array has length {1}")]
    ArrayIndexOutOfBounds(usize, usize),

    #[error("Cannot access array at {0}, array has length {1}")]
    IndexOutOfBounds(usize, usize),

    #[error("Type Error. Requested {0}, but got {1}")]
    TypeError(&'static str, &'static str),

    #[error("Value at '{0}' not there")]
    NotAvailable(String),
}
<|endoftext|>


<commit_before>//! Error types for screeps-api.
extern crate hyper;
extern crate serde_json;

use self::ErrorType::*;
use std::error::Error as StdError;
use std::fmt;
use std::io;
use std::marker;

#[derive(Debug)]
/// Possible error types for library errors.
pub enum ErrorType {
    /// Unauthorized access. This is caused by either attempting to access a login-only endpoint without a token,
    /// attempting to access a login-only endpoint with an expired token, or providing incorrect login details to the
    /// login endpoint.
    Unauthorized,
    /// Error parsing a server response. This is most likely caused by the server providing unparsable JSON, but it
    /// could also be the server's API response structure has changed and no longer matches the expected data structure.
    SerdeJson(serde_json::error::Error),
    /// Error connecting to the server, or error parsing a URL provided.
    Hyper(hyper::error::Error),
    /// IO error.
    Io(io::Error),
    /// Error for when the server responds with a non-success status code.
    StatusCode(hyper::status::StatusCode),
    /// API Error. Either missing fields in the response that were expected, or the API did not include the regular
    /// `"ok": 1` which indicates success.
    Api(ApiError),
    /// A marker variant that tells the compiler that users of this enum cannot match it exhaustively.
    #[doc(hidden)]
    __Nonexhaustive,
}

/// Error deriving from some API call.
#[derive(Debug)]
pub struct Error {
    /// The type specifying what kind of error, and a detailed description if available.
    pub err: ErrorType,
    /// The whole URL which was being accessed when this error occurred (not included for URL parsing errors).
    pub url: Option<hyper::Url>,
    /// The json data from the request which resulted in this error (not included for URL or JSON parsing errors).
    pub json: Option<serde_json::Value>,
    /// Phantom data in order to allow adding any additional fields in the future.
    #[doc(hidden)]
    pub _phantom: marker::PhantomData<()>,
}

impl Error {
    /// Creates a new error from the given error and the given possible url.
    pub fn with_url<T: Into<Error>>(err: T, url: Option<hyper::Url>) -> Error { Error::with_json(err, url, None) }
    /// Creates a new error from the given error, the given possible url, and the given possible JSON data.
    pub fn with_json<T: Into<Error>>(err: T, url: Option<hyper::Url>, json: Option<serde_json::Value>) -> Error {
        let err = err.into();
        Error {
            err: err.err,
            url: url.or(err.url),
            json: json.or(err.json),
            _phantom: marker::PhantomData,
        }
    }
}

/// Result type for screeps API operations.
pub type Result<T> = ::std::result::Result<T, Error>;

impl From<ErrorType> for Error {
    fn from(err: ErrorType) -> Error {
        Error {
            err: err,
            url: None,
            json: None,
            _phantom: marker::PhantomData,
        }
    }
}

impl From<serde_json::error::Error> for Error {
    fn from(err: serde_json::error::Error) -> Error { ErrorType::SerdeJson(err).into() }
}

impl From<hyper::error::Error> for Error {
    fn from(err: hyper::error::Error) -> Error { ErrorType::Hyper(err).into() }
}

impl From<hyper::error::ParseError> for Error {
    fn from(err: hyper::error::ParseError) -> Error { ErrorType::Hyper(hyper::Error::Uri(err)).into() }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error { ErrorType::Io(err).into() }
}

impl From<hyper::status::StatusCode> for Error {
    fn from(code: hyper::status::StatusCode) -> Error {
        (if code == hyper::status::StatusCode::Unauthorized {
                ErrorType::Unauthorized
            } else {
                ErrorType::StatusCode(code)
            })
            .into()
    }
}

impl From<ApiError> for Error {
    fn from(err: ApiError) -> Error { ErrorType::Api(err).into() }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.err {
            SerdeJson(ref err) => fmt::Display::fmt(err, f)?,
            Hyper(ref err) => fmt::Display::fmt(err, f)?,
            Io(ref err) => fmt::Display::fmt(err, f)?,
            StatusCode(ref status) => fmt::Display::fmt(status, f)?,
            Api(ref err) => fmt::Display::fmt(err, f)?,
            Unauthorized => {
                write!(f,
                       "access not authorized: token expired, username/password
                       incorrect or no login provided")?;
            }
            ErrorType::__Nonexhaustive => unreachable!(),
        }
        if let Some(ref url) = self.url {
            write!(f, " | at url '{}'", url)?;
        }
        if let Some(ref json) = self.json {
            write!(f, " | return json: '{}'", json)?;
        }
        Ok(())
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match self.err {
            SerdeJson(ref err) => err.description(),
            Hyper(ref err) => err.description(),
            Io(ref err) => err.description(),
            StatusCode(ref status) => {
                match status.canonical_reason() {
                    Some(reason) => reason,
                    None => {
                        use hyper::status::StatusClass::*;
                        match status.class() {
                            Informational => "status code error: informational",
                            Success => "status code error: success",
                            Redirection => "status code error: redirection",
                            ClientError => "status code error: client error",
                            ServerError => "status code error: server error",
                            NoClass => "status code error: strange status",
                        }
                    }
                }
            }
            Api(ref err) => err.description(),
            Unauthorized => "access not authorized: token expired, username/password incorrect or no login provided",
            __Nonexhaustive => unreachable!(),
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match self.err {
            SerdeJson(ref err) => Some(err),
            Hyper(ref err) => Some(err),
            Io(ref err) => Some(err),
            StatusCode(_) => None,
            Api(ref err) => Some(err),
            Unauthorized => None,
            __Nonexhaustive => unreachable!(),
        }
    }
}

/// Error representing some abnormal response from the API.
#[derive(Debug, Clone)]
pub enum ApiError {
    /// The server responded with an "ok" code which was not `1`.
    NotOk(i32),
    /// A known response to a query about an invalid room.
    InvalidRoom,
    /// An error found from the API. Data is the raw error string reported by the server.
    GenericError(String),
    /// The server response was missing a top-level JSON field that was expected.
    MissingField(&'static str),
    /// A malformed response, including a formatted String description of the error.
    MalformedResponse(String),
    /// A marker variant that tells the compiler that users of this enum cannot match it exhaustively.
    #[doc(hidden)]
    __Nonexhaustive,
}

impl fmt::Display for ApiError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ApiError::NotOk(code) => write!(f, "non-ok result from api result: {}", code),
            ApiError::MissingField(field) => write!(f, "missing field from api result: {}", field),
            ApiError::MalformedResponse(ref desc) => write!(f, "malformed field from api result: {}", desc),
            ApiError::InvalidRoom => write!(f, "malformed api call: invalid room name"),
            ApiError::GenericError(ref err) => write!(f, "api call resulted in error: {}", err),
            ApiError::__Nonexhaustive => unreachable!(),
        }
    }
}

impl StdError for ApiError {
    fn description(&self) -> &str {
        match *self {
            ApiError::NotOk(_) => "non-ok result from api call",
            ApiError::MissingField(_) => "missing field in api result",
            ApiError::MalformedResponse(_) => "malformed field in api result",
            ApiError::GenericError(_) => "api call resulted in error",
            ApiError::InvalidRoom => "malformed api call: invalid room",
            ApiError::__Nonexhaustive => unreachable!(),
        }
    }

    fn cause(&self) -> Option<&StdError> { None }
}
<commit_msg>I'm not sure how I expected this to format, but I'm thinking not using (if { .. } else { .. }).into() is a better idea here!<commit_after>//! Error types for screeps-api.
extern crate hyper;
extern crate serde_json;

use self::ErrorType::*;
use std::error::Error as StdError;
use std::fmt;
use std::io;
use std::marker;

#[derive(Debug)]
/// Possible error types for library errors.
pub enum ErrorType {
    /// Unauthorized access. This is caused by either attempting to access a login-only endpoint without a token,
    /// attempting to access a login-only endpoint with an expired token, or providing incorrect login details to the
    /// login endpoint.
    Unauthorized,
    /// Error parsing a server response. This is most likely caused by the server providing unparsable JSON, but it
    /// could also be the server's API response structure has changed and no longer matches the expected data structure.
    SerdeJson(serde_json::error::Error),
    /// Error connecting to the server, or error parsing a URL provided.
    Hyper(hyper::error::Error),
    /// IO error.
    Io(io::Error),
    /// Error for when the server responds with a non-success status code.
    StatusCode(hyper::status::StatusCode),
    /// API Error. Either missing fields in the response that were expected, or the API did not include the regular
    /// `"ok": 1` which indicates success.
    Api(ApiError),
    /// A marker variant that tells the compiler that users of this enum cannot match it exhaustively.
    #[doc(hidden)]
    __Nonexhaustive,
}

/// Error deriving from some API call.
#[derive(Debug)]
pub struct Error {
    /// The type specifying what kind of error, and a detailed description if available.
    pub err: ErrorType,
    /// The whole URL which was being accessed when this error occurred (not included for URL parsing errors).
    pub url: Option<hyper::Url>,
    /// The json data from the request which resulted in this error (not included for URL or JSON parsing errors).
    pub json: Option<serde_json::Value>,
    /// Phantom data in order to allow adding any additional fields in the future.
    #[doc(hidden)]
    pub _phantom: marker::PhantomData<()>,
}

impl Error {
    /// Creates a new error from the given error and the given possible url.
    pub fn with_url<T: Into<Error>>(err: T, url: Option<hyper::Url>) -> Error { Error::with_json(err, url, None) }
    /// Creates a new error from the given error, the given possible url, and the given possible JSON data.
    pub fn with_json<T: Into<Error>>(err: T, url: Option<hyper::Url>, json: Option<serde_json::Value>) -> Error {
        let err = err.into();
        Error {
            err: err.err,
            url: url.or(err.url),
            json: json.or(err.json),
            _phantom: marker::PhantomData,
        }
    }
}

/// Result type for screeps API operations.
pub type Result<T> = ::std::result::Result<T, Error>;

impl From<ErrorType> for Error {
    fn from(err: ErrorType) -> Error {
        Error {
            err: err,
            url: None,
            json: None,
            _phantom: marker::PhantomData,
        }
    }
}

impl From<serde_json::error::Error> for Error {
    fn from(err: serde_json::error::Error) -> Error { ErrorType::SerdeJson(err).into() }
}

impl From<hyper::error::Error> for Error {
    fn from(err: hyper::error::Error) -> Error { ErrorType::Hyper(err).into() }
}

impl From<hyper::error::ParseError> for Error {
    fn from(err: hyper::error::ParseError) -> Error { ErrorType::Hyper(hyper::Error::Uri(err)).into() }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error { ErrorType::Io(err).into() }
}

impl From<hyper::status::StatusCode> for Error {
    fn from(code: hyper::status::StatusCode) -> Error {
        if code == hyper::status::StatusCode::Unauthorized {
            ErrorType::Unauthorized.into()
        } else {
            ErrorType::StatusCode(code).into()
        }
    }
}

impl From<ApiError> for Error {
    fn from(err: ApiError) -> Error { ErrorType::Api(err).into() }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.err {
            SerdeJson(ref err) => fmt::Display::fmt(err, f)?,
            Hyper(ref err) => fmt::Display::fmt(err, f)?,
            Io(ref err) => fmt::Display::fmt(err, f)?,
            StatusCode(ref status) => fmt::Display::fmt(status, f)?,
            Api(ref err) => fmt::Display::fmt(err, f)?,
            Unauthorized => {
                write!(f,
                       "access not authorized: token expired, username/password
                       incorrect or no login provided")?;
            }
            ErrorType::__Nonexhaustive => unreachable!(),
        }
        if let Some(ref url) = self.url {
            write!(f, " | at url '{}'", url)?;
        }
        if let Some(ref json) = self.json {
            write!(f, " | return json: '{}'", json)?;
        }
        Ok(())
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match self.err {
            SerdeJson(ref err) => err.description(),
            Hyper(ref err) => err.description(),
            Io(ref err) => err.description(),
            StatusCode(ref status) => {
                match status.canonical_reason() {
                    Some(reason) => reason,
                    None => {
                        use hyper::status::StatusClass::*;
                        match status.class() {
                            Informational => "status code error: informational",
                            Success => "status code error: success",
                            Redirection => "status code error: redirection",
                            ClientError => "status code error: client error",
                            ServerError => "status code error: server error",
                            NoClass => "status code error: strange status",
                        }
                    }
                }
            }
            Api(ref err) => err.description(),
            Unauthorized => "access not authorized: token expired, username/password incorrect or no login provided",
            __Nonexhaustive => unreachable!(),
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match self.err {
            SerdeJson(ref err) => Some(err),
            Hyper(ref err) => Some(err),
            Io(ref err) => Some(err),
            StatusCode(_) => None,
            Api(ref err) => Some(err),
            Unauthorized => None,
            __Nonexhaustive => unreachable!(),
        }
    }
}

/// Error representing some abnormal response from the API.
#[derive(Debug, Clone)]
pub enum ApiError {
    /// The server responded with an "ok" code which was not `1`.
    NotOk(i32),
    /// A known response to a query about an invalid room.
    InvalidRoom,
    /// An error found from the API. Data is the raw error string reported by the server.
    GenericError(String),
    /// The server response was missing a top-level JSON field that was expected.
    MissingField(&'static str),
    /// A malformed response, including a formatted String description of the error.
    MalformedResponse(String),
    /// A marker variant that tells the compiler that users of this enum cannot match it exhaustively.
    #[doc(hidden)]
    __Nonexhaustive,
}

impl fmt::Display for ApiError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ApiError::NotOk(code) => write!(f, "non-ok result from api result: {}", code),
            ApiError::MissingField(field) => write!(f, "missing field from api result: {}", field),
            ApiError::MalformedResponse(ref desc) => write!(f, "malformed field from api result: {}", desc),
            ApiError::InvalidRoom => write!(f, "malformed api call: invalid room name"),
            ApiError::GenericError(ref err) => write!(f, "api call resulted in error: {}", err),
            ApiError::__Nonexhaustive => unreachable!(),
        }
    }
}

impl StdError for ApiError {
    fn description(&self) -> &str {
        match *self {
            ApiError::NotOk(_) => "non-ok result from api call",
            ApiError::MissingField(_) => "missing field in api result",
            ApiError::MalformedResponse(_) => "malformed field in api result",
            ApiError::GenericError(_) => "api call resulted in error",
            ApiError::InvalidRoom => "malformed api call: invalid room",
            ApiError::__Nonexhaustive => unreachable!(),
        }
    }

    fn cause(&self) -> Option<&StdError> { None }
}
<|endoftext|>


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

use nom::types::CompleteStr;
use petgraph::graph::{UnGraph, NodeIndex, DefaultIx};

use canonical::CanonicalUnit;
use ast::*;
use ir::ConversionRatio;

pub type UnitID = usize;

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct UndeclaredUnit<'a>(UnitName<'a>);

/// Attempt to insert a unit twice
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct DuplicateUnit<'a>(UnitName<'a>);

#[derive(Debug, Clone)]
pub struct UnitGraph<'a> {
    next_id: UnitID,
    unit_ids: HashMap<UnitName<'a>, UnitID>,
    unit_symbols: HashMap<UnitID, (UnitName<'a>, Span<'a>)>,
    graph_ids: HashMap<CanonicalUnit, NodeIndex<DefaultIx>>,
    conversions: UnGraph<CanonicalUnit, ConversionRatio>,
}

impl<'a> Default for UnitGraph<'a> {
    fn default() -> Self {
        let mut graph = UnitGraph {
            next_id: Default::default(),
            unit_ids: Default::default(),
            unit_symbols: Default::default(),
            graph_ids: Default::default(),
            conversions: Default::default(),
        };
        graph.insert_unit(UnitName::unitless(), Span::new(CompleteStr("")))
            .unwrap_or_else(|_| unreachable!("'_ was already declared"));

        graph
    }
}

impl<'a> UnitGraph<'a> {
    /// Returns a unit representing when a quantity is unitless
    ///
    /// In lion programs, this is denoted '_
    pub fn unitless(&self) -> UnitID {
        self.unit_id(UnitName::unitless())
            .unwrap_or_else(|_| unreachable!("bug: '_ was not defined"))
    }

    /// Returns the unique unit ID for the given unit name.
    /// Returns an Err if the name was not already a defined unit
    ///
    /// **Note:** name must be given without "'", i.e. to lookup 'foo, use unit_id("foo")
    pub fn unit_id(&self, name: UnitName<'a>) -> Result<UnitID, UndeclaredUnit> {
        self.unit_ids.get(&name).map(|id| *id).ok_or_else(|| UndeclaredUnit(name))
    }

    /// Returns the unit name for the given unit ID
    ///
    /// # Panics
    ///
    /// Panics if the unit ID was not declared since that should not be possible
    pub fn unit_name(&self, unit: UnitID) -> UnitName<'a> {
        match self.unit_symbols.get(&unit) {
            Some(&(name, _)) => name,
            None => unreachable!("Looked up an ID that did not exist"),
        }
    }

    /// Creates the given unit if it does not exist yet
    ///
    /// If it does exist, this function will return an error
    pub fn insert_unit(&mut self, name: UnitName<'a>, span: Span<'a>) -> Result<(), DuplicateUnit<'a>> {
        if self.unit_ids.contains_key(&name) {
            return Err(DuplicateUnit(name));
        }

        let id = self.next_id;
        self.next_id += 1;
        assert!(self.unit_ids.insert(name, id).is_none(),
            "bug: failed to detect duplicate declaration");
        assert!(self.unit_symbols.insert(id, (name, span)).is_none(),
            "bug: failed to detect duplicate declaration");

        let node = CanonicalUnit::from(id);
        let graph_id = self.conversions.add_node(node.clone());
        assert!(self.graph_ids.insert(node, graph_id).is_none(),
            "bug: failed to detect duplicate declaration");

        Ok(())
    }

    /// Adds the given conversion ratio to the graph
    pub fn add_conversion(&mut self, ratio: ConversionRatio) -> Result<(), ()> {
        //TODO: Check if all units in CanonicalUnits are declared and return an Err if not
        unimplemented!()
    }
}

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

    #[test]
    fn unitless_exists() {
        let units = UnitGraph::default();
        // Test to make sure that if we lookup unitless from elsewhere in the AST we get the same
        // value back as calling units.unitless()
        assert_eq!(units.unitless(), units.unit_id(UnitName::unitless()).unwrap());
        // Check that the unit name of the return value of units.unitless() is unitless
        assert_eq!(units.unit_name(units.unitless()), UnitName::unitless());
    }
}
<commit_msg>Using a Vec instead of a HashMap<UnitID, ...><commit_after>use std::collections::HashMap;

use nom::types::CompleteStr;
use petgraph::graph::{UnGraph, NodeIndex, DefaultIx};

use canonical::CanonicalUnit;
use ast::*;
use ir::ConversionRatio;

pub type UnitID = usize;

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct UndeclaredUnit<'a>(UnitName<'a>);

/// Attempt to insert a unit twice
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct DuplicateUnit<'a>(UnitName<'a>);

#[derive(Debug, Clone)]
pub struct UnitGraph<'a> {
    unit_ids: HashMap<UnitName<'a>, UnitID>,
    units: Vec<(UnitName<'a>, Span<'a>)>,
    graph_ids: HashMap<CanonicalUnit, NodeIndex<DefaultIx>>,
    conversions: UnGraph<CanonicalUnit, ConversionRatio>,
}

impl<'a> Default for UnitGraph<'a> {
    fn default() -> Self {
        let mut graph = UnitGraph {
            unit_ids: Default::default(),
            units: Default::default(),
            graph_ids: Default::default(),
            conversions: Default::default(),
        };
        graph.insert_unit(UnitName::unitless(), Span::new(CompleteStr("")))
            .unwrap_or_else(|_| unreachable!("'_ was already declared"));

        graph
    }
}

impl<'a> UnitGraph<'a> {
    /// Returns a unit representing when a quantity is unitless
    ///
    /// In lion programs, this is denoted '_
    pub fn unitless(&self) -> UnitID {
        self.unit_id(UnitName::unitless())
            .unwrap_or_else(|_| unreachable!("bug: '_ was not defined"))
    }

    /// Returns the unique unit ID for the given unit name.
    /// Returns an Err if the name was not already a defined unit
    ///
    /// **Note:** name must be given without "'", i.e. to lookup 'foo, use unit_id("foo")
    pub fn unit_id(&self, name: UnitName<'a>) -> Result<UnitID, UndeclaredUnit> {
        self.unit_ids.get(&name).map(|id| *id).ok_or_else(|| UndeclaredUnit(name))
    }

    /// Returns the unit name for the given unit ID
    ///
    /// # Panics
    ///
    /// Panics if the unit ID was not declared since that should not be possible
    pub fn unit_name(&self, unit: UnitID) -> UnitName<'a> {
        match self.units.get(unit) {
            Some(&(name, _)) => name,
            None => unreachable!("Looked up an ID that did not exist"),
        }
    }

    /// Creates the given unit if it does not exist yet
    ///
    /// If it does exist, this function will return an error
    pub fn insert_unit(&mut self, name: UnitName<'a>, span: Span<'a>) -> Result<(), DuplicateUnit<'a>> {
        if self.unit_ids.contains_key(&name) {
            return Err(DuplicateUnit(name));
        }

        let id = self.unit_ids.len();
        assert!(self.unit_ids.insert(name, id).is_none(),
            "bug: failed to detect duplicate declaration");
        self.units.push((name, span));

        let node = CanonicalUnit::from(id);
        let graph_id = self.conversions.add_node(node.clone());
        assert!(self.graph_ids.insert(node, graph_id).is_none(),
            "bug: failed to detect duplicate declaration");

        Ok(())
    }

    /// Adds the given conversion ratio to the graph
    pub fn add_conversion(&mut self, ratio: ConversionRatio) -> Result<(), ()> {
        //TODO: Check if all units in CanonicalUnits are declared and return an Err if not
        unimplemented!()
    }
}

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

    #[test]
    fn unitless_exists() {
        let units = UnitGraph::default();
        // Test to make sure that if we lookup unitless from elsewhere in the AST we get the same
        // value back as calling units.unitless()
        assert_eq!(units.unitless(), units.unit_id(UnitName::unitless()).unwrap());
        // Check that the unit name of the return value of units.unitless() is unitless
        assert_eq!(units.unit_name(units.unitless()), UnitName::unitless());
    }
}
<|endoftext|>


<commit_before>//! Glyph caching

extern crate rusttype as rt;

use std::io;
use std::path::{Path};
use std::collections::hash_map::{ HashMap, Entry };
use graphics::character::{ CharacterCache, Character };
use graphics::types::{FontSize, Scalar};
use { gfx, Texture, TextureSettings };
use gfx::CombinedError;

/// An enum to represent various possible run-time errors that may occur.
#[derive(Debug)]
pub enum Error {
    /// An error happened when creating a gfx texture.
    Texture(CombinedError),
    /// An io error happened when reading font files.
    IoError(io::Error),
    /// No font was found in the file.
    NoFont,
}

impl From<CombinedError> for Error {
    fn from(tex_err: CombinedError) -> Self {
        Error::Texture(tex_err)
    }
}

impl From<io::Error> for Error {
    fn from(io_error: io::Error) -> Self {
        Error::IoError(io_error)
    }
}

/// A struct used for caching a rendered font.
pub struct GlyphCache<R, F> where R: gfx::Resources {
    /// The font.
    pub font: rt::Font<'static>,
    factory: F,
    // Maps from fontsize and character to offset, size and texture.
    data: HashMap<(FontSize, char), ([Scalar; 2], [Scalar; 2], Texture<R>)>
}

impl<R, F> GlyphCache<R, F> where R: gfx::Resources {
     /// Constructor for a GlyphCache.
    pub fn new<P>(font_path: P, factory: F) -> Result<Self, Error>
        where P: AsRef<Path>    {

        use std::io::Read;
        use std::fs::File;

        let mut file = try!(File::open(font_path));
        let mut file_buffer = Vec::new();
        try!(file.read_to_end(&mut file_buffer));

        let collection = rt::FontCollection::from_bytes(file_buffer);
        let font = match collection.into_font() {
            Some(font) => font,
            None => return Err(Error::NoFont),
        };

        Ok(GlyphCache {
            font: font,
            factory: factory,
            data: HashMap::new(),
        })
    }
}

impl<R, F> CharacterCache for GlyphCache<R, F> where
    R: gfx::Resources,
    F: gfx::Factory<R>,
{
    type Texture = Texture<R>;

    fn character<'a>(
        &'a mut self,
        size: FontSize,
        ch: char
    ) -> Character<'a, Self::Texture> {
        let size = ((size as f32) * 1.333).round() as u32 ; // convert points to pixels

        match self.data.entry((size, ch)) {
            //returning `into_mut()' to get reference with 'a lifetime
            Entry::Occupied(v) => {
                let &mut (offset, size, ref texture) = v.into_mut();
                Character {
                    offset: offset,
                    size: size,
                    texture: texture
                }
            }
            Entry::Vacant(v) => {
                let glyph = self.font.glyph(ch).unwrap(); // this is only None for invalid GlyphIds, but char is converted to a Codepoint which must result in a glyph.
                let scale = rt::Scale::uniform(size as f32);
                let mut glyph = glyph.scaled(scale);

                // some fonts do not contain glyph zero as fallback, instead try U+FFFD.
                if glyph.id() == rt::GlyphId(0) && glyph.shape().is_none() {
                    glyph = self.font.glyph('\u{FFFD}').unwrap().scaled(scale);
                }

                let h_metrics = glyph.h_metrics();
                let bounding_box = glyph.exact_bounding_box().unwrap_or(rt::Rect{min: rt::Point{x: 0.0, y: 0.0}, max: rt::Point{x: 0.0, y: 0.0} });
                let glyph = glyph.positioned(rt::point(0.0, 0.0));
                let pixel_bounding_box = glyph.pixel_bounding_box().unwrap_or(rt::Rect{min: rt::Point{x: 0, y: 0}, max: rt::Point{x: 0, y: 0} });
                let pixel_bb_width = pixel_bounding_box.width() + 2;
                let pixel_bb_height = pixel_bounding_box.height() + 2;

                let mut image_buffer = Vec::<u8>::new();
                image_buffer.resize((pixel_bb_width * pixel_bb_height) as usize, 0);
                glyph.draw(|x, y, v| {
                   let pos = ((x+1) + (y+1) * (pixel_bb_width as u32)) as usize;
                   image_buffer[pos] = (255.0 * v) as u8;
                });

                let &mut (offset, size, ref texture) = v.insert((
                    [
                        bounding_box.min.x as Scalar - 1.0,
                        -pixel_bounding_box.min.y as Scalar + 1.0,
                    ],
                    [
                        h_metrics.advance_width as Scalar,
                        0 as Scalar,
                    ],
                    {
                        if pixel_bb_width == 0 || pixel_bb_height == 0 {
                            Texture::empty(&mut self.factory)
                                    .unwrap()
                        } else {
                            Texture::from_memory_alpha(
                                &mut self.factory,
                                &image_buffer,
                                pixel_bb_width as u32,
                                pixel_bb_height as u32,
                                &TextureSettings::new()
                            ).unwrap()
                        }
                    },
                ));
                Character {
                    offset: offset,
                    size: size,
                    texture: texture
                }
            }
        }
    }
}
<commit_msg>Add GlyphCache::from_font constructor<commit_after>//! Glyph caching

extern crate rusttype as rt;

use std::io;
use std::path::{Path};
use std::collections::hash_map::{ HashMap, Entry };
use graphics::character::{ CharacterCache, Character };
use graphics::types::{FontSize, Scalar};
use { gfx, Texture, TextureSettings };
use gfx::CombinedError;

/// An enum to represent various possible run-time errors that may occur.
#[derive(Debug)]
pub enum Error {
    /// An error happened when creating a gfx texture.
    Texture(CombinedError),
    /// An io error happened when reading font files.
    IoError(io::Error),
    /// No font was found in the file.
    NoFont,
}

impl From<CombinedError> for Error {
    fn from(tex_err: CombinedError) -> Self {
        Error::Texture(tex_err)
    }
}

impl From<io::Error> for Error {
    fn from(io_error: io::Error) -> Self {
        Error::IoError(io_error)
    }
}

/// A struct used for caching a rendered font.
pub struct GlyphCache<R, F> where R: gfx::Resources {
    /// The font.
    pub font: rt::Font<'static>,
    factory: F,
    // Maps from fontsize and character to offset, size and texture.
    data: HashMap<(FontSize, char), ([Scalar; 2], [Scalar; 2], Texture<R>)>
}

impl<R, F> GlyphCache<R, F> where R: gfx::Resources {
    /// Constructs a GlyphCache from a Font.
    pub fn from_font(font: rt::Font<'static>, factory: F) -> Self {
        GlyphCache {
            font: font,
            factory: factory,
            data: HashMap::new(),
        }
    }

     /// Constructor for a GlyphCache.
    pub fn new<P>(font_path: P, factory: F) -> Result<Self, Error>
        where P: AsRef<Path>    {

        use std::io::Read;
        use std::fs::File;

        let mut file = try!(File::open(font_path));
        let mut file_buffer = Vec::new();
        try!(file.read_to_end(&mut file_buffer));

        let collection = rt::FontCollection::from_bytes(file_buffer);
        let font = match collection.into_font() {
            Some(font) => font,
            None => return Err(Error::NoFont),
        };

        Ok(Self::from_font(font, factory))
    }
}

impl<R, F> CharacterCache for GlyphCache<R, F> where
    R: gfx::Resources,
    F: gfx::Factory<R>,
{
    type Texture = Texture<R>;

    fn character<'a>(
        &'a mut self,
        size: FontSize,
        ch: char
    ) -> Character<'a, Self::Texture> {
        let size = ((size as f32) * 1.333).round() as u32 ; // convert points to pixels

        match self.data.entry((size, ch)) {
            //returning `into_mut()' to get reference with 'a lifetime
            Entry::Occupied(v) => {
                let &mut (offset, size, ref texture) = v.into_mut();
                Character {
                    offset: offset,
                    size: size,
                    texture: texture
                }
            }
            Entry::Vacant(v) => {
                let glyph = self.font.glyph(ch).unwrap(); // this is only None for invalid GlyphIds, but char is converted to a Codepoint which must result in a glyph.
                let scale = rt::Scale::uniform(size as f32);
                let mut glyph = glyph.scaled(scale);

                // some fonts do not contain glyph zero as fallback, instead try U+FFFD.
                if glyph.id() == rt::GlyphId(0) && glyph.shape().is_none() {
                    glyph = self.font.glyph('\u{FFFD}').unwrap().scaled(scale);
                }

                let h_metrics = glyph.h_metrics();
                let bounding_box = glyph.exact_bounding_box().unwrap_or(rt::Rect{min: rt::Point{x: 0.0, y: 0.0}, max: rt::Point{x: 0.0, y: 0.0} });
                let glyph = glyph.positioned(rt::point(0.0, 0.0));
                let pixel_bounding_box = glyph.pixel_bounding_box().unwrap_or(rt::Rect{min: rt::Point{x: 0, y: 0}, max: rt::Point{x: 0, y: 0} });
                let pixel_bb_width = pixel_bounding_box.width() + 2;
                let pixel_bb_height = pixel_bounding_box.height() + 2;

                let mut image_buffer = Vec::<u8>::new();
                image_buffer.resize((pixel_bb_width * pixel_bb_height) as usize, 0);
                glyph.draw(|x, y, v| {
                   let pos = ((x+1) + (y+1) * (pixel_bb_width as u32)) as usize;
                   image_buffer[pos] = (255.0 * v) as u8;
                });

                let &mut (offset, size, ref texture) = v.insert((
                    [
                        bounding_box.min.x as Scalar - 1.0,
                        -pixel_bounding_box.min.y as Scalar + 1.0,
                    ],
                    [
                        h_metrics.advance_width as Scalar,
                        0 as Scalar,
                    ],
                    {
                        if pixel_bb_width == 0 || pixel_bb_height == 0 {
                            Texture::empty(&mut self.factory)
                                    .unwrap()
                        } else {
                            Texture::from_memory_alpha(
                                &mut self.factory,
                                &image_buffer,
                                pixel_bb_width as u32,
                                pixel_bb_height as u32,
                                &TextureSettings::new()
                            ).unwrap()
                        }
                    },
                ));
                Character {
                    offset: offset,
                    size: size,
                    texture: texture
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate kappa_lisp;
use kappa_lisp::read;
use kappa_lisp::util::*;

#[test]
fn test_read_empty() {
    //    assert_eq!(read(""), (keOF));
    //    assert_eq!(read("(a b"), (keOF));
}

#[test]
fn test_read_nil() {
    assert_eq!(read("nil"), (knil()));
}

#[test]
fn test_read_int() {
    assert_eq!(read("0"), (kint(0)));
    assert_eq!(read("10"), (kint(10)));
    assert_eq!(read("-10"), (kint(-10)));
    assert_eq!(read("+10"), (kint(10)));
}

#[test]
fn test_read_float() {
    assert_eq!(read("0.0"), (kfloat(0.0)));
    assert_eq!(read("10.123"), (kfloat(10.123)));
    assert_eq!(read("-0.1"), (kfloat(-0.1)));
    assert_eq!(read("-10.1"), (kfloat(-10.1)));
    assert_eq!(read("+0.0"), (kfloat(0.0)));
    assert_eq!(read("+10.0123"), (kfloat(10.0123)));
}

#[test]
fn test_read_list() {
    assert_eq!(read("()"), (knil()));
    assert_eq!(read("(1)"), (klist!(kint(1))));
    assert_eq!(read("(1 2)"), (klist!(kint(1), kint(2))));
    assert_eq!(read("(1 . 2)"), (kcons(kint(1), kint(2))));
    assert_eq!(read("(1 2 . 3)"), (kcons(kint(1), kcons(kint(2), kint(3)))));
    assert_eq!(
        read("'(1 (2 . 3))"),
        klist!(ksym("quote"), (klist!(kint(1), kcons(kint(2), kint(3)))))
    );
}

#[test]
fn test_read_symbol() {
    assert_eq!(read("symbol"), (ksym("symbol")));
    assert_eq!(read("+symbol"), (ksym("+symbol")));
    assert_eq!(read("-symbol"), (ksym("-symbol")));
    assert_eq!(read("sym-bol"), (ksym("sym-bol")));
    assert_eq!(read("symbol2"), (ksym("symbol2")));
}

#[test]
fn test_read_string() {
    assert_eq!(read("\"string\""), (kstr("string")));
    assert_eq!(read("\"str()ing\""), (kstr("str()ing")));
    assert_eq!(read("\"str123ing\""), (kstr("str123ing")));
    assert_eq!(read("\"()string\""), (kstr("()string")));
    assert_eq!(read("\"123string\""), (kstr("123string")));
    assert_eq!(read("(\"string\")"), (klist!(kstr("string"))));
}

#[test]
fn test_read_quote() {
    assert_eq!(read("'1"), (klist!(ksym("quote"), kint(1))));
    assert_eq!(read("'symbol"), (klist!(ksym("quote"), ksym("symbol"))));
    assert_eq!(read("'\"string\""), (klist!(ksym("quote"), kstr("string"))));
    assert_eq!(
        read("'(1 2)"),
        (klist!(ksym("quote"), klist!(kint(1), kint(2))))
    )
}

#[test]
fn test_read_function() {
    assert_eq!(read("#'1"), (klist!(ksym("function"), kint(1))));
    assert_eq!(read("#'symbol"), (klist!(ksym("function"), ksym("symbol"))));
    assert_eq!(
        read("#'\"string\""),
        (klist!(ksym("function"), kstr("string")))
    );
    assert_eq!(
        read("#'(1 2)"),
        (klist!(ksym("function"), klist!(kint(1), kint(2))))
    )
}
<commit_msg>fix test<commit_after>#[macro_use]
extern crate kappa_lisp;
use kappa_lisp::read;
use kappa_lisp::util::*;

#[test]
fn test_read_empty() {
    //    assert_eq!(read(""), (keOF));
    //    assert_eq!(read("(a b"), (keOF));
}

#[test]
fn test_read_nil() {
    assert_eq!(read("nil"), Ok(knil()));
}

#[test]
fn test_read_int() {
    assert_eq!(read("0"), Ok(kint(0)));
    assert_eq!(read("10"), Ok(kint(10)));
    assert_eq!(read("-10"), Ok(kint(-10)));
    assert_eq!(read("+10"), Ok(kint(10)));
}

#[test]
fn test_read_float() {
    assert_eq!(read("0.0"), Ok(kfloat(0.0)));
    assert_eq!(read("10.123"), Ok(kfloat(10.123)));
    assert_eq!(read("-0.1"), Ok(kfloat(-0.1)));
    assert_eq!(read("-10.1"), Ok(kfloat(-10.1)));
    assert_eq!(read("+0.0"), Ok(kfloat(0.0)));
    assert_eq!(read("+10.0123"), Ok(kfloat(10.0123)));
}

#[test]
fn test_read_list() {
    assert_eq!(read("()"), Ok(knil()));
    assert_eq!(read("(1)"), Ok(klist!(kint(1))));
    assert_eq!(read("(1 2)"), Ok(klist!(kint(1), kint(2))));
    assert_eq!(read("(1 . 2)"), Ok(kcons(kint(1), kint(2))));
    assert_eq!(
        read("(1 2 . 3)"),
        Ok(kcons(kint(1), kcons(kint(2), kint(3))))
    );
    assert_eq!(
        read("'(1 (2 . 3))"),
        Ok(klist!(
            ksym("quote"),
            klist!(kint(1), kcons(kint(2), kint(3)))
        ))
    );
}

#[test]
fn test_read_symbol() {
    assert_eq!(read("symbol"), Ok(ksym("symbol")));
    assert_eq!(read("+symbol"), Ok(ksym("+symbol")));
    assert_eq!(read("-symbol"), Ok(ksym("-symbol")));
    assert_eq!(read("sym-bol"), Ok(ksym("sym-bol")));
    assert_eq!(read("symbol2"), Ok(ksym("symbol2")));
}

#[test]
fn test_read_string() {
    assert_eq!(read("\"string\""), Ok(kstr("string")));
    assert_eq!(read("\"str()ing\""), Ok(kstr("str()ing")));
    assert_eq!(read("\"str123ing\""), Ok(kstr("str123ing")));
    assert_eq!(read("\"()string\""), Ok(kstr("()string")));
    assert_eq!(read("\"123string\""), Ok(kstr("123string")));
    assert_eq!(read("(\"string\")"), Ok(klist!(kstr("string"))));
}

#[test]
fn test_read_quote() {
    assert_eq!(read("'1"), Ok(klist!(ksym("quote"), kint(1))));
    assert_eq!(read("'symbol"), Ok(klist!(ksym("quote"), ksym("symbol"))));
    assert_eq!(
        read("'\"string\""),
        Ok(klist!(ksym("quote"), kstr("string")))
    );
    assert_eq!(
        read("'(1 2)"),
        Ok(klist!(ksym("quote"), klist!(kint(1), kint(2))))
    )
}

#[test]
fn test_read_function() {
    assert_eq!(read("#'1"), Ok(klist!(ksym("function"), kint(1))));
    assert_eq!(
        read("#'symbol"),
        Ok(klist!(ksym("function"), ksym("symbol")))
    );
    assert_eq!(
        read("#'\"string\""),
        Ok(klist!(ksym("function"), kstr("string")))
    );
    assert_eq!(
        read("#'(1 2)"),
        Ok(klist!(ksym("function"), klist!(kint(1), kint(2))))
    )
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::{self, Debug, Formatter};
use std::marker::PhantomData;
use std::u32;
use Command;

/// Macro for merging commands.
///
/// # Examples
/// ```
/// # use std::error::Error;
/// # use undo::*;
/// #[derive(Debug)]
/// struct Add(char);
///
/// impl Command<String> for Add {
///     fn apply(&mut self, s: &mut String) -> Result<(), Box<dyn Error + Send + Sync>> {
///         s.push(self.0);
///         Ok(())
///     }
///
///     fn undo(&mut self, s: &mut String) -> Result<(), Box<dyn Error + Send + Sync>> {
///         self.0 = s.pop().ok_or("`s` is empty")?;
///         Ok(())
///     }
/// }
///
/// fn main() -> Result<(), Box<dyn Error>> {
///     let mut record = Record::default();
///
///     let cmd = merge![Add('a'), Add('b'), Add('c')];
///     record.apply(cmd)?;
///     assert_eq!(record.as_receiver(), "abc");
///     record.undo().unwrap()?;
///     assert_eq!(record.as_receiver(), "");
///     record.redo().unwrap()?;
///     assert_eq!(record.as_receiver(), "abc");
///
///     Ok(())
/// }
/// ```
#[macro_export]
macro_rules! merge {
    ($cmd1:expr, $cmd2:expr) => (
        Merged::new($cmd1, $cmd2)
    );
    ($cmd1:expr, $cmd2:expr, $($tail:expr),+) => (
        merge![Merged::new($cmd1, $cmd2), $($tail),*]
    );
}

/// A command wrapper which always merges with itself.
///
/// This wrapper has an [`id`] of `u32::MAX`.
///
/// [`id`]: trait.Command.html#method.id
pub struct Merger<R, C: Command<R> + 'static> {
    cmd: C,
    _marker: PhantomData<Box<dyn Command<R> + 'static>>,
}

impl<R, C: Command<R> + 'static> Merger<R, C> {
    /// Returns a new merger command.
    #[inline]
    pub fn new(cmd: C) -> Merger<R, C> {
        Merger {
            cmd,
            _marker: PhantomData,
        }
    }
}

impl<R, C: Command<R> + 'static> From<C> for Merger<R, C> {
    #[inline]
    fn from(cmd: C) -> Self {
        Merger::new(cmd)
    }
}

impl<R, C: Command<R> + 'static> Command<R> for Merger<R, C> {
    #[inline]
    fn apply(&mut self, receiver: &mut R) -> Result<(), Box<dyn Error + Send + Sync>> {
        self.cmd.apply(receiver)
    }

    #[inline]
    fn undo(&mut self, receiver: &mut R) -> Result<(), Box<dyn Error + Send + Sync>> {
        self.cmd.undo(receiver)
    }

    #[inline]
    fn redo(&mut self, receiver: &mut R) -> Result<(), Box<dyn Error + Send + Sync>> {
        self.cmd.redo(receiver)
    }

    #[inline]
    fn id(&self) -> Option<u32> {
        Some(u32::MAX)
    }
}

impl<R, C: Command<R> + 'static> Debug for Merger<R, C> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Merger").field("cmd", &self.cmd).finish()
    }
}

#[cfg(feature = "display")]
impl<R, C: Command<R> + 'static> fmt::Display for Merger<R, C> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        (&self.cmd as &fmt::Display).fmt(f)
    }
}

/// The result of merging two commands.
pub struct Merged<R, C1: Command<R> + 'static, C2: Command<R> + 'static> {
    cmd1: C1,
    cmd2: C2,
    _marker: PhantomData<Box<dyn Command<R> + 'static>>,
}

impl<R, C1: Command<R> + 'static, C2: Command<R> + 'static> Merged<R, C1, C2> {
    /// Merges `cmd1` and `cmd2` into a single command.
    #[inline]
    pub fn new(cmd1: C1, cmd2: C2) -> Merged<R, C1, C2> {
        Merged {
            cmd1,
            cmd2,
            _marker: PhantomData,
        }
    }
}

impl<R, C1: Command<R> + 'static, C2: Command<R> + 'static> Command<R> for Merged<R, C1, C2> {
    #[inline]
    fn apply(&mut self, receiver: &mut R) -> Result<(), Box<dyn Error + Send + Sync>> {
        self.cmd1.apply(receiver)?;
        self.cmd2.apply(receiver)
    }

    #[inline]
    fn undo(&mut self, receiver: &mut R) -> Result<(), Box<dyn Error + Send + Sync>> {
        self.cmd2.undo(receiver)?;
        self.cmd1.undo(receiver)
    }

    #[inline]
    fn redo(&mut self, receiver: &mut R) -> Result<(), Box<dyn Error + Send + Sync>> {
        self.cmd1.redo(receiver)?;
        self.cmd2.redo(receiver)
    }

    #[inline]
    fn id(&self) -> Option<u32> {
        self.cmd1.id()
    }
}

impl<R, C1: Command<R> + 'static, C2: Command<R> + 'static> Debug for Merged<R, C1, C2> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Merged")
            .field("cmd1", &self.cmd1)
            .field("cmd2", &self.cmd2)
            .finish()
    }
}

#[cfg(feature = "display")]
impl<R, C1: Command<R> + 'static, C2: Command<R> + 'static> fmt::Display for Merged<R, C1, C2> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{cmd1} + {cmd2}", cmd1 = self.cmd1, cmd2 = self.cmd2)
    }
}
<commit_msg>Add into methods for Merged and Merger<commit_after>use std::error::Error;
use std::fmt::{self, Debug, Formatter};
use std::marker::PhantomData;
use Command;

/// Macro for merging commands.
///
/// # Examples
/// ```
/// # use std::error::Error;
/// # use undo::*;
/// #[derive(Debug)]
/// struct Add(char);
///
/// impl Command<String> for Add {
///     fn apply(&mut self, s: &mut String) -> Result<(), Box<dyn Error + Send + Sync>> {
///         s.push(self.0);
///         Ok(())
///     }
///
///     fn undo(&mut self, s: &mut String) -> Result<(), Box<dyn Error + Send + Sync>> {
///         self.0 = s.pop().ok_or("`s` is empty")?;
///         Ok(())
///     }
/// }
///
/// fn main() -> Result<(), Box<dyn Error>> {
///     let mut record = Record::default();
///
///     let cmd = merge![Add('a'), Add('b'), Add('c')];
///     record.apply(cmd)?;
///     assert_eq!(record.as_receiver(), "abc");
///     record.undo().unwrap()?;
///     assert_eq!(record.as_receiver(), "");
///     record.redo().unwrap()?;
///     assert_eq!(record.as_receiver(), "abc");
///
///     Ok(())
/// }
/// ```
#[macro_export]
macro_rules! merge {
    ($cmd1:expr, $cmd2:expr) => (
        Merged::new($cmd1, $cmd2)
    );
    ($cmd1:expr, $cmd2:expr, $($tail:expr),+) => (
        merge![Merged::new($cmd1, $cmd2), $($tail),*]
    );
}

/// A command wrapper which always merges with itself.
///
/// This wrapper has an [`id`] of [`u32::max_value`].
///
/// [`id`]: trait.Command.html#method.id
/// [`u32::max_value`]: https://doc.rust-lang.org/std/primitive.u32.html#method.max_value
pub struct Merger<R, C: Command<R> + 'static> {
    cmd: C,
    _marker: PhantomData<Box<dyn Command<R> + 'static>>,
}

impl<R, C: Command<R> + 'static> Merger<R, C> {
    /// Returns a new merger command.
    #[inline]
    pub fn new(cmd: C) -> Merger<R, C> {
        Merger {
            cmd,
            _marker: PhantomData,
        }
    }

    /// Returns the inner command.
    #[inline]
    pub fn into_command(self) -> C {
        self.cmd
    }
}

impl<R, C: Command<R> + 'static> From<C> for Merger<R, C> {
    #[inline]
    fn from(cmd: C) -> Self {
        Merger::new(cmd)
    }
}

impl<R, C: Command<R> + 'static> Command<R> for Merger<R, C> {
    #[inline]
    fn apply(&mut self, receiver: &mut R) -> Result<(), Box<dyn Error + Send + Sync>> {
        self.cmd.apply(receiver)
    }

    #[inline]
    fn undo(&mut self, receiver: &mut R) -> Result<(), Box<dyn Error + Send + Sync>> {
        self.cmd.undo(receiver)
    }

    #[inline]
    fn redo(&mut self, receiver: &mut R) -> Result<(), Box<dyn Error + Send + Sync>> {
        self.cmd.redo(receiver)
    }

    #[inline]
    fn id(&self) -> Option<u32> {
        Some(u32::max_value())
    }
}

impl<R, C: Command<R> + 'static> Debug for Merger<R, C> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Merger").field("cmd", &self.cmd).finish()
    }
}

#[cfg(feature = "display")]
impl<R, C: Command<R> + 'static> fmt::Display for Merger<R, C> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        (&self.cmd as &fmt::Display).fmt(f)
    }
}

/// The result of merging two commands.
///
/// The [`merge!`](macro.merge.html) macro can be used for convenience when merging commands.
pub struct Merged<R, C1: Command<R> + 'static, C2: Command<R> + 'static> {
    cmd1: C1,
    cmd2: C2,
    _marker: PhantomData<Box<dyn Command<R> + 'static>>,
}

impl<R, C1: Command<R> + 'static, C2: Command<R> + 'static> Merged<R, C1, C2> {
    /// Merges `cmd1` and `cmd2` into a single command.
    ///
    /// The [`id`] of the command will be the `cmd1`s [`id`].
    ///
    /// [`id`]: trait.Command.html#method.id
    #[inline]
    pub fn new(cmd1: C1, cmd2: C2) -> Merged<R, C1, C2> {
        Merged {
            cmd1,
            cmd2,
            _marker: PhantomData,
        }
    }

    /// Returns the two merged commands.
    #[inline]
    pub fn into_commands(self) -> (C1, C2) {
        (self.cmd1, self.cmd2)
    }
}

impl<R, C1: Command<R> + 'static, C2: Command<R> + 'static> Command<R> for Merged<R, C1, C2> {
    #[inline]
    fn apply(&mut self, receiver: &mut R) -> Result<(), Box<dyn Error + Send + Sync>> {
        self.cmd1.apply(receiver)?;
        self.cmd2.apply(receiver)
    }

    #[inline]
    fn undo(&mut self, receiver: &mut R) -> Result<(), Box<dyn Error + Send + Sync>> {
        self.cmd2.undo(receiver)?;
        self.cmd1.undo(receiver)
    }

    #[inline]
    fn redo(&mut self, receiver: &mut R) -> Result<(), Box<dyn Error + Send + Sync>> {
        self.cmd1.redo(receiver)?;
        self.cmd2.redo(receiver)
    }

    #[inline]
    fn id(&self) -> Option<u32> {
        self.cmd1.id()
    }
}

impl<R, C1: Command<R> + 'static, C2: Command<R> + 'static> Debug for Merged<R, C1, C2> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Merged")
            .field("cmd1", &self.cmd1)
            .field("cmd2", &self.cmd2)
            .finish()
    }
}

#[cfg(feature = "display")]
impl<R, C1: Command<R> + 'static, C2: Command<R> + 'static> fmt::Display for Merged<R, C1, C2> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{cmd1} + {cmd2}", cmd1 = self.cmd1, cmd2 = self.cmd2)
    }
}
<|endoftext|>