<commit_before>extern crate chrono;

use self::chrono::offset::Local;
use std::fmt;
use std::fs::{File, OpenOptions};
use std::io::{self, 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) -> io::Result<()> {
        if level > self.loglevel {
            return Ok(());
        }

        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);

            logfile.write_all(line.as_bytes())?;
        }

        Ok(())
    }

    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>Do not return anything from Logger::log<commit_after>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(())
    }
}
<|endoftext|>


<commit_before>#[macro_export]
macro_rules! pub_use_defaults {
	() => {
		pub use plygui_api::callbacks;
	    pub use plygui_api::controls::*;
	    pub use plygui_api::ids::*;
	    pub use plygui_api::layout;
	    pub use plygui_api::types::*;
	    pub use plygui_api::utils;

	    pub mod imp {
	        pub use crate::application::Application;
	        pub use crate::button::Button;
	        pub use crate::frame::Frame;
	        pub use crate::image::Image;
	        pub use crate::layout_linear::LinearLayout;
	        pub use crate::message::Message;
	        pub use crate::splitted::Splitted;
	        pub use crate::text::Text;
	        pub use crate::tray::Tray;
	        pub use crate::window::Window;
	    }
	}
}

#[macro_export]
macro_rules! impl_markup_register_members_default {
	() => {
		#[cfg(feature = "markup")]
		pub fn register_members(registry: &mut plygui_api::markup::MarkupRegistry) {
		    registry.register_member(plygui_api::markup::MEMBER_TYPE_BUTTON.into(), button::spawn).unwrap();
		    registry.register_member(plygui_api::markup::MEMBER_TYPE_LINEAR_LAYOUT.into(), layout_linear::spawn).unwrap();
		    registry.register_member(plygui_api::markup::MEMBER_TYPE_FRAME.into(), frame::spawn).unwrap();
		    registry.register_member(plygui_api::markup::MEMBER_TYPE_SPLITTED.into(), splitted::spawn).unwrap();
		}
	}
}

#[macro_export]
macro_rules! impl_all_defaults {
    ($typ: ty) => {
        impl_as_any! {$typ}
        impl_as_member! {$typ}
    };
}

#[macro_export]
macro_rules! impl_as_any {
    ($typ: ty) => {
        unsafe fn _as_any_mut(base: &mut ::plygui_api::development::MemberBase) -> &mut ::std::any::Any {
            ::plygui_api::utils::base_to_impl_mut::<$typ>(base)
        }
        unsafe fn _as_any(base: &::plygui_api::development::MemberBase) -> &::std::any::Any {
            ::plygui_api::utils::base_to_impl::<$typ>(base)
        }
    };
}

#[macro_export]
macro_rules! impl_as_member {
    ($typ: ty) => {
        unsafe fn _as_member_mut(base: &mut ::plygui_api::development::MemberBase) -> &mut ::plygui_api::controls::Member {
            ::plygui_api::utils::base_to_impl_mut::<$typ>(base)
        }
        unsafe fn _as_member(base: &::plygui_api::development::MemberBase) -> &::plygui_api::controls::Member {
            ::plygui_api::utils::base_to_impl::<$typ>(base)
        }
    };
}
<commit_msg>De-prelude ready<commit_after>#[macro_export]
macro_rules! default_pub_use {
    () => {
        pub use plygui_api::callbacks;
        pub use plygui_api::controls::*;
        pub use plygui_api::external;
        pub use plygui_api::ids::*;
        pub use plygui_api::layout;
        pub use plygui_api::types::*;
        pub use plygui_api::utils;

        pub mod imp {
            pub use crate::application::Application;
            pub use crate::button::Button;
            pub use crate::frame::Frame;
            pub use crate::image::Image;
            pub use crate::layout_linear::LinearLayout;
            pub use crate::message::Message;
            pub use crate::splitted::Splitted;
            pub use crate::text::Text;
            pub use crate::tray::Tray;
            pub use crate::window::Window;
        }
    };
}

#[macro_export]
macro_rules! default_markup_register_members {
    () => {
        #[cfg(feature = "markup")]
        pub fn register_members(registry: &mut plygui_api::markup::MarkupRegistry) {
            registry.register_member(plygui_api::markup::MEMBER_TYPE_BUTTON.into(), button::spawn).unwrap();
            registry.register_member(plygui_api::markup::MEMBER_TYPE_LINEAR_LAYOUT.into(), layout_linear::spawn).unwrap();
            registry.register_member(plygui_api::markup::MEMBER_TYPE_FRAME.into(), frame::spawn).unwrap();
            registry.register_member(plygui_api::markup::MEMBER_TYPE_SPLITTED.into(), splitted::spawn).unwrap();
        }
    };
}

#[macro_export]
macro_rules! default_impls_as {
    ($typ: ty) => {
        impl_as_any! {$typ}
        impl_as_member! {$typ}
    };
}

#[macro_export]
macro_rules! impl_as_any {
    ($typ: ty) => {
        unsafe fn _as_any_mut(base: &mut ::plygui_api::development::MemberBase) -> &mut ::std::any::Any {
            ::plygui_api::utils::base_to_impl_mut::<$typ>(base)
        }
        unsafe fn _as_any(base: &::plygui_api::development::MemberBase) -> &::std::any::Any {
            ::plygui_api::utils::base_to_impl::<$typ>(base)
        }
    };
}

#[macro_export]
macro_rules! impl_as_member {
    ($typ: ty) => {
        unsafe fn _as_member_mut(base: &mut ::plygui_api::development::MemberBase) -> &mut ::plygui_api::controls::Member {
            ::plygui_api::utils::base_to_impl_mut::<$typ>(base)
        }
        unsafe fn _as_member(base: &::plygui_api::development::MemberBase) -> &::plygui_api::controls::Member {
            ::plygui_api::utils::base_to_impl::<$typ>(base)
        }
    };
}
<|endoftext|>


<commit_before>#[macro_export]
macro_rules! gc_ref_type {
    { @as_item $it:item } => { $it };

    {
        pub struct $($x:tt)*
    } => {
        gc_ref_type! {
            @gc_heap_struct (pub) struct $($x)*
        }
    };
    {
        struct $($x:tt)*
    } => {
        gc_ref_type! {
            @gc_heap_struct () struct $($x)*
        }
    };

    {
        @gc_heap_struct ( $($maybe_pub:tt)* )
        struct $fields_type:ident / $ref_type:ident / $storage_type:ident / $ref_storage_type:ident <'a> {
            $($field_name:ident / $field_setter_name:ident : $field_type: ty),*
        }
    } => {
        // === $storage_type: the InHeap representation of the struct
        gc_ref_type! {
            @as_item
            $($maybe_pub)* struct $storage_type<'a> {
                $( pub $field_name: <$field_type as $crate::traits::IntoHeap<'a>>::In ),*
            }
        }

        unsafe impl<'a> $crate::traits::InHeap<'a> for $storage_type<'a> {
            type Out = $fields_type<'a>;

            unsafe fn mark(&self) {
                if !$crate::Heap::get_mark_bit(self) {
                    $crate::Heap::set_mark_bit(self);
                    $(
                        $crate::traits::InHeap::mark(&self.$field_name);
                    )*
                }
            }

            unsafe fn from_heap(&self) -> $fields_type<'a> {
                $fields_type {
                    $( $field_name: $crate::traits::InHeap::from_heap(&self.$field_name) ),*
                }
            }
        }

        // === $fields_type: A safe version of the struct
        gc_ref_type! {
            @as_item
            #[derive(Clone, Debug)]
            $($maybe_pub)* struct $fields_type<'a> {
                $( pub $field_name: $field_type ),*
            }
        }

        unsafe impl<'a> $crate::traits::IntoHeap<'a> for $fields_type<'a> {
            type In = $storage_type<'a>;

            fn into_heap(self) -> $storage_type<'a> {
                $storage_type {
                    $( $field_name: $crate::traits::IntoHeap::into_heap(self.$field_name) ),*
                }
            }
        }

        impl<'a> $crate::traits::IntoHeapAllocation<'a> for $fields_type<'a> {
            type Ref = $ref_type<'a>;

            fn wrap_gcref(gcref: $crate::GCRef<'a, $storage_type<'a>>) -> $ref_type<'a> {
                $ref_type(gcref)
            }
        }

        // === $ref_storage_type: The InHeap representation of a reference to the struct
        gc_ref_type! {
            @as_item
            #[derive(Clone, Copy, Debug, PartialEq, Eq)]
            $($maybe_pub)* struct $ref_storage_type<'a>(*mut $storage_type<'a>);
        }

        unsafe impl<'a> $crate::traits::InHeap<'a> for $ref_storage_type<'a> {
            type Out = $ref_type<'a>;

            unsafe fn mark(&self) {
                let ptr = self.0;
                if !ptr.is_null() {
                    $crate::traits::InHeap::mark(&*ptr);
                }
            }

            unsafe fn from_heap(&self) -> $ref_type<'a> {
                $ref_type($crate::GCRef::new(self.0))
            }
        }

        // === $ref_type: A safe reference to the struct
        gc_ref_type! {
            @as_item
            #[derive(Clone, Debug, PartialEq, Eq)]
            $($maybe_pub)* struct $ref_type<'a>($crate::GCRef<'a, $storage_type<'a>>);
        }

        unsafe impl<'a> $crate::traits::IntoHeap<'a> for $ref_type<'a> {
            type In = $ref_storage_type<'a>;

            fn into_heap(self) -> $ref_storage_type<'a> {
                $ref_storage_type(self.0.as_mut_ptr())
            }
        }

        impl<'a> $ref_type<'a> {
            // Field accessors.
            $(
                pub fn $field_name(&self) -> $field_type {
                    let ptr = self.0.as_ptr();
                    unsafe {
                        $crate::traits::InHeap::from_heap(&(*ptr).$field_name)
                    }
                }

                pub fn $field_setter_name(&self, v: $field_type) {
                    let ptr = self.0.as_mut_ptr();
                    let u = $crate::traits::IntoHeap::into_heap(v);
                    unsafe {
                        (*ptr).$field_name = u;
                    }
                }
            )*

            pub fn as_mut_ptr(&self) -> *mut $storage_type<'a> {
                self.0.as_mut_ptr()
            }
        }
    }
}

