<commit_before>extern crate chrono;

use self::chrono::offset::Local;
use std::fmt;
use std::fs::{File, OpenOptions};
use std::io::Write;

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Level {
    None,
    UserError,
    Critical,
    Error,
    Warn,
    Info,
    Debug,
}

impl fmt::Display for Level {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Level::None => write!(f, "NONE"),
            Level::UserError => write!(f, "USERERROR"),
            Level::Critical => write!(f, "CRITICAL"),
            Level::Error => write!(f, "ERROR"),
            Level::Warn => write!(f, "WARNING"),
            Level::Info => write!(f, "INFO"),
            Level::Debug => write!(f, "DEBUG"),
        }
    }
}

pub struct Logger {
    logfile: Option<File>,
    loglevel: Level,
}

impl Logger {
    pub fn new() -> Logger {
        Logger {
            logfile: None,
            loglevel: Level::None,
        }
    }

    pub fn set_logfile(&mut self, filename: &str) {
        let file = OpenOptions::new()
            .create(true)
            .append(true)
            .open(filename);

        match file {
            Ok(file) => self.logfile = Some(file),
            Err(error) => eprintln!("Couldn't open `{}' as a logfile: {}", filename, error),
        }
    }

    pub fn log(&mut self, level: Level, message: &str) {
        if level > self.loglevel {
            return;
        }

        if let Some(ref mut logfile) = self.logfile {
            let timestamp = Local::now().format("%Y-%m-%d %H:%M:%S");
            let line = format!("[{}] {}: {}\n", timestamp, level, message);

            // Ignoring the error since checking every log() call will be too bothersome.
            let _ = logfile.write_all(line.as_bytes());
        }
    }

    pub fn set_loglevel(&mut self, level: Level) {
        self.loglevel = level;
    }
}

#[cfg(test)]
mod tests {
    extern crate tempfile;

    use super::*;

    use self::tempfile::TempDir;
    use self::chrono::{TimeZone, Duration};
    use std::io::{self, BufReader, BufRead};
    use std::path;

    fn setup_logger() -> io::Result<(TempDir, path::PathBuf, Logger)> {
        let tmp = TempDir::new()?;
        let logfile = {
            let mut logfile = tmp.path().to_owned();
            logfile.push("example.log");
            logfile
        };
        assert!(!logfile.exists());

        let mut logger = Logger::new();
        logger.set_logfile(logfile.to_str().unwrap());

        Ok((tmp, logfile, logger))
    }

    fn parse_log_line(line: &str) -> Option<(&str, &str, &str)> {
        if !line.starts_with("[") {
            return None;
        }

        let timestamp_end = line.find(']').expect("Failed to find the end of the timestamp");
        // Timestamp starts with "[", we skip it by starting at 1 rather than 0.
        let timestamp = &line[1..timestamp_end];

        // "]" is an ASCII character, so it occupies one byte in UTF-8. As a result, we
        // can simply add one to get the next character's byte offset. And since the
        // next char should be a space, which is ASCII as well, we can just add 2.
        //
        // If timestamp is followed by something non-ASCII, indexing into &str will
        // panic and fail the test, which is good.
        if &line[timestamp_end+1..timestamp_end+2] != " " {
            return None;
        }

        let level_end =
            line[timestamp_end+2..]
            .find(':')
            .expect("Failed to find the end of the loglevel");
        let level = &line[timestamp_end+2..timestamp_end+2+level_end];

        // Message starts after ": " that follows the level, hence +2.
        let message = &line[timestamp_end+2+level_end+2..];

        Some((timestamp, level, message))
    }

    fn log_contains_n_lines(logfile: &path::Path, n: usize)  -> io::Result<()> {
        let file = File::open(logfile)?;
        let reader = BufReader::new(file);
        assert_eq!(reader.lines().count(), n);
        Ok(())
    }

    #[test]
    fn t_set_logfile() -> io::Result<()> {
        let (_tmp, logfile, _logger) = setup_logger()?;

        assert!(logfile.exists());

        Ok(())
    }

    #[test]
    fn t_log_writes_message_to_the_file() -> io::Result<()> {
        let (_tmp, logfile, mut logger) = setup_logger()?;

        let messages = vec![
            "Hello, world!",
            "I'm doing fine, how are you?",
            "Time to wrap up, see ya!",
        ];

        let start_time = Local::now();
        for msg in &messages {
            logger.log(Level::Debug, msg);
        }
        let finish_time = Local::now();

        // Dropping logger to force it to flush the log and close the file
        drop(logger);

        let file = File::open(logfile)?;
        let reader = BufReader::new(file);
        for (line, expected) in reader.lines().zip(messages) {
            match line {
                Ok(line) => {
                    let (timestamp_str, _level, message) =
                        parse_log_line(&line)
                        .expect("Failed to split the log line into parts");

                    let timestamp =
                        Local::now()
                        .timezone()
                        .datetime_from_str(timestamp_str, "%Y-%m-%d %H:%M:%S")
                        .expect("Failed to parse the timestamp from the log file");
                    // `start_time` and `end_time` may have millisecond precision or better,
                    // whereas `timestamp` is limited to seconds. Therefore, we account for
                    // a situation where `start_time` is slightly bigger than `timestamp`.
                    assert!(timestamp - start_time > Duration::seconds(-1));
                    assert!(finish_time >= timestamp);

                    assert_eq!(message, expected);
                }
                Err(e) => return Err(e),
            }
        }

        Ok(())
    }

    #[test]
    fn t_different_loglevels_have_different_names() -> io::Result<()> {
        let (_tmp, logfile, mut logger) = setup_logger()?;

        let levels = vec![
            (Level::UserError, "USERERROR"),
            (Level::Critical, "CRITICAL"),
            (Level::Error, "ERROR"),
            (Level::Warn, "WARNING"),
            (Level::Info, "INFO"),
            (Level::Debug, "DEBUG"),
        ];

        let msg = "Some test message";

        for (level, _level_str) in &levels {
            logger.log(*level, msg);
        }

        // Dropping logger to force it to flush the log and close the file
        drop(logger);

        let file = File::open(logfile)?;
        let reader = BufReader::new(file);
        for (line, expected) in reader.lines().zip(levels.iter().map(|(_, l)| l)) {
            match line {
                Ok(line) => {
                    let (_timestamp_str, level, _message) =
                        parse_log_line(&line)
                        .expect("Failed to split the log line into parts");

                    assert_eq!(&level, expected);
                }
                Err(e) => return Err(e),
            }
        }

        Ok(())
    }

    #[test]
    fn t_if_curlevel_is_none_nothing_is_logged() -> io::Result<()> {
        let (_tmp, logfile, mut logger) = setup_logger()?;

        logger.set_loglevel(Level::None);

        let levels = vec![
            (Level::UserError, "USERERROR"),
            (Level::Critical, "CRITICAL"),
            (Level::Error, "ERROR"),
            (Level::Warn, "WARNING"),
            (Level::Info, "INFO"),
            (Level::Debug, "DEBUG"),
        ];

        let msg = "Some test message";

        for (level, _level_str) in &levels {
            logger.log(*level, msg);
        }

        // Dropping logger to force it to flush the log and close the file
        drop(logger);

        log_contains_n_lines(&logfile, 0)?;

        Ok(())
    }

    #[test]
    fn t_user_errors_are_logged_at_all_curlevels_beside_none() -> io::Result<()> {
        {
            let (_tmp, logfile, mut logger) = setup_logger()?;
            logger.set_loglevel(Level::None);

            logger.log(Level::UserError, "hello");

            drop(logger);

            log_contains_n_lines(&logfile, 0)?;
        }

        let levels = vec![
            Level::UserError,
            Level::Critical,
            Level::Error,
            Level::Warn,
            Level::Info,
            Level::Debug,
        ];

        for level in levels {
            let (_tmp, logfile, mut logger) = setup_logger()?;
            logger.set_loglevel(level);

            logger.log(Level::UserError, "hello");

            drop(logger);

            log_contains_n_lines(&logfile, 1)?;
        };

        Ok(())
    }

    #[test]
    fn t_critial_msgs_are_logged_at_curlevels_starting_with_critical() -> io::Result<()> {
        let nolog_levels = vec![
            Level::None,
            Level::UserError,
        ];

        for level in nolog_levels {
            let (_tmp, logfile, mut logger) = setup_logger()?;
            logger.set_loglevel(level);

            logger.log(Level::Critical, "hello");

            drop(logger);

            log_contains_n_lines(&logfile, 0)?;
        }

        let log_levels = vec![
            Level::Critical,
            Level::Error,
            Level::Warn,
            Level::Info,
            Level::Debug,
        ];

        for level in log_levels {
            let (_tmp, logfile, mut logger) = setup_logger()?;
            logger.set_loglevel(level);

            logger.log(Level::Critical, "hello");

            drop(logger);

            log_contains_n_lines(&logfile, 1)?;
        };

        Ok(())
    }

