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
117
118
119
120
121
122
123
|
//! Per-nick word/line statistics
use ilc_base::{self, Context, Decode, Event};
use ilc_base::event::Type;
use std::collections::HashMap;
use std::io::BufRead;
use serde::ser::{MapVisitor, Serialize, Serializer};
pub struct Stats {
pub freqs: HashMap<String, NickStat>,
}
impl Serialize for Stats {
fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
where S: Serializer
{
struct Visitor<'a>(&'a Stats);
impl<'a> MapVisitor for Visitor<'a> {
fn visit<S>(&mut self, s: &mut S) -> Result<Option<()>, S::Error>
where S: Serializer
{
try!(s.serialize_struct_elt("freqs", &self.0.freqs));
Ok(None)
}
fn len(&self) -> Option<usize> {
Some(1)
}
}
s.serialize_struct("Stats", Visitor(self))
}
}
pub struct NickStat {
pub lines: u32,
pub alpha_lines: u32,
pub words: u32,
}
impl Serialize for NickStat {
fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
where S: Serializer
{
struct Visitor<'a>(&'a NickStat);
impl<'a> MapVisitor for Visitor<'a> {
fn visit<S>(&mut self, s: &mut S) -> Result<Option<()>, S::Error>
where S: Serializer
{
try!(s.serialize_struct_elt("lines", self.0.lines));
try!(s.serialize_struct_elt("alpha_lines", self.0.alpha_lines));
try!(s.serialize_struct_elt("words", self.0.words));
Ok(None)
}
fn len(&self) -> Option<usize> {
Some(3)
}
}
s.serialize_struct("NickStat", Visitor(self))
}
}
fn words_alpha(s: &str) -> (u32, bool) {
let mut alpha = false;
let mut words = 0;
for w in s.split_whitespace() {
if !w.is_empty() {
words += 1;
if w.chars().any(char::is_alphabetic) {
alpha = true
}
}
}
(words, alpha)
}
fn strip_nick(s: &str) -> &str {
if s.is_empty() {
return s;
}
match s.as_bytes()[0] {
b'~' | b'&' | b'@' | b'%' | b'+' => &s[1..],
_ => s,
}
.trim_right_matches('_')
}
/// Return all active nicks, with lines, words and words per lines counted.
pub fn stats(ctx: &Context, input: &mut BufRead, decoder: &mut Decode) -> ilc_base::Result<Stats> {
let mut freqs: HashMap<String, NickStat> = HashMap::new();
for e in decoder.decode(&ctx, input) {
let m = try!(e);
match m {
Event { ty: Type::Msg { ref from, ref content, .. }, .. } => {
let nick = strip_nick(from);
if freqs.contains_key(nick) {
let p: &mut NickStat = freqs.get_mut(nick).unwrap();
let (words, alpha) = words_alpha(content);
p.lines += 1;
if alpha {
p.alpha_lines += 1
}
p.words += words;
} else {
let (words, alpha) = words_alpha(content);
freqs.insert(nick.to_owned(),
NickStat {
lines: 1,
alpha_lines: if alpha { 1 } else { 0 },
words: words,
});
}
}
_ => (),
}
}
Ok(Stats { freqs: freqs })
}
|