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::MetricItem;
15
16/// Trait for iterating over the fields of a struct.
17pub trait Iterable {
18    /// Returns the number of fields in the struct.
19    fn field_count(&self) -> usize;
20    /// Returns the field name and dyn reference to the field.
21    fn field_ref(&self, n: usize) -> Option<MetricItem<'_>>;
22}
23
24/// Helper trait to convert from `self` to `dyn Iterable`.
25pub trait IntoIterable {
26    /// Returns `self` as `dyn Iterable`
27    fn as_iterable(&self) -> &dyn Iterable;
28
29    /// Returns an iterator over the fields of the struct.
30    fn field_iter(&self) -> FieldIter<'_> {
31        FieldIter::new(self.as_iterable())
32    }
33}
34
35impl<T> IntoIterable for T
36where
37    T: Iterable,
38{
39    fn as_iterable(&self) -> &dyn Iterable {
40        self
41    }
42}
43
44/// Iterator over the fields of a struct.
45///
46/// Returned from [`IntoIterable::field_iter`].
47pub struct FieldIter<'a> {
48    pos: usize,
49    inner: &'a dyn Iterable,
50}
51
52impl fmt::Debug for FieldIter<'_> {
53    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54        write!(f, "FieldIter")
55    }
56}
57
58impl<'a> FieldIter<'a> {
59    pub(crate) fn new(inner: &'a dyn Iterable) -> Self {
60        Self { pos: 0, inner }
61    }
62}
63impl<'a> Iterator for FieldIter<'a> {
64    type Item = MetricItem<'a>;
65
66    fn next(&mut self) -> Option<Self::Item> {
67        if self.pos == self.inner.field_count() {
68            None
69        } else {
70            let out = self.inner.field_ref(self.pos);
71            self.pos += 1;
72            out
73        }
74    }
75
76    fn size_hint(&self) -> (usize, Option<usize>) {
77        let n = self.inner.field_count() - self.pos;
78        (n, Some(n))
79    }
80}