    #[test]
    fn t_error_msgs_are_logged_at_curlevels_starting_with_error() -> io::Result<()> {
        let nolog_levels = vec![
            Level::None,
            Level::UserError,
            Level::Critical,
        ];

        for level in nolog_levels {
            let (_tmp, logfile, mut logger) = setup_logger()?;
            logger.set_loglevel(level);

            logger.log(Level::Error, "hello");

            drop(logger);

            log_contains_n_lines(&logfile, 0)?;
        }

        let log_levels = vec![
            Level::Error,
            Level::Warn,
            Level::Info,
            Level::Debug,
        ];

        for level in log_levels {
            let (_tmp, logfile, mut logger) = setup_logger()?;
            logger.set_loglevel(level);

            logger.log(Level::Error, "hello");

            drop(logger);

            log_contains_n_lines(&logfile, 1)?;
        };

        Ok(())
    }

    #[test]
    fn t_warning_msgs_are_logged_at_curlevels_starting_with_warning() -> io::Result<()> {
        let nolog_levels = vec![
            Level::None,
            Level::UserError,
            Level::Critical,
            Level::Error,
        ];

        for level in nolog_levels {
            let (_tmp, logfile, mut logger) = setup_logger()?;
            logger.set_loglevel(level);

            logger.log(Level::Warn, "hello");

            drop(logger);

            log_contains_n_lines(&logfile, 0)?;
        }

        let log_levels = vec![
            Level::Warn,
            Level::Info,
            Level::Debug,
        ];

        for level in log_levels {
            let (_tmp, logfile, mut logger) = setup_logger()?;
            logger.set_loglevel(level);

            logger.log(Level::Warn, "hello");

            drop(logger);

            log_contains_n_lines(&logfile, 1)?;
        };

        Ok(())
    }

    #[test]
    fn t_info_msgs_are_logged_at_curlevels_starting_with_info() -> io::Result<()> {
        let nolog_levels = vec![
            Level::None,
            Level::UserError,
            Level::Critical,
            Level::Error,
            Level::Warn,
        ];

        for level in nolog_levels {
            let (_tmp, logfile, mut logger) = setup_logger()?;
            logger.set_loglevel(level);

            logger.log(Level::Info, "hello");

            drop(logger);

            log_contains_n_lines(&logfile, 0)?;
        }

        let log_levels = vec![
            Level::Info,
            Level::Debug,
        ];

        for level in log_levels {
            let (_tmp, logfile, mut logger) = setup_logger()?;
            logger.set_loglevel(level);

            logger.log(Level::Info, "hello");

            drop(logger);

            log_contains_n_lines(&logfile, 1)?;
        };

        Ok(())
    }

    #[test]
    fn t_debug_msgs_are_logged_only_at_curlevel_debug() -> io::Result<()> {
        let nolog_levels = vec![
            Level::None,
            Level::UserError,
            Level::Critical,
            Level::Error,
            Level::Warn,
            Level::Info,
        ];

        for level in nolog_levels {
            let (_tmp, logfile, mut logger) = setup_logger()?;
            logger.set_loglevel(level);

            logger.log(Level::Debug, "hello");

            drop(logger);

            log_contains_n_lines(&logfile, 0)?;
        }

        let log_levels = vec![
            Level::Debug,
        ];

        for level in log_levels {
            let (_tmp, logfile, mut logger) = setup_logger()?;
            logger.set_loglevel(level);

            logger.log(Level::Debug, "hello");

            drop(logger);

            log_contains_n_lines(&logfile, 1)?;
        };

        Ok(())
    }
}
<commit_msg>Document everything in Logger<commit_after>//! Keeps a record of what the program did.

extern crate chrono;

use self::chrono::offset::Local;
use std::fmt;
use std::fs::{File, OpenOptions};
use std::io::Write;

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
/// "Importance levels" for log messages.
///
/// Each message is assigned a level. set_loglevel instructs Logger to only store messages at and
/// above a certain importance level, making the log file shorter and easier to understand.
pub enum Level {
    /// Not important at all, don't log.
    ///
    /// This level is purely for Logger's internal use, and shouldn't be passed to log(). That
    /// isn't enforced in any way, though.
    None,

    /// An error that can potentially be resolved by the user.
    ///
    /// This level should be used for configuration errors and the like.
    UserError,

    /// An error that prevents program from working at all.
    ///
    /// E.g. failure to open a cache file is a critical error, because we can't do anything without
    /// cache.
    Critical,

    /// An error that prevents some function from working.
    ///
    /// E.g. failure to find an item in the cache prevents Newsboat from displaying it, but other
    /// functions are still working, so overall it's not critical.
    Error,

    /// Warning about a potential problem.
    Warn,

    /// Useful information that can roughly explain what's going on.
    ///
    /// This level should be used with rough descriptions of stages that the program is going
    /// through. Fine details (indices, array sizes etc.) should be logged at Level::Debug instead.
    Info,

    /// May be useful to programmers when debugging.
    ///
    /// This level should be used for the most minutiae details about program execution, like byte
    /// offsets, indices, sizes of internal data structures and so forth.
    Debug,
}

impl fmt::Display for Level {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Level::None => write!(f, "NONE"),
            Level::UserError => write!(f, "USERERROR"),
            Level::Critical => write!(f, "CRITICAL"),
            Level::Error => write!(f, "ERROR"),
            Level::Warn => write!(f, "WARNING"),
            Level::Info => write!(f, "INFO"),
            Level::Debug => write!(f, "DEBUG"),
        }
    }
}

/// Keeps a record of what the program did.
///
/// Each message in the log is time-stamped, and marked with its importance level.
///
/// This is meant to be a long-lived, shared object that exists for the duration of the program.
/// Users would call its `log` method to add messages to the log file, like this:
///
/// ```
/// // Create and configure the logger
/// let logger = Logger::new();
/// logger.set_logfile("/path/to/my/log.txt");
///
/// // Only log critical and configuration errors
/// logger.set_loglevel(Level::Critical);
///
/// // -- snip --
///
/// logger.log(Level::UserError, "Please specify a remote API to use");
///
/// // This one won't be logged because its importance level is too low
/// logger.log(Level::Debug, format!("feeds.len() == {}", 42));
/// ```
pub struct Logger {
    logfile: Option<File>,

    /// Maximum "importance level" of the messages that will be written to the log.
    loglevel: Level,
}

impl Logger {
    /// Constructs an object that doesn't log anything.
    ///
    /// To make that Logger useful, you need to call set_logfile() and set_loglevel().
    pub fn new() -> Logger {
        Logger {
            logfile: None,
            loglevel: Level::None,
        }
    }

    /// Specifies the file to which the messages will be written.
    ///
    /// The file will be created if it doesn't exist yet. It will be opened in the append mode, so
    /// its previous content will stay unchanged.
    ///
    /// # Errors
    ///
    /// This can't fail, but if the file couldn't be created or opened, an error message will be
    /// printed to stderr.
    pub fn set_logfile(&mut self, filename: &str) {
        let file = OpenOptions::new()
            .create(true)
            .append(true)
            .open(filename);

        match file {
            Ok(file) => self.logfile = Some(file),
            Err(error) => eprintln!("Couldn't open `{}' as a logfile: {}", filename, error),
        }
    }

    /// Writes a message to a log.
    ///
    /// If `level` is lower than the logger's current level, the message won't be written. For
    /// example, if Logger's level is set to Level::Critical, then Level::Error won't be written.
    ///
    /// # Errors
    ///
    /// If the message couldn't be written for whatever reason, this function ignores the failure.
    /// Were you to check the return value of every log() call, you'd just stop writing logs.
    pub fn log(&mut self, level: Level, message: &str) {
        if level > self.loglevel {
            return;
        }

        if let Some(ref mut logfile) = self.logfile {
            let timestamp = Local::now().format("%Y-%m-%d %H:%M:%S");
            let line = format!("[{}] {}: {}\n", timestamp, level, message);

            // Ignoring the error since checking every log() call will be too bothersome.
            let _ = logfile.write_all(line.as_bytes());
        }
    }

    /// Sets maximum "importance level" of the messages that will be written to the log.
    ///
    /// For example, after the call to set_loglevel(Level::Error), only UserError, Critical, and
    /// Error messages will be written.
    pub fn set_loglevel(&mut self, level: Level) {
        self.loglevel = level;
    }
}

#[cfg(test)]
mod tests {
    extern crate tempfile;

    use super::*;

