#[derive(Debug, Clone)]
pub enum FieldKind {
Open,
Closed(&'static [&'static str]),
}
#[derive(Debug, Clone)]
pub struct FieldDescriptor {
pub name: String,
pub kind: FieldKind,
}
pub trait ClosedValues {
fn all_variants() -> &'static [&'static str];
fn variant_str(&self) -> &str;
}
pub trait AggregableFields {
fn descriptors() -> Vec<FieldDescriptor>;
fn field_values(&self) -> Vec<(String, String)>;
}
impl<T: ClosedValues> AggregableFields for T {
fn descriptors() -> Vec<FieldDescriptor> {
vec![FieldDescriptor {
name: "value".into(),
kind: FieldKind::Closed(T::all_variants()),
}]
}
fn field_values(&self) -> Vec<(String, String)> {
vec![("value".into(), self.variant_str().to_string())]
}
}
impl AggregableFields for () {
fn descriptors() -> Vec<FieldDescriptor> {
vec![]
}
fn field_values(&self) -> Vec<(String, String)> {
vec![]
}
}
pub trait Aggregable {
fn group_key(&self) -> String;
fn instance_descriptors(&self) -> Vec<FieldDescriptor>;
fn observations(&self) -> Vec<Vec<(String, String)>>;
fn pivoted<F>(&self, f: F) -> Pivoted<'_, Self, F>
where
Self: Sized,
F: Fn(&Self) -> String,
{
Pivoted {
inner: self,
key_extractor: f,
}
}
}
pub struct Pivoted<'a, A: Aggregable, F: Fn(&A) -> String> {
pub inner: &'a A,
pub key_extractor: F,
}
impl<A: Aggregable, F: Fn(&A) -> String> Aggregable for Pivoted<'_, A, F> {
fn group_key(&self) -> String {
(self.key_extractor)(self.inner)
}
fn instance_descriptors(&self) -> Vec<FieldDescriptor> {
self.inner.instance_descriptors()
}
fn observations(&self) -> Vec<Vec<(String, String)>> {
self.inner.observations()
}
}
pub mod digest;