Skip to main content

fuchsia_inspect/writer/types/
value_list.rs

1// Copyright 2021 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
5use super::*;
6use derivative::Derivative;
7use fuchsia_sync::Mutex;
8
9/// An enum representing any standard Inspect type that can be recorded in a `ValueList`.
10///
11/// Types that are 16 bytes or less are stored directly in the enum. Types that are larger than
12/// 16 bytes must be boxed in a `Boxed` variant.
13#[derive(Debug)]
14pub enum RecordedInspectType {
15    Node(Node),
16    BoolProperty(BoolProperty),
17    BytesProperty(BytesProperty),
18    DoubleProperty(DoubleProperty),
19    IntProperty(IntProperty),
20    StringProperty(StringProperty),
21    UintProperty(UintProperty),
22    DoubleArray(DoubleArrayProperty),
23    IntArray(IntArrayProperty),
24    StringArray(StringArrayProperty),
25    UintArray(UintArrayProperty),
26    LazyNode(LazyNode),
27    Boxed(Box<dyn InspectType>),
28}
29
30// Ensure that we don't inadvertently increase the size of RecordedInspectType by adding a new
31// variant with an unboxed payload larger than 16 bytes.
32const _RECORDED_INSPECT_TYPE_SIZE_ASSERTION: () = assert!(
33    std::mem::size_of::<RecordedInspectType>() == 24,
34    "RecordedInspectType size changed! Expected 24 bytes (1 byte tag + 7 bytes padding + \
35     16 bytes max unboxed payload)."
36);
37
38type InspectTypeList = Vec<RecordedInspectType>;
39
40/// Holds a list of inspect types that won't change.
41#[derive(Derivative)]
42#[derivative(Debug, PartialEq)]
43pub struct ValueList {
44    #[derivative(PartialEq = "ignore")]
45    #[derivative(Debug = "ignore")]
46    values: Mutex<Option<InspectTypeList>>,
47}
48
49impl Default for ValueList {
50    fn default() -> Self {
51        ValueList::new()
52    }
53}
54
55impl ValueList {
56    /// Creates a new empty value list.
57    pub fn new() -> Self {
58        Self { values: Mutex::new(None) }
59    }
60
61    /// Stores an inspect type that won't change.
62    pub fn record(&self, value: impl InspectType + 'static) {
63        let converted_value = value.into_recorded();
64        let mut values_lock = self.values.lock();
65        if let Some(ref mut values) = *values_lock {
66            values.push(converted_value);
67        } else {
68            *values_lock = Some(vec![converted_value]);
69        }
70    }
71
72    /// Clears all values from ValueList, rendering it empty.
73    /// `InspectType` values contained will be dropped.
74    pub fn clear(&self) {
75        let mut values_lock = self.values.lock();
76        *values_lock = None;
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83    use crate::writer::types::Inspector;
84    use diagnostics_assertions::assert_json_diff;
85
86    #[fuchsia::test]
87    fn value_list_record() {
88        let inspector = Inspector::default();
89        let child = inspector.root().create_child("test");
90        let value_list = ValueList::new();
91        assert!(value_list.values.lock().is_none());
92        value_list.record(child);
93        assert_eq!(value_list.values.lock().as_ref().unwrap().len(), 1);
94    }
95
96    #[fuchsia::test]
97    async fn value_list_drop_recorded() {
98        let inspector = Inspector::default();
99        let child = inspector.root().create_child("test");
100        let value_list = ValueList::new();
101        assert!(value_list.values.lock().is_none());
102        value_list.record(child);
103        assert_eq!(value_list.values.lock().as_ref().unwrap().len(), 1);
104        assert_json_diff!(inspector, root: {
105            test: {},
106        });
107
108        value_list.clear();
109        assert!(value_list.values.lock().is_none());
110        assert_json_diff!(inspector, root: {});
111    }
112}