6 releases (3 breaking)
0.4.0 | Sep 15, 2021 |
---|---|
0.3.0 | Aug 16, 2021 |
0.2.2 | Aug 13, 2021 |
0.1.0 | Aug 11, 2021 |
#1233 in Rust patterns
17KB
57 lines
variant-counter
The efficient and elegant crate to count variants of Rust's Enum.
Get started
#[derive(VariantCount)]
#[derive(VariantCount)]
pub enum Enum {
Variant1,
Variant2,
}
Record your variant
let mut counter = Enum::counter();
counter.record(&Enum::Variant1);
Erase the record with erase_*()
methods
counter.erase_variant1();
Those erase_*()
methods are under erase
feature flag, and disabled by default.
Check the record with check_*()
methods
assert_eq!(counter.check_variant1(), 1);
Those check_*()
methods are under check
feature flag, and disabled by default.
discard()
, or reset()
the data
// Clear the `Enum::Variant1`'s data.
counter.discard(&Enum::Variant1);
// Clear all variants data.
counter.reset();
Ignore a variant
#[derive(VariantCount)]
pub enum Level {
#[counter(ignore)]
Trace,
Debug,
Info,
Warn,
Error,
}
If a variant was ignored, it has no effect when you record that variant.
let mut counter = Level::counter();
// Record nothing...
counter.record(&Level::Trace);
Aggregate your data
let data = counter.aggregate();
Group variants
#[derive(VariantCount)]
pub enum Platform {
#[counter(group = "Mobile")]
Android,
#[counter(group = "Mobile")]
IOS,
#[counter(group = "Desktop")]
Windows,
#[counter(group = "Desktop")]
Linux,
#[counter(group = "Desktop")]
MacOS,
#[counter(group = "Desktop")]
ChromeOS,
Others,
}
let counter = Platform::counter();
// Group version of aggregate method
let group_data = counter.group_aggregate();
Statistics
// Sum
counter.sum();
// Average
counter.avg();
// Variance
counter.variance();
// Standard deviation
counter.sd();
Weighted
#[derive(VariantCount)]
enum Rating {
#[counter(weight = 1)]
Hated,
#[counter(weight = 2)]
Disliked,
#[counter(weight = 3)]
Ok,
#[counter(weight = 4)]
Liked,
#[counter(weight = 5)]
Loved,
}
let mut counter = Rating::counter();
counter.record(&Rating::Loved);
let w = counter.weighted();
// Sum
w.sum();
// Average
w.avg();
// Variance
w.variance();
// Standard deviation
w.sd();
Macro expand
You can use carg-expand to expand the derived VariantCount
macro.
Here is the expanded code:
enum Enum {
Variant1,
Variant2,
}
impl Enum {
#[inline]
const fn variant_count() -> usize {
2usize
}
}
impl variant_counter::VariantCount for Enum {
type Counter = EnumCounter;
fn counter() -> Self::Counter {
EnumCounter::new()
}
}
/// The concrete counter struct auto-generated by macro.
#[must_use]
struct EnumCounter {
/// An array store the frequency of each variant which not be ignored.
frequency: [usize; 2usize],
}
impl EnumCounter {
const fn new() -> EnumCounter {
EnumCounter {
frequency: [0; 2usize],
}
}
/// Record a variant. It has no effect if you record an ignored variant.
fn record(&mut self, target: &Enum) {
let pair = match target {
Enum::Variant1 => Some(0usize),
Enum::Variant2 => Some(1usize),
_ => None,
};
if let Some(index) = pair {
self.frequency[index] = self.frequency[index].saturating_add(1);
}
}
/// Discard the record of the target variant.
/// It has no effect if you discard an ignored variant.
fn discard(&mut self, target: &Enum) {
let index = match target {
Enum::Variant1 => Some(0usize),
Enum::Variant2 => Some(1usize),
_ => None,
};
if let Some(index) = index {
self.frequency[index] = 0;
}
}
/// Reset the records.
fn reset(&mut self) {
self.frequency = [0; 2usize];
}
/// Aggregate the data to a HashMap.
#[cfg(feature = "std")]
fn aggregate(&self) -> std::collections::HashMap<&'static str, usize> {
IntoIterator::into_iter([
("Variant1", self.frequency[0usize]),
("Variant2", self.frequency[1usize]),
])
.collect()
}
/// Get the sum of frequency.
#[inline]
fn sum(&self) -> usize {
self.frequency.iter().sum()
}
}
Feature flags
-
full
: Enable all features. -
check
: Generatecheck
methods for variants. -
erase
: Generateerase
methods for variants. -
stats
: Generate statistics methods, such asavg()
,variance()
, andsd()
, etc. -
std
: Enablestd
crate supported. Enabled by default. Please disable this feature to supportno_std
.
Dependencies
~1.5MB
~35K SLoC