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
// Copyright 2021 Twitter, Inc.
// Licensed under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0

use crate::{Metric, Value};
use std::any::Any;
use std::sync::atomic::{AtomicU64, Ordering};

/// A counter. Can be incremented or added to.
///
/// In case of overflow the counter will wrap around. However, internally it
/// uses an unsigned 64-bit integer so for most use cases this should be
/// unlikely.
///
/// # Example
/// ```
/// # use metriken::{metric, Counter};
/// #[metric(name = "my.custom.metric")]
/// static MY_COUNTER: Counter = Counter::new();
///
/// fn a_method() {
///     MY_COUNTER.increment();
///     // ...
/// }
/// # a_method();
/// ```
#[derive(Default, Debug)]
pub struct Counter(AtomicU64);

impl Counter {
    /// Create a counter initialized to 0.
    pub const fn new() -> Self {
        Self::with_value(0)
    }

    /// Create a counter initialized to `value`.
    pub const fn with_value(value: u64) -> Self {
        Self(AtomicU64::new(value))
    }

    #[inline]
    pub fn increment(&self) -> u64 {
        self.add(1)
    }

    #[inline]
    pub fn add(&self, value: u64) -> u64 {
        self.0.fetch_add(value, Ordering::Relaxed)
    }

    #[inline]
    pub fn value(&self) -> u64 {
        self.0.load(Ordering::Relaxed)
    }

    #[inline]
    pub fn set(&self, value: u64) -> u64 {
        self.0.swap(value, Ordering::Relaxed)
    }

    #[inline]
    pub fn reset(&self) -> u64 {
        self.set(0)
    }
}

impl Metric for Counter {
    fn as_any(&self) -> Option<&dyn Any> {
        Some(self)
    }

    fn value(&self) -> Option<Value> {
        Some(Value::Counter(self.value()))
    }
}