    use self::tempfile::TempDir;
    use self::chrono::{TimeZone, Duration};
    use std::io::{self, BufReader, BufRead};
    use std::path;

    fn setup_logger() -> io::Result<(TempDir, path::PathBuf, Logger)> {
        let tmp = TempDir::new()?;
        let logfile = {
            let mut logfile = tmp.path().to_owned();
            logfile.push("example.log");
            logfile
        };
        assert!(!logfile.exists());

        let mut logger = Logger::new();
        logger.set_logfile(logfile.to_str().unwrap());

        Ok((tmp, logfile, logger))
    }

    fn parse_log_line(line: &str) -> Option<(&str, &str, &str)> {
        if !line.starts_with("[") {
            return None;
        }

        let timestamp_end = line.find(']').expect("Failed to find the end of the timestamp");
        // Timestamp starts with "[", we skip it by starting at 1 rather than 0.
        let timestamp = &line[1..timestamp_end];

        // "]" is an ASCII character, so it occupies one byte in UTF-8. As a result, we
        // can simply add one to get the next character's byte offset. And since the
        // next char should be a space, which is ASCII as well, we can just add 2.
        //
        // If timestamp is followed by something non-ASCII, indexing into &str will
        // panic and fail the test, which is good.
        if &line[timestamp_end+1..timestamp_end+2] != " " {
            return None;
        }

        let level_end =
            line[timestamp_end+2..]
            .find(':')
            .expect("Failed to find the end of the loglevel");
        let level = &line[timestamp_end+2..timestamp_end+2+level_end];

        // Message starts after ": " that follows the level, hence +2.
        let message = &line[timestamp_end+2+level_end+2..];

        Some((timestamp, level, message))
    }

    fn log_contains_n_lines(logfile: &path::Path, n: usize)  -> io::Result<()> {
        let file = File::open(logfile)?;
        let reader = BufReader::new(file);
        assert_eq!(reader.lines().count(), n);
        Ok(())
    }

    #[test]
    fn t_set_logfile() -> io::Result<()> {
        let (_tmp, logfile, _logger) = setup_logger()?;

        assert!(logfile.exists());

        Ok(())
    }

    #[test]
    fn t_log_writes_message_to_the_file() -> io::Result<()> {
        let (_tmp, logfile, mut logger) = setup_logger()?;

        let messages = vec![
            "Hello, world!",
            "I'm doing fine, how are you?",
            "Time to wrap up, see ya!",
        ];

        let start_time = Local::now();
        for msg in &messages {
            logger.log(Level::Debug, msg);
        }
        let finish_time = Local::now();

        // Dropping logger to force it to flush the log and close the file
        drop(logger);

        let file = File::open(logfile)?;
        let reader = BufReader::new(file);
        for (line, expected) in reader.lines().zip(messages) {
            match line {
                Ok(line) => {
                    let (timestamp_str, _level, message) =
                        parse_log_line(&line)
                        .expect("Failed to split the log line into parts");

                    let timestamp =
                        Local::now()
                        .timezone()
                        .datetime_from_str(timestamp_str, "%Y-%m-%d %H:%M:%S")
                        .expect("Failed to parse the timestamp from the log file");
                    // `start_time` and `end_time` may have millisecond precision or better,
                    // whereas `timestamp` is limited to seconds. Therefore, we account for
                    // a situation where `start_time` is slightly bigger than `timestamp`.
                    assert!(timestamp - start_time > Duration::seconds(-1));
                    assert!(finish_time >= timestamp);

                    assert_eq!(message, expected);
                }
                Err(e) => return Err(e),
            }
        }

        Ok(())
    }

    #[test]
    fn t_different_loglevels_have_different_names() -> io::Result<()> {
        let (_tmp, logfile, mut logger) = setup_logger()?;

        let levels = vec![
            (Level::UserError, "USERERROR"),
            (Level::Critical, "CRITICAL"),
            (Level::Error, "ERROR"),
            (Level::Warn, "WARNING"),
            (Level::Info, "INFO"),
            (Level::Debug, "DEBUG"),
        ];

        let msg = "Some test message";

        for (level, _level_str) in &levels {
            logger.log(*level, msg);
        }

        // Dropping logger to force it to flush the log and close the file
        drop(logger);

        let file = File::open(logfile)?;
        let reader = BufReader::new(file);
        for (line, expected) in reader.lines().zip(levels.iter().map(|(_, l)| l)) {
            match line {
                Ok(line) => {
                    let (_timestamp_str, level, _message) =
                        parse_log_line(&line)
                        .expect("Failed to split the log line into parts");

                    assert_eq!(&level, expected);
                }
                Err(e) => return Err(e),
            }
        }

        Ok(())
    }

    #[test]
    fn t_if_curlevel_is_none_nothing_is_logged() -> io::Result<()> {
        let (_tmp, logfile, mut logger) = setup_logger()?;

        logger.set_loglevel(Level::None);

        let levels = vec![
            (Level::UserError, "USERERROR"),
            (Level::Critical, "CRITICAL"),
            (Level::Error, "ERROR"),
            (Level::Warn, "WARNING"),
            (Level::Info, "INFO"),
            (Level::Debug, "DEBUG"),
        ];

        let msg = "Some test message";

        for (level, _level_str) in &levels {
            logger.log(*level, msg);
        }

        // Dropping logger to force it to flush the log and close the file
        drop(logger);

        log_contains_n_lines(&logfile, 0)?;

        Ok(())
    }

    #[test]
    fn t_user_errors_are_logged_at_all_curlevels_beside_none() -> io::Result<()> {
        {
            let (_tmp, logfile, mut logger) = setup_logger()?;
            logger.set_loglevel(Level::None);

            logger.log(Level::UserError, "hello");

            drop(logger);

            log_contains_n_lines(&logfile, 0)?;
        }

        let levels = vec![
            Level::UserError,
            Level::Critical,
            Level::Error,
            Level::Warn,
            Level::Info,
            Level::Debug,
        ];

        for level in levels {
            let (_tmp, logfile, mut logger) = setup_logger()?;
            logger.set_loglevel(level);

            logger.log(Level::UserError, "hello");

            drop(logger);

            log_contains_n_lines(&logfile, 1)?;
        };

        Ok(())
    }

    #[test]
    fn t_critial_msgs_are_logged_at_curlevels_starting_with_critical() -> io::Result<()> {
        let nolog_levels = vec![
            Level::None,
            Level::UserError,
        ];

        for level in nolog_levels {
            let (_tmp, logfile, mut logger) = setup_logger()?;
            logger.set_loglevel(level);

            logger.log(Level::Critical, "hello");

            drop(logger);

            log_contains_n_lines(&logfile, 0)?;
        }

        let log_levels = vec![
            Level::Critical,
            Level::Error,
            Level::Warn,
            Level::Info,
            Level::Debug,
        ];

        for level in log_levels {
            let (_tmp, logfile, mut logger) = setup_logger()?;
            logger.set_loglevel(level);

            logger.log(Level::Critical, "hello");

            drop(logger);

            log_contains_n_lines(&logfile, 1)?;
        };

        Ok(())
    }

    #[test]
    fn t_error_msgs_are_logged_at_curlevels_starting_with_error() -> io::Result<()> {
        let nolog_levels = vec![
            Level::None,
            Level::UserError,
            Level::Critical,
        ];

        for level in nolog_levels {
            let (_tmp, logfile, mut logger) = setup_logger()?;
            logger.set_loglevel(level);

            logger.log(Level::Error, "hello");

            drop(logger);

            log_contains_n_lines(&logfile, 0)?;
        }

        let log_levels = vec![
            Level::Error,
            Level::Warn,
            Level::Info,
            Level::Debug,
        ];

        for level in log_levels {
            let (_tmp, logfile, mut logger) = setup_logger()?;
            logger.set_loglevel(level);

            logger.log(Level::Error, "hello");

            drop(logger);

            log_contains_n_lines(&logfile, 1)?;
        };

        Ok(())
    }

    #[test]
    fn t_warning_msgs_are_logged_at_curlevels_starting_with_warning() -> io::Result<()> {
        let nolog_levels = vec![
            Level::None,
            Level::UserError,
            Level::Critical,
            Level::Error,
        ];

        for level in nolog_levels {
            let (_tmp, logfile, mut logger) = setup_logger()?;
            logger.set_loglevel(level);

            logger.log(Level::Warn, "hello");

            drop(logger);

            log_contains_n_lines(&logfile, 0)?;
        }

        let log_levels = vec![
            Level::Warn,
            Level::Info,
            Level::Debug,
        ];

        for level in log_levels {
            let (_tmp, logfile, mut logger) = setup_logger()?;
            logger.set_loglevel(level);

            logger.log(Level::Warn, "hello");

            drop(logger);

            log_contains_n_lines(&logfile, 1)?;
        };

        Ok(())
    }

