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.
45use crate::writer::{Error, Node, State};
6use derivative::Derivative;
7use inspect_format::BlockIndex;
8use private::InspectTypeInternal;
9use std::fmt::Debug;
10use std::sync::{Arc, Weak};
1112/// Trait implemented by all inspect types.
13pub trait InspectType: Send + Sync + Debug {}
1415pub(crate) mod private {
16use crate::writer::State;
17use inspect_format::BlockIndex;
1819/// Trait implemented by all inspect types. It provides constructor functions that are not
20 /// intended for use outside the crate.
21 /// Use `impl_inspect_type_internal` for easy implementation.
22pub trait InspectTypeInternal {
23fn new(state: State, block_index: BlockIndex) -> Self;
24fn new_no_op() -> Self;
25fn is_valid(&self) -> bool;
26fn block_index(&self) -> Option<BlockIndex>;
27fn state(&self) -> Option<State>;
28fn atomic_access<R, F: FnOnce(&Self) -> R>(&self, accessor: F) -> R;
29 }
30}
3132/// Trait allowing a `Node` to adopt any Inspect type as its child, removing
33/// it from the original parent's tree.
34///
35/// This trait is not implementable by external types.
36pub trait InspectTypeReparentable: private::InspectTypeInternal {
37#[doc(hidden)]
38/// This function is called by a child with the new parent as an argument.
39 /// The child will be removed from its current parent and added to the tree
40 /// under new_parent.
41fn reparent(&self, new_parent: &Node) -> Result<(), Error> {
42if let (
43Some(child_state),
44Some(child_index),
45Some(new_parent_state),
46Some(new_parent_index),
47 ) = (self.state(), self.block_index(), new_parent.state(), new_parent.block_index())
48 {
49if new_parent_state != child_state {
50return Err(Error::AdoptionIntoWrongVmo);
51 }
5253 new_parent_state
54 .try_lock()
55 .and_then(|mut state| state.reparent(child_index, new_parent_index))?;
56 }
5758Ok(())
59 }
60}
6162impl<T: private::InspectTypeInternal> InspectTypeReparentable for T {}
6364/// Macro to generate private::InspectTypeInternal
65macro_rules! impl_inspect_type_internal {
66 ($type_name:ident) => {
67impl $crate::private::InspectTypeInternal for $type_name {
68fn 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 }
7475fn is_valid(&self) -> bool {
76self.inner.is_valid()
77 }
7879fn new_no_op() -> $type_name {
80$type_name { inner: $crate::writer::types::base::Inner::None }
81 }
8283fn state(&self) -> Option<$crate::writer::State> {
84Some(self.inner.inner_ref()?.state.clone())
85 }
8687fn block_index(&self) -> Option<inspect_format::BlockIndex> {
88if let Some(ref inner_ref) = self.inner.inner_ref() {
89Some(inner_ref.block_index)
90 } else {
91None
92}
93 }
9495fn atomic_access<R, F: FnOnce(&Self) -> R>(&self, accessor: F) -> R {
96match self.inner.inner_ref() {
97None => {
98// If the node was a no-op we still execute the `accessor` even if all
99 // operations inside it will be no-ops to return `R`.
100accessor(&self)
101 }
102Some(inner_ref) => {
103// Silently ignore the error when fail to lock (as in any regular operation).
104 // All operations performed in the `accessor` won't update the vmo
105 // generation count since we'll be holding one lock here.
106inner_ref.state.begin_transaction();
107let result = accessor(&self);
108 inner_ref.state.end_transaction();
109 result
110 }
111 }
112 }
113 }
114 };
115}
116117pub(crate) use impl_inspect_type_internal;
118119/// An inner type of all inspect nodes and properties. Each variant implies a
120/// different relationship with the underlying inspect VMO.
121#[derive(Debug, Derivative)]
122#[derivative(Default)]
123pub(crate) enum Inner<T: InnerType> {
124/// The node or property is not attached to the inspect VMO.
125#[derivative(Default)]
126None,
127128/// The node or property is attached to the inspect VMO, iff its strong
129 /// reference is still alive.
130Weak(Weak<InnerRef<T>>),
131132/// The node or property is attached to the inspect VMO.
133Strong(Arc<InnerRef<T>>),
134}
135136impl<T: InnerType> Inner<T> {
137/// Creates a new Inner with the desired block index within the inspect VMO
138pub(crate) fn new(state: State, block_index: BlockIndex) -> Self {
139Self::Strong(Arc::new(InnerRef { state, block_index, data: T::Data::default() }))
140 }
141142/// Returns true if the number of strong references to this node or property
143 /// is greater than 0.
144pub(crate) fn is_valid(&self) -> bool {
145match self {
146Self::None => false,
147Self::Weak(weak_ref) => match weak_ref.upgrade() {
148None => false,
149Some(inner_ref) => inner_ref.data.is_valid(),
150 },
151Self::Strong(inner_ref) => inner_ref.data.is_valid(),
152 }
153 }
154155/// Returns a `Some(Arc<InnerRef>)` iff the node or property is currently
156 /// attached to inspect, or `None` otherwise. Weak pointers are upgraded
157 /// if possible, but their lifetime as strong references are expected to be
158 /// short.
159pub(crate) fn inner_ref(&self) -> Option<Arc<InnerRef<T>>> {
160match self {
161Self::None => None,
162Self::Weak(weak_ref) => {
163if let Some(inner_ref) = weak_ref.upgrade() {
164if inner_ref.data.is_valid() {
165return Some(inner_ref);
166 }
167 }
168None
169}
170Self::Strong(inner_ref) => {
171if inner_ref.data.is_valid() {
172Some(Arc::clone(inner_ref))
173 } else {
174None
175}
176 }
177 }
178 }
179180/// Make a weak reference.
181pub(crate) fn clone_weak(&self) -> Self {
182match self {
183Self::None => Self::None,
184Self::Weak(weak_ref) => Self::Weak(weak_ref.clone()),
185Self::Strong(inner_ref) => {
186if inner_ref.data.is_valid() {
187Self::Weak(Arc::downgrade(inner_ref))
188 } else {
189Self::None
190 }
191 }
192 }
193 }
194}
195196/// Inspect API types implement Eq,PartialEq returning true all the time so that
197/// structs embedding inspect types can derive these traits as well.
198/// IMPORTANT: Do not rely on these traits implementations for real comparisons
199/// or validation tests, instead leverage the reader.
200impl<T: InnerType> PartialEq for Inner<T> {
201fn eq(&self, _other: &Self) -> bool {
202true
203}
204}
205206impl<T: InnerType> Eq for Inner<T> {}
207208/// A type that is owned by inspect nodes and properties, sharing ownership of
209/// the inspect VMO heap, and with numerical pointers to the location in the
210/// heap in which it resides.
211#[derive(Debug)]
212pub(crate) struct InnerRef<T: InnerType> {
213/// Index of the block in the VMO.
214pub(crate) block_index: BlockIndex,
215216/// Reference to the VMO heap.
217pub(crate) state: State,
218219/// Associated data for this type.
220pub(crate) data: T::Data,
221}
222223impl<T: InnerType> Drop for InnerRef<T> {
224/// InnerRef has a manual drop impl, to guarantee a single deallocation in
225 /// the case of multiple strong references.
226fn drop(&mut self) {
227 T::free(&self.state, &self.data, self.block_index).unwrap();
228 }
229}
230231/// De-allocation behavior and associated data for an inner type.
232pub(crate) trait InnerType {
233/// Associated data stored on the InnerRef
234type Data: Default + Debug + InnerData;
235236/// De-allocation behavior for when the InnerRef gets dropped
237fn free(state: &State, data: &Self::Data, block_index: BlockIndex) -> Result<(), Error>;
238}
239240pub(crate) trait InnerData {
241fn is_valid(&self) -> bool;
242}
243244impl InnerData for () {
245fn is_valid(&self) -> bool {
246true
247}
248}
249250#[derive(Default, Debug)]
251pub(crate) struct InnerValueType;
252253impl InnerType for InnerValueType {
254type Data = ();
255fn free(state: &State, _: &Self::Data, block_index: BlockIndex) -> Result<(), Error> {
256let mut state_lock = state.try_lock()?;
257 state_lock.free_value(block_index).map_err(|err| Error::free("value", block_index, err))
258 }
259}
260261#[cfg(test)]
262mod tests {
263use super::*;
264use crate::Inspector;
265use diagnostics_assertions::assert_data_tree;
266267#[fuchsia::test]
268fn test_reparent_from_state() {
269let insp = Inspector::default();
270let root = insp.root();
271let a = root.create_child("a");
272let b = a.create_child("b");
273274assert_data_tree!(insp, root: {
275 a: {
276 b: {},
277 },
278 });
279280 b.reparent(root).unwrap();
281282assert_data_tree!(insp, root: {
283 b: {},
284 a: {},
285 });
286 }
287288#[fuchsia::test]
289fn reparent_from_wrong_state() {
290let insp1 = Inspector::default();
291let insp2 = Inspector::default();
292293assert!(insp1.root().reparent(insp2.root()).is_err());
294295let a = insp1.root().create_child("a");
296let b = insp2.root().create_child("b");
297298assert!(a.reparent(&b).is_err());
299assert!(b.reparent(&a).is_err());
300 }
301}