fuchsia_inspect_contrib/nodes/
lru_cache.rs1use fuchsia_inspect::Node;
6use fuchsia_inspect_derive::Unit;
7use lru_cache::LruCache;
8use std::hash::Hash;
9
10use crate::nodes::NodeTimeExt;
11
12pub struct LruCacheNode<T: Unit + Eq + Hash> {
15 node: Node,
16 items: LruCache<T, CacheItem<T>>,
17}
18
19impl<T: Unit + Eq + Hash> LruCacheNode<T> {
20 pub fn new(node: Node, capacity: usize) -> Self {
21 Self { node, items: LruCache::new(capacity) }
22 }
23
24 pub fn insert(&mut self, item: T) -> usize {
32 match self.items.get_mut(&item) {
33 Some(entry) => entry.index,
34 None => {
35 let index = if self.items.len() < self.items.capacity() {
36 self.items.len()
37 } else {
38 self.items.remove_lru().map(|entry| entry.1.index).unwrap_or(0)
39 };
40 let child = self.node.create_child(index.to_string());
41 NodeTimeExt::<zx::BootTimeline>::record_time(&child, "@time");
42 let data = item.inspect_create(&child, "data");
43 self.items.insert(item, CacheItem { index, _node: child, _data: data });
44 index
45 }
46 }
47 }
48}
49struct CacheItem<T: Unit> {
50 index: usize,
51 _node: Node,
52 _data: <T as Unit>::Data,
53}
54
55#[cfg(test)]
56mod tests {
57 use super::*;
58 use diagnostics_assertions::{assert_data_tree, AnyNumericProperty};
59 use fuchsia_inspect::Inspector;
60
61 #[fuchsia::test]
62 fn test_insert() {
63 let inspector = Inspector::default();
64 let cache_node = inspector.root().create_child("cache");
65 let mut cache_node = LruCacheNode::new(cache_node, 3);
66 assert_eq!(cache_node.insert(111), 0);
68 assert_eq!(cache_node.insert(222), 1);
69 assert_eq!(cache_node.insert(333), 2);
70 assert_data_tree!(inspector, root: {
71 cache: {
72 "0": { "@time": AnyNumericProperty, "data": 111i64},
73 "1": { "@time": AnyNumericProperty, "data": 222i64},
74 "2": { "@time": AnyNumericProperty, "data": 333i64},
75 }
76 });
77
78 assert_eq!(cache_node.insert(222), 1);
80 assert_eq!(cache_node.insert(111), 0);
81 assert_eq!(cache_node.insert(333), 2);
82 assert_data_tree!(inspector, root: {
83 cache: {
84 "0": { "@time": AnyNumericProperty, "data": 111i64},
85 "1": { "@time": AnyNumericProperty, "data": 222i64},
86 "2": { "@time": AnyNumericProperty, "data": 333i64},
87 }
88 });
89
90 assert_eq!(cache_node.insert(444), 1);
92 assert_data_tree!(inspector, root: {
93 cache: {
94 "0": { "@time": AnyNumericProperty, "data": 111i64},
95 "1": { "@time": AnyNumericProperty, "data": 444i64},
96 "2": { "@time": AnyNumericProperty, "data": 333i64},
97 }
98 });
99
100 assert_eq!(cache_node.insert(222), 0);
102 assert_data_tree!(inspector, root: {
103 cache: {
104 "0": { "@time": AnyNumericProperty, "data": 222i64},
105 "1": { "@time": AnyNumericProperty, "data": 444i64},
106 "2": { "@time": AnyNumericProperty, "data": 333i64},
107 }
108 });
109 }
110
111 #[derive(PartialEq, Eq, Hash, Unit)]
112 struct Item {
113 num: u64,
114 string: String,
115 }
116
117 #[fuchsia::test]
118 fn test_insert_custom_struct() {
119 let inspector = Inspector::default();
120 let cache_node = inspector.root().create_child("cache");
121 let mut cache_node = LruCacheNode::new(cache_node, 3);
122 assert_eq!(cache_node.insert(Item { num: 1337u64, string: "42".to_string() }), 0);
123 assert_eq!(cache_node.insert(Item { num: 1337u64, string: "43".to_string() }), 1);
124 assert_data_tree!(inspector, root: {
125 cache: {
126 "0": {
127 "@time": AnyNumericProperty,
128 "data": { num: 1337u64, string: "42".to_string() }
129 },
130 "1": {
131 "@time": AnyNumericProperty,
132 "data": { num: 1337u64, string: "43".to_string() }
133 },
134 }
135 });
136 }
137}