Skip to main content

iroh_metrics/
iterable.rs

1//! Traits for iterating over the fields of structs.
2
3use std::fmt;
4
5/// Derives [`Iterable`] for a struct.
6///
7/// You can use this derive instead of [`MetricsGroup`] if you want to implement `Default`
8/// and `MetricsGroup` manually, but still use a derived `Iterable` impl.
9///
10/// [`Iterable`]: ::iroh_metrics::iterable::Iterable
11/// [`MetricsGroup`]: ::iroh_metrics::MetricsGroup
12pub use iroh_metrics_derive::Iterable;
13
14use crate::{FamilyItem, MetricItem};
15
16/// Trait for iterating over the fields of a struct.
17pub trait Iterable {
18    /// Returns the number of metric fields in the struct.
19    fn metric_field_count(&self) -> usize;
20    /// Returns the metric field at the given index.
21    fn metric_field_ref(&self, n: usize) -> Option<MetricItem<'_>>;
22    /// Returns the number of [`Family`](crate::Family) fields in the struct.
23    fn family_field_count(&self) -> usize {
24        0
25    }
26    /// Returns the [`Family`](crate::Family) field at the given index.
27    fn family_field_ref(&self, _n: usize) -> Option<FamilyItem<'_>> {
28        None
29    }
30}
31
32/// Helper trait to convert from `self` to `dyn Iterable`.
33pub trait IntoIterable {
34    /// Returns `self` as `dyn Iterable`
35    fn as_iterable(&self) -> &dyn Iterable;
36
37    /// Returns an iterator over the metric fields of the struct.
38    fn field_iter(&self) -> FieldIter<'_> {
39        FieldIter::new(self.as_iterable())
40    }
41
42    /// Returns an iterator over the Family fields of the struct.
43    fn family_iter(&self) -> FamilyIter<'_> {
44        FamilyIter::new(self.as_iterable())
45    }
46}
47
48impl<T> IntoIterable for T
49where
50    T: Iterable,
51{
52    fn as_iterable(&self) -> &dyn Iterable {
53        self
54    }
55}
56
57/// Iterator over the fields of a struct.
58///
59/// Returned from [`IntoIterable::field_iter`].
60pub struct FieldIter<'a> {
61    pos: usize,
62    inner: &'a dyn Iterable,
63}
64
65impl fmt::Debug for FieldIter<'_> {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        write!(f, "FieldIter")
68    }
69}
70
71impl<'a> FieldIter<'a> {
72    pub(crate) fn new(inner: &'a dyn Iterable) -> Self {
73        Self { pos: 0, inner }
74    }
75}
76impl<'a> Iterator for FieldIter<'a> {
77    type Item = MetricItem<'a>;
78
79    fn next(&mut self) -> Option<Self::Item> {
80        if self.pos == self.inner.metric_field_count() {
81            None
82        } else {
83            let out = self.inner.metric_field_ref(self.pos);
84            self.pos += 1;
85            out
86        }
87    }
88
89    fn size_hint(&self) -> (usize, Option<usize>) {
90        let n = self.inner.metric_field_count() - self.pos;
91        (n, Some(n))
92    }
93}
94
95/// Iterator over Family fields of a struct.
96pub struct FamilyIter<'a> {
97    pos: usize,
98    inner: &'a dyn Iterable,
99}
100
101impl fmt::Debug for FamilyIter<'_> {
102    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103        write!(f, "FamilyIter")
104    }
105}
106
107impl<'a> FamilyIter<'a> {
108    pub(crate) fn new(inner: &'a dyn Iterable) -> Self {
109        Self { pos: 0, inner }
110    }
111}
112
113impl<'a> Iterator for FamilyIter<'a> {
114    type Item = FamilyItem<'a>;
115
116    fn next(&mut self) -> Option<Self::Item> {
117        if self.pos == self.inner.family_field_count() {
118            None
119        } else {
120            let out = self.inner.family_field_ref(self.pos);
121            self.pos += 1;
122            out
123        }
124    }
125
126    fn size_hint(&self) -> (usize, Option<usize>) {
127        let n = self.inner.family_field_count() - self.pos;
128        (n, Some(n))
129    }
130}