fuchsia_inspect/writer/types/
string_reference.rs

1// Copyright 2020 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 std::borrow::{Borrow, Cow};
6use std::ops::Deref;
7use std::sync::Arc;
8
9/// StringReference is a type that can be constructed and passed into
10/// the Inspect API as a name of a Node. If this is done, only one
11/// reference counted instance of the string will be allocated per
12/// Inspector. They can be safely used with LazyNodes.
13///
14/// StringReference dereferences into a `&str` for convenience.
15#[derive(Hash, Eq, PartialEq, Debug, Clone)]
16pub struct StringReference(Arc<str>);
17
18impl Deref for StringReference {
19    type Target = str;
20
21    fn deref(&self) -> &Self::Target {
22        self.as_ref()
23    }
24}
25
26impl Borrow<str> for StringReference {
27    fn borrow(&self) -> &str {
28        self.as_ref()
29    }
30}
31
32impl AsRef<str> for StringReference {
33    fn as_ref(&self) -> &str {
34        self.0.as_ref()
35    }
36}
37
38/// Internally clones itself without allocation or copy
39impl From<&'_ StringReference> for StringReference {
40    fn from(sref: &'_ StringReference) -> Self {
41        sref.clone()
42    }
43}
44
45/// Consumes the input without allocation or copy
46impl From<String> for StringReference {
47    fn from(data: String) -> Self {
48        StringReference(Arc::from(data.into_boxed_str()))
49    }
50}
51
52/// Consumes the input without allocation or copy
53impl From<Arc<str>> for StringReference {
54    fn from(data: Arc<str>) -> Self {
55        StringReference(data)
56    }
57}
58
59/// Allocates an `Arc<String>` from `data`
60impl From<&String> for StringReference {
61    fn from(data: &String) -> Self {
62        StringReference(Arc::from(data.as_ref()))
63    }
64}
65
66/// Allocates an `Arc<String>` from `data`
67impl From<&str> for StringReference {
68    fn from(data: &str) -> Self {
69        StringReference(data.into())
70    }
71}
72
73/// Allocates an `Arc<String>` from `data`
74impl From<Cow<'_, str>> for StringReference {
75    fn from(data: Cow<'_, str>) -> Self {
76        StringReference(data.as_ref().into())
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use crate::writer::testing_utils::{get_state, GetBlockExt};
83    use crate::writer::{Inspector, Node};
84    use diagnostics_assertions::assert_data_tree;
85
86    #[fuchsia::test]
87    fn string_references_as_names() {
88        let inspector = Inspector::default();
89        inspector.root().record_int("foo", 0);
90        let child = inspector.root().create_child("bar");
91        child.record_double("foo", 3.25);
92
93        assert_data_tree!(inspector, root: {
94            foo: 0i64,
95            bar: {
96                foo: 3.25,
97            },
98        });
99
100        {
101            let _baz_property = child.create_uint("baz", 4);
102            assert_data_tree!(inspector, root: {
103                foo: 0i64,
104                bar: {
105                    baz: 4u64,
106                    foo: 3.25,
107                },
108            });
109        }
110
111        assert_data_tree!(inspector, root: {
112            foo: 0i64,
113            bar: {
114                foo: 3.25,
115            },
116        });
117
118        let pre_loop_allocated =
119            inspector.state().unwrap().try_lock().unwrap().stats().allocated_blocks;
120        let pre_loop_deallocated =
121            inspector.state().unwrap().try_lock().unwrap().stats().deallocated_blocks;
122
123        for i in 0..300 {
124            child.record_int("bar", i);
125        }
126
127        assert_eq!(
128            inspector.state().unwrap().try_lock().unwrap().stats().allocated_blocks,
129            pre_loop_allocated + 300
130        );
131        assert_eq!(
132            inspector.state().unwrap().try_lock().unwrap().stats().deallocated_blocks,
133            pre_loop_deallocated
134        );
135
136        let pre_loop_count = pre_loop_allocated + 300;
137
138        for i in 0..300 {
139            child.record_int("abcd", i);
140        }
141
142        assert_eq!(
143            inspector.state().unwrap().try_lock().unwrap().stats().allocated_blocks,
144            pre_loop_count + 300 /* the int blocks */ + 1 /* individual block for "abcd" */
145        );
146        assert_eq!(
147            inspector.state().unwrap().try_lock().unwrap().stats().deallocated_blocks,
148            pre_loop_deallocated
149        );
150    }
151
152    #[fuchsia::test]
153    fn owned_method_argument_properties() {
154        let state = get_state(4096);
155        let root = Node::new_root(state);
156        let node = root.create_child("node");
157        {
158            let _string_property =
159                node.create_string(String::from("string_property"), String::from("test"));
160            let _bytes_property =
161                node.create_bytes(String::from("bytes_property"), vec![0, 1, 2, 3]);
162            let _double_property = node.create_double(String::from("double_property"), 1.0);
163            let _int_property = node.create_int(String::from("int_property"), 1);
164            let _uint_property = node.create_uint(String::from("uint_property"), 1);
165            node.get_block::<_, inspect_format::Node>(|node_block| {
166                assert_eq!(node_block.child_count(), 5);
167            });
168        }
169        node.get_block::<_, inspect_format::Node>(|node_block| {
170            assert_eq!(node_block.child_count(), 0);
171        });
172    }
173}