fuchsia_inspect/writer/types/
base.rs1use crate::writer::{Error, Node, State};
6use derivative::Derivative;
7use inspect_format::BlockIndex;
8use private::InspectTypeInternal;
9use std::fmt::Debug;
10use std::sync::{Arc, Weak};
11
12pub trait InspectType: Send + Sync + Debug {}
14
15pub(crate) mod private {
16 use crate::writer::State;
17 use inspect_format::BlockIndex;
18
19 pub trait InspectTypeInternal {
23 fn new(state: State, block_index: BlockIndex) -> Self;
24 fn new_no_op() -> Self;
25 fn is_valid(&self) -> bool;
26 fn block_index(&self) -> Option<BlockIndex>;
27 fn state(&self) -> Option<State>;
28 fn atomic_access<R, F: FnOnce(&Self) -> R>(&self, accessor: F) -> R;
29 }
30}
31
32pub trait InspectTypeReparentable: private::InspectTypeInternal {
37 #[doc(hidden)]
38 fn reparent(&self, new_parent: &Node) -> Result<(), Error> {
42 if let (
43 Some(child_state),
44 Some(child_index),
45 Some(new_parent_state),
46 Some(new_parent_index),
47 ) = (self.state(), self.block_index(), new_parent.state(), new_parent.block_index())
48 {
49 if new_parent_state != child_state {
50 return Err(Error::AdoptionIntoWrongVmo);
51 }
52
53 new_parent_state
54 .try_lock()
55 .and_then(|mut state| state.reparent(child_index, new_parent_index))?;
56 }
57
58 Ok(())
59 }
60}
61
62impl<T: private::InspectTypeInternal> InspectTypeReparentable for T {}
63
64macro_rules! impl_inspect_type_internal {
66 ($type_name:ident) => {
67 impl $crate::private::InspectTypeInternal for $type_name {
68 fn new(
69 state: $crate::writer::State,
70 block_index: inspect_format::BlockIndex,
71 ) -> $type_name {
72 $type_name { inner: $crate::writer::types::base::Inner::new(state, block_index) }
73 }
74
75 fn is_valid(&self) -> bool {
76 self.inner.is_valid()
77 }
78
79 fn new_no_op() -> $type_name {
80 $type_name { inner: $crate::writer::types::base::Inner::None }
81 }
82
83 fn state(&self) -> Option<$crate::writer::State> {
84 Some(self.inner.inner_ref()?.state.clone())
85 }
86
87 fn block_index(&self) -> Option<inspect_format::BlockIndex> {
88 if let Some(ref inner_ref) = self.inner.inner_ref() {
89 Some(inner_ref.block_index)
90 } else {
91 None
92 }
93 }
94
95 fn atomic_access<R, F: FnOnce(&Self) -> R>(&self, accessor: F) -> R {
96 match self.inner.inner_ref() {
97 None => {
98 accessor(&self)
101 }
102 Some(inner_ref) => {
103 inner_ref.state.begin_transaction();
107 let result = accessor(&self);
108 inner_ref.state.end_transaction();
109 result
110 }
111 }
112 }
113 }
114 };
115}
116
117pub(crate) use impl_inspect_type_internal;
118
119#[derive(Debug, Derivative)]
122#[derivative(Default)]
123pub(crate) enum Inner<T: InnerType> {
124 #[derivative(Default)]
126 None,
127
128 Weak(Weak<InnerRef<T>>),
131
132 Strong(Arc<InnerRef<T>>),
134}
135
136impl<T: InnerType> Inner<T> {
137 pub(crate) fn new(state: State, block_index: BlockIndex) -> Self {
139 Self::Strong(Arc::new(InnerRef { state, block_index, data: T::Data::default() }))
140 }
141
142 pub(crate) fn is_valid(&self) -> bool {
145 match self {
146 Self::None => false,
147 Self::Weak(weak_ref) => match weak_ref.upgrade() {
148 None => false,
149 Some(inner_ref) => inner_ref.data.is_valid(),
150 },
151 Self::Strong(inner_ref) => inner_ref.data.is_valid(),
152 }
153 }
154
155 pub(crate) fn inner_ref(&self) -> Option<Arc<InnerRef<T>>> {
160 match self {
161 Self::None => None,
162 Self::Weak(weak_ref) => {
163 if let Some(inner_ref) = weak_ref.upgrade() {
164 if inner_ref.data.is_valid() {
165 return Some(inner_ref);
166 }
167 }
168 None
169 }
170 Self::Strong(inner_ref) => {
171 if inner_ref.data.is_valid() {
172 Some(Arc::clone(inner_ref))
173 } else {
174 None
175 }
176 }
177 }
178 }
179
180 pub(crate) fn clone_weak(&self) -> Self {
182 match self {
183 Self::None => Self::None,
184 Self::Weak(weak_ref) => Self::Weak(weak_ref.clone()),
185 Self::Strong(inner_ref) => {
186 if inner_ref.data.is_valid() {
187 Self::Weak(Arc::downgrade(inner_ref))
188 } else {
189 Self::None
190 }
191 }
192 }
193 }
194}
195
196impl<T: InnerType> PartialEq for Inner<T> {
201 fn eq(&self, _other: &Self) -> bool {
202 true
203 }
204}
205
206impl<T: InnerType> Eq for Inner<T> {}
207
208#[derive(Debug)]
212pub(crate) struct InnerRef<T: InnerType> {
213 pub(crate) block_index: BlockIndex,
215
216 pub(crate) state: State,
218
219 pub(crate) data: T::Data,
221}
222
223impl<T: InnerType> Drop for InnerRef<T> {
224 fn drop(&mut self) {
227 T::free(&self.state, &self.data, self.block_index).unwrap();
228 }
229}
230
231pub(crate) trait InnerType {
233 type Data: Default + Debug + InnerData;
235
236 fn free(state: &State, data: &Self::Data, block_index: BlockIndex) -> Result<(), Error>;
238}
239
240pub(crate) trait InnerData {
241 fn is_valid(&self) -> bool;
242}
243
244impl InnerData for () {
245 fn is_valid(&self) -> bool {
246 true
247 }
248}
249
250#[derive(Default, Debug)]
251pub(crate) struct InnerValueType;
252
253impl InnerType for InnerValueType {
254 type Data = ();
255 fn free(state: &State, _: &Self::Data, block_index: BlockIndex) -> Result<(), Error> {
256 let mut state_lock = state.try_lock()?;
257 state_lock.free_value(block_index).map_err(|err| Error::free("value", block_index, err))
258 }
259}
260
261#[cfg(test)]
262mod tests {
263 use super::*;
264 use crate::Inspector;
265 use diagnostics_assertions::assert_data_tree;
266
267 #[fuchsia::test]
268 fn test_reparent_from_state() {
269 let insp = Inspector::default();
270 let root = insp.root();
271 let a = root.create_child("a");
272 let b = a.create_child("b");
273
274 assert_data_tree!(insp, root: {
275 a: {
276 b: {},
277 },
278 });
279
280 b.reparent(root).unwrap();
281
282 assert_data_tree!(insp, root: {
283 b: {},
284 a: {},
285 });
286 }
287
288 #[fuchsia::test]
289 fn reparent_from_wrong_state() {
290 let insp1 = Inspector::default();
291 let insp2 = Inspector::default();
292
293 assert!(insp1.root().reparent(insp2.root()).is_err());
294
295 let a = insp1.root().create_child("a");
296 let b = insp2.root().create_child("b");
297
298 assert!(a.reparent(&b).is_err());
299 assert!(b.reparent(&a).is_err());
300 }
301}