    #[test]
    fn t_info_msgs_are_logged_at_curlevels_starting_with_info() -> io::Result<()> {
        let nolog_levels = vec![
            Level::None,
            Level::UserError,
            Level::Critical,
            Level::Error,
            Level::Warn,
        ];

        for level in nolog_levels {
            let (_tmp, logfile, mut logger) = setup_logger()?;
            logger.set_loglevel(level);

            logger.log(Level::Info, "hello");

            drop(logger);

            log_contains_n_lines(&logfile, 0)?;
        }

        let log_levels = vec![
            Level::Info,
            Level::Debug,
        ];

        for level in log_levels {
            let (_tmp, logfile, mut logger) = setup_logger()?;
            logger.set_loglevel(level);

            logger.log(Level::Info, "hello");

            drop(logger);

            log_contains_n_lines(&logfile, 1)?;
        };

        Ok(())
    }

    #[test]
    fn t_debug_msgs_are_logged_only_at_curlevel_debug() -> io::Result<()> {
        let nolog_levels = vec![
            Level::None,
            Level::UserError,
            Level::Critical,
            Level::Error,
            Level::Warn,
            Level::Info,
        ];

        for level in nolog_levels {
            let (_tmp, logfile, mut logger) = setup_logger()?;
            logger.set_loglevel(level);

            logger.log(Level::Debug, "hello");

            drop(logger);

            log_contains_n_lines(&logfile, 0)?;
        }

        let log_levels = vec![
            Level::Debug,
        ];

        for level in log_levels {
            let (_tmp, logfile, mut logger) = setup_logger()?;
            logger.set_loglevel(level);

            logger.log(Level::Debug, "hello");

            drop(logger);

            log_contains_n_lines(&logfile, 1)?;
        };

        Ok(())
    }
}
<|endoftext|>


<commit_before>#[macro_export]
macro_rules! gen_uri
{
	( $api_class:expr, $($api_func:expr)* ) =>
	({
		use BASE_URL;
		use API_VERSION;
		let mut func_calls = String::new();
		$(
			func_calls.push_str(&format!("/{}", $api_func));
		)*
		format!("{}{}/{}{}", BASE_URL, API_VERSION,
			$api_class, func_calls)
	});
}

macro_rules! gen_upload_uri
{
	( $api_class:expr, $($api_func:expr)* ) =>
	({
		use UPLOAD_URL;
		use API_VERSION;
		let mut func_calls = String::new();
		$(
			func_calls.push_str(&format!("/{}", $api_func));
		)*
		format!("{}{}/{}{}", UPLOAD_URL, API_VERSION,
			$api_class, func_calls)
	});
}

#[macro_export]
macro_rules! build_object {
	() => ();
}
<commit_msg>added missing comma in macros<commit_after>#[macro_export]
macro_rules! gen_uri
{
	( $api_class:expr, $($api_func:expr),* ) =>
	({
		use BASE_URL;
		use API_VERSION;
		let mut func_calls = String::new();
		$(
			func_calls.push_str(&format!("/{}", $api_func));
		)*
		format!("{}{}/{}{}", BASE_URL, API_VERSION,
			$api_class, func_calls)
	});
}

macro_rules! gen_upload_uri
{
	( $api_class:expr, $($api_func:expr),* ) =>
	({
		use UPLOAD_URL;
		use API_VERSION;
		let mut func_calls = String::new();
		$(
			func_calls.push_str(&format!("/{}", $api_func));
		)*
		format!("{}{}/{}{}", UPLOAD_URL, API_VERSION,
			$api_class, func_calls)
	});
}

#[macro_export]
macro_rules! build_object {
	() => ();
}
<|endoftext|>


<commit_before>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/// The standard logging macro.
///
/// This macro will generically log with the specified `Level` and `format!`
/// based argument list.
///
/// # Examples
///
/// ```edition2018
/// use log::{log, Level};
///
/// # fn main() {
/// let data = (42, "Forty-two");
/// let private_data = "private";
///
/// log!(Level::Error, "Received errors: {}, {}", data.0, data.1);
/// log!(target: "app_events", Level::Warn, "App warning: {}, {}, {}",
///     data.0, data.1, private_data);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! log {
    (target: $target:expr, $lvl:expr, $message:expr) => ({
        let lvl = $lvl;
        if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {
            // ensure that $message is a valid format string literal
            let _ = __log_format_args!($message);
            $crate::__private_api_log_lit(
                $message,
                lvl,
                &($target, __log_module_path!(), __log_file!(), __log_line!()),
            );
        }
    });
    (target: $target:expr, $lvl:expr, $($arg:tt)+) => ({
        let lvl = $lvl;
        if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {
            $crate::__private_api_log(
                __log_format_args!($($arg)+),
                lvl,
                &($target, __log_module_path!(), __log_file!(), __log_line!()),
            );
        }
    });
    ($lvl:expr, $($arg:tt)+) => (log!(target: __log_module_path!(), $lvl, $($arg)+))
}

/// Logs a message at the error level.
///
/// # Examples
///
/// ```edition2018
/// use log::error;
///
/// # fn main() {
/// let (err_info, port) = ("No connection", 22);
///
/// error!("Error: {} on port {}", err_info, port);
/// error!(target: "app_events", "App Error: {}, Port: {}", err_info, 22);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! error {
    (target: $target:expr, $($arg:tt)+) => (
        log!(target: $target, $crate::Level::Error, $($arg)+);
    );
    ($($arg:tt)+) => (
        log!($crate::Level::Error, $($arg)+);
    )
}

/// Logs a message at the warn level.
///
/// # Examples
///
/// ```edition2018
/// use log::warn;
///
/// # fn main() {
/// let warn_description = "Invalid Input";
///
/// warn!("Warning! {}!", warn_description);
/// warn!(target: "input_events", "App received warning: {}", warn_description);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! warn {
    (target: $target:expr, $($arg:tt)+) => (
        log!(target: $target, $crate::Level::Warn, $($arg)+);
    );
    ($($arg:tt)+) => (
        log!($crate::Level::Warn, $($arg)+);
    )
}

/// Logs a message at the info level.
///
/// # Examples
///
/// ```edition2018
/// use log::info;
///
/// # fn main() {
/// # struct Connection { port: u32, speed: f32 }
/// let conn_info = Connection { port: 40, speed: 3.20 };
///
/// info!("Connected to port {} at {} Mb/s", conn_info.port, conn_info.speed);
/// info!(target: "connection_events", "Successfull connection, port: {}, speed: {}",
///       conn_info.port, conn_info.speed);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! info {
    (target: $target:expr, $($arg:tt)+) => (
        log!(target: $target, $crate::Level::Info, $($arg)+);
    );
    ($($arg:tt)+) => (
        log!($crate::Level::Info, $($arg)+);
    )
}

/// Logs a message at the debug level.
///
/// # Examples
///
/// ```edition2018
/// use log::debug;
///
/// # fn main() {
/// # struct Position { x: f32, y: f32 }
/// let pos = Position { x: 3.234, y: -1.223 };
///
/// debug!("New position: x: {}, y: {}", pos.x, pos.y);
/// debug!(target: "app_events", "New position: x: {}, y: {}", pos.x, pos.y);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! debug {
    (target: $target:expr, $($arg:tt)+) => (
        log!(target: $target, $crate::Level::Debug, $($arg)+);
    );
    ($($arg:tt)+) => (
        log!($crate::Level::Debug, $($arg)+);
    )
}

/// Logs a message at the trace level.
///
/// # Examples
///
/// ```edition2018
/// use log::trace;
///
/// # fn main() {
/// # struct Position { x: f32, y: f32 }
/// let pos = Position { x: 3.234, y: -1.223 };
///
/// trace!("Position is: x: {}, y: {}", pos.x, pos.y);
/// trace!(target: "app_events", "x is {} and y is {}",
///        if pos.x >= 0.0 { "positive" } else { "negative" },
///        if pos.y >= 0.0 { "positive" } else { "negative" });
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! trace {
    (target: $target:expr, $($arg:tt)+) => (
        log!(target: $target, $crate::Level::Trace, $($arg)+);
    );
    ($($arg:tt)+) => (
        log!($crate::Level::Trace, $($arg)+);
    )
}

