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 fn into_recorded(self) -> crate::writer::types::RecordedInspectType
15 where
16 Self: Sized + 'static;
17}
18
19pub(crate) mod private {
20 use crate::writer::State;
21 use inspect_format::BlockIndex;
22
23 pub trait InspectTypeInternal {
27 fn new(state: State, block_index: BlockIndex) -> Self;
28 fn new_no_op() -> Self;
29 fn is_valid(&self) -> bool;
30 fn block_index(&self) -> Option<BlockIndex>;
31 fn state(&self) -> Option<State>;
32 fn atomic_access<R, F: FnOnce(&Self) -> R>(&self, accessor: F) -> R;
33 }
34}
35
36pub trait InspectTypeReparentable: private::InspectTypeInternal {
41 #[doc(hidden)]
42 fn reparent(&self, new_parent: &Node) -> Result<(), Error> {
46 if let (
47 Some(child_state),
48 Some(child_index),
49 Some(new_parent_state),
50 Some(new_parent_index),
51 ) = (self.state(), self.block_index(), new_parent.state(), new_parent.block_index())
52 {
53 if new_parent_state != child_state {
54 return Err(Error::AdoptionIntoWrongVmo);
55 }
56
57 new_parent_state
58 .try_lock()
59 .and_then(|mut state| state.reparent(child_index, new_parent_index))?;
60 }
61
62 Ok(())
63 }
64}
65
66impl<T: private::InspectTypeInternal> InspectTypeReparentable for T {}
67
68macro_rules! impl_inspect_type_internal {
70 ($type_name:ident) => {
71 impl $crate::private::InspectTypeInternal for $type_name {
72 fn new(
73 state: $crate::writer::State,
74 block_index: inspect_format::BlockIndex,
75 ) -> $type_name {
76 $type_name { inner: $crate::writer::types::base::Inner::new(state, block_index) }
77 }
78
79 fn is_valid(&self) -> bool {
80 self.inner.is_valid()
81 }
82
83 fn new_no_op() -> $type_name {
84 $type_name { inner: $crate::writer::types::base::Inner::None }
85 }
86
87 fn state(&self) -> Option<$crate::writer::State> {
88 Some(self.inner.inner_ref()?.state.clone())
89 }
90
91 fn block_index(&self) -> Option<inspect_format::BlockIndex> {
92 if let Some(ref inner_ref) = self.inner.inner_ref() {
93 Some(inner_ref.block_index)
94 } else {
95 None
96 }
97 }
98
99 fn atomic_access<R, F: FnOnce(&Self) -> R>(&self, accessor: F) -> R {
100 match self.inner.inner_ref() {
101 None => {
102 accessor(&self)
105 }
106 Some(inner_ref) => {
107 inner_ref.state.begin_transaction();
111 let result = accessor(&self);
112 inner_ref.state.end_transaction();
113 result
114 }
115 }
116 }
117 }
118 };
119}
120
121pub(crate) use impl_inspect_type_internal;
122
123#[derive(Debug, Derivative)]
126#[derivative(Default)]
127pub(crate) enum Inner<T: InnerType> {
128 #[derivative(Default)]
130 None,
131
132 Weak(Weak<InnerRef<T>>),
135
136 Strong(Arc<InnerRef<T>>),
138}
139
140impl<T: InnerType> Inner<T> {
141 pub(crate) fn new(state: State, block_index: BlockIndex) -> Self {
143 Self::Strong(Arc::new(InnerRef { state, block_index, data: T::Data::default() }))
144 }
145
146 pub(crate) fn is_valid(&self) -> bool {
149 match self {
150 Self::None => false,
151 Self::Weak(weak_ref) => match weak_ref.upgrade() {
152 None => false,
153 Some(inner_ref) => inner_ref.data.is_valid(),
154 },
155 Self::Strong(inner_ref) => inner_ref.data.is_valid(),
156 }
157 }
158
159 pub(crate) fn inner_ref(&self) -> Option<Arc<InnerRef<T>>> {
164 match self {
165 Self::None => None,
166 Self::Weak(weak_ref) => {
167 if let Some(inner_ref) = weak_ref.upgrade()
168 && inner_ref.data.is_valid()
169 {
170 return Some(inner_ref);
171 }
172 None
173 }
174 Self::Strong(inner_ref) => {
175 if inner_ref.data.is_valid() {
176 Some(Arc::clone(inner_ref))
177 } else {
178 None
179 }
180 }
181 }
182 }
183
184 pub(crate) fn clone_weak(&self) -> Self {
186 match self {
187 Self::None => Self::None,
188 Self::Weak(weak_ref) => Self::Weak(weak_ref.clone()),
189 Self::Strong(inner_ref) => {
190 if inner_ref.data.is_valid() {
191 Self::Weak(Arc::downgrade(inner_ref))
192 } else {
193 Self::None
194 }
195 }
196 }
197 }
198}
199
200impl<T: InnerType> PartialEq for Inner<T> {
205 fn eq(&self, _other: &Self) -> bool {
206 true
207 }
208}
209
210impl<T: InnerType> Eq for Inner<T> {}
211
212#[derive(Debug)]
216pub(crate) struct InnerRef<T: InnerType> {
217 pub(crate) block_index: BlockIndex,
219
220 pub(crate) state: State,
222
223 pub(crate) data: T::Data,
225}
226
227impl<T: InnerType> Drop for InnerRef<T> {
228 fn drop(&mut self) {
231 T::free(&self.state, &self.data, self.block_index).unwrap();
232 }
233}
234
235pub(crate) trait InnerType {
237 type Data: Default + Debug + InnerData;
239
240 fn free(state: &State, data: &Self::Data, block_index: BlockIndex) -> Result<(), Error>;
242}
243
244pub(crate) trait InnerData {
245 fn is_valid(&self) -> bool;
246}
247
248impl InnerData for () {
249 fn is_valid(&self) -> bool {
250 true
251 }
252}
253
254#[derive(Default, Debug)]
255pub(crate) struct InnerValueType;
256
257impl InnerType for InnerValueType {
258 type Data = ();
259 fn free(state: &State, _: &Self::Data, block_index: BlockIndex) -> Result<(), Error> {
260 let mut state_lock = state.try_lock()?;
261 state_lock.free_value(block_index).map_err(|err| Error::free("value", block_index, err))
262 }
263}
264
265#[cfg(test)]
266mod tests {
267 use super::*;
268 use crate::Inspector;
269 use diagnostics_assertions::assert_data_tree;
270
271 #[fuchsia::test]
272 async fn test_reparent_from_state() {
273 let insp = Inspector::default();
274 let root = insp.root();
275 let a = root.create_child("a");
276 let b = a.create_child("b");
277
278 assert_data_tree!(insp, root: {
279 a: {
280 b: {},
281 },
282 });
283
284 b.reparent(root).unwrap();
285
286 assert_data_tree!(insp, root: {
287 b: {},
288 a: {},
289 });
290 }
291
292 #[fuchsia::test]
293 fn reparent_from_wrong_state() {
294 let insp1 = Inspector::default();
295 let insp2 = Inspector::default();
296
297 assert!(insp1.root().reparent(insp2.root()).is_err());
298
299 let a = insp1.root().create_child("a");
300 let b = insp2.root().create_child("b");
301
302 assert!(a.reparent(&b).is_err());
303 assert!(b.reparent(&a).is_err());
304 }
305}