#[macro_export]
macro_rules! gc_inline_enum {
    { @as_item $x:item } => { $x };
    { @as_expr $x:expr } => { $x };

    {
        @for_each_variant $_helper:tt {} $all_results:tt ($($ctn:tt)*)
    } => {
        gc_inline_enum! { $($ctn)* $all_results }
    };

    {
        @for_each_variant ($($helper:tt)*)
        { $variant_name:ident } $acc:tt $ctn:tt
    } => {
        gc_inline_enum! {
            $($helper)* $variant_name NO_FIELDS
                (@next_variant ($($helper)*) {} $acc $ctn)
        }
    };

    {
        @for_each_variant ($($helper:tt)*)
        { $variant_name:ident , $($more_variants:tt)* }
        $acc:tt $ctn:tt
    } => {
        gc_inline_enum! {
            $($helper)* $variant_name NO_FIELDS
                (@next_variant ($($helper)*) { $($more_variants)* } $acc $ctn)
        }
    };

    {
        @for_each_variant ($($helper:tt)*)
        { $variant_name:ident ( $($field_types:tt)* ) }
        $acc:tt $ctn:tt
    } => {
        gc_inline_enum! {
            $($helper)* $variant_name ( $($field_types)* )
                (@next_variant ($($helper)*) {} $acc $ctn)
        }
    };

    {
        @for_each_variant ($($helper:tt)*)
        { $variant_name:ident ( $($field_types:tt)* ), $($more_variants:tt)*  }
        $acc:tt $ctn:tt
    } => {
        gc_inline_enum! {
            $($helper)* $variant_name ( $($field_types)* )
                (@next_variant ($($helper)*) { $($more_variants)* } $acc $ctn)
        }
    };

    {
        @next_variant $helper:tt $more_variants:tt { $($acc:tt)* } $ctn:tt { $($rv:tt)* }
    } => {
        gc_inline_enum! {
            @for_each_variant $helper $more_variants { $($acc)* $($rv)* } $ctn
        }
    };

    {
        @declare_storage_type ( $($maybe_pub:tt)* ) $storage_type:ident
            { $($variants:tt)* }
    } => {
        gc_inline_enum! {
            @as_item
            $($maybe_pub)*
            enum $storage_type<'a> {
                $($variants)*
            }
        }
    };

    {
        @storage_type_variant $variant_name:ident NO_FIELDS ($($ctn:tt)*)
    } => {
        gc_inline_enum! {
            $($ctn)* { $variant_name, }
        }
    };

    {
        @storage_type_variant $variant_name:ident ( $($field_type:ty),* ) ($($ctn:tt)*)
    } => {
        gc_inline_enum! {
            $($ctn)* {
                $variant_name($(<$field_type as $crate::traits::IntoHeap<'a>>::In),*),
            }
        }
    };

    {
        @mark_expr ($self_ref:expr) { $($arms:tt)* }
    } => {
        gc_inline_enum! {
            @as_expr
            match *$self_ref {
                $($arms)*
            }
        }
    };

    {
        @mark_variant $storage_type:ident
            $name:ident NO_FIELDS ($($ctn:tt)*)
    } => {
        gc_inline_enum! {
            $($ctn)* { $storage_type::$name => (), }
        }
    };

    {
        @mark_variant $storage_type:ident
            $name:ident ( $($field_type:ty),* ) $ctn:tt
    } => {
        gc_inline_enum! {
            @zip_idents_with_types (a b c d e f g h i j k l m n o p q r s t u v w x y z)
                ( $($field_type),*, ) ()
                (@mark_variant_continued $storage_type $name $ctn)
        }
    };

    {
        @mark_variant_continued $storage_type:ident $name:ident ($($ctn:tt)*)
            ( $(($binding:ident : $field_type:ty))* )
    } => {
        gc_inline_enum! {
            $($ctn)* {
                $storage_type::$name ( $(ref $binding),* ) => {
                    $( $crate::traits::InHeap::mark($binding); )*
                },
            }
        }
    };

    {
        @into_heap_expr ($self_:expr)
        { $($accumulated_output:tt)* }
    } => {
        gc_inline_enum! {
            @as_expr
            match $self_ {
                $($accumulated_output)*
            }
        }
    };

    {
        @variant_into_heap $stack_type:ident $storage_type:ident
            $name:ident NO_FIELDS
            ($($ctn:tt)*)
    } => {
        gc_inline_enum! {
            $($ctn)* { $stack_type::$name => $storage_type::$name, }
        }
    };

    {
        @variant_into_heap $stack_type:ident $storage_type:ident
            $name:ident ( $($field_type:ty),* )
            $ctn:tt
    } => {
        gc_inline_enum! {
            @zip_idents_with_types (a b c d e f g h i j k l m n o p q r s t u v w x y z)
                ( $($field_type),*, ) ()
                (@variant_into_heap_continued $stack_type $storage_type $name $ctn)
        }
    };

    {
        @zip_idents_with_types $_leftovers:tt () ($(($binding:ident : $btype:ty))*) ($($ctn:tt)*)
    } => {
        gc_inline_enum! { $($ctn)* ($(($binding : $btype))*) }
    };
    {
        @zip_idents_with_types
        ($id:ident $($ids:tt)*)
        ($t:ty, $($ts:ty),*)
        ($($acc:tt)*)
        $ctn:tt
    } => {
        gc_inline_enum! {
            @zip_idents_with_types
            ($($ids)*)
            ($($ts),*)
            ($($acc)* ($id : $t))
            $ctn
        }
    };

    {
        @variant_into_heap_continued $stack_type:ident $storage_type:ident $name:ident ($($ctn:tt)*)
            ( $(($binding:ident : $field_type:ty))* )
    } => {
        gc_inline_enum! {
            $($ctn)* {
                $stack_type::$name ( $($binding),* ) =>
                    $storage_type::$name( $($crate::traits::IntoHeap::into_heap($binding)),* ),
            }
        }
    };

    {
        @from_heap_expr ($self_ref:expr) { $($arms:tt)* }
    } => {
        gc_inline_enum! {
            @as_expr
            match $self_ref {
                $($arms)*
            }
        }
    };

    {
        @from_heap_variant $stack_type:ident $storage_type:ident
            $name:ident NO_FIELDS ($($ctn:tt)*)
    } => {
        gc_inline_enum! {
            $($ctn)* { &$storage_type::$name => $stack_type::$name, }
        }
    };

    {
        @from_heap_variant $stack_type:ident $storage_type:ident
            $name:ident ( $($field_type:ty),* ) $ctn:tt
    } => {
        gc_inline_enum! {
            @zip_idents_with_types (a b c d e f g h i j k l m n o p q r s t u v w x y z)
                ( $($field_type),*, ) ()
                (@from_heap_variant_continued $stack_type $storage_type $name $ctn)
        }
    };

    {
        @from_heap_variant_continued $stack_type:ident $storage_type:ident $name:ident ($($ctn:tt)*)
            ( $(($binding:ident : $field_type:ty))* )
    } => {
        gc_inline_enum! {
            $($ctn)* {
                &$storage_type::$name ( ref $($binding),* ) =>
                    $stack_type::$name( $($crate::traits::InHeap::from_heap($binding)),* ),
            }
        }
    };

    {
        pub enum $($x:tt)*
    } => {
        gc_inline_enum! {
            @gc_heap_enum (pub) enum $($x)*
        }
    };

    {
        enum $($x:tt)*
    } => {
        gc_inline_enum! {
            @gc_heap_enum () enum $($x)*
        }
    };

    {
        @gc_heap_enum
        ($($maybe_pub:tt)*)
        enum $stack_type:ident / $storage_type:ident <'a>
        $variants:tt
    } => {
        gc_inline_enum! {
            @for_each_variant (@storage_type_variant) $variants {}
                (@declare_storage_type ( $($maybe_pub)* ) $storage_type)
        }

        gc_inline_enum! {
            @as_item
            #[derive(Debug, Clone, PartialEq)]
            $($maybe_pub)*
            enum $stack_type<'a>
                $variants
        }

        unsafe impl<'a> $crate::traits::InHeap<'a> for $storage_type<'a> {
            type Out = $stack_type<'a>;

            unsafe fn mark(&self) {
                gc_inline_enum! {
                    @for_each_variant (@mark_variant $storage_type) $variants {}
                    (@mark_expr (self))
                }
            }

            unsafe fn from_heap(&self) -> $stack_type<'a> {
                gc_inline_enum! {
                    @for_each_variant (@from_heap_variant $stack_type $storage_type) $variants {}
                    (@from_heap_expr (self))
                }
            }
        }

        unsafe impl<'a> $crate::traits::IntoHeap<'a> for $stack_type<'a> {
            type In = $storage_type<'a>;

            fn into_heap(self) -> $storage_type<'a> {
                gc_inline_enum! {
                    @for_each_variant (@variant_into_heap $stack_type $storage_type) $variants {}
                    (@into_heap_expr (self))
                }
            }
        }
    }
}
<commit_msg>Macro cleanup.<commit_after>#[macro_export]
macro_rules! gc_ref_type {
    { @as_item $it:item } => { $it };

    {
        pub struct $($x:tt)*
    } => {
        gc_ref_type! {
            @gc_heap_struct (pub) struct $($x)*
        }
    };
    {
        struct $($x:tt)*
    } => {
        gc_ref_type! {
            @gc_heap_struct () struct $($x)*
        }
    };

    {
        @gc_heap_struct ( $($maybe_pub:tt)* )
        struct $fields_type:ident / $ref_type:ident / $storage_type:ident / $ref_storage_type:ident <'a> {
            $($field_name:ident / $field_setter_name:ident : $field_type: ty),*
        }
    } => {
        // === $storage_type: the InHeap representation of the struct
        gc_ref_type! {
            @as_item
            $($maybe_pub)* struct $storage_type<'a> {
                $( pub $field_name: <$field_type as $crate::traits::IntoHeap<'a>>::In ),*
            }
        }

        unsafe impl<'a> $crate::traits::InHeap<'a> for $storage_type<'a> {
            type Out = $fields_type<'a>;

            unsafe fn mark(&self) {
                if !$crate::Heap::get_mark_bit(self) {
                    $crate::Heap::set_mark_bit(self);
                    $(
                        $crate::traits::InHeap::mark(&self.$field_name);
                    )*
                }
            }

            unsafe fn from_heap(&self) -> $fields_type<'a> {
                $fields_type {
                    $( $field_name: $crate::traits::InHeap::from_heap(&self.$field_name) ),*
                }
            }
        }

        // === $fields_type: A safe version of the struct
        gc_ref_type! {
            @as_item
            #[derive(Clone, Debug)]
            $($maybe_pub)* struct $fields_type<'a> {
                $( pub $field_name: $field_type ),*
            }
        }

        unsafe impl<'a> $crate::traits::IntoHeap<'a> for $fields_type<'a> {
            type In = $storage_type<'a>;

            fn into_heap(self) -> $storage_type<'a> {
                $storage_type {
                    $( $field_name: $crate::traits::IntoHeap::into_heap(self.$field_name) ),*
                }
            }
        }

        impl<'a> $crate::traits::IntoHeapAllocation<'a> for $fields_type<'a> {
            type Ref = $ref_type<'a>;

            fn wrap_gcref(gcref: $crate::GCRef<'a, $storage_type<'a>>) -> $ref_type<'a> {
                $ref_type(gcref)
            }
        }

        // === $ref_storage_type: The InHeap representation of a reference to the struct
        gc_ref_type! {
            @as_item
            #[derive(Clone, Copy, Debug, PartialEq, Eq)]
            $($maybe_pub)* struct $ref_storage_type<'a>(*mut $storage_type<'a>);
        }

        unsafe impl<'a> $crate::traits::InHeap<'a> for $ref_storage_type<'a> {
            type Out = $ref_type<'a>;

            unsafe fn mark(&self) {
                let ptr = self.0;
                if !ptr.is_null() {
                    $crate::traits::InHeap::mark(&*ptr);
                }
            }

            unsafe fn from_heap(&self) -> $ref_type<'a> {
                $ref_type($crate::GCRef::new(self.0))
            }
        }

        // === $ref_type: A safe reference to the struct
        gc_ref_type! {
            @as_item
            #[derive(Clone, Debug, PartialEq, Eq)]
            $($maybe_pub)* struct $ref_type<'a>($crate::GCRef<'a, $storage_type<'a>>);
        }

        unsafe impl<'a> $crate::traits::IntoHeap<'a> for $ref_type<'a> {
            type In = $ref_storage_type<'a>;

            fn into_heap(self) -> $ref_storage_type<'a> {
                $ref_storage_type(self.0.as_mut_ptr())
            }
        }

        impl<'a> $ref_type<'a> {
            // Field accessors.
            $(
                pub fn $field_name(&self) -> $field_type {
                    let ptr = self.0.as_ptr();
                    unsafe {
                        $crate::traits::InHeap::from_heap(&(*ptr).$field_name)
                    }
                }

                pub fn $field_setter_name(&self, v: $field_type) {
                    let ptr = self.0.as_mut_ptr();
                    let u = $crate::traits::IntoHeap::into_heap(v);
                    unsafe {
                        (*ptr).$field_name = u;
                    }
                }
            )*

            pub fn as_mut_ptr(&self) -> *mut $storage_type<'a> {
                self.0.as_mut_ptr()
            }
        }
    }
}