/// Determines if a message logged at the specified level in that module will
/// be logged.
///
/// This can be used to avoid expensive computation of log message arguments if
/// the message would be ignored anyway.
///
/// # Examples
///
/// ```edition2018
/// use log::Level::Debug;
/// use log::{debug, log_enabled};
///
/// # fn foo() {
/// if log_enabled!(Debug) {
///     let data = expensive_call();
///     debug!("expensive debug data: {} {}", data.x, data.y);
/// }
/// if log_enabled!(target: "Global", Debug) {
///    let data = expensive_call();
///    debug!(target: "Global", "expensive debug data: {} {}", data.x, data.y);
/// }
/// # }
/// # struct Data { x: u32, y: u32 }
/// # fn expensive_call() -> Data { Data { x: 0, y: 0 } }
/// # fn main() {}
/// ```
#[macro_export(local_inner_macros)]
macro_rules! log_enabled {
    (target: $target:expr, $lvl:expr) => {{
        let lvl = $lvl;
        lvl <= $crate::STATIC_MAX_LEVEL
            && lvl <= $crate::max_level()
            && $crate::__private_api_enabled(lvl, $target)
    }};
    ($lvl:expr) => {
        log_enabled!(target: __log_module_path!(), $lvl)
    };
}

// The log macro above cannot invoke format_args directly because it uses
// local_inner_macros. A format_args invocation there would resolve to
// $crate::format_args which does not exist. Instead invoke format_args here
// outside of local_inner_macros so that it resolves (probably) to
// core::format_args or std::format_args. Same for the several macros that
// follow.
//
// This is a workaround until we drop support for pre-1.30 compilers. At that
// point we can remove use of local_inner_macros, use $crate:: when invoking
// local macros, and invoke format_args directly.
#[doc(hidden)]
#[macro_export]
macro_rules! __log_format_args {
    ($($args:tt)*) => {
        format_args!($($args)*)
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __log_module_path {
    () => {
        module_path!()
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __log_file {
    () => {
        file!()
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __log_line {
    () => {
        line!()
    };
}
<commit_msg>Remove some trailing semicolons from macro definitions<commit_after>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/// The standard logging macro.
///
/// This macro will generically log with the specified `Level` and `format!`
/// based argument list.
///
/// # Examples
///
/// ```edition2018
/// use log::{log, Level};
///
/// # fn main() {
/// let data = (42, "Forty-two");
/// let private_data = "private";
///
/// log!(Level::Error, "Received errors: {}, {}", data.0, data.1);
/// log!(target: "app_events", Level::Warn, "App warning: {}, {}, {}",
///     data.0, data.1, private_data);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! log {
    (target: $target:expr, $lvl:expr, $message:expr) => ({
        let lvl = $lvl;
        if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {
            // ensure that $message is a valid format string literal
            let _ = __log_format_args!($message);
            $crate::__private_api_log_lit(
                $message,
                lvl,
                &($target, __log_module_path!(), __log_file!(), __log_line!()),
            );
        }
    });
    (target: $target:expr, $lvl:expr, $($arg:tt)+) => ({
        let lvl = $lvl;
        if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {
            $crate::__private_api_log(
                __log_format_args!($($arg)+),
                lvl,
                &($target, __log_module_path!(), __log_file!(), __log_line!()),
            );
        }
    });
    ($lvl:expr, $($arg:tt)+) => (log!(target: __log_module_path!(), $lvl, $($arg)+))
}

/// Logs a message at the error level.
///
/// # Examples
///
/// ```edition2018
/// use log::error;
///
/// # fn main() {
/// let (err_info, port) = ("No connection", 22);
///
/// error!("Error: {} on port {}", err_info, port);
/// error!(target: "app_events", "App Error: {}, Port: {}", err_info, 22);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! error {
    (target: $target:expr, $($arg:tt)+) => (
        log!(target: $target, $crate::Level::Error, $($arg)+)
    );
    ($($arg:tt)+) => (
        log!($crate::Level::Error, $($arg)+)
    )
}

/// Logs a message at the warn level.
///
/// # Examples
///
/// ```edition2018
/// use log::warn;
///
/// # fn main() {
/// let warn_description = "Invalid Input";
///
/// warn!("Warning! {}!", warn_description);
/// warn!(target: "input_events", "App received warning: {}", warn_description);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! warn {
    (target: $target:expr, $($arg:tt)+) => (
        log!(target: $target, $crate::Level::Warn, $($arg)+)
    );
    ($($arg:tt)+) => (
        log!($crate::Level::Warn, $($arg)+)
    )
}

/// Logs a message at the info level.
///
/// # Examples
///
/// ```edition2018
/// use log::info;
///
/// # fn main() {
/// # struct Connection { port: u32, speed: f32 }
/// let conn_info = Connection { port: 40, speed: 3.20 };
///
/// info!("Connected to port {} at {} Mb/s", conn_info.port, conn_info.speed);
/// info!(target: "connection_events", "Successfull connection, port: {}, speed: {}",
///       conn_info.port, conn_info.speed);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! info {
    (target: $target:expr, $($arg:tt)+) => (
        log!(target: $target, $crate::Level::Info, $($arg)+)
    );
    ($($arg:tt)+) => (
        log!($crate::Level::Info, $($arg)+)
    )
}

/// Logs a message at the debug level.
///
/// # Examples
///
/// ```edition2018
/// use log::debug;
///
/// # fn main() {
/// # struct Position { x: f32, y: f32 }
/// let pos = Position { x: 3.234, y: -1.223 };
///
/// debug!("New position: x: {}, y: {}", pos.x, pos.y);
/// debug!(target: "app_events", "New position: x: {}, y: {}", pos.x, pos.y);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! debug {
    (target: $target:expr, $($arg:tt)+) => (
        log!(target: $target, $crate::Level::Debug, $($arg)+)
    );
    ($($arg:tt)+) => (
        log!($crate::Level::Debug, $($arg)+)
    )
}

/// Logs a message at the trace level.
///
/// # Examples
///
/// ```edition2018
/// use log::trace;
///
/// # fn main() {
/// # struct Position { x: f32, y: f32 }
/// let pos = Position { x: 3.234, y: -1.223 };
///
/// trace!("Position is: x: {}, y: {}", pos.x, pos.y);
/// trace!(target: "app_events", "x is {} and y is {}",
///        if pos.x >= 0.0 { "positive" } else { "negative" },
///        if pos.y >= 0.0 { "positive" } else { "negative" });
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! trace {
    (target: $target:expr, $($arg:tt)+) => (
        log!(target: $target, $crate::Level::Trace, $($arg)+)
    );
    ($($arg:tt)+) => (
        log!($crate::Level::Trace, $($arg)+)
    )
}

/// Determines if a message logged at the specified level in that module will
/// be logged.
///
/// This can be used to avoid expensive computation of log message arguments if
/// the message would be ignored anyway.
///
/// # Examples
///
/// ```edition2018
/// use log::Level::Debug;
/// use log::{debug, log_enabled};
///
/// # fn foo() {
/// if log_enabled!(Debug) {
///     let data = expensive_call();
///     debug!("expensive debug data: {} {}", data.x, data.y);
/// }
/// if log_enabled!(target: "Global", Debug) {
///    let data = expensive_call();
///    debug!(target: "Global", "expensive debug data: {} {}", data.x, data.y);
/// }
/// # }
/// # struct Data { x: u32, y: u32 }
/// # fn expensive_call() -> Data { Data { x: 0, y: 0 } }
/// # fn main() {}
/// ```
#[macro_export(local_inner_macros)]
macro_rules! log_enabled {
    (target: $target:expr, $lvl:expr) => {{
        let lvl = $lvl;
        lvl <= $crate::STATIC_MAX_LEVEL
            && lvl <= $crate::max_level()
            && $crate::__private_api_enabled(lvl, $target)
    }};
    ($lvl:expr) => {
        log_enabled!(target: __log_module_path!(), $lvl)
    };
}

// The log macro above cannot invoke format_args directly because it uses
// local_inner_macros. A format_args invocation there would resolve to
// $crate::format_args which does not exist. Instead invoke format_args here
// outside of local_inner_macros so that it resolves (probably) to
// core::format_args or std::format_args. Same for the several macros that
// follow.
//
// This is a workaround until we drop support for pre-1.30 compilers. At that
// point we can remove use of local_inner_macros, use $crate:: when invoking
// local macros, and invoke format_args directly.
#[doc(hidden)]
#[macro_export]
macro_rules! __log_format_args {
    ($($args:tt)*) => {
        format_args!($($args)*)
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __log_module_path {
    () => {
        module_path!()
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __log_file {
    () => {
        file!()
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __log_line {
    () => {
        line!()
    };
}
<|endoftext|>


<commit_before>#![allow(unknown_lints)] // older rustc doesn't know `unused_macros`
#![allow(unused_macros)]

macro_rules! forward_val_val_binop {
    (impl $imp:ident for $res:ty, $method:ident) => {
        impl $imp<$res> for $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: $res) -> $res {
                // forward to val-ref
                $imp::$method(self, &other)
            }
        }
    };
}

macro_rules! forward_val_val_binop_commutative {
    (impl $imp:ident for $res:ty, $method:ident) => {
        impl $imp<$res> for $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: $res) -> $res {
                // forward to val-ref, with the larger capacity as val
                if self.capacity() >= other.capacity() {
                    $imp::$method(self, &other)
                } else {
                    $imp::$method(other, &self)
                }
            }
        }
    };
}

macro_rules! forward_ref_val_binop {
    (impl $imp:ident for $res:ty, $method:ident) => {
        impl<'a> $imp<$res> for &'a $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: $res) -> $res {
                // forward to ref-ref
                $imp::$method(self, &other)
            }
        }
    };
}

macro_rules! forward_ref_val_binop_commutative {
    (impl $imp:ident for $res:ty, $method:ident) => {
        impl<'a> $imp<$res> for &'a $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: $res) -> $res {
                // reverse, forward to val-ref
                $imp::$method(other, self)
            }
        }
    };
}

