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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use prometheus_client::{
    encoding::{EncodeLabelSet, EncodeMetric},
    metrics::{counter::Counter, TypedMetric},
};

use std::hash::Hash;

use crate::{
    traits::{GaugeValue, HistogramValue},
    wrappers::{Family, Gauge, Histogram, Info},
    Buckets,
};

/// Builder of a single metric or a [`Family`] of metrics. Parameterized by buckets
/// (only applicable to [`Histogram`]s and their families) and labels (only applicable
/// to families).
#[derive(Debug, Clone, Copy)]
pub struct MetricBuilder<B = (), L = ()> {
    buckets: B,
    labels: L,
}

impl MetricBuilder {
    /// Creates a builder with buckets and labels not configured.
    pub const fn new() -> Self {
        Self {
            buckets: (),
            labels: (),
        }
    }
}

impl<L> MetricBuilder<(), L> {
    /// Configures buckets for this builder.
    pub fn with_buckets(self, buckets: impl Into<Buckets>) -> MetricBuilder<Buckets, L> {
        MetricBuilder {
            buckets: buckets.into(),
            labels: self.labels,
        }
    }
}

impl<B> MetricBuilder<B> {
    /// Configures labels for this builder.
    pub fn with_labels<L>(self, labels: L) -> MetricBuilder<B, L> {
        MetricBuilder {
            buckets: self.buckets,
            labels,
        }
    }
}

/// Metric that can be constructed from a [`MetricBuilder`].
pub trait BuildMetric: 'static + Sized + EncodeMetric + TypedMetric {
    /// Metric builder used to construct a metric.
    type Builder: Copy;

    /// Creates a metric given its builder.
    fn build(builder: Self::Builder) -> Self;
}

impl<N, A> BuildMetric for Counter<N, A>
where
    Counter<N, A>: 'static + EncodeMetric + Default,
{
    type Builder = MetricBuilder;

    fn build(_builder: Self::Builder) -> Self {
        Self::default()
    }
}

impl<V: GaugeValue> BuildMetric for Gauge<V> {
    type Builder = MetricBuilder;

    fn build(_builder: Self::Builder) -> Self {
        Self::default()
    }
}

impl<V: HistogramValue> BuildMetric for Histogram<V> {
    type Builder = MetricBuilder<Buckets>;

    fn build(builder: Self::Builder) -> Self {
        Histogram::new(builder.buckets)
    }
}

impl<S: 'static + EncodeLabelSet> BuildMetric for Info<S> {
    type Builder = MetricBuilder;

    fn build(_builder: Self::Builder) -> Self {
        Self::default()
    }
}

impl<S, M, B, L> BuildMetric for Family<S, M, L>
where
    S: 'static + Clone + Eq + Hash,
    M: BuildMetric<Builder = MetricBuilder<B, ()>>,
    B: Copy,
    L: 'static + Copy,
    Family<S, M, L>: EncodeMetric,
{
    type Builder = MetricBuilder<B, L>;

    fn build(builder: Self::Builder) -> Self {
        let item_builder = MetricBuilder {
            buckets: builder.buckets,
            labels: (),
        };
        Family::new(item_builder, builder.labels)
    }
}