use rustc_serialize::json::Json;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::{BTreeMap, HashMap, HashSet};
use std::marker::PhantomData;
use std::mem::size_of;
use indexing::*;
use misc::{vec_with_size, Flatten, LinearBuckets, SerializationFormat};
use service::{PrivateAccess, Service};
use task::{BackEnd, KeyedRawStorage, Op};
pub trait KeyedHistogram<K, T>: Clone {
fn record(&self, key: K, value: T) {
self.record_cb(|| Some((key, value)))
}
fn record_cb<F>(&self, _: F)
where
F: FnOnce() -> Option<(K, T)>;
}
impl<K> BackEnd<Keyed<K>>
where
K: ToString,
{
fn raw_record(&self, k: &Key<Keyed<K>>, key: String, value: u32) {
self.sender
.send(Op::RecordKeyed(k.index, key, value))
.unwrap();
}
fn raw_record_cb<F, T>(&self, cb: F) -> bool
where
F: FnOnce() -> Option<(K, T)>,
T: Flatten,
{
if let Some(k) = self.get_key() {
if let Some((key, v)) = cb() {
self.raw_record(&k, key.to_string(), v.as_u32());
true
} else {
false
}
} else {
false
}
}
}
#[derive(Default)]
pub struct KeyedIgnoring<T, U> {
witness: PhantomData<(T, U)>,
}
impl<T, U> KeyedIgnoring<T, U> {
pub fn new() -> KeyedIgnoring<T, U> {
KeyedIgnoring {
witness: PhantomData,
}
}
}
impl<K, T> KeyedHistogram<K, T> for KeyedIgnoring<K, T> {
fn record_cb<F>(&self, _: F)
where
F: FnOnce() -> Option<(K, T)>,
{
}
}
impl<T, U> Clone for KeyedIgnoring<T, U> {
fn clone(&self) -> Self {
KeyedIgnoring {
witness: PhantomData,
}
}
}
pub struct KeyedFlag<T> {
back_end: BackEnd<Keyed<T>>,
}
impl<K> KeyedFlag<K>
where
K: ToString,
{
pub fn new(service: &Service, name: String) -> KeyedFlag<K> {
let storage = Box::new(KeyedFlagStorage {
encountered: HashSet::new(),
});
let key = PrivateAccess::register_keyed(service, name, storage);
KeyedFlag {
back_end: BackEnd::new(service, key),
}
}
}
struct KeyedFlagStorage {
encountered: HashSet<String>,
}
impl KeyedRawStorage for KeyedFlagStorage {
fn store(&mut self, k: String, _: u32) {
self.encountered.insert(k);
}
fn to_json(&self, format: &SerializationFormat) -> Json {
match format {
SerializationFormat::SimpleJson => {
let mut keys: Vec<&String> = self.encountered.iter().collect();
keys.sort();
let array = keys.iter().map(|&x| Json::String(x.clone())).collect();
Json::Array(array)
}
}
}
}
impl<K> KeyedHistogram<K, ()> for KeyedFlag<K>
where
K: ToString,
{
fn record_cb<F>(&self, cb: F)
where
F: FnOnce() -> Option<(K, ())>,
{
self.back_end.raw_record_cb(cb);
}
}
impl<T> Clone for KeyedFlag<T> {
fn clone(&self) -> Self {
KeyedFlag {
back_end: self.back_end.clone(),
}
}
}
pub struct KeyedLinear<K, T>
where
T: Flatten,
{
witness: PhantomData<T>,
back_end: BackEnd<Keyed<K>>,
}
type KeyedLinearBuckets = LinearBuckets;
struct KeyedLinearStorage {
values: HashMap<String, Vec<u32>>,
shape: KeyedLinearBuckets,
}
impl KeyedLinearStorage {
fn new(shape: KeyedLinearBuckets) -> KeyedLinearStorage {
KeyedLinearStorage {
values: HashMap::new(),
shape,
}
}
}
impl KeyedRawStorage for KeyedLinearStorage {
fn store(&mut self, key: String, value: u32) {
let index = self.shape.get_bucket(value);
match self.values.entry(key) {
Occupied(mut e) => {
e.get_mut()[index] += 1;
}
Vacant(e) => {
let mut vec = vec_with_size(self.shape.buckets, 0);
vec[index] += 1;
e.insert(vec);
}
}
}
fn to_json(&self, _: &SerializationFormat) -> Json {
let mut values: Vec<_> = self.values.iter().collect();
values.sort();
let mut tree = BTreeMap::new();
for value in values {
let (name, vec) = value;
let array = Json::Array(vec.iter().map(|&x| Json::I64(x as i64)).collect());
tree.insert(name.clone(), array);
}
Json::Object(tree)
}
}
impl<K, T> KeyedLinear<K, T>
where
K: ToString,
T: Flatten,
{
pub fn new(
service: &Service,
name: String,
min: u32,
max: u32,
buckets: usize,
) -> KeyedLinear<K, T> {
assert!(size_of::<u32>() <= size_of::<usize>());
assert!(min < max);
assert!(max - min >= buckets as u32);
let shape = KeyedLinearBuckets::new(min, max, buckets);
let storage = Box::new(KeyedLinearStorage::new(shape));
let key = PrivateAccess::register_keyed(service, name, storage);
KeyedLinear {
witness: PhantomData,
back_end: BackEnd::new(service, key),
}
}
}
impl<K, T> KeyedHistogram<K, T> for KeyedLinear<K, T>
where
K: ToString,
T: Flatten,
{
fn record_cb<F>(&self, cb: F)
where
F: FnOnce() -> Option<(K, T)>,
{
self.back_end.raw_record_cb(cb);
}
}
impl<K, T> Clone for KeyedLinear<K, T>
where
T: Flatten,
{
fn clone(&self) -> Self {
KeyedLinear {
back_end: self.back_end.clone(),
witness: PhantomData,
}
}
}
pub struct KeyedCount<K> {
back_end: BackEnd<Keyed<K>>,
}
struct KeyedCountStorage {
values: HashMap<String, u32>,
}
impl KeyedRawStorage for KeyedCountStorage {
fn store(&mut self, key: String, value: u32) {
match self.values.entry(key) {
Occupied(mut e) => {
let v = *e.get();
e.insert(v + value);
}
Vacant(e) => {
e.insert(value);
}
}
}
fn to_json(&self, format: &SerializationFormat) -> Json {
match format {
SerializationFormat::SimpleJson => {
let mut values: Vec<_> = self.values.iter().collect();
values.sort();
let mut tree = BTreeMap::new();
for value in values {
let (name, val) = value;
tree.insert(name.clone(), Json::I64(*val as i64));
}
Json::Object(tree)
}
}
}
}
impl<K> KeyedHistogram<K, u32> for KeyedCount<K>
where
K: ToString,
{
fn record_cb<F>(&self, cb: F)
where
F: FnOnce() -> Option<(K, u32)>,
{
self.back_end.raw_record_cb(cb);
}
}
impl<K> KeyedCount<K> {
pub fn new(service: &Service, name: String) -> KeyedCount<K> {
let storage = Box::new(KeyedCountStorage {
values: HashMap::new(),
});
let key = PrivateAccess::register_keyed(service, name, storage);
KeyedCount {
back_end: BackEnd::new(service, key),
}
}
}
impl<K> Clone for KeyedCount<K> {
fn clone(&self) -> Self {
KeyedCount {
back_end: self.back_end.clone(),
}
}
}
pub struct KeyedEnum<K, T>
where
K: ToString,
T: Flatten,
{
witness: PhantomData<T>,
back_end: BackEnd<Keyed<K>>,
}
struct KeyedEnumStorage {
values: HashMap<String, Vec<u32>>,
}
impl KeyedRawStorage for KeyedEnumStorage {
fn store(&mut self, key: String, value: u32) {
match self.values.entry(key) {
Occupied(mut e) => {
let vec = e.get_mut();
vec.resize(value as usize + 1, 0);
vec[value as usize] += 1;
}
Vacant(e) => {
let mut vec = Vec::new();
vec.resize(value as usize + 1, 0);
vec[value as usize] = 1;
e.insert(vec);
}
}
}
fn to_json(&self, format: &SerializationFormat) -> Json {
match format {
SerializationFormat::SimpleJson => {
let mut values: Vec<_> = self.values.iter().collect();
values.sort();
let mut tree = BTreeMap::new();
for value in values {
let (name, array) = value;
let vec = array.iter().map(|&x| Json::I64(x as i64)).collect();
tree.insert(name.clone(), Json::Array(vec));
}
Json::Object(tree)
}
}
}
}
impl<K, T> KeyedHistogram<K, T> for KeyedEnum<K, T>
where
K: ToString,
T: Flatten,
{
fn record_cb<F>(&self, cb: F)
where
F: FnOnce() -> Option<(K, T)>,
{
self.back_end.raw_record_cb(cb);
}
}
impl<K, T> KeyedEnum<K, T>
where
K: ToString,
T: Flatten,
{
pub fn new(service: &Service, name: String) -> KeyedEnum<K, T> {
let storage = Box::new(KeyedEnumStorage {
values: HashMap::new(),
});
let key = PrivateAccess::register_keyed(service, name, storage);
KeyedEnum {
witness: PhantomData,
back_end: BackEnd::new(service, key),
}
}
}
impl<K, T> Clone for KeyedEnum<K, T>
where
K: ToString,
T: Flatten,
{
fn clone(&self) -> Self {
KeyedEnum {
back_end: self.back_end.clone(),
witness: PhantomData,
}
}
}