macro_rules! forward_val_ref_binop {
    (impl $imp:ident for $res:ty, $method:ident) => {
        impl<'a> $imp<&'a $res> for $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: &$res) -> $res {
                // forward to ref-ref
                $imp::$method(&self, other)
            }
        }
    };
}

macro_rules! forward_ref_ref_binop {
    (impl $imp:ident for $res:ty, $method:ident) => {
        impl<'a, 'b> $imp<&'b $res> for &'a $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: &$res) -> $res {
                // forward to val-ref
                $imp::$method(self.clone(), other)
            }
        }
    };
}

macro_rules! forward_ref_ref_binop_commutative {
    (impl $imp:ident for $res:ty, $method:ident) => {
        impl<'a, 'b> $imp<&'b $res> for &'a $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: &$res) -> $res {
                // forward to val-ref, choosing the larger to clone
                if self.len() >= other.len() {
                    $imp::$method(self.clone(), other)
                } else {
                    $imp::$method(other.clone(), self)
                }
            }
        }
    };
}

macro_rules! forward_val_assign {
    (impl $imp:ident for $res:ty, $method:ident) => {
        impl $imp<$res> for $res {
            #[inline]
            fn $method(&mut self, other: $res) {
                self.$method(&other);
            }
        }
    };
}

macro_rules! forward_val_assign_scalar {
    (impl $imp:ident for $res:ty, $scalar:ty, $method:ident) => {
        impl $imp<$res> for $scalar {
            #[inline]
            fn $method(&mut self, other: $res) {
                self.$method(&other);
            }
        }
    };
}

/// use this if val_val_binop is already implemented and the reversed order is required
macro_rules! forward_scalar_val_val_binop_commutative {
    (impl $imp:ident < $scalar:ty > for $res:ty, $method:ident) => {
        impl $imp<$res> for $scalar {
            type Output = $res;

            #[inline]
            fn $method(self, other: $res) -> $res {
                $imp::$method(other, self)
            }
        }
    };
}

// Forward scalar to ref-val, when reusing storage is not helpful
macro_rules! forward_scalar_val_val_binop_to_ref_val {
    (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
        impl $imp<$scalar> for $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: $scalar) -> $res {
                $imp::$method(&self, other)
            }
        }

        impl $imp<$res> for $scalar {
            type Output = $res;

            #[inline]
            fn $method(self, other: $res) -> $res {
                $imp::$method(self, &other)
            }
        }
    };
}

macro_rules! forward_scalar_ref_ref_binop_to_ref_val {
    (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
        impl<'a, 'b> $imp<&'b $scalar> for &'a $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: &$scalar) -> $res {
                $imp::$method(self, *other)
            }
        }

        impl<'a, 'b> $imp<&'a $res> for &'b $scalar {
            type Output = $res;

            #[inline]
            fn $method(self, other: &$res) -> $res {
                $imp::$method(*self, other)
            }
        }
    };
}

macro_rules! forward_scalar_val_ref_binop_to_ref_val {
    (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
        impl<'a> $imp<&'a $scalar> for $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: &$scalar) -> $res {
                $imp::$method(&self, *other)
            }
        }

        impl<'a> $imp<$res> for &'a $scalar {
            type Output = $res;

            #[inline]
            fn $method(self, other: $res) -> $res {
                $imp::$method(*self, other)
            }
        }
    };
}

macro_rules! forward_scalar_val_ref_binop_to_val_val {
    (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
        impl<'a> $imp<&'a $scalar> for $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: &$scalar) -> $res {
                $imp::$method(self, *other)
            }
        }

        impl<'a> $imp<$res> for &'a $scalar {
            type Output = $res;

            #[inline]
            fn $method(self, other: $res) -> $res {
                $imp::$method(*self, other)
            }
        }
    };
}

macro_rules! forward_scalar_ref_val_binop_to_val_val {
    (impl $imp:ident < $scalar:ty > for $res:ty, $method:ident) => {
        impl<'a> $imp<$scalar> for &'a $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: $scalar) -> $res {
                $imp::$method(self.clone(), other)
            }
        }

        impl<'a> $imp<&'a $res> for $scalar {
            type Output = $res;

            #[inline]
            fn $method(self, other: &$res) -> $res {
                $imp::$method(self, other.clone())
            }
        }
    };
}

macro_rules! forward_scalar_ref_ref_binop_to_val_val {
    (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
        impl<'a, 'b> $imp<&'b $scalar> for &'a $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: &$scalar) -> $res {
                $imp::$method(self.clone(), *other)
            }
        }

        impl<'a, 'b> $imp<&'a $res> for &'b $scalar {
            type Output = $res;

            #[inline]
            fn $method(self, other: &$res) -> $res {
                $imp::$method(*self, other.clone())
            }
        }
    };
}

macro_rules! promote_scalars {
    (impl $imp:ident<$promo:ty> for $res:ty, $method:ident, $( $scalar:ty ),*) => {
        $(
            forward_all_scalar_binop_to_val_val!(impl $imp<$scalar> for $res, $method);

            impl $imp<$scalar> for $res {
                type Output = $res;

                #[inline]
                fn $method(self, other: $scalar) -> $res {
                    $imp::$method(self, other as $promo)
                }
            }

            impl $imp<$res> for $scalar {
                type Output = $res;

                #[inline]
                fn $method(self, other: $res) -> $res {
                    $imp::$method(self as $promo, other)
                }
            }
        )*
    }
}
macro_rules! promote_scalars_assign {
    (impl $imp:ident<$promo:ty> for $res:ty, $method:ident, $( $scalar:ty ),*) => {
        $(
            impl $imp<$scalar> for $res {
                #[inline]
                fn $method(&mut self, other: $scalar) {
                    self.$method(other as $promo);
                }
            }
        )*
    }
}

macro_rules! promote_unsigned_scalars {
    (impl $imp:ident for $res:ty, $method:ident) => {
        promote_scalars!(impl $imp<u32> for $res, $method, u8, u16);
        promote_scalars!(impl $imp<UsizePromotion> for $res, $method, usize);
    }
}

macro_rules! promote_unsigned_scalars_assign {
    (impl $imp:ident for $res:ty, $method:ident) => {
        promote_scalars_assign!(impl $imp<u32> for $res, $method, u8, u16);
        promote_scalars_assign!(impl $imp<UsizePromotion> for $res, $method, usize);
    }
}

macro_rules! promote_signed_scalars {
    (impl $imp:ident for $res:ty, $method:ident) => {
        promote_scalars!(impl $imp<i32> for $res, $method, i8, i16);
        promote_scalars!(impl $imp<IsizePromotion> for $res, $method, isize);
    }
}

macro_rules! promote_signed_scalars_assign {
    (impl $imp:ident for $res:ty, $method:ident) => {
        promote_scalars_assign!(impl $imp<i32> for $res, $method, i8, i16);
        promote_scalars_assign!(impl $imp<UsizePromotion> for $res, $method, isize);
    }
}

// Forward everything to ref-ref, when reusing storage is not helpful
macro_rules! forward_all_binop_to_ref_ref {
    (impl $imp:ident for $res:ty, $method:ident) => {
        forward_val_val_binop!(impl $imp for $res, $method);
        forward_val_ref_binop!(impl $imp for $res, $method);
        forward_ref_val_binop!(impl $imp for $res, $method);
    };
}

// Forward everything to val-ref, so LHS storage can be reused
macro_rules! forward_all_binop_to_val_ref {
    (impl $imp:ident for $res:ty, $method:ident) => {
        forward_val_val_binop!(impl $imp for $res, $method);
        forward_ref_val_binop!(impl $imp for $res, $method);
        forward_ref_ref_binop!(impl $imp for $res, $method);
    };
}

