1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use crate::Counters;
use crate::filters::Select;
use std::io;
use std::cell::RefCell;

/// Helper to print counters as a table in csv format.
///
/// # Example
///
/// ```
/// use counters::*;
/// 
/// let counters = Counters::new();
/// let table = Table::new(&["foo", "bar", "meh"]);
/// 
/// for _ in 0..5 {
///     counters.event("bar");
/// }
/// counters.event("foo");
/// 
/// // "baz" isn't in the table labels, it will be ignored.
/// counters.event("baz");
/// 
/// table.add_row(&counters);
/// 
/// // Start a second row...
/// counters.reset_all();
/// 
/// counters.event("foo");
/// 
/// table.add_row(&counters);
///
/// // This prints the following to stdout:
/// // foo,bar,meh
/// // 1,5,0
/// // 1,0,0
/// table.print_to_stdout();
/// ```
#[derive(Clone, Debug)]
pub struct Table {
    labels: Vec<&'static str>,
    rows: RefCell<Vec<Counters>>,
}

impl Table {
    pub fn new(label_slice: &[&'static str]) -> Self {
        let mut labels = Vec::new();
        labels.extend_from_slice(label_slice);
        Table {
            labels,
            rows: RefCell::new(Vec::new()),
        }
    }

    /// Add collected counters as a row, preserving only the counters that match this table's labels.
    pub fn add_row(&self, row: &Counters) -> usize {
        let row = row.clone();
        row.retain(Select(|ref key, _| self.labels.iter().any(|label| label == key) ));
        self.rows.borrow_mut().push(row);

        self.rows.borrow().len()
    }

    /// Print in csv format to an io stream.
    pub fn print(&self, to: &mut io::Write) -> io::Result<()> {
        for (i, label) in self.labels.iter().enumerate() {
            if i != 0 {
                write!(to, ",")?;
            }
            write!(to, "{}", label)?;
        }
        writeln!(to, "")?;
        for row in self.rows.borrow().iter() {

            for (i, label) in self.labels.iter().enumerate() {
                if i != 0 {
                    write!(to, ", ")?;                
                }
                write!(to, "{}", row.get(label))?;
            }
            writeln!(to, "")?;
        }

        Ok(())
    }

    /// Print in csv format to stdout.
    pub fn print_to_stdout(&self) {
        self.print(&mut io::stdout()).unwrap();
    }
}

#[cfg(feature = "dummy_serialization")]
use serde::{Serialize, Deserialize};
#[cfg(feature = "dummy_serialization")]
use crate::Dummy;

#[cfg(feature = "dummy_serialization")]
impl Serialize for Table {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where S: serde::Serializer {
        Dummy.serialize(serializer)
    }
}

#[cfg(feature = "dummy_serialization")]
impl<'de> Deserialize<'de> for Table {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where D: serde::Deserializer<'de> {
        Dummy::deserialize(deserializer)?;
        Ok(Table {
            labels: Vec::new(),
            rows: RefCell::new(Vec::new()),
        })
    }
}