fuchsia_inspect_contrib/
id_enum.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Provides trait and functions to log mapping from IDs of an enum to its variants
6//! or mapped variant values.
7//!
8//! ## Example
9//!
10//! ```rust
11//! use diagnostics_assertions::assert_data_tree;
12//! use fuchsia_inspect::Inspector;
13//! use strum_macros::{Display, EnumIter};
14//!
15//! #[derive(Display, EnumIter)]
16//! enum Enum {
17//!     A,
18//!     B,
19//! }
20//!
21//! impl IdEnum for Enum {
22//!     type Id = u8;
23//!     fn to_id(&self) -> Self::Id {
24//!         match self {
25//!             Self::A => 0,
26//!             Self::B => 1,
27//!         }
28//!     }
29//! }
30//!
31//! let inspector = Inspector::default();
32//! inspect_record_id_enum::<Enum>(inspector.root(), "enum");
33//! assert_data_tree!(inspector, root: {
34//!     "enum": {
35//!         "0": "A",
36//!         "1": "B",
37//!     }
38//! });
39//!
40//! inspect_record_id_enum_mapped::<Enum, _>(inspector.root(), "highlight", |variant| {
41//!     match variant {
42//!         Enum::A => None,
43//!         Enum::B => Some(2u8),
44//!     }
45//! });
46//! assert_data_tree!(inspector, root: contains {
47//!     "highlight": {
48//!         "1": 2u64,
49//!     }
50//! });
51//! ```
52
53use fuchsia_inspect::Node as InspectNode;
54use std::fmt::Display;
55use strum;
56
57use crate::log::WriteInspect;
58
59pub trait IdEnum {
60    type Id: Into<u64>;
61    fn to_id(&self) -> Self::Id;
62}
63
64/// Record the mapping of `IdEnum`'s ids to variants in Inspect.
65pub fn inspect_record_id_enum<R>(node: &InspectNode, name: &str)
66where
67    R: IdEnum + strum::IntoEnumIterator + Display,
68{
69    let enum_node = node.create_child(name);
70    for variant in R::iter() {
71        enum_node.record_string(variant.to_id().into().to_string(), format!("{variant}"));
72    }
73    node.record(enum_node);
74}
75
76/// Record the mapping of `IdEnum`'s ids to mapped variant values.
77/// Only variants with mapped `Some` values are recorded.
78pub fn inspect_record_id_enum_mapped<R, V>(
79    node: &InspectNode,
80    name: &str,
81    map_fn: impl Fn(&R) -> Option<V>,
82) where
83    R: IdEnum + strum::IntoEnumIterator,
84    V: WriteInspect,
85{
86    let enum_node = node.create_child(name);
87    for variant in R::iter() {
88        let value = map_fn(&variant);
89        if let Some(value) = value {
90            let key = variant.to_id().into().to_string();
91            value.write_inspect(&enum_node, key);
92        }
93    }
94    node.record(enum_node);
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100    use diagnostics_assertions::assert_data_tree;
101    use fuchsia_inspect::Inspector;
102    use strum_macros::{Display, EnumIter};
103
104    #[derive(Display, EnumIter)]
105    enum Enum {
106        A,
107        B,
108    }
109
110    impl IdEnum for Enum {
111        type Id = u8;
112        fn to_id(&self) -> Self::Id {
113            match self {
114                Self::A => 0,
115                Self::B => 1,
116            }
117        }
118    }
119
120    #[test]
121    fn test_inspect_record_id_enum() {
122        let inspector = Inspector::default();
123        inspect_record_id_enum::<Enum>(inspector.root(), "enum");
124        assert_data_tree!(inspector, root: {
125            "enum": {
126                "0": "A",
127                "1": "B",
128            }
129        });
130    }
131
132    #[test]
133    fn test_inspect_record_id_enum_mapped() {
134        let inspector = Inspector::default();
135        inspect_record_id_enum_mapped::<Enum, _>(inspector.root(), "highlight", |variant| {
136            match variant {
137                Enum::A => None,
138                Enum::B => Some(2u8),
139            }
140        });
141        assert_data_tree!(inspector, root: {
142            "highlight": {
143                "1": 2u64,
144            },
145        });
146    }
147}