// Forward everything to val-ref, commutatively, so either LHS or RHS storage can be reused
macro_rules! forward_all_binop_to_val_ref_commutative {
    (impl $imp:ident for $res:ty, $method:ident) => {
        forward_val_val_binop_commutative!(impl $imp for $res, $method);
        forward_ref_val_binop_commutative!(impl $imp for $res, $method);
        forward_ref_ref_binop_commutative!(impl $imp for $res, $method);
    };
}

macro_rules! forward_all_scalar_binop_to_ref_val {
    (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
        forward_scalar_val_val_binop_to_ref_val!(impl $imp<$scalar> for $res, $method);
        forward_scalar_val_ref_binop_to_ref_val!(impl $imp<$scalar> for $res, $method);
        forward_scalar_ref_ref_binop_to_ref_val!(impl $imp<$scalar> for $res, $method);
    }
}

macro_rules! forward_all_scalar_binop_to_val_val {
    (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
        forward_scalar_val_ref_binop_to_val_val!(impl $imp<$scalar> for $res, $method);
        forward_scalar_ref_val_binop_to_val_val!(impl $imp<$scalar> for $res, $method);
        forward_scalar_ref_ref_binop_to_val_val!(impl $imp<$scalar> for $res, $method);
    }
}

macro_rules! forward_all_scalar_binop_to_val_val_commutative {
    (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
        forward_scalar_val_val_binop_commutative!(impl $imp<$scalar> for $res, $method);
        forward_all_scalar_binop_to_val_val!(impl $imp<$scalar> for $res, $method);
    }
}

macro_rules! promote_all_scalars {
    (impl $imp:ident for $res:ty, $method:ident) => {
        promote_unsigned_scalars!(impl $imp for $res, $method);
        promote_signed_scalars!(impl $imp for $res, $method);
    }
}

macro_rules! promote_all_scalars_assign {
    (impl $imp:ident for $res:ty, $method:ident) => {
        promote_unsigned_scalars_assign!(impl $imp for $res, $method);
        promote_signed_scalars_assign!(impl $imp for $res, $method);
    }
}

macro_rules! impl_sum_iter_type {
    ($res:ty) => {
        impl<T> Sum<T> for $res
        where
            $res: Add<T, Output = $res>,
        {
            fn sum<I>(iter: I) -> Self
            where
                I: Iterator<Item = T>,
            {
                iter.fold(Zero::zero(), <$res>::add)
            }
        }
    };
}

macro_rules! impl_product_iter_type {
    ($res:ty) => {
        impl<T> Product<T> for $res
        where
            $res: Mul<T, Output = $res>,
        {
            fn product<I>(iter: I) -> Self
            where
                I: Iterator<Item = T>,
            {
                iter.fold(One::one(), <$res>::mul)
            }
        }
    };
}
<commit_msg>Add a ref in forward_scalar_val_ref_binop_to_ref_val<commit_after>#![allow(unknown_lints)] // older rustc doesn't know `unused_macros`
#![allow(unused_macros)]

macro_rules! forward_val_val_binop {
    (impl $imp:ident for $res:ty, $method:ident) => {
        impl $imp<$res> for $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: $res) -> $res {
                // forward to val-ref
                $imp::$method(self, &other)
            }
        }
    };
}

macro_rules! forward_val_val_binop_commutative {
    (impl $imp:ident for $res:ty, $method:ident) => {
        impl $imp<$res> for $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: $res) -> $res {
                // forward to val-ref, with the larger capacity as val
                if self.capacity() >= other.capacity() {
                    $imp::$method(self, &other)
                } else {
                    $imp::$method(other, &self)
                }
            }
        }
    };
}

macro_rules! forward_ref_val_binop {
    (impl $imp:ident for $res:ty, $method:ident) => {
        impl<'a> $imp<$res> for &'a $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: $res) -> $res {
                // forward to ref-ref
                $imp::$method(self, &other)
            }
        }
    };
}

macro_rules! forward_ref_val_binop_commutative {
    (impl $imp:ident for $res:ty, $method:ident) => {
        impl<'a> $imp<$res> for &'a $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: $res) -> $res {
                // reverse, forward to val-ref
                $imp::$method(other, self)
            }
        }
    };
}

macro_rules! forward_val_ref_binop {
    (impl $imp:ident for $res:ty, $method:ident) => {
        impl<'a> $imp<&'a $res> for $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: &$res) -> $res {
                // forward to ref-ref
                $imp::$method(&self, other)
            }
        }
    };
}

macro_rules! forward_ref_ref_binop {
    (impl $imp:ident for $res:ty, $method:ident) => {
        impl<'a, 'b> $imp<&'b $res> for &'a $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: &$res) -> $res {
                // forward to val-ref
                $imp::$method(self.clone(), other)
            }
        }
    };
}

macro_rules! forward_ref_ref_binop_commutative {
    (impl $imp:ident for $res:ty, $method:ident) => {
        impl<'a, 'b> $imp<&'b $res> for &'a $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: &$res) -> $res {
                // forward to val-ref, choosing the larger to clone
                if self.len() >= other.len() {
                    $imp::$method(self.clone(), other)
                } else {
                    $imp::$method(other.clone(), self)
                }
            }
        }
    };
}

macro_rules! forward_val_assign {
    (impl $imp:ident for $res:ty, $method:ident) => {
        impl $imp<$res> for $res {
            #[inline]
            fn $method(&mut self, other: $res) {
                self.$method(&other);
            }
        }
    };
}

macro_rules! forward_val_assign_scalar {
    (impl $imp:ident for $res:ty, $scalar:ty, $method:ident) => {
        impl $imp<$res> for $scalar {
            #[inline]
            fn $method(&mut self, other: $res) {
                self.$method(&other);
            }
        }
    };
}

/// use this if val_val_binop is already implemented and the reversed order is required
macro_rules! forward_scalar_val_val_binop_commutative {
    (impl $imp:ident < $scalar:ty > for $res:ty, $method:ident) => {
        impl $imp<$res> for $scalar {
            type Output = $res;

            #[inline]
            fn $method(self, other: $res) -> $res {
                $imp::$method(other, self)
            }
        }
    };
}

// Forward scalar to ref-val, when reusing storage is not helpful
macro_rules! forward_scalar_val_val_binop_to_ref_val {
    (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
        impl $imp<$scalar> for $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: $scalar) -> $res {
                $imp::$method(&self, other)
            }
        }

        impl $imp<$res> for $scalar {
            type Output = $res;

            #[inline]
            fn $method(self, other: $res) -> $res {
                $imp::$method(self, &other)
            }
        }
    };
}

macro_rules! forward_scalar_ref_ref_binop_to_ref_val {
    (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
        impl<'a, 'b> $imp<&'b $scalar> for &'a $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: &$scalar) -> $res {
                $imp::$method(self, *other)
            }
        }

        impl<'a, 'b> $imp<&'a $res> for &'b $scalar {
            type Output = $res;

            #[inline]
            fn $method(self, other: &$res) -> $res {
                $imp::$method(*self, other)
            }
        }
    };
}

macro_rules! forward_scalar_val_ref_binop_to_ref_val {
    (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
        impl<'a> $imp<&'a $scalar> for $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: &$scalar) -> $res {
                $imp::$method(&self, *other)
            }
        }

        impl<'a> $imp<$res> for &'a $scalar {
            type Output = $res;

            #[inline]
            fn $method(self, other: $res) -> $res {
                $imp::$method(*self, &other)
            }
        }
    };
}

macro_rules! forward_scalar_val_ref_binop_to_val_val {
    (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
        impl<'a> $imp<&'a $scalar> for $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: &$scalar) -> $res {
                $imp::$method(self, *other)
            }
        }

        impl<'a> $imp<$res> for &'a $scalar {
            type Output = $res;

            #[inline]
            fn $method(self, other: $res) -> $res {
                $imp::$method(*self, other)
            }
        }
    };
}

macro_rules! forward_scalar_ref_val_binop_to_val_val {
    (impl $imp:ident < $scalar:ty > for $res:ty, $method:ident) => {
        impl<'a> $imp<$scalar> for &'a $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: $scalar) -> $res {
                $imp::$method(self.clone(), other)
            }
        }

        impl<'a> $imp<&'a $res> for $scalar {
            type Output = $res;

            #[inline]
            fn $method(self, other: &$res) -> $res {
                $imp::$method(self, other.clone())
            }
        }
    };
}

macro_rules! forward_scalar_ref_ref_binop_to_val_val {
    (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
        impl<'a, 'b> $imp<&'b $scalar> for &'a $res {
            type Output = $res;

            #[inline]
            fn $method(self, other: &$scalar) -> $res {
                $imp::$method(self.clone(), *other)
            }
        }

        impl<'a, 'b> $imp<&'a $res> for &'b $scalar {
            type Output = $res;

            #[inline]
            fn $method(self, other: &$res) -> $res {
                $imp::$method(*self, other.clone())
            }
        }
    };
}

