The efficient and elegant crate to count variants of Rust's Enum.

Overview

variant-counter

Crates.io docs.rs

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:

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() } } ">
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: Generate check methods for variants.

  • erase: Generate erase methods for variants.

  • stats: Generate statistics methods, such as avg(), variance(), and sd(), etc.

  • std: Enable std crate supported. Enabled by default. Please disable this feature to support no_std.

You might also like...
A memory efficient immutable string type that can store up to 24* bytes on the stack

compact_str A memory efficient immutable string type that can store up to 24* bytes on the stack. * 12 bytes for 32-bit architectures About A CompactS

An efficient method of heaplessly converting numbers into their string representations, storing the representation within a reusable byte array.

NumToA #![no_std] Compatible with Zero Heap Allocations The standard library provides a convenient method of converting numbers into strings, but thes

A flexible, simple to use, immutable, clone-efficient String replacement for Rust

A flexible, simple to use, immutable, clone-efficient String replacement for Rust. It unifies literals, inlined, and heap allocated strings into a single type.

An efficient async condition variable for lock-free algorithms

async-event An efficient async condition variable for lock-free algorithms, a.k.a. "eventcount". Overview Eventcount-like primitives are useful to mak

Better touch. Efficient file creation with templates.

touchx Better touch. Efficient file creation with templates. If you save files such as LICENSE or .editorconfig, you can create files with similar con

This crate allows writing a struct in Rust and have it derive a struct of arrays layed out in memory according to the arrow format.

Arrow2-derive - derive for Arrow2 This crate allows writing a struct in Rust and have it derive a struct of arrays layed out in memory according to th

This crate bridges between gstreamer and tracing ecosystems.

This crate provides a bridge between gstreamer and the tracing ecosystem. The goal is to allow Rust applications utilizing GStreamer to better integra

Membrane is an opinionated crate that generates a Dart package from a Rust library. Extremely fast performance with strict typing and zero copy returns over the FFI boundary via bincode.

Membrane is an opinionated crate that generates a Dart package from a Rust library. Extremely fast performance with strict typing and zero copy returns over the FFI boundary via bincode.

A Rust crate that provides a simple interface for LZMA compression and decompression.

rust-lzma Documentation This crate provides a simple interface to liblzma. LZMA is more commonly known as XZ or 7zip, (as in, files with the .xz or .7

Owner
Folyd
Creator of https://huhu.io, https://anyshortcut.com, https://paybase.cn
Folyd
Count and convert between different indexing schemes on utf8 string slices

Str Indices Count and convert between different indexing schemes on utf8 string slices. The following schemes are currently supported: Chars (or "Unic

Nathan Vegdahl 11 Dec 25, 2022
Count zeroes on a disk or a file

Count zeroes on a disk or a file

Cecile Tonglet 1 Dec 12, 2021
Count lines from files in a directory.

rust-cloc Count lines from files in a directory. Features Count the number of empty and non-empty lines in total from all files in a directory. Count

Daniel Liu 2 Apr 27, 2022
Generate enum from a trait, with converters between them

Derive macro for Rust that turns traits into enums, providing tools for calling funtions over channels

Vitaly Shukela 16 Nov 3, 2022
Output the individual word-count statistics from a set of files

Output the individual word-count statistics from a set of files, or generate a curated word list

Johnny Tidemand Vestergaard 1 Apr 3, 2022
Proc. macro to generate C-like `enum` tags.

Continuous Integration Documentation Crates.io #[derive(EnumTag)] This crate provides a proc. macro to derive the EnumTag trait for the given Rust enu

Robin Freyler 5 Mar 27, 2023
Bolt is a desktop application that is designed to make the process of developing and testing APIs easier and more efficient.

Bolt ⚡ Bolt is a desktop application that is designed to make the process of developing and testing APIs easier and more efficient. Quick start ??‍??

0xHiro 6 Mar 26, 2023
Simple and efficient time representation in Rust.

timens-rs Simple and efficient timestamp representation. The main objective being interoperability with OCaml Core_kernel.Time_ns. A significant part

Laurent Mazare 7 Oct 17, 2022
A simple, efficient Rust library for handling asynchronous job processing and task queuing.

job_queue Setup cargo add job_queue Usage Create a job use job_queue::{Error, Job, typetag, async_trait, serde}; #[derive(Debug, serde::Deserialize,

Georges KABBOUCHI 3 Nov 30, 2023
Concrete is a simple programming language specifically crafted for creating highly scalable systems that are reliable, efficient, and easy to maintain.

The Concrete Programming Language Most ideas come from previous ideas - Alan C. Kay, The Early History Of Smalltalk In the realm of low-level programm

Lambdaclass 126 Nov 22, 2024