#[macro_export]
macro_rules! gc_inline_enum {
    { @as_item $x:item } => { $x };
    { @as_expr $x:expr } => { $x };

    {
        @for_each_variant $_helper:tt {} $all_results:tt ($($ctn:tt)*)
    } => {
        gc_inline_enum! { $($ctn)* $all_results }
    };

    {
        @for_each_variant ($($helper:tt)*)
        { $variant_name:ident } $acc:tt $ctn:tt
    } => {
        gc_inline_enum! {
            $($helper)* $variant_name NO_FIELDS
                (@next_variant ($($helper)*) {} $acc $ctn)
        }
    };

    {
        @for_each_variant ($($helper:tt)*)
        { $variant_name:ident , $($more_variants:tt)* }
        $acc:tt $ctn:tt
    } => {
        gc_inline_enum! {
            $($helper)* $variant_name NO_FIELDS
                (@next_variant ($($helper)*) { $($more_variants)* } $acc $ctn)
        }
    };

    {
        @for_each_variant ($($helper:tt)*)
        { $variant_name:ident ( $($field_types:tt)* ) }
        $acc:tt $ctn:tt
    } => {
        gc_inline_enum! {
            $($helper)* $variant_name ( $($field_types)* )
                (@next_variant ($($helper)*) {} $acc $ctn)
        }
    };

    {
        @for_each_variant ($($helper:tt)*)
        { $variant_name:ident ( $($field_types:tt)* ), $($more_variants:tt)*  }
        $acc:tt $ctn:tt
    } => {
        gc_inline_enum! {
            $($helper)* $variant_name ( $($field_types)* )
                (@next_variant ($($helper)*) { $($more_variants)* } $acc $ctn)
        }
    };

    {
        @next_variant $helper:tt $more_variants:tt { $($acc:tt)* } $ctn:tt { $($rv:tt)* }
    } => {
        gc_inline_enum! {
            @for_each_variant $helper $more_variants { $($acc)* $($rv)* } $ctn
        }
    };

    {
        @storage_type_variant $variant_name:ident NO_FIELDS ($($ctn:tt)*)
    } => {
        gc_inline_enum! {
            $($ctn)* { $variant_name, }
        }
    };

    {
        @storage_type_variant $variant_name:ident ( $($field_type:ty),* ) ($($ctn:tt)*)
    } => {
        gc_inline_enum! {
            $($ctn)* {
                $variant_name($(<$field_type as $crate::traits::IntoHeap<'a>>::In),*),
            }
        }
    };

    {
        @declare_storage_type ( $($maybe_pub:tt)* ) $storage_type:ident
            { $($variants:tt)* }
    } => {
        gc_inline_enum! {
            @as_item
            $($maybe_pub)*
            enum $storage_type<'a> {
                $($variants)*
            }
        }
    };

    {
        @mark_variant $storage_type:ident
            $name:ident NO_FIELDS ($($ctn:tt)*)
    } => {
        gc_inline_enum! {
            $($ctn)* { $storage_type::$name => (), }
        }
    };

    {
        @mark_variant $storage_type:ident
            $name:ident ( $($field_type:ty),* ) $ctn:tt
    } => {
        gc_inline_enum! {
            @zip_idents_with_types (a b c d e f g h i j k l m n o p q r s t u v w x y z)
                ( $($field_type),*, ) ()
                (@mark_variant_continued $storage_type $name $ctn)
        }
    };

    {
        @mark_variant_continued $storage_type:ident $name:ident ($($ctn:tt)*)
            ( $(($binding:ident : $field_type:ty))* )
    } => {
        gc_inline_enum! {
            $($ctn)* {
                $storage_type::$name ( $(ref $binding),* ) => {
                    $( $crate::traits::InHeap::mark($binding); )*
                },
            }
        }
    };

    {
        @mark_expr ($self_ref:expr) { $($arms:tt)* }
    } => {
        gc_inline_enum! {
            @as_expr
            match *$self_ref {
                $($arms)*
            }
        }
    };

    {
        @into_heap_variant $stack_type:ident $storage_type:ident
            $name:ident NO_FIELDS
            ($($ctn:tt)*)
    } => {
        gc_inline_enum! {
            $($ctn)* { $stack_type::$name => $storage_type::$name, }
        }
    };

    {
        @into_heap_variant $stack_type:ident $storage_type:ident
            $name:ident ( $($field_type:ty),* )
            $ctn:tt
    } => {
        gc_inline_enum! {
            @zip_idents_with_types (a b c d e f g h i j k l m n o p q r s t u v w x y z)
                ( $($field_type),*, ) ()
                (@into_heap_variant_continued $stack_type $storage_type $name $ctn)
        }
    };

    {
        @into_heap_variant_continued $stack_type:ident $storage_type:ident $name:ident ($($ctn:tt)*)
            ( $(($binding:ident : $field_type:ty))* )
    } => {
        gc_inline_enum! {
            $($ctn)* {
                $stack_type::$name ( $($binding),* ) =>
                    $storage_type::$name( $($crate::traits::IntoHeap::into_heap($binding)),* ),
            }
        }
    };

    {
        @into_heap_expr ($self_:expr)
        { $($accumulated_output:tt)* }
    } => {
        gc_inline_enum! {
            @as_expr
            match $self_ {
                $($accumulated_output)*
            }
        }
    };

    {
        @zip_idents_with_types $_leftovers:tt () ($(($binding:ident : $btype:ty))*) ($($ctn:tt)*)
    } => {
        gc_inline_enum! { $($ctn)* ($(($binding : $btype))*) }
    };
    {
        @zip_idents_with_types
        ($id:ident $($ids:tt)*)
        ($t:ty, $($ts:ty),*)
        ($($acc:tt)*)
        $ctn:tt
    } => {
        gc_inline_enum! {
            @zip_idents_with_types
            ($($ids)*)
            ($($ts),*)
            ($($acc)* ($id : $t))
            $ctn
        }
    };

    {
        @from_heap_expr ($self_ref:expr) { $($arms:tt)* }
    } => {
        gc_inline_enum! {
            @as_expr
            match $self_ref {
                $($arms)*
            }
        }
    };

    {
        @from_heap_variant $stack_type:ident $storage_type:ident
            $name:ident NO_FIELDS ($($ctn:tt)*)
    } => {
        gc_inline_enum! {
            $($ctn)* { &$storage_type::$name => $stack_type::$name, }
        }
    };

    {
        @from_heap_variant $stack_type:ident $storage_type:ident
            $name:ident ( $($field_type:ty),* ) $ctn:tt
    } => {
        gc_inline_enum! {
            @zip_idents_with_types (a b c d e f g h i j k l m n o p q r s t u v w x y z)
                ( $($field_type),*, ) ()
                (@from_heap_variant_continued $stack_type $storage_type $name $ctn)
        }
    };

    {
        @from_heap_variant_continued $stack_type:ident $storage_type:ident $name:ident ($($ctn:tt)*)
            ( $(($binding:ident : $field_type:ty))* )
    } => {
        gc_inline_enum! {
            $($ctn)* {
                &$storage_type::$name ( ref $($binding),* ) =>
                    $stack_type::$name( $($crate::traits::InHeap::from_heap($binding)),* ),
            }
        }
    };

    {
        pub enum $($x:tt)*
    } => {
        gc_inline_enum! {
            @gc_heap_enum (pub) enum $($x)*
        }
    };

    {
        enum $($x:tt)*
    } => {
        gc_inline_enum! {
            @gc_heap_enum () enum $($x)*
        }
    };

    {
        @gc_heap_enum
        ($($maybe_pub:tt)*)
        enum $stack_type:ident / $storage_type:ident <'a>
        $variants:tt
    } => {
        gc_inline_enum! {
            @for_each_variant (@storage_type_variant) $variants {}
                (@declare_storage_type ( $($maybe_pub)* ) $storage_type)
        }

        gc_inline_enum! {
            @as_item
            #[derive(Debug, Clone, PartialEq)]
            $($maybe_pub)*
            enum $stack_type<'a>
                $variants
        }

        unsafe impl<'a> $crate::traits::InHeap<'a> for $storage_type<'a> {
            type Out = $stack_type<'a>;

            unsafe fn mark(&self) {
                gc_inline_enum! {
                    @for_each_variant (@mark_variant $storage_type) $variants {}
                    (@mark_expr (self))
                }
            }

            unsafe fn from_heap(&self) -> $stack_type<'a> {
                gc_inline_enum! {
                    @for_each_variant (@from_heap_variant $stack_type $storage_type) $variants {}
                    (@from_heap_expr (self))
                }
            }
        }

        unsafe impl<'a> $crate::traits::IntoHeap<'a> for $stack_type<'a> {
            type In = $storage_type<'a>;

            fn into_heap(self) -> $storage_type<'a> {
                gc_inline_enum! {
                    @for_each_variant (@into_heap_variant $stack_type $storage_type) $variants {}
                    (@into_heap_expr (self))
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>
#[macro_export]
macro_rules! impl_func_delegate {
	($name:ident) => (
		impl FuncDelegate for $name {
		    fn delegate(&mut self) -> &mut Function {
    		    &mut self.delegate
    		}
		}

	)
}

#[macro_export]
macro_rules! impl_mod_delegate {
	($name:ident) => (
		impl<T:Default+Copy> ModDelegate<T> for $name<T> {
		    fn delegate(&mut self) -> &mut Module<T> {
    		    &mut self.delegate
    		}
		}

	)
}

#[macro_export]
macro_rules! typecast {
    ($value:expr, $type:ident) => {$value as *mut $type}
}

#[macro_export]
macro_rules! impl_func {
	($name:ident) => (
		#[derive(Clone)]
		pub struct $name {
    		delegate: Function,
		}
		impl $name {
    		pub fn new() -> FIWrap<Self> {
        		FIWrap::new($name { delegate: Function::new() })
    		}
		}
		impl FuncDelegate for $name {
		    fn delegate(&mut self) -> &mut Function {
    		    &mut self.delegate
    		}
		}

	)
}

#[macro_export]
macro_rules! impl_func_args {
	($name:ident, $args:ident) => (

#[derive(Clone)]
pub struct $name {
    delegate: Function,
    args: $args,
}

impl $name {
    pub fn new(args: & $args) -> FIWrap<Self> {
        FIWrap::new($name {
                        delegate: Function::new(),
                        args: args.clone(),
                    })
    }
}

impl FuncDelegate for $name {
    fn delegate(&mut self) -> &mut Function {
        &mut self.delegate
    }
}
)}
<commit_msg>add map macros<commit_after>
#[macro_export]
macro_rules! impl_func_delegate {
	($name:ident) => (
		impl FuncDelegate for $name {
		    fn delegate(&mut self) -> &mut Function {
    		    &mut self.delegate
    		}
		}

	)
}

#[macro_export]
macro_rules! impl_mod_delegate {
	($name:ident) => (
		impl<T:Default+Copy> ModDelegate<T> for $name<T> {
		    fn delegate(&mut self) -> &mut Module<T> {
    		    &mut self.delegate
    		}
		}

	)
}

#[macro_export]
macro_rules! typecast {
    ($value:expr, $type:ident) => {$value as *mut $type}
}

#[macro_export]
macro_rules! impl_func {
	($name:ident) => (
		#[derive(Clone)]
		pub struct $name {
    		delegate: Function,
		}
		impl $name {
    		pub fn new() -> FIWrap<Self> {
        		FIWrap::new($name { delegate: Function::new() })
    		}
		}
		impl FuncDelegate for $name {
		    fn delegate(&mut self) -> &mut Function {
    		    &mut self.delegate
    		}
		}

	)
}

#[macro_export]
macro_rules! impl_func_args {
	($name:ident, $args:ident) => (

#[derive(Clone)]
pub struct $name {
    delegate: Function,
    args: $args,
}

impl $name {
    pub fn new(args: & $args) -> FIWrap<Self> {
        FIWrap::new($name {
                        delegate: Function::new(),
                        args: args.clone(),
                    })
    }
}

impl FuncDelegate for $name {
    fn delegate(&mut self) -> &mut Function {
        &mut self.delegate
    }
}
)}

#[macro_export]
macro_rules! map(
    { $($key:expr => $value:expr),+ } => {
        {
            let mut m = ::std::collections::HashMap::new();
            $(
                m.insert($key, $value);
            )+
            m
        }
     };
);

#[macro_export]
macro_rules! map_opt(
    { $($key:expr => $value:expr),+ } => {
        {
            let mut m = ::std::collections::HashMap::<&'static str, OptimOpts>::new();
            $(
                m.insert($key, $value .into());
            )+
            m
        }
     };
);
<|endoftext|>


<commit_before>macro_rules! ast_struct {
    (
        @@ [$($attrs_pub:tt)*]
        struct $name:ident #full $($rest:tt)*
    ) => {
        #[cfg(feature = "full")]
        #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
        #[cfg_attr(feature = "clone-impls", derive(Clone))]
        $($attrs_pub)* struct $name $($rest)*

        #[cfg(not(feature = "full"))]
        #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
        #[cfg_attr(feature = "clone-impls", derive(Clone))]
        $($attrs_pub)* struct $name {
            _noconstruct: (),
        }

        #[cfg(all(not(feature = "full"), feature = "printing"))]
        impl ::quote::ToTokens for $name {
            fn to_tokens(&self, _: &mut ::proc_macro2::TokenStream) {
                unreachable!()
            }
        }
    };

    (
        @@ [$($attrs_pub:tt)*]
        struct $name:ident #manual_extra_traits $($rest:tt)*
    ) => {
        #[cfg_attr(feature = "extra-traits", derive(Debug))]
        #[cfg_attr(feature = "clone-impls", derive(Clone))]
        $($attrs_pub)* struct $name $($rest)*
    };

    (
        @@ [$($attrs_pub:tt)*]
        struct $name:ident $($rest:tt)*
    ) => {
        #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
        #[cfg_attr(feature = "clone-impls", derive(Clone))]
        $($attrs_pub)* struct $name $($rest)*
    };

    ($($t:tt)*) => {
        strip_attrs_pub!(ast_struct!($($t)*));
    };
}

macro_rules! ast_enum {
    // Drop the `#no_visit` attribute, if present.
    (
        @@ [$($attrs_pub:tt)*]
        enum $name:ident #no_visit $($rest:tt)*
    ) => (
        ast_enum!(@@ [$($attrs_pub)*] enum $name $($rest)*);
    );

    (
        @@ [$($attrs_pub:tt)*]
        enum $name:ident #manual_extra_traits $($rest:tt)*
    ) => (
        #[cfg_attr(feature = "extra-traits", derive(Debug))]
        #[cfg_attr(feature = "clone-impls", derive(Clone))]
        $($attrs_pub)* enum $name $($rest)*
    );

    (
        @@ [$($attrs_pub:tt)*]
        enum $name:ident $($rest:tt)*
    ) => (
        #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
        #[cfg_attr(feature = "clone-impls", derive(Clone))]
        $($attrs_pub)* enum $name $($rest)*
    );

    ($($t:tt)*) => {
        strip_attrs_pub!(ast_enum!($($t)*));
    };
}

macro_rules! ast_enum_of_structs {
    (
        $(#[$enum_attr:meta])*
        $pub:ident $enum:ident $name:ident #$tag:ident $body:tt
        $($remaining:tt)*
    ) => {
        ast_enum!($(#[$enum_attr])* $pub $enum $name #$tag $body);
        ast_enum_of_structs_impl!($pub $enum $name $body $($remaining)*);
    };

    (
        $(#[$enum_attr:meta])*
        $pub:ident $enum:ident $name:ident $body:tt
        $($remaining:tt)*
    ) => {
        ast_enum!($(#[$enum_attr])* $pub $enum $name $body);
        ast_enum_of_structs_impl!($pub $enum $name $body $($remaining)*);
    };
}

macro_rules! ast_enum_of_structs_impl {
    (
        $pub:ident $enum:ident $name:ident {
            $(
                $(#[$variant_attr:meta])*
                $variant:ident $( ($member:ident) )*,
            )*
        }

        $($remaining:tt)*
    ) => {
        check_keyword_matches!(pub $pub);
        check_keyword_matches!(enum $enum);

        $(
            $(
                impl From<$member> for $name {
                    fn from(e: $member) -> $name {
                        $name::$variant(e)
                    }
                }
            )*
        )*

        #[cfg(feature = "printing")]
        generate_to_tokens! {
            $($remaining)*
            ()
            tokens
            $name { $($variant $($member)*,)* }
        }
    };
}

#[cfg(feature = "printing")]
macro_rules! generate_to_tokens {
    (do_not_generate_to_tokens $($foo:tt)*) => ();

    (($($arms:tt)*) $tokens:ident $name:ident { $variant:ident, $($next:tt)*}) => {
        generate_to_tokens!(
            ($($arms)* $name::$variant => {})
            $tokens $name { $($next)* }
        );
    };

    (($($arms:tt)*) $tokens:ident $name:ident { $variant:ident $member:ident, $($next:tt)*}) => {
        generate_to_tokens!(
            ($($arms)* $name::$variant(_e) => _e.to_tokens($tokens),)
            $tokens $name { $($next)* }
        );
    };

    (($($arms:tt)*) $tokens:ident $name:ident {}) => {
        impl ::quote::ToTokens for $name {
            fn to_tokens(&self, $tokens: &mut ::proc_macro2::TokenStream) {
                match self {
                    $($arms)*
                }
            }
        }
    };
}

macro_rules! strip_attrs_pub {
    ($mac:ident!($(#[$m:meta])* $pub:ident $($t:tt)*)) => {
        check_keyword_matches!(pub $pub);

        $mac!(@@ [$(#[$m])* $pub] $($t)*);
    };
}

macro_rules! check_keyword_matches {
    (struct struct) => {};
    (enum enum) => {};
    (pub pub) => {};
}
<commit_msg>Remove unneeded disambiguator in ast macros<commit_after>macro_rules! ast_struct {
    (
        [$($attrs_pub:tt)*]
        struct $name:ident #full $($rest:tt)*
    ) => {
        #[cfg(feature = "full")]
        #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
        #[cfg_attr(feature = "clone-impls", derive(Clone))]
        $($attrs_pub)* struct $name $($rest)*

        #[cfg(not(feature = "full"))]
        #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
        #[cfg_attr(feature = "clone-impls", derive(Clone))]
        $($attrs_pub)* struct $name {
            _noconstruct: (),
        }

        #[cfg(all(not(feature = "full"), feature = "printing"))]
        impl ::quote::ToTokens for $name {
            fn to_tokens(&self, _: &mut ::proc_macro2::TokenStream) {
                unreachable!()
            }
        }
    };

    (
        [$($attrs_pub:tt)*]
        struct $name:ident #manual_extra_traits $($rest:tt)*
    ) => {
        #[cfg_attr(feature = "extra-traits", derive(Debug))]
        #[cfg_attr(feature = "clone-impls", derive(Clone))]
        $($attrs_pub)* struct $name $($rest)*
    };

    (
        [$($attrs_pub:tt)*]
        struct $name:ident $($rest:tt)*
    ) => {
        #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
        #[cfg_attr(feature = "clone-impls", derive(Clone))]
        $($attrs_pub)* struct $name $($rest)*
    };

    ($($t:tt)*) => {
        strip_attrs_pub!(ast_struct!($($t)*));
    };
}

macro_rules! ast_enum {
    // Drop the `#no_visit` attribute, if present.
    (
        [$($attrs_pub:tt)*]
        enum $name:ident #no_visit $($rest:tt)*
    ) => (
        ast_enum!([$($attrs_pub)*] enum $name $($rest)*);
    );

    (
        [$($attrs_pub:tt)*]
        enum $name:ident #manual_extra_traits $($rest:tt)*
    ) => (
        #[cfg_attr(feature = "extra-traits", derive(Debug))]
        #[cfg_attr(feature = "clone-impls", derive(Clone))]
        $($attrs_pub)* enum $name $($rest)*
    );

    (
        [$($attrs_pub:tt)*]
        enum $name:ident $($rest:tt)*
    ) => (
        #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
        #[cfg_attr(feature = "clone-impls", derive(Clone))]
        $($attrs_pub)* enum $name $($rest)*
    );

    ($($t:tt)*) => {
        strip_attrs_pub!(ast_enum!($($t)*));
    };
}

macro_rules! ast_enum_of_structs {
    (
        $(#[$enum_attr:meta])*
        $pub:ident $enum:ident $name:ident #$tag:ident $body:tt
        $($remaining:tt)*
    ) => {
        ast_enum!($(#[$enum_attr])* $pub $enum $name #$tag $body);
        ast_enum_of_structs_impl!($pub $enum $name $body $($remaining)*);
    };

    (
        $(#[$enum_attr:meta])*
        $pub:ident $enum:ident $name:ident $body:tt
        $($remaining:tt)*
    ) => {
        ast_enum!($(#[$enum_attr])* $pub $enum $name $body);
        ast_enum_of_structs_impl!($pub $enum $name $body $($remaining)*);
    };
}

macro_rules! ast_enum_of_structs_impl {
    (
        $pub:ident $enum:ident $name:ident {
            $(
                $(#[$variant_attr:meta])*
                $variant:ident $( ($member:ident) )*,
            )*
        }

        $($remaining:tt)*
    ) => {
        check_keyword_matches!(pub $pub);
        check_keyword_matches!(enum $enum);

        $(
            $(
                impl From<$member> for $name {
                    fn from(e: $member) -> $name {
                        $name::$variant(e)
                    }
                }
            )*
        )*

        #[cfg(feature = "printing")]
        generate_to_tokens! {
            $($remaining)*
            ()
            tokens
            $name { $($variant $($member)*,)* }
        }
    };
}

#[cfg(feature = "printing")]
macro_rules! generate_to_tokens {
    (do_not_generate_to_tokens $($foo:tt)*) => ();

    (($($arms:tt)*) $tokens:ident $name:ident { $variant:ident, $($next:tt)*}) => {
        generate_to_tokens!(
            ($($arms)* $name::$variant => {})
            $tokens $name { $($next)* }
        );
    };

    (($($arms:tt)*) $tokens:ident $name:ident { $variant:ident $member:ident, $($next:tt)*}) => {
        generate_to_tokens!(
            ($($arms)* $name::$variant(_e) => _e.to_tokens($tokens),)
            $tokens $name { $($next)* }
        );
    };

    (($($arms:tt)*) $tokens:ident $name:ident {}) => {
        impl ::quote::ToTokens for $name {
            fn to_tokens(&self, $tokens: &mut ::proc_macro2::TokenStream) {
                match self {
                    $($arms)*
                }
            }
        }
    };
}

macro_rules! strip_attrs_pub {
    ($mac:ident!($(#[$m:meta])* $pub:ident $($t:tt)*)) => {
        check_keyword_matches!(pub $pub);

        $mac!([$(#[$m])* $pub] $($t)*);
    };
}

macro_rules! check_keyword_matches {
    (struct struct) => {};
    (enum enum) => {};
    (pub pub) => {};
}
<|endoftext|>


<commit_before>/// Errors related to matrix operations
#[deriving(Show)]
pub enum MatErr{
    EmptyMatrix,
    DimensionsMismatch,
    NonSquareMatrix,
}
<commit_msg>not a vector error defined.<commit_after>/// Errors related to matrix operations
#[deriving(Show)]
pub enum MatErr{
    /// The matrix is empty
    EmptyMatrix,
    /// The dimensions of two matrices mismatch
    DimensionsMismatch,
    /// The matrix is not a square matrix
    NonSquareMatrix,
    /// The object is not a vector
    NotAVector,
}
<|endoftext|>


<commit_before>
pub trait Monoid : Sized {
    fn id() -> Self;
    fn op(self, other: Self) -> Self;
    fn fold<I>(values: I) -> Self
        where I: IntoIterator<Item=Self> {
        let mut iter = values.into_iter();
        match iter.next() {
            None => Self::id(),
            Some(x0) => {
                iter.fold(x0, |res, x| res.op(x))
            }
        }
    }
}

impl Monoid for usize {
    fn id() -> Self { 0 }
    fn op(self, other: Self) -> Self { self + other }
}
<commit_msg>Removed unused monoid module<commit_after><|endoftext|>


<commit_before>//
//
use std::env;

#[cfg(unix)]
fn is_executable() {
   println!("is unix");
   }
#[cfg(windows)]
fn is_executable() {
   println!("is windows");
   }

pub fn pargs() {
    for (key,value) in env::vars_os() {
    println!("{:?}: {:?}", key, value);
    }
}

fn main() {
pargs();
is_executable();
println!("Hallo World");
}

#[test]
fn its_really_works() {
}
<commit_msg>Update myprog.rs<commit_after>//
//
use std::env;

#[cfg(unix)]
fn is_executable() {
   println!("is unix");
   }
#[cfg(windows)]
fn is_executable() {
   println!("is windows");
   }
  /*
pub fn pargs() {
    for (key,value) in env::vars_os() {
    println!("{:?}: {:?}", key, value);
    }
}
*/
fn main() {
//pargs();
is_executable();
println!("Hallo World");
}

#[test]
fn its_really_works() {
}
<|endoftext|>


<commit_before>use tokenizer::Tokenizer;
use event::{Event, Rule};
use variable_mapper::VariableMapper;

pub fn nested<'a, I>(tokenizer: &mut I) -> String
    where I: Iterator<Item = Event<'a>>
{
    let mut vm = VariableMapper::new(tokenizer);
    let mut parents = Vec::new();
    nested_inner(&mut vm, &mut parents)
}

pub fn nested_inner<'a, I>(tokenizer: &mut I, parents: &mut Vec<String>) -> String
    where I: Iterator<Item = Event<'a>>
{
    let mut last = Event::End(Rule::SassRule);
    let mut current = String::new();
    let mut properties = String::new();
    let mut children = String::new();

    while let Some(token) = tokenizer.next() {
       match token.clone() {
            Event::Start(_) => {
                match children.len() {
                    0 => children = nested_inner(tokenizer, parents),
                    _ => {
                        children.push_str("\n\n");
                        children.push_str(&nested_inner(tokenizer, parents));
                    },
                };
            },
            Event::Selector(name) => {
                parents.push((*name).to_string());
                current.push_str(&format!("{} ", name));
            },
            Event::Property(name, value) => {
                match last {
                    Event::Selector(_) => properties.push_str(&format!("{{\n  {}: {};", name, value)),
                    _ => properties.push_str(&format!("\n  {}: {};", name, value)),
                }
            },
            Event::End(_) => {
                match (properties.len(), children.len()) {
                    (0, 0) => current.push_str(" }\n"),
                    (_, 0) => {
                        current.push_str(&properties);
                        current.push_str(" }");
                    },
                    (0, _) => {
                        current.push_str(&children);
                    },
                    (_, _) => {
                        current.push_str(&properties);
                        current.push_str(" }\n  ");
                        current.push_str(&parents.connect(" "));
                        current.push_str(" ");
                        current.push_str(&children.split('\n').collect::<Vec<_>>().connect("\n  "));
                    },
                }
                parents.pop();
                return current
            },
            Event::Variable(..) => unreachable!(),
            Event::Comment(body) => unimplemented!(),
        };
        last = token;
    }
    children
}

pub fn compressed<'a, I>(tokenizer: &mut I) -> String
    where I: Iterator<Item = Event<'a>>
{
    let mut vm = VariableMapper::new(tokenizer);
    let mut parents = Vec::new();
    compressed_inner(&mut vm, &mut parents)
}

fn compressed_inner<'a, I>(tokenizer: &mut I, parents: &mut Vec<String>) -> String
    where I: Iterator<Item = Event<'a>>
{
    let mut last = Event::End(Rule::SassRule);
    let mut current = String::new();
    let mut properties = String::new();
    let mut children = String::new();

    while let Some(token) = tokenizer.next() {
        match token.clone() {
            Event::Start(_) => {
                match children.len() {
                    0 => children = compressed_inner(tokenizer, parents),
                    _ => {
                        children.push_str(&compressed_inner(tokenizer, parents));
                    },
                };
            },
            Event::Selector(name) => {
                parents.push((*name).to_string());
                match last {
                    Event::Selector(_) => current.push_str(&format!(" {}", name)),
                    _ => current.push_str(&format!("{}", name)),
                }
            },
            Event::Property(name, value) => {
                match last {
                    Event::Selector(..) => properties.push_str(&format!("{{{}:{}", name, value)),
                    Event::Property(..) => properties.push_str(&format!(";{}:{}", name, value)),
                    _ => properties.push_str(&format!("{}:{}", name, value)),
                }
            },
            Event::End(_) => {
                match (properties.len(), children.len()) {
                    (0, 0) => current.push_str("}"),
                    (_, 0) => {
                        current.push_str(&properties);
                        current.push_str("}");
                    },
                    (0, _) => {
                        current.push_str(" ");
                        current.push_str(&children);
                    },
                    (_, _) => {
                        current.push_str(&properties);
                        current.push_str("}");
                        current.push_str(&parents.connect(" "));
                        current.push_str(" ");
                        current.push_str(&children);
                    },
                }
                parents.pop();
                return current
            },
            Event::Variable(..) => unreachable!(),
            Event::Comment(body) => unimplemented!(),
        };
        last = token;
    }
    children
}

pub fn expanded<'a, I>(tokenizer: &mut I) -> String
    where I: Iterator<Item = Event<'a>>
{
    let mut vm = VariableMapper::new(tokenizer);
    let mut parents = Vec::new();
    expanded_inner(&mut vm, &mut parents)
}

fn expanded_inner<'a, I>(tokenizer: &mut I, parents: &mut Vec<String>) -> String
    where I: Iterator<Item = Event<'a>>
{
    let mut last = Event::End(Rule::SassRule);
    let mut current = String::new();
    let mut properties = String::new();
    let mut children = String::new();

    while let Some(token) = tokenizer.next() {
        match token.clone() {
            Event::Start(_) => {
                match children.len() {
                    0 => children = expanded_inner(tokenizer, parents),
                    _ => {
                        children.push_str("\n\n");
                        children.push_str(&expanded_inner(tokenizer, parents));
                    },
                };
            },
            Event::Selector(name) => {
                parents.push((*name).to_string());
                match last {
                    Event::Selector(_) => current.push_str(&format!(" {}", name)),
                    Event::End(_) => current.push_str(&format!("{}", name)),
                    _ => current.push_str(&format!("{}", name)),
                }
            },
            Event::Property(name, value) => {
                match last {
                    Event::Selector(_) => properties.push_str(&format!(" {{\n  {}: {};", name, value)),
                    _ => properties.push_str(&format!("\n  {}: {};", name, value)),
                }
            },
            Event::End(_) => {
                match (properties.len(), children.len()) {
                    (_, 0) => {
                        current.push_str(&properties);
                        current.push_str("\n}");
                    },
                    (0, _) => {
                        current.push_str(" ");
                        current.push_str(&children);
                    },
                    (_, _) => {
                        current.push_str(&properties);
                        current.push_str("\n}\n");
                        current.push_str(&parents.connect(" "));
                        current.push_str(" ");
                        current.push_str(&children);
                    },
                }
                parents.pop();
                return current
            },
            Event::Variable(..) => unreachable!(),
            Event::Comment(body) => unimplemented!(),
        };

        last = token;
    }
    children
}

pub fn compact<'a, I>(tokenizer: &mut I) -> String
    where I: Iterator<Item = Event<'a>>
{
    let mut vm = VariableMapper::new(tokenizer);
    let mut parents = Vec::new();
    compact_inner(&mut vm, &mut parents)
}

fn compact_inner<'a, I>(tokenizer: &mut I, parents: &mut Vec<String>) -> String
    where I: Iterator<Item = Event<'a>>
{
    let mut last = Event::End(Rule::SassRule);
    let mut current = String::new();
    let mut properties = String::new();
    let mut children = String::new();

    while let Some(token) = tokenizer.next() {
        match token.clone() {
            Event::Start(_) => {
                match children.len() {
                    0 => children = compact_inner(tokenizer, parents),
                    _ => {
                        children.push_str("\n");
                        children.push_str(&compact_inner(tokenizer, parents));
                    },
                };
            },
            Event::Selector(name) => {
                parents.push((*name).to_string());
                match last {
                    Event::Selector(_) => current.push_str(&format!(" {}", name)),
                    Event::End(_) => current.push_str(&format!("{}", name)),
                    _ => current.push_str(&format!("{}", name)),
                }
            },
            Event::Property(name, value) => {
                match last {
                    Event::Selector(_) => properties.push_str(&format!(" {{ {}: {};", name, value)),
                    _ => properties.push_str(&format!(" {}: {};", name, value)),
                }
            },
            Event::End(_) => {
                match (properties.len(), children.len()) {
                    (0, 0) => current.push_str(" }"),
                    (_, 0) => {
                        current.push_str(&properties);
                        current.push_str(" }\n");
                    },
                    (0, _) => {
                        current.push_str(" ");
                        current.push_str(&children);
                    },
                    (_, _) => {
                        current.push_str(&properties);
                        current.push_str(" }\n");
                        current.push_str(&parents.connect(" "));
                        current.push_str(" ");
                        current.push_str(&children);
                    },
                }
                parents.pop();
                return current
            },
            Event::Variable(..) => unreachable!(),
            Event::Comment(body) => unimplemented!(),
        };
        last = token;
    }
    children
}

pub fn debug(tokenizer: &mut Tokenizer) -> String {
    let mut output = String::new();
    let mut current = String::new();

    while let Some(token) = tokenizer.next() {
        current.push_str(&format!("{:?}\n", token));
        match token {
            Event::End(_) => {
                output.push_str(&current);
                current = String::new();
            },
            _ => {},
        }
    }
    output
}
<commit_msg>Print out comments; start fiddling with expanded<commit_after>use tokenizer::Tokenizer;
use event::{Event, Rule};
use variable_mapper::VariableMapper;

pub fn nested<'a, I>(tokenizer: &mut I) -> String
    where I: Iterator<Item = Event<'a>>
{
    let mut vm = VariableMapper::new(tokenizer);
    let mut parents = Vec::new();
    nested_inner(&mut vm, &mut parents)
}

pub fn nested_inner<'a, I>(tokenizer: &mut I, parents: &mut Vec<String>) -> String
    where I: Iterator<Item = Event<'a>>
{
    let mut last = Event::End(Rule::SassRule);
    let mut current = String::new();
    let mut properties = String::new();
    let mut children = String::new();

    while let Some(token) = tokenizer.next() {
       match token.clone() {
            Event::Start(_) => {
                match children.len() {
                    0 => children = nested_inner(tokenizer, parents),
                    _ => {
                        children.push_str("\n\n");
                        children.push_str(&nested_inner(tokenizer, parents));
                    },
                };
            },
            Event::Selector(name) => {
                parents.push((*name).to_string());
                current.push_str(&format!("{} ", name));
            },
            Event::Property(name, value) => {
                match last {
                    Event::Selector(_) => properties.push_str(&format!("{{\n  {}: {};", name, value)),
                    _ => properties.push_str(&format!("\n  {}: {};", name, value)),
                }
            },
            Event::End(_) => {
                match (properties.len(), children.len()) {
                    (0, 0) => current.push_str(" }\n"),
                    (_, 0) => {
                        current.push_str(&properties);
                        current.push_str(" }");
                    },
                    (0, _) => {
                        current.push_str(&children);
                    },
                    (_, _) => {
                        current.push_str(&properties);
                        current.push_str(" }\n  ");
                        current.push_str(&parents.connect(" "));
                        current.push_str(" ");
                        current.push_str(&children.split('\n').collect::<Vec<_>>().connect("\n  "));
                    },
                }
                parents.pop();
                return current
            },
            Event::Comment(body) => current.push_str(&body),
            Event::Variable(..) => unreachable!(),
        };
        last = token;
    }
    children
}

pub fn compressed<'a, I>(tokenizer: &mut I) -> String
    where I: Iterator<Item = Event<'a>>
{
    let mut vm = VariableMapper::new(tokenizer);
    let mut parents = Vec::new();
    compressed_inner(&mut vm, &mut parents)
}

fn compressed_inner<'a, I>(tokenizer: &mut I, parents: &mut Vec<String>) -> String
    where I: Iterator<Item = Event<'a>>
{
    let mut last = Event::End(Rule::SassRule);
    let mut current = String::new();
    let mut properties = String::new();
    let mut children = String::new();

    while let Some(token) = tokenizer.next() {
        match token.clone() {
            Event::Start(_) => {
                match children.len() {
                    0 => children = compressed_inner(tokenizer, parents),
                    _ => {
                        children.push_str(&compressed_inner(tokenizer, parents));
                    },
                };
            },
            Event::Selector(name) => {
                parents.push((*name).to_string());
                match last {
                    Event::Selector(_) => current.push_str(&format!(" {}", name)),
                    _ => current.push_str(&format!("{}", name)),
                }
            },
            Event::Property(name, value) => {
                match last {
                    Event::Selector(..) => properties.push_str(&format!("{{{}:{}", name, value)),
                    Event::Property(..) => properties.push_str(&format!(";{}:{}", name, value)),
                    _ => properties.push_str(&format!("{}:{}", name, value)),
                }
            },
            Event::End(_) => {
                match (properties.len(), children.len()) {
                    (0, 0) => current.push_str("}"),
                    (_, 0) => {
                        current.push_str(&properties);
                        current.push_str("}");
                    },
                    (0, _) => {
                        current.push_str(" ");
                        current.push_str(&children);
                    },
                    (_, _) => {
                        current.push_str(&properties);
                        current.push_str("}");
                        current.push_str(&parents.connect(" "));
                        current.push_str(" ");
                        current.push_str(&children);
                    },
                }
                parents.pop();
                return current
            },
            Event::Comment(body) => current.push_str(&body),
            Event::Variable(..) => unreachable!(),
        };
        last = token;
    }
    children
}

pub fn expanded<'a, I>(tokenizer: &mut I) -> String
    where I: Iterator<Item = Event<'a>>
{
    let mut vm = VariableMapper::new(tokenizer);
    let mut parents = Vec::new();
    expanded_inner(&mut vm, &mut parents)
}

fn expanded_inner<'a, I>(tokenizer: &mut I, parents: &mut Vec<String>) -> String
    where I: Iterator<Item = Event<'a>>
{
    let mut last = Event::End(Rule::SassRule);
    let mut current = String::new();
    let mut properties = String::new();
    let mut children = String::new();

    while let Some(token) = tokenizer.next() {
        match token.clone() {
            Event::Start(_) => {
                match children.len() {
                    0 => children = expanded_inner(tokenizer, parents),
                    _ => {
                        children.push_str("\n\n");
                        children.push_str(&expanded_inner(tokenizer, parents));
                    },
                };
            },
            Event::Selector(name) => {
                parents.push((*name).to_string());
                match last {
                    Event::Selector(_) => current.push_str(&format!(" {}", name)),
                    Event::End(_) => current.push_str(&format!("{}", name)),
                    _ => current.push_str(&format!("{}", name)),
                }
            },
            Event::Property(name, value) => {
                match last {
                    Event::Selector(_) => properties.push_str(&format!(" {{\n  {}: {};", name, value)),
                    _ => properties.push_str(&format!("\n  {}: {};", name, value)),
                }
            },
            Event::End(_) => {
                match (properties.len(), children.len()) {
                    (_, 0) => {
                        current.push_str(&properties);
                        current.push_str("\n}");
                    },
                    (0, _) => {
                        current.push_str(" ");
                        current.push_str(&children);
                    },
                    (_, _) => {
                        current.push_str(&properties);
                        current.push_str("\n}\n");
                        current.push_str(&parents.connect(" "));
                        current.push_str(" ");
                        current.push_str(&children);
                    },
                }
                parents.pop();
                return current
            },
            Event::Comment(body) => {
                match last {
                    Event::Property(..) => properties.push_str(&body),
                    _ => current.push_str(&format!("{}\n", body)),
                }
            },
            Event::Variable(..) => unreachable!(),
        };

        last = token;
    }
    current.push_str(&children);
    current
}

pub fn compact<'a, I>(tokenizer: &mut I) -> String
    where I: Iterator<Item = Event<'a>>
{
    let mut vm = VariableMapper::new(tokenizer);
    let mut parents = Vec::new();
    compact_inner(&mut vm, &mut parents)
}

fn compact_inner<'a, I>(tokenizer: &mut I, parents: &mut Vec<String>) -> String
    where I: Iterator<Item = Event<'a>>
{
    let mut last = Event::End(Rule::SassRule);
    let mut current = String::new();
    let mut properties = String::new();
    let mut children = String::new();

    while let Some(token) = tokenizer.next() {
        match token.clone() {
            Event::Start(_) => {
                match children.len() {
                    0 => children = compact_inner(tokenizer, parents),
                    _ => {
                        children.push_str("\n");
                        children.push_str(&compact_inner(tokenizer, parents));
                    },
                };
            },
            Event::Selector(name) => {
                parents.push((*name).to_string());
                match last {
                    Event::Selector(_) => current.push_str(&format!(" {}", name)),
                    Event::End(_) => current.push_str(&format!("{}", name)),
                    _ => current.push_str(&format!("{}", name)),
                }
            },
            Event::Property(name, value) => {
                match last {
                    Event::Selector(_) => properties.push_str(&format!(" {{ {}: {};", name, value)),
                    _ => properties.push_str(&format!(" {}: {};", name, value)),
                }
            },
            Event::End(_) => {
                match (properties.len(), children.len()) {
                    (0, 0) => current.push_str(" }"),
                    (_, 0) => {
                        current.push_str(&properties);
                        current.push_str(" }\n");
                    },
                    (0, _) => {
                        current.push_str(" ");
                        current.push_str(&children);
                    },
                    (_, _) => {
                        current.push_str(&properties);
                        current.push_str(" }\n");
                        current.push_str(&parents.connect(" "));
                        current.push_str(" ");
                        current.push_str(&children);
                    },
                }
                parents.pop();
                return current
            },
            Event::Comment(body) => current.push_str(&body),
            Event::Variable(..) => unreachable!(),
        };
        last = token;
    }
    children
}

pub fn debug(tokenizer: &mut Tokenizer) -> String {
    let mut output = String::new();
    let mut current = String::new();

    while let Some(token) = tokenizer.next() {
        current.push_str(&format!("{:?}\n", token));
        match token {
            Event::End(_) => {
                output.push_str(&current);
                current = String::new();
            },
            _ => {},
        }
    }
    output
}
<|endoftext|>