Skip to main content

prometheus_client/
encoding.rs

1//! Exposition format implementations.
2
3#![allow(deprecated)]
4
5pub use prometheus_client_derive_encode::*;
6
7use crate::metrics::exemplar::Exemplar;
8use crate::metrics::MetricType;
9use crate::registry::{Prefix, Unit};
10use std::borrow::Cow;
11use std::collections::HashMap;
12use std::fmt::Write;
13use std::ops::Deref;
14use std::rc::Rc;
15use std::sync::Arc;
16use std::time::{SystemTime, UNIX_EPOCH};
17
18#[cfg(feature = "openmetrics_protobuf")]
19#[cfg_attr(docsrs, doc(cfg(feature = "openmetrics_protobuf")))]
20#[cfg_attr(
21    not(test),
22    deprecated(
23        note = "OpenMetrics protobuf support is deprecated. Use prometheus_protobuf instead."
24    )
25)]
26pub mod openmetrics_protobuf;
27#[cfg(feature = "prometheus_protobuf")]
28#[cfg_attr(docsrs, doc(cfg(feature = "prometheus_protobuf")))]
29pub mod prometheus_protobuf;
30pub mod text;
31
32#[cfg(feature = "openmetrics_protobuf")]
33#[deprecated(note = "Use openmetrics_protobuf instead.")]
34pub use openmetrics_protobuf as protobuf;
35
36/// Native histogram fields shared by encoders.
37#[derive(Clone, Copy, Debug)]
38pub struct NativeHistogram<'a> {
39    /// Native histogram schema.
40    pub schema: i32,
41    /// Breadth of the zero bucket.
42    pub zero_threshold: f64,
43    /// Count in the zero bucket.
44    pub zero_count: u64,
45    /// Negative sparse buckets.
46    pub negative: NativeHistogramBuckets<'a>,
47    /// Positive sparse buckets.
48    pub positive: NativeHistogramBuckets<'a>,
49    /// Native histogram creation timestamp.
50    pub created: Option<SystemTime>,
51}
52
53/// Sparse bucket span and delta encoding for one side of a native histogram.
54#[derive(Clone, Copy, Debug)]
55pub struct NativeHistogramBuckets<'a> {
56    /// Bucket spans.
57    pub spans: &'a [(i32, u32)],
58    /// Bucket count deltas.
59    pub deltas: &'a [i64],
60}
61
62macro_rules! for_both_mut {
63    ($self:expr, $inner:ident, $pattern:pat, $fn:expr) => {
64        match &mut $self.0 {
65            $inner::Text($pattern) => $fn,
66            #[cfg(feature = "openmetrics_protobuf")]
67            $inner::Protobuf($pattern) => $fn,
68            #[cfg(feature = "prometheus_protobuf")]
69            $inner::PrometheusProtobuf($pattern) => $fn,
70        }
71    };
72}
73
74macro_rules! for_both {
75    ($self:expr, $inner:ident, $pattern:pat, $fn:expr) => {
76        match $self.0 {
77            $inner::Text($pattern) => $fn,
78            #[cfg(feature = "openmetrics_protobuf")]
79            $inner::Protobuf($pattern) => $fn,
80            #[cfg(feature = "prometheus_protobuf")]
81            $inner::PrometheusProtobuf($pattern) => $fn,
82        }
83    };
84}
85
86/// Trait implemented by each metric type, e.g.
87/// [`Counter`](crate::metrics::counter::Counter), to implement its encoding in
88/// the OpenMetric text format.
89pub trait EncodeMetric {
90    /// Encode the given instance in the OpenMetrics text encoding.
91    // TODO: Lifetimes on MetricEncoder needed?
92    fn encode(&self, encoder: MetricEncoder) -> Result<(), std::fmt::Error>;
93
94    /// The OpenMetrics metric type of the instance.
95    // One can not use [`TypedMetric`] directly, as associated constants are not
96    // object safe and thus can not be used with dynamic dispatching.
97    fn metric_type(&self) -> MetricType;
98
99    /// Check if the metric is empty.
100    ///
101    /// An empty metric is a metric that has no data to encode, and thus should not have any
102    /// descriptor in the final output.
103    ///
104    /// By default, this returns `false`, ensuring the metric and its description is always
105    /// encoded.
106    fn is_empty(&self) -> bool {
107        false
108    }
109}
110
111impl EncodeMetric for Box<dyn EncodeMetric> {
112    fn encode(&self, encoder: MetricEncoder) -> Result<(), std::fmt::Error> {
113        self.deref().encode(encoder)
114    }
115
116    fn metric_type(&self) -> MetricType {
117        self.deref().metric_type()
118    }
119}
120
121/// Encoder for a Metric Descriptor.
122#[derive(Debug)]
123pub struct DescriptorEncoder<'a>(DescriptorEncoderInner<'a>);
124
125#[derive(Debug)]
126enum DescriptorEncoderInner<'a> {
127    Text(text::DescriptorEncoder<'a>),
128
129    #[cfg(feature = "openmetrics_protobuf")]
130    Protobuf(openmetrics_protobuf::DescriptorEncoder<'a>),
131
132    #[cfg(feature = "prometheus_protobuf")]
133    PrometheusProtobuf(prometheus_protobuf::DescriptorEncoder<'a>),
134}
135
136impl<'a> From<text::DescriptorEncoder<'a>> for DescriptorEncoder<'a> {
137    fn from(e: text::DescriptorEncoder<'a>) -> Self {
138        Self(DescriptorEncoderInner::Text(e))
139    }
140}
141
142#[cfg(feature = "openmetrics_protobuf")]
143impl<'a> From<openmetrics_protobuf::DescriptorEncoder<'a>> for DescriptorEncoder<'a> {
144    fn from(e: openmetrics_protobuf::DescriptorEncoder<'a>) -> Self {
145        Self(DescriptorEncoderInner::Protobuf(e))
146    }
147}
148
149#[cfg(feature = "prometheus_protobuf")]
150impl<'a> From<prometheus_protobuf::DescriptorEncoder<'a>> for DescriptorEncoder<'a> {
151    fn from(e: prometheus_protobuf::DescriptorEncoder<'a>) -> Self {
152        Self(DescriptorEncoderInner::PrometheusProtobuf(e))
153    }
154}
155
156impl DescriptorEncoder<'_> {
157    pub(crate) fn with_prefix_and_labels<'s>(
158        &'s mut self,
159        prefix: Option<&'s Prefix>,
160        labels: &'s [(Cow<'static, str>, Cow<'static, str>)],
161        // TODO: result needed?
162    ) -> DescriptorEncoder<'s> {
163        for_both_mut!(
164            self,
165            DescriptorEncoderInner,
166            e,
167            e.with_prefix_and_labels(prefix, labels).into()
168        )
169    }
170
171    /// Encode a descriptor.
172    pub fn encode_descriptor<'s>(
173        &'s mut self,
174        name: &'s str,
175        help: &str,
176        unit: Option<&'s Unit>,
177        metric_type: MetricType,
178    ) -> Result<MetricEncoder<'s>, std::fmt::Error> {
179        for_both_mut!(
180            self,
181            DescriptorEncoderInner,
182            e,
183            Ok(e.encode_descriptor(name, help, unit, metric_type)?.into())
184        )
185    }
186}
187
188/// Encoder for a metric.
189#[derive(Debug)]
190pub struct MetricEncoder<'a>(MetricEncoderInner<'a>);
191
192#[derive(Debug)]
193enum MetricEncoderInner<'a> {
194    Text(text::MetricEncoder<'a>),
195
196    #[cfg(feature = "openmetrics_protobuf")]
197    Protobuf(openmetrics_protobuf::MetricEncoder<'a>),
198
199    #[cfg(feature = "prometheus_protobuf")]
200    PrometheusProtobuf(prometheus_protobuf::MetricEncoder<'a>),
201}
202
203impl<'a> From<text::MetricEncoder<'a>> for MetricEncoder<'a> {
204    fn from(e: text::MetricEncoder<'a>) -> Self {
205        Self(MetricEncoderInner::Text(e))
206    }
207}
208
209#[cfg(feature = "openmetrics_protobuf")]
210impl<'a> From<openmetrics_protobuf::MetricEncoder<'a>> for MetricEncoder<'a> {
211    fn from(e: openmetrics_protobuf::MetricEncoder<'a>) -> Self {
212        Self(MetricEncoderInner::Protobuf(e))
213    }
214}
215
216#[cfg(feature = "prometheus_protobuf")]
217impl<'a> From<prometheus_protobuf::MetricEncoder<'a>> for MetricEncoder<'a> {
218    fn from(e: prometheus_protobuf::MetricEncoder<'a>) -> Self {
219        Self(MetricEncoderInner::PrometheusProtobuf(e))
220    }
221}
222
223impl MetricEncoder<'_> {
224    /// Encode a counter.
225    pub fn encode_counter<
226        S: EncodeLabelSet,
227        CounterValue: EncodeCounterValue,
228        ExemplarValue: EncodeExemplarValue,
229    >(
230        &mut self,
231        v: &CounterValue,
232        exemplar: Option<&Exemplar<S, ExemplarValue>>,
233    ) -> Result<(), std::fmt::Error> {
234        for_both_mut!(self, MetricEncoderInner, e, e.encode_counter(v, exemplar))
235    }
236
237    /// Encode a gauge.
238    pub fn encode_gauge<GaugeValue: EncodeGaugeValue>(
239        &mut self,
240        v: &GaugeValue,
241    ) -> Result<(), std::fmt::Error> {
242        for_both_mut!(self, MetricEncoderInner, e, e.encode_gauge(v))
243    }
244
245    /// Encode an info.
246    pub fn encode_info(&mut self, label_set: &impl EncodeLabelSet) -> Result<(), std::fmt::Error> {
247        for_both_mut!(self, MetricEncoderInner, e, e.encode_info(label_set))
248    }
249
250    /// Encode a histogram.
251    pub fn encode_histogram<S: EncodeLabelSet>(
252        &mut self,
253        sum: f64,
254        count: u64,
255        buckets: &[(f64, u64)],
256        exemplars: Option<&HashMap<usize, Exemplar<S, f64>>>,
257    ) -> Result<(), std::fmt::Error> {
258        for_both_mut!(
259            self,
260            MetricEncoderInner,
261            e,
262            e.encode_histogram(sum, count, buckets, exemplars)
263        )
264    }
265
266    /// Encode a histogram that may have native buckets.
267    ///
268    /// Encoders without native histogram support encode the classic buckets when
269    /// present and reject native-only histograms.
270    pub fn encode_histogram_with_native<S: EncodeLabelSet>(
271        &mut self,
272        sum: f64,
273        count: u64,
274        buckets: &[(f64, u64)],
275        exemplars: Option<&HashMap<usize, Exemplar<S, f64>>>,
276        native: NativeHistogram<'_>,
277    ) -> Result<(), std::fmt::Error> {
278        for_both_mut!(
279            self,
280            MetricEncoderInner,
281            e,
282            e.encode_histogram_with_native(sum, count, buckets, exemplars, native)
283        )
284    }
285
286    /// Encode a metric family.
287    pub fn encode_family<'s, S: EncodeLabelSet>(
288        &'s mut self,
289        label_set: &'s S,
290    ) -> Result<MetricEncoder<'s>, std::fmt::Error> {
291        for_both_mut!(
292            self,
293            MetricEncoderInner,
294            e,
295            e.encode_family(label_set).map(Into::into)
296        )
297    }
298}
299
300/// An encodable label set.
301pub trait EncodeLabelSet {
302    /// Encode oneself into the given encoder.
303    fn encode(&self, encoder: &mut LabelSetEncoder) -> Result<(), std::fmt::Error>;
304}
305
306/// Encoder for a label set.
307#[derive(Debug)]
308pub struct LabelSetEncoder<'a>(LabelSetEncoderInner<'a>);
309
310#[derive(Debug)]
311enum LabelSetEncoderInner<'a> {
312    Text(text::LabelSetEncoder<'a>),
313    #[cfg(feature = "openmetrics_protobuf")]
314    Protobuf(openmetrics_protobuf::LabelSetEncoder<'a>),
315    #[cfg(feature = "prometheus_protobuf")]
316    PrometheusProtobuf(prometheus_protobuf::LabelSetEncoder<'a>),
317}
318
319impl<'a> From<text::LabelSetEncoder<'a>> for LabelSetEncoder<'a> {
320    fn from(e: text::LabelSetEncoder<'a>) -> Self {
321        Self(LabelSetEncoderInner::Text(e))
322    }
323}
324
325#[cfg(feature = "openmetrics_protobuf")]
326impl<'a> From<openmetrics_protobuf::LabelSetEncoder<'a>> for LabelSetEncoder<'a> {
327    fn from(e: openmetrics_protobuf::LabelSetEncoder<'a>) -> Self {
328        Self(LabelSetEncoderInner::Protobuf(e))
329    }
330}
331
332#[cfg(feature = "prometheus_protobuf")]
333impl<'a> From<prometheus_protobuf::LabelSetEncoder<'a>> for LabelSetEncoder<'a> {
334    fn from(e: prometheus_protobuf::LabelSetEncoder<'a>) -> Self {
335        Self(LabelSetEncoderInner::PrometheusProtobuf(e))
336    }
337}
338
339impl LabelSetEncoder<'_> {
340    /// Encode the given label.
341    pub fn encode_label(&mut self) -> LabelEncoder<'_> {
342        for_both_mut!(self, LabelSetEncoderInner, e, e.encode_label().into())
343    }
344}
345
346impl<T: EncodeLabel, const N: usize> EncodeLabelSet for [T; N] {
347    fn encode(&self, encoder: &mut LabelSetEncoder) -> Result<(), std::fmt::Error> {
348        self.as_ref().encode(encoder)
349    }
350}
351
352impl<T: EncodeLabel> EncodeLabelSet for &[T] {
353    fn encode(&self, encoder: &mut LabelSetEncoder) -> Result<(), std::fmt::Error> {
354        if self.is_empty() {
355            return Ok(());
356        }
357
358        for label in self.iter() {
359            let encoder = encoder.encode_label();
360            label.encode(encoder)?
361        }
362
363        Ok(())
364    }
365}
366
367impl<T: EncodeLabel> EncodeLabelSet for Vec<T> {
368    fn encode(&self, encoder: &mut LabelSetEncoder) -> Result<(), std::fmt::Error> {
369        self.as_slice().encode(encoder)
370    }
371}
372
373impl<A, B> EncodeLabelSet for (A, B)
374where
375    A: EncodeLabelSet,
376    B: EncodeLabelSet,
377{
378    fn encode(&self, encoder: &mut LabelSetEncoder) -> Result<(), std::fmt::Error> {
379        let (a, b) = self;
380
381        a.encode(encoder)?;
382        b.encode(encoder)?;
383
384        Ok(())
385    }
386}
387
388/// Uninhabited type to represent the lack of a label set for a metric
389#[derive(Debug)]
390pub enum NoLabelSet {}
391
392impl EncodeLabelSet for NoLabelSet {
393    fn encode(&self, _encoder: &mut LabelSetEncoder) -> Result<(), std::fmt::Error> {
394        Ok(())
395    }
396}
397
398/// An encodable label.
399pub trait EncodeLabel {
400    /// Encode oneself into the given encoder.
401    fn encode(&self, encoder: LabelEncoder) -> Result<(), std::fmt::Error>;
402}
403
404/// Encoder for a label.
405#[derive(Debug)]
406pub struct LabelEncoder<'a>(LabelEncoderInner<'a>);
407
408#[derive(Debug)]
409enum LabelEncoderInner<'a> {
410    Text(text::LabelEncoder<'a>),
411    #[cfg(feature = "openmetrics_protobuf")]
412    Protobuf(openmetrics_protobuf::LabelEncoder<'a>),
413    #[cfg(feature = "prometheus_protobuf")]
414    PrometheusProtobuf(prometheus_protobuf::LabelEncoder<'a>),
415}
416
417impl<'a> From<text::LabelEncoder<'a>> for LabelEncoder<'a> {
418    fn from(e: text::LabelEncoder<'a>) -> Self {
419        Self(LabelEncoderInner::Text(e))
420    }
421}
422
423#[cfg(feature = "openmetrics_protobuf")]
424impl<'a> From<openmetrics_protobuf::LabelEncoder<'a>> for LabelEncoder<'a> {
425    fn from(e: openmetrics_protobuf::LabelEncoder<'a>) -> Self {
426        Self(LabelEncoderInner::Protobuf(e))
427    }
428}
429
430#[cfg(feature = "prometheus_protobuf")]
431impl<'a> From<prometheus_protobuf::LabelEncoder<'a>> for LabelEncoder<'a> {
432    fn from(e: prometheus_protobuf::LabelEncoder<'a>) -> Self {
433        Self(LabelEncoderInner::PrometheusProtobuf(e))
434    }
435}
436
437impl LabelEncoder<'_> {
438    /// Encode a label.
439    pub fn encode_label_key(&mut self) -> Result<LabelKeyEncoder<'_>, std::fmt::Error> {
440        for_both_mut!(
441            self,
442            LabelEncoderInner,
443            e,
444            e.encode_label_key().map(Into::into)
445        )
446    }
447}
448
449impl<K: EncodeLabelKey, V: EncodeLabelValue> EncodeLabel for (K, V) {
450    fn encode(&self, mut encoder: LabelEncoder) -> Result<(), std::fmt::Error> {
451        let (key, value) = self;
452
453        let mut label_key_encoder = encoder.encode_label_key()?;
454        key.encode(&mut label_key_encoder)?;
455
456        let mut label_value_encoder = label_key_encoder.encode_label_value()?;
457        value.encode(&mut label_value_encoder)?;
458        label_value_encoder.finish()?;
459
460        Ok(())
461    }
462}
463
464/// An encodable label key.
465pub trait EncodeLabelKey {
466    /// Encode oneself into the given encoder.
467    fn encode(&self, encoder: &mut LabelKeyEncoder) -> Result<(), std::fmt::Error>;
468}
469
470/// Encoder for a label key.
471#[derive(Debug)]
472pub struct LabelKeyEncoder<'a>(LabelKeyEncoderInner<'a>);
473
474#[derive(Debug)]
475enum LabelKeyEncoderInner<'a> {
476    Text(text::LabelKeyEncoder<'a>),
477    #[cfg(feature = "openmetrics_protobuf")]
478    Protobuf(openmetrics_protobuf::LabelKeyEncoder<'a>),
479    #[cfg(feature = "prometheus_protobuf")]
480    PrometheusProtobuf(prometheus_protobuf::LabelKeyEncoder<'a>),
481}
482
483impl<'a> From<text::LabelKeyEncoder<'a>> for LabelKeyEncoder<'a> {
484    fn from(e: text::LabelKeyEncoder<'a>) -> Self {
485        Self(LabelKeyEncoderInner::Text(e))
486    }
487}
488
489#[cfg(feature = "openmetrics_protobuf")]
490impl<'a> From<openmetrics_protobuf::LabelKeyEncoder<'a>> for LabelKeyEncoder<'a> {
491    fn from(e: openmetrics_protobuf::LabelKeyEncoder<'a>) -> Self {
492        Self(LabelKeyEncoderInner::Protobuf(e))
493    }
494}
495
496#[cfg(feature = "prometheus_protobuf")]
497impl<'a> From<prometheus_protobuf::LabelKeyEncoder<'a>> for LabelKeyEncoder<'a> {
498    fn from(e: prometheus_protobuf::LabelKeyEncoder<'a>) -> Self {
499        Self(LabelKeyEncoderInner::PrometheusProtobuf(e))
500    }
501}
502
503impl std::fmt::Write for LabelKeyEncoder<'_> {
504    fn write_str(&mut self, s: &str) -> std::fmt::Result {
505        for_both_mut!(self, LabelKeyEncoderInner, e, e.write_str(s))
506    }
507}
508
509impl<'a> LabelKeyEncoder<'a> {
510    /// Encode a label value.
511    pub fn encode_label_value(self) -> Result<LabelValueEncoder<'a>, std::fmt::Error> {
512        for_both!(
513            self,
514            LabelKeyEncoderInner,
515            e,
516            e.encode_label_value().map(LabelValueEncoder::from)
517        )
518    }
519}
520
521impl EncodeLabelKey for &str {
522    fn encode(&self, encoder: &mut LabelKeyEncoder) -> Result<(), std::fmt::Error> {
523        encoder.write_str(self)?;
524        Ok(())
525    }
526}
527
528impl EncodeLabelKey for String {
529    fn encode(&self, encoder: &mut LabelKeyEncoder) -> Result<(), std::fmt::Error> {
530        EncodeLabelKey::encode(&self.as_str(), encoder)
531    }
532}
533
534impl EncodeLabelKey for Cow<'_, str> {
535    fn encode(&self, encoder: &mut LabelKeyEncoder) -> Result<(), std::fmt::Error> {
536        EncodeLabelKey::encode(&self.as_ref(), encoder)
537    }
538}
539
540impl<T> EncodeLabelKey for Box<T>
541where
542    T: ?Sized,
543    for<'a> &'a T: EncodeLabelKey,
544{
545    fn encode(&self, encoder: &mut LabelKeyEncoder) -> Result<(), std::fmt::Error> {
546        EncodeLabelKey::encode(&self.as_ref(), encoder)
547    }
548}
549
550impl<T> EncodeLabelKey for Arc<T>
551where
552    T: ?Sized,
553    for<'a> &'a T: EncodeLabelKey,
554{
555    fn encode(&self, encoder: &mut LabelKeyEncoder) -> Result<(), std::fmt::Error> {
556        EncodeLabelKey::encode(&self.as_ref(), encoder)
557    }
558}
559
560impl<T> EncodeLabelKey for Rc<T>
561where
562    T: ?Sized,
563    for<'a> &'a T: EncodeLabelKey,
564{
565    fn encode(&self, encoder: &mut LabelKeyEncoder) -> Result<(), std::fmt::Error> {
566        EncodeLabelKey::encode(&self.as_ref(), encoder)
567    }
568}
569
570/// An encodable label value.
571pub trait EncodeLabelValue {
572    /// Encode oneself into the given encoder.
573    fn encode(&self, encoder: &mut LabelValueEncoder) -> Result<(), std::fmt::Error>;
574}
575
576/// Encoder for a label value.
577#[derive(Debug)]
578pub struct LabelValueEncoder<'a>(LabelValueEncoderInner<'a>);
579
580#[derive(Debug)]
581enum LabelValueEncoderInner<'a> {
582    Text(text::LabelValueEncoder<'a>),
583    #[cfg(feature = "openmetrics_protobuf")]
584    Protobuf(openmetrics_protobuf::LabelValueEncoder<'a>),
585    #[cfg(feature = "prometheus_protobuf")]
586    PrometheusProtobuf(prometheus_protobuf::LabelValueEncoder<'a>),
587}
588
589impl<'a> From<text::LabelValueEncoder<'a>> for LabelValueEncoder<'a> {
590    fn from(e: text::LabelValueEncoder<'a>) -> Self {
591        LabelValueEncoder(LabelValueEncoderInner::Text(e))
592    }
593}
594
595#[cfg(feature = "openmetrics_protobuf")]
596impl<'a> From<openmetrics_protobuf::LabelValueEncoder<'a>> for LabelValueEncoder<'a> {
597    fn from(e: openmetrics_protobuf::LabelValueEncoder<'a>) -> Self {
598        LabelValueEncoder(LabelValueEncoderInner::Protobuf(e))
599    }
600}
601
602#[cfg(feature = "prometheus_protobuf")]
603impl<'a> From<prometheus_protobuf::LabelValueEncoder<'a>> for LabelValueEncoder<'a> {
604    fn from(e: prometheus_protobuf::LabelValueEncoder<'a>) -> Self {
605        LabelValueEncoder(LabelValueEncoderInner::PrometheusProtobuf(e))
606    }
607}
608
609impl std::fmt::Write for LabelValueEncoder<'_> {
610    fn write_str(&mut self, s: &str) -> std::fmt::Result {
611        for_both_mut!(self, LabelValueEncoderInner, e, e.write_str(s))
612    }
613}
614
615impl LabelValueEncoder<'_> {
616    pub(crate) fn write_str_unescaped(&mut self, s: &str) -> Result<(), std::fmt::Error> {
617        for_both_mut!(self, LabelValueEncoderInner, e, e.write_str_unescaped(s))
618    }
619
620    /// Finish encoding the label value.
621    pub fn finish(self) -> Result<(), std::fmt::Error> {
622        for_both!(self, LabelValueEncoderInner, e, e.finish())
623    }
624}
625
626impl EncodeLabelValue for &str {
627    fn encode(&self, encoder: &mut LabelValueEncoder) -> Result<(), std::fmt::Error> {
628        encoder.write_str(self)?;
629        Ok(())
630    }
631}
632
633impl EncodeLabelValue for String {
634    fn encode(&self, encoder: &mut LabelValueEncoder) -> Result<(), std::fmt::Error> {
635        EncodeLabelValue::encode(&self.as_str(), encoder)
636    }
637}
638
639impl EncodeLabelValue for &String {
640    fn encode(&self, encoder: &mut LabelValueEncoder) -> Result<(), std::fmt::Error> {
641        EncodeLabelValue::encode(&self.as_str(), encoder)
642    }
643}
644
645impl EncodeLabelValue for Cow<'_, str> {
646    fn encode(&self, encoder: &mut LabelValueEncoder) -> Result<(), std::fmt::Error> {
647        EncodeLabelValue::encode(&self.as_ref(), encoder)
648    }
649}
650
651impl<T> EncodeLabelValue for Box<T>
652where
653    T: ?Sized,
654    for<'a> &'a T: EncodeLabelValue,
655{
656    fn encode(&self, encoder: &mut LabelValueEncoder) -> Result<(), std::fmt::Error> {
657        EncodeLabelValue::encode(&self.as_ref(), encoder)
658    }
659}
660
661impl<T> EncodeLabelValue for Arc<T>
662where
663    T: ?Sized,
664    for<'a> &'a T: EncodeLabelValue,
665{
666    fn encode(&self, encoder: &mut LabelValueEncoder) -> Result<(), std::fmt::Error> {
667        EncodeLabelValue::encode(&self.as_ref(), encoder)
668    }
669}
670
671impl<T> EncodeLabelValue for Rc<T>
672where
673    T: ?Sized,
674    for<'a> &'a T: EncodeLabelValue,
675{
676    fn encode(&self, encoder: &mut LabelValueEncoder) -> Result<(), std::fmt::Error> {
677        EncodeLabelValue::encode(&self.as_ref(), encoder)
678    }
679}
680
681impl EncodeLabelValue for f64 {
682    fn encode(&self, encoder: &mut LabelValueEncoder) -> Result<(), std::fmt::Error> {
683        encoder.write_str_unescaped(dtoa::Buffer::new().format(*self))
684    }
685}
686
687impl<T> EncodeLabelValue for Option<T>
688where
689    T: EncodeLabelValue,
690{
691    fn encode(&self, encoder: &mut LabelValueEncoder) -> Result<(), std::fmt::Error> {
692        match self {
693            Some(v) => EncodeLabelValue::encode(v, encoder),
694            None => EncodeLabelValue::encode(&"", encoder),
695        }
696    }
697}
698
699impl EncodeLabelValue for bool {
700    fn encode(&self, encoder: &mut LabelValueEncoder) -> Result<(), std::fmt::Error> {
701        encoder.write_str_unescaped(if *self { "true" } else { "false" })
702    }
703}
704
705macro_rules! impl_encode_label_value_for_integer {
706    ($($t:ident),*) => {$(
707        impl EncodeLabelValue for $t {
708            fn encode(&self, encoder: &mut LabelValueEncoder) -> Result<(), std::fmt::Error> {
709                encoder.write_str_unescaped(itoa::Buffer::new().format(*self))
710            }
711        }
712    )*};
713}
714
715impl_encode_label_value_for_integer!(
716    u128, i128, u64, i64, u32, i32, u16, i16, u8, i8, usize, isize
717);
718
719/// An encodable gauge value.
720pub trait EncodeGaugeValue {
721    /// Encode the given instance in the OpenMetrics text encoding.
722    fn encode(&self, encoder: &mut GaugeValueEncoder) -> Result<(), std::fmt::Error>;
723}
724
725impl EncodeGaugeValue for u32 {
726    fn encode(&self, encoder: &mut GaugeValueEncoder) -> Result<(), std::fmt::Error> {
727        encoder.encode_u32(*self)
728    }
729}
730
731impl EncodeGaugeValue for i64 {
732    fn encode(&self, encoder: &mut GaugeValueEncoder) -> Result<(), std::fmt::Error> {
733        encoder.encode_i64(*self)
734    }
735}
736
737impl EncodeGaugeValue for u64 {
738    fn encode(&self, encoder: &mut GaugeValueEncoder) -> Result<(), std::fmt::Error> {
739        encoder.encode_u64(*self)
740    }
741}
742
743impl EncodeGaugeValue for isize {
744    fn encode(&self, encoder: &mut GaugeValueEncoder) -> Result<(), std::fmt::Error> {
745        // Is infallible for 32-bit or 64-bit platforms
746        encoder.encode_i64(i64::try_from(*self).map_err(|_err| std::fmt::Error)?)
747    }
748}
749
750impl EncodeGaugeValue for usize {
751    fn encode(&self, encoder: &mut GaugeValueEncoder) -> Result<(), std::fmt::Error> {
752        // For 32-bit platforms this is infallible, for 64-bit platforms the argument is the same
753        // as the one for u64 values
754        encoder.encode_i64(i64::try_from(*self).map_err(|_err| std::fmt::Error)?)
755    }
756}
757
758impl EncodeGaugeValue for f64 {
759    fn encode(&self, encoder: &mut GaugeValueEncoder) -> Result<(), std::fmt::Error> {
760        encoder.encode_f64(*self)
761    }
762}
763
764impl EncodeGaugeValue for i32 {
765    fn encode(&self, encoder: &mut GaugeValueEncoder) -> Result<(), std::fmt::Error> {
766        encoder.encode_i64(i64::from(*self))
767    }
768}
769
770impl EncodeGaugeValue for f32 {
771    fn encode(&self, encoder: &mut GaugeValueEncoder) -> Result<(), std::fmt::Error> {
772        encoder.encode_f64(f64::from(*self))
773    }
774}
775
776/// Encoder for a gauge value.
777#[derive(Debug)]
778pub struct GaugeValueEncoder<'a>(GaugeValueEncoderInner<'a>);
779
780#[derive(Debug)]
781enum GaugeValueEncoderInner<'a> {
782    Text(text::GaugeValueEncoder<'a>),
783    #[cfg(feature = "openmetrics_protobuf")]
784    Protobuf(openmetrics_protobuf::GaugeValueEncoder<'a>),
785    #[cfg(feature = "prometheus_protobuf")]
786    PrometheusProtobuf(prometheus_protobuf::GaugeValueEncoder<'a>),
787}
788
789impl GaugeValueEncoder<'_> {
790    fn encode_u32(&mut self, v: u32) -> Result<(), std::fmt::Error> {
791        for_both_mut!(self, GaugeValueEncoderInner, e, e.encode_u32(v))
792    }
793
794    fn encode_u64(&mut self, v: u64) -> Result<(), std::fmt::Error> {
795        for_both_mut!(self, GaugeValueEncoderInner, e, e.encode_u64(v))
796    }
797
798    fn encode_i64(&mut self, v: i64) -> Result<(), std::fmt::Error> {
799        for_both_mut!(self, GaugeValueEncoderInner, e, e.encode_i64(v))
800    }
801
802    fn encode_f64(&mut self, v: f64) -> Result<(), std::fmt::Error> {
803        for_both_mut!(self, GaugeValueEncoderInner, e, e.encode_f64(v))
804    }
805}
806
807impl<'a> From<text::GaugeValueEncoder<'a>> for GaugeValueEncoder<'a> {
808    fn from(e: text::GaugeValueEncoder<'a>) -> Self {
809        GaugeValueEncoder(GaugeValueEncoderInner::Text(e))
810    }
811}
812
813#[cfg(feature = "openmetrics_protobuf")]
814impl<'a> From<openmetrics_protobuf::GaugeValueEncoder<'a>> for GaugeValueEncoder<'a> {
815    fn from(e: openmetrics_protobuf::GaugeValueEncoder<'a>) -> Self {
816        GaugeValueEncoder(GaugeValueEncoderInner::Protobuf(e))
817    }
818}
819
820#[cfg(feature = "prometheus_protobuf")]
821impl<'a> From<prometheus_protobuf::GaugeValueEncoder<'a>> for GaugeValueEncoder<'a> {
822    fn from(e: prometheus_protobuf::GaugeValueEncoder<'a>) -> Self {
823        GaugeValueEncoder(GaugeValueEncoderInner::PrometheusProtobuf(e))
824    }
825}
826
827/// An encodable counter value.
828pub trait EncodeCounterValue {
829    /// Encode the given instance in the OpenMetrics text encoding.
830    fn encode(&self, encoder: &mut CounterValueEncoder) -> Result<(), std::fmt::Error>;
831}
832
833impl EncodeCounterValue for u64 {
834    fn encode(&self, encoder: &mut CounterValueEncoder) -> Result<(), std::fmt::Error> {
835        encoder.encode_u64(*self)
836    }
837}
838
839impl EncodeCounterValue for usize {
840    fn encode(&self, encoder: &mut CounterValueEncoder) -> Result<(), std::fmt::Error> {
841        // Is infallible for 32-bit and 64-bit platforms
842        encoder.encode_u64(u64::try_from(*self).map_err(|_err| std::fmt::Error)?)
843    }
844}
845
846impl EncodeCounterValue for f64 {
847    fn encode(&self, encoder: &mut CounterValueEncoder) -> Result<(), std::fmt::Error> {
848        encoder.encode_f64(*self)
849    }
850}
851
852impl EncodeCounterValue for u32 {
853    fn encode(&self, encoder: &mut CounterValueEncoder) -> Result<(), std::fmt::Error> {
854        encoder.encode_u64(u64::from(*self))
855    }
856}
857
858impl EncodeCounterValue for f32 {
859    fn encode(&self, encoder: &mut CounterValueEncoder) -> Result<(), std::fmt::Error> {
860        encoder.encode_f64(f64::from(*self))
861    }
862}
863
864/// Encoder for a counter value.
865#[derive(Debug)]
866pub struct CounterValueEncoder<'a>(CounterValueEncoderInner<'a>);
867
868#[derive(Debug)]
869enum CounterValueEncoderInner<'a> {
870    Text(text::CounterValueEncoder<'a>),
871    #[cfg(feature = "openmetrics_protobuf")]
872    Protobuf(openmetrics_protobuf::CounterValueEncoder<'a>),
873    #[cfg(feature = "prometheus_protobuf")]
874    PrometheusProtobuf(prometheus_protobuf::CounterValueEncoder<'a>),
875}
876
877impl<'a> From<text::CounterValueEncoder<'a>> for CounterValueEncoder<'a> {
878    fn from(e: text::CounterValueEncoder<'a>) -> Self {
879        CounterValueEncoder(CounterValueEncoderInner::Text(e))
880    }
881}
882
883#[cfg(feature = "openmetrics_protobuf")]
884impl<'a> From<openmetrics_protobuf::CounterValueEncoder<'a>> for CounterValueEncoder<'a> {
885    fn from(e: openmetrics_protobuf::CounterValueEncoder<'a>) -> Self {
886        CounterValueEncoder(CounterValueEncoderInner::Protobuf(e))
887    }
888}
889
890#[cfg(feature = "prometheus_protobuf")]
891impl<'a> From<prometheus_protobuf::CounterValueEncoder<'a>> for CounterValueEncoder<'a> {
892    fn from(e: prometheus_protobuf::CounterValueEncoder<'a>) -> Self {
893        CounterValueEncoder(CounterValueEncoderInner::PrometheusProtobuf(e))
894    }
895}
896
897impl CounterValueEncoder<'_> {
898    fn encode_f64(&mut self, v: f64) -> Result<(), std::fmt::Error> {
899        for_both_mut!(self, CounterValueEncoderInner, e, e.encode_f64(v))
900    }
901
902    fn encode_u64(&mut self, v: u64) -> Result<(), std::fmt::Error> {
903        for_both_mut!(self, CounterValueEncoderInner, e, e.encode_u64(v))
904    }
905}
906
907/// An encodable exemplar value.
908pub trait EncodeExemplarValue {
909    /// Encode the given instance in the OpenMetrics text encoding.
910    fn encode(&self, encoder: ExemplarValueEncoder) -> Result<(), std::fmt::Error>;
911}
912
913impl EncodeExemplarValue for f64 {
914    fn encode(&self, mut encoder: ExemplarValueEncoder) -> Result<(), std::fmt::Error> {
915        encoder.encode(*self)
916    }
917}
918
919impl EncodeExemplarValue for u64 {
920    fn encode(&self, mut encoder: ExemplarValueEncoder) -> Result<(), std::fmt::Error> {
921        encoder.encode(*self as f64)
922    }
923}
924
925impl EncodeExemplarValue for f32 {
926    fn encode(&self, mut encoder: ExemplarValueEncoder) -> Result<(), std::fmt::Error> {
927        encoder.encode(f64::from(*self))
928    }
929}
930
931impl EncodeExemplarValue for u32 {
932    fn encode(&self, mut encoder: ExemplarValueEncoder) -> Result<(), std::fmt::Error> {
933        encoder.encode(f64::from(*self))
934    }
935}
936
937/// An encodable exemplar time.
938pub trait EncodeExemplarTime {
939    /// Encode the time in the OpenMetrics text encoding.
940    fn encode(&self, encoder: ExemplarValueEncoder) -> Result<(), std::fmt::Error>;
941}
942
943impl EncodeExemplarTime for SystemTime {
944    fn encode(&self, mut encoder: ExemplarValueEncoder) -> Result<(), std::fmt::Error> {
945        encoder.encode(self.duration_since(UNIX_EPOCH).unwrap().as_secs_f64())
946    }
947}
948
949/// Encoder for an exemplar value.
950#[derive(Debug)]
951pub struct ExemplarValueEncoder<'a>(ExemplarValueEncoderInner<'a>);
952
953#[derive(Debug)]
954enum ExemplarValueEncoderInner<'a> {
955    Text(text::ExemplarValueEncoder<'a>),
956    #[cfg(feature = "openmetrics_protobuf")]
957    Protobuf(openmetrics_protobuf::ExemplarValueEncoder<'a>),
958    #[cfg(feature = "prometheus_protobuf")]
959    PrometheusProtobuf(prometheus_protobuf::ExemplarValueEncoder<'a>),
960}
961
962impl<'a> From<text::ExemplarValueEncoder<'a>> for ExemplarValueEncoder<'a> {
963    fn from(e: text::ExemplarValueEncoder<'a>) -> Self {
964        ExemplarValueEncoder(ExemplarValueEncoderInner::Text(e))
965    }
966}
967
968#[cfg(feature = "openmetrics_protobuf")]
969impl<'a> From<openmetrics_protobuf::ExemplarValueEncoder<'a>> for ExemplarValueEncoder<'a> {
970    fn from(e: openmetrics_protobuf::ExemplarValueEncoder<'a>) -> Self {
971        ExemplarValueEncoder(ExemplarValueEncoderInner::Protobuf(e))
972    }
973}
974
975#[cfg(feature = "prometheus_protobuf")]
976impl<'a> From<prometheus_protobuf::ExemplarValueEncoder<'a>> for ExemplarValueEncoder<'a> {
977    fn from(e: prometheus_protobuf::ExemplarValueEncoder<'a>) -> Self {
978        ExemplarValueEncoder(ExemplarValueEncoderInner::PrometheusProtobuf(e))
979    }
980}
981
982impl ExemplarValueEncoder<'_> {
983    fn encode(&mut self, v: f64) -> Result<(), std::fmt::Error> {
984        for_both_mut!(self, ExemplarValueEncoderInner, e, e.encode(v))
985    }
986}