macro_rules! promote_scalars {
    (impl $imp:ident<$promo:ty> for $res:ty, $method:ident, $( $scalar:ty ),*) => {
        $(
            forward_all_scalar_binop_to_val_val!(impl $imp<$scalar> for $res, $method);

            impl $imp<$scalar> for $res {
                type Output = $res;

                #[inline]
                fn $method(self, other: $scalar) -> $res {
                    $imp::$method(self, other as $promo)
                }
            }

            impl $imp<$res> for $scalar {
                type Output = $res;

                #[inline]
                fn $method(self, other: $res) -> $res {
                    $imp::$method(self as $promo, other)
                }
            }
        )*
    }
}
macro_rules! promote_scalars_assign {
    (impl $imp:ident<$promo:ty> for $res:ty, $method:ident, $( $scalar:ty ),*) => {
        $(
            impl $imp<$scalar> for $res {
                #[inline]
                fn $method(&mut self, other: $scalar) {
                    self.$method(other as $promo);
                }
            }
        )*
    }
}

macro_rules! promote_unsigned_scalars {
    (impl $imp:ident for $res:ty, $method:ident) => {
        promote_scalars!(impl $imp<u32> for $res, $method, u8, u16);
        promote_scalars!(impl $imp<UsizePromotion> for $res, $method, usize);
    }
}

macro_rules! promote_unsigned_scalars_assign {
    (impl $imp:ident for $res:ty, $method:ident) => {
        promote_scalars_assign!(impl $imp<u32> for $res, $method, u8, u16);
        promote_scalars_assign!(impl $imp<UsizePromotion> for $res, $method, usize);
    }
}

macro_rules! promote_signed_scalars {
    (impl $imp:ident for $res:ty, $method:ident) => {
        promote_scalars!(impl $imp<i32> for $res, $method, i8, i16);
        promote_scalars!(impl $imp<IsizePromotion> for $res, $method, isize);
    }
}

macro_rules! promote_signed_scalars_assign {
    (impl $imp:ident for $res:ty, $method:ident) => {
        promote_scalars_assign!(impl $imp<i32> for $res, $method, i8, i16);
        promote_scalars_assign!(impl $imp<UsizePromotion> for $res, $method, isize);
    }
}

// Forward everything to ref-ref, when reusing storage is not helpful
macro_rules! forward_all_binop_to_ref_ref {
    (impl $imp:ident for $res:ty, $method:ident) => {
        forward_val_val_binop!(impl $imp for $res, $method);
        forward_val_ref_binop!(impl $imp for $res, $method);
        forward_ref_val_binop!(impl $imp for $res, $method);
    };
}

// Forward everything to val-ref, so LHS storage can be reused
macro_rules! forward_all_binop_to_val_ref {
    (impl $imp:ident for $res:ty, $method:ident) => {
        forward_val_val_binop!(impl $imp for $res, $method);
        forward_ref_val_binop!(impl $imp for $res, $method);
        forward_ref_ref_binop!(impl $imp for $res, $method);
    };
}

// Forward everything to val-ref, commutatively, so either LHS or RHS storage can be reused
macro_rules! forward_all_binop_to_val_ref_commutative {
    (impl $imp:ident for $res:ty, $method:ident) => {
        forward_val_val_binop_commutative!(impl $imp for $res, $method);
        forward_ref_val_binop_commutative!(impl $imp for $res, $method);
        forward_ref_ref_binop_commutative!(impl $imp for $res, $method);
    };
}

macro_rules! forward_all_scalar_binop_to_ref_val {
    (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
        forward_scalar_val_val_binop_to_ref_val!(impl $imp<$scalar> for $res, $method);
        forward_scalar_val_ref_binop_to_ref_val!(impl $imp<$scalar> for $res, $method);
        forward_scalar_ref_ref_binop_to_ref_val!(impl $imp<$scalar> for $res, $method);
    }
}

macro_rules! forward_all_scalar_binop_to_val_val {
    (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
        forward_scalar_val_ref_binop_to_val_val!(impl $imp<$scalar> for $res, $method);
        forward_scalar_ref_val_binop_to_val_val!(impl $imp<$scalar> for $res, $method);
        forward_scalar_ref_ref_binop_to_val_val!(impl $imp<$scalar> for $res, $method);
    }
}

macro_rules! forward_all_scalar_binop_to_val_val_commutative {
    (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
        forward_scalar_val_val_binop_commutative!(impl $imp<$scalar> for $res, $method);
        forward_all_scalar_binop_to_val_val!(impl $imp<$scalar> for $res, $method);
    }
}

macro_rules! promote_all_scalars {
    (impl $imp:ident for $res:ty, $method:ident) => {
        promote_unsigned_scalars!(impl $imp for $res, $method);
        promote_signed_scalars!(impl $imp for $res, $method);
    }
}

macro_rules! promote_all_scalars_assign {
    (impl $imp:ident for $res:ty, $method:ident) => {
        promote_unsigned_scalars_assign!(impl $imp for $res, $method);
        promote_signed_scalars_assign!(impl $imp for $res, $method);
    }
}

macro_rules! impl_sum_iter_type {
    ($res:ty) => {
        impl<T> Sum<T> for $res
        where
            $res: Add<T, Output = $res>,
        {
            fn sum<I>(iter: I) -> Self
            where
                I: Iterator<Item = T>,
            {
                iter.fold(Zero::zero(), <$res>::add)
            }
        }
    };
}

macro_rules! impl_product_iter_type {
    ($res:ty) => {
        impl<T> Product<T> for $res
        where
            $res: Mul<T, Output = $res>,
        {
            fn product<I>(iter: I) -> Self
            where
                I: Iterator<Item = T>,
            {
                iter.fold(One::one(), <$res>::mul)
            }
        }
    };
}
<|endoftext|>


<commit_before>#[macro_use]

macro_rules! string_enum {
    ($name:ident { $($value:ident,)* }) => {

        #[derive(Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Copy)]
        pub enum $name {
            $($value,)*
        }

        impl $name {
            #[allow(dead_code)]
            pub fn all() -> ::std::collections::BTreeSet<$name> {
                use self::$name::*;
                vec!($($value,)*).into_iter().collect()
            }
        }

        impl From<$name> for &'static str {
            fn from(entity: $name) -> &'static str {
                use self::$name::*;
                match entity {
                    $($value => stringify!($value),)*
                }
            }
        }

        impl From<$name> for String {
            fn from(entity: $name) -> String {
                Into::<&str>::into(entity).to_owned()
            }
        }

        impl <'a> From<&'a $name> for &'static str {
            fn from(entity: &'a $name) -> &'static str {
                use self::$name::*;
                match *entity {
                    $($value => stringify!($value),)*
                }
            }
        }

        impl <'a> From<&'a $name> for String {
            fn from(entity: &'a $name) -> String {
                Into::<&str>::into(entity).to_owned()
            }
        }

        impl ::std::str::FromStr for $name {
            type Err = ::error::Error;

            fn from_str(string: &str) -> ::error::Result<$name> {
                use self::$name::*;
                match string {
                    $(stringify!($value) => Ok($value),)*
                    _ => Err(::error::Error::parsing(stringify!($name), string))
                }
            }
        }

    }
}
<commit_msg>reduce duplication<commit_after>#[macro_use]

macro_rules! string_enum {
    ($name:ident { $($value:ident,)* }) => {

        #[derive(Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Copy)]
        pub enum $name {
            $($value,)*
        }

        impl $name {
            #[allow(dead_code)]
            pub fn all() -> ::std::collections::BTreeSet<$name> {
                use self::$name::*;
                vec!($($value,)*).into_iter().collect()
            }
        }

        impl From<$name> for &'static str {
            fn from(entity: $name) -> &'static str {
                From::from(&entity)
            }
        }

        impl From<$name> for String {
            fn from(entity: $name) -> String {
                From::from(&entity)
            }
        }

        impl <'a> From<&'a $name> for &'static str {
            fn from(entity: &'a $name) -> &'static str {
                use self::$name::*;
                match *entity {
                    $($value => stringify!($value),)*
                }
            }
        }

        impl <'a> From<&'a $name> for String {
            fn from(entity: &'a $name) -> String {
                Into::<&str>::into(entity).to_owned()
            }
        }

        impl ::std::str::FromStr for $name {
            type Err = ::error::Error;

            fn from_str(string: &str) -> ::error::Result<$name> {
                use self::$name::*;
                match string {
                    $(stringify!($value) => Ok($value),)*
                    _ => Err(::error::Error::parsing(stringify!($name), string))
                }
            }
        }

    }
}
<|endoftext|>