1pub mod json;
6pub mod table;
7
8pub type Message = (String, Result<Stats, String>);
9
10pub trait Output {
11 type Options;
12 type Error;
13 fn to_writer<W: Write>(self, options: Self::Options, writter: W) -> Result<(), Self::Error>;
14}
15
16use std::{
17 fmt::Display,
18 io::Write,
19 ops::{Add, AddAssign},
20};
21
22use serde::Serialize;
23use tabled::Tabled;
24use wz_core::*;
25
26#[derive(Debug, Eq, PartialEq, Clone, Copy, Serialize, Default, Tabled)]
30pub struct Stats {
31 #[tabled(display_with = "display_option")]
32 #[serde(skip_serializing_if = "Option::is_none")]
33 lines: Option<usize>,
34 #[tabled(display_with = "display_option")]
35 #[serde(skip_serializing_if = "Option::is_none")]
36 words: Option<usize>,
37 #[tabled(display_with = "display_option")]
38 #[serde(skip_serializing_if = "Option::is_none")]
39 characters: Option<usize>,
40 #[tabled(display_with = "display_option")]
41 #[serde(skip_serializing_if = "Option::is_none")]
42 bytes: Option<usize>,
43 #[tabled(display_with = "display_option")]
44 #[serde(skip_serializing_if = "Option::is_none")]
45 max: Option<usize>,
46}
47
48impl Stats {
49 pub fn identity() -> Self {
51 Self {
52 lines: Some(0),
53 words: Some(0),
54 characters: Some(0),
55 bytes: Some(0),
56 max: Some(0),
57 }
58 }
59}
60fn display_option<T: Display>(opt: &Option<T>) -> String {
64 match opt {
65 Some(x) => x.to_string(),
66 None => Default::default(),
67 }
68}
69
70macro_rules! add_name {
73 ( $($x1:ident $x2:ident $name:tt ), * ) => {
74 $(let $name = $x1.$name.zip($x2.$name).map(|(x,y)|x+y) ;)*
75 };
76}
77
78impl Add for Stats {
79 type Output = Stats;
80
81 fn add(self, rhs: Self) -> Self::Output {
82 add_name!(
83 self rhs lines,
84 self rhs words,
85 self rhs characters,
86 self rhs bytes
87 );
88 let max_line_length = self.max.zip(rhs.max).map(|(x, y)| std::cmp::max(x, y));
89 Self {
90 lines,
91 words,
92 characters,
93 bytes,
94 max: max_line_length,
95 }
96 }
97}
98
99impl AddAssign for Stats {
100 fn add_assign(&mut self, rhs: Self) {
101 *self = *self + rhs
102 }
103}
104
105macro_rules! impl_collector_stats {
107 ( $($name:ty=>$field:tt), *) => {
108 $(
109 impl $name for Stats {
110 fn collect(&mut self, count: usize) {
111 self.$field = Some(count);
112 }
113 }
114 )*
115 };
116}
117
118impl_collector_stats!(
119 LinesCollector=>lines,
120 WordsCollector=>words,
121 CharsCollector=>characters,
122 BytesCollector=>bytes,
123 MaxLineLengthCollector=>max
124);