diff options
| author | Daniel <kingdread@gmx.de> | 2019-06-03 02:02:44 +0200 | 
|---|---|---|
| committer | Daniel <kingdread@gmx.de> | 2019-06-03 02:02:44 +0200 | 
| commit | 5d2f51ab8593946a0f24db367a887a37258901d5 (patch) | |
| tree | 498f2af9584046ed63f256375169bbf5756bfb7d /src/output | |
| parent | c731b470fc162e56f6d81c475bacb41230a5e2d3 (diff) | |
| download | raidgrep-5d2f51ab8593946a0f24db367a887a37258901d5.tar.gz raidgrep-5d2f51ab8593946a0f24db367a887a37258901d5.tar.bz2 raidgrep-5d2f51ab8593946a0f24db367a887a37258901d5.zip | |
[WIP] rewrite output logic as a pipeline
Diffstat (limited to 'src/output')
| -rw-r--r-- | src/output/aggregators.rs | 32 | ||||
| -rw-r--r-- | src/output/formats.rs | 68 | ||||
| -rw-r--r-- | src/output/mod.rs | 26 | ||||
| -rw-r--r-- | src/output/pipeline.rs | 27 | 
4 files changed, 153 insertions, 0 deletions
| diff --git a/src/output/aggregators.rs b/src/output/aggregators.rs new file mode 100644 index 0000000..9934fb3 --- /dev/null +++ b/src/output/aggregators.rs @@ -0,0 +1,32 @@ +//! Different aggregators for output. +//! +//! An aggregator is something that "controls the order" of the output. Aggregators can either save +//! all items that they're and output them once the search is finished, or write them straight +//! to the output stream. +//! +//! Aggregators must be shareable across threads, as the search will be multi-threaded. This is why +//! an Aggregator must make sure that the data is protected by a mutex or similar. +use super::{super::LogResult, formats::Format}; + +use std::{io::Write, sync::Mutex}; + +pub trait Aggregator: Sync { +    fn push_item(&self, item: &LogResult, format: &Format, stream: &mut Write); +    fn finish(self, format: &Format, stream: &mut Write); +} + + +/// An aggregator that just pushes through each item to the output stream without any sorting or +/// whatsoever. +pub struct WriteThrough; + + +impl Aggregator for WriteThrough { +    fn push_item(&self, item: &LogResult, format: &Format, stream: &mut Write) { +        let text = format.format_result(item); +        println!("Aggregator::push_item {:?}", text); +        stream.write_all(text.as_bytes()).unwrap(); +    } + +    fn finish(self, format: &Format, stream: &mut Write) {} +} diff --git a/src/output/formats.rs b/src/output/formats.rs new file mode 100644 index 0000000..fe6e982 --- /dev/null +++ b/src/output/formats.rs @@ -0,0 +1,68 @@ +//! A crate defining different output formats for search results. +use std::fmt::Write; + +use super::{LogResult, FightOutcome}; + +/// An output format +pub trait Format: Sync + Send { +    /// Format a single log result +    fn format_result(&self, item: &LogResult) -> String; +} + + +impl<T: Format + ?Sized> Format for Box<T> { +    fn format_result(&self, item: &LogResult) -> String { +        (&*self).format_result(item) +    } +} + + +/// The human readable, colored format. +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct HumanReadable; + + +impl Format for HumanReadable { +    fn format_result(&self, item: &LogResult) -> String { +        use colored::Colorize; +        let mut result = String::new(); + +        writeln!(result, "{}: {:?}", "File".green(), item.log_file).unwrap(); +        let outcome = match item.outcome { +            FightOutcome::Success => "SUCCESS".green(), +            FightOutcome::Wipe => "WIPE".red(), +        }; +        writeln!( +            result, +            "{}: {} - {}: {} {}", +            "Date".green(), +            item.time.format("%Y-%m-%d %H:%M:%S %a"), +            "Boss".green(), +            item.boss_name, +            outcome, +        ).unwrap(); +        for player in &item.players { +            writeln!( +                result, +                "  {:2} {:20} {:19} {}", +                player.subgroup, +                player.account_name.yellow(), +                player.character_name.cyan(), +                player.profession +            ).unwrap(); +        } +        result +    } +} + + +/// A format which outputs only the file-name +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct FileOnly; + + +impl Format for FileOnly { +    fn format_result(&self, item: &LogResult) -> String { +        item.log_file.to_string_lossy().into_owned() +    } +} diff --git a/src/output/mod.rs b/src/output/mod.rs new file mode 100644 index 0000000..dfb3ea8 --- /dev/null +++ b/src/output/mod.rs @@ -0,0 +1,26 @@ +use super::errors::RuntimeError; +use super::{FightOutcome, LogResult, Opt}; + +use std::io; + +pub mod formats; +pub mod aggregators; +pub mod pipeline; + +use self::formats::Format; +use self::aggregators::Aggregator; +pub use self::pipeline::Pipeline; + + +/// Build an pipeline for the given command line options. +pub fn build_pipeline(opt: &Opt) -> Pipeline { +    let stream = io::stdout(); + +    let formatter: Box<dyn Format> = if opt.file_name_only { +        Box::new(formats::FileOnly) +    } else { +        Box::new(formats::HumanReadable) +    }; + +    Pipeline::new(stream, formatter, aggregators::WriteThrough) +} diff --git a/src/output/pipeline.rs b/src/output/pipeline.rs new file mode 100644 index 0000000..9b3c7e5 --- /dev/null +++ b/src/output/pipeline.rs @@ -0,0 +1,27 @@ +use super::{formats::Format, aggregators::Aggregator}; +use super::super::LogResult; + +use std::{io::Write, sync::Mutex}; + + +pub struct Pipeline { +    format: Box<dyn Format>, +    aggregator: Box<dyn Aggregator>, +    writer: Mutex<Box<dyn Write>>, +} + + +impl Pipeline { +    pub fn new<W: Write + 'static, F: Format + 'static, A: Aggregator + 'static>(writer: W, format: F, aggregator: A) -> Pipeline { +        Pipeline { +            format: Box::new(format), +            aggregator: Box::new(aggregator), +            writer: Mutex::new(Box::new(writer)), +        } +    } + +    pub fn push_item(&self, item: &LogResult) { +        let mut writer = self.writer.lock().unwrap(); +        self.aggregator.push_item(item, &self.format, &mut *writer); +    } +} | 
