1use super::{Data, LazyNode, Metrics, Node, Payload, Property, ROOT_NAME};
6use crate::metrics::{BlockMetrics, BlockStatus};
7use anyhow::{Context, Error, bail, format_err};
8use fuchsia_inspect::reader as ireader;
9use fuchsia_inspect::reader::snapshot::ScannedBlock;
10use inspect_format::constants::MIN_ORDER_SIZE;
11use inspect_format::*;
12use std::cmp::min;
13use std::collections::{HashMap, HashSet};
14use zx::Vmo;
15
16#[derive(Debug)]
37pub struct Scanner {
38 nodes: HashMap<BlockIndex, ScannedNode>,
39 names: HashMap<BlockIndex, ScannedName>,
40 properties: HashMap<BlockIndex, ScannedProperty>,
41 extents: HashMap<BlockIndex, ScannedExtent>,
42 final_dereferenced_strings: HashMap<BlockIndex, String>,
43 final_nodes: HashMap<BlockIndex, Node>,
44 final_properties: HashMap<BlockIndex, Property>,
45 metrics: Metrics,
46 child_trees: Option<HashMap<String, LazyNode>>,
47}
48
49impl TryFrom<&[u8]> for Scanner {
50 type Error = Error;
51
52 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
53 let scanner = Scanner::new(None);
54 scanner.scan(ireader::snapshot::Snapshot::try_from(bytes.to_vec())?, bytes)
55 }
56}
57
58impl TryFrom<&Vmo> for Scanner {
59 type Error = Error;
60 fn try_from(vmo: &Vmo) -> Result<Self, Self::Error> {
61 let scanner = Scanner::new(None);
62 scanner.scan(ireader::snapshot::Snapshot::try_from(vmo)?, &vmo_as_buffer(vmo)?)
63 }
64}
65
66impl TryFrom<LazyNode> for Scanner {
67 type Error = Error;
68
69 fn try_from(mut vmo_tree: LazyNode) -> Result<Self, Self::Error> {
70 let snapshot = ireader::snapshot::Snapshot::try_from(vmo_tree.vmo())?;
71 let buffer = vmo_as_buffer(vmo_tree.vmo())?;
72 let scanner = Scanner::new(vmo_tree.take_children());
73 scanner.scan(snapshot, &buffer)
74 }
75}
76
77fn vmo_as_buffer(vmo: &Vmo) -> Result<Vec<u8>, Error> {
78 let size = vmo.get_size()?;
81 let mut buffer = vec![0u8; size as usize];
82 vmo.read(&mut buffer[..], 0)?;
83 Ok(buffer)
84}
85
86fn low_bits(number: u8, n_bits: usize) -> u8 {
87 let n_bits = min(n_bits, 8);
88 let mask = !(0xff_u16 << n_bits) as u8;
89 number & mask
90}
91
92fn high_bits(number: u8, n_bits: usize) -> u8 {
93 let n_bits = min(n_bits, 8);
94 let mask = !(0xff_u16 >> n_bits) as u8;
95 number & mask
96}
97
98const BITS_PER_BYTE: usize = 8;
99
100fn order_to_size(order: u8) -> usize {
102 MIN_ORDER_SIZE << (order as usize)
103}
104
105fn check_zero_bits(
107 buffer: &[u8],
108 block: &ScannedBlock<'_, Unknown>,
109 start: usize,
110 end: usize,
111) -> Result<(), Error> {
112 if end < start {
113 return Err(format_err!("End must be >= start"));
114 }
115 let bits_in_block = order_to_size(block.order()) * BITS_PER_BYTE;
116 if start > bits_in_block - 1 {
117 return Ok(());
118 }
119 let end = min(end, bits_in_block - 1);
120 let block_offset = usize::from(block.index()) * MIN_ORDER_SIZE;
121 let low_byte = start / BITS_PER_BYTE;
122 let high_byte = end / BITS_PER_BYTE;
123 let bottom_bits = high_bits(buffer[low_byte + block_offset], 8 - (start % 8));
124 let top_bits = low_bits(buffer[high_byte + block_offset], (end % 8) + 1);
125 if low_byte == high_byte {
126 match bottom_bits & top_bits {
127 0 => return Ok(()),
128 nonzero => bail!(
129 "Bits {}...{} of block type {:?} at {} have nonzero value {}",
130 start,
131 end,
132 block.block_type(),
133 block.index(),
134 nonzero
135 ),
136 }
137 }
138 if bottom_bits != 0 {
139 bail!(
140 "Non-zero value {} for bits {}.. of block type {:?} at {}",
141 bottom_bits,
142 start,
143 block.block_type(),
144 block.index()
145 );
146 }
147 if top_bits != 0 {
148 bail!(
149 "Non-zero value {} for bits ..{} of block type {:?} at {}",
150 top_bits,
151 end,
152 block.block_type(),
153 block.index()
154 );
155 }
156 for byte in low_byte + 1..high_byte {
157 if buffer[byte + block_offset] != 0 {
158 bail!(
159 "Non-zero value {} for byte {} of block type {:?} at {}",
160 buffer[byte],
161 byte,
162 block.block_type(),
163 block.index()
164 );
165 }
166 }
167 Ok(())
168}
169
170impl Scanner {
171 fn new(child_trees: Option<HashMap<String, LazyNode>>) -> Scanner {
172 let mut ret = Scanner {
173 nodes: HashMap::new(),
174 names: HashMap::new(),
175 properties: HashMap::new(),
176 extents: HashMap::new(),
177 final_dereferenced_strings: HashMap::new(),
178 metrics: Metrics::new(),
179 final_nodes: HashMap::new(),
180 final_properties: HashMap::new(),
181 child_trees,
182 };
183 ret.nodes.insert(
186 BlockIndex::ROOT,
187 ScannedNode {
188 validated: true,
189 parent: BlockIndex::ROOT,
190 name: BlockIndex::ROOT,
191 children: HashSet::new(),
192 properties: HashSet::new(),
193 metrics: None,
194 },
195 );
196 ret
197 }
198
199 fn scan(mut self, snapshot: ireader::snapshot::Snapshot, buffer: &[u8]) -> Result<Self, Error> {
200 let mut link_blocks: Vec<ScannedBlock<'_, Unknown>> = Vec::new();
201 let mut string_references: Vec<ScannedStringReference> = Vec::new();
202 for block in snapshot.scan() {
203 match block.block_type().ok_or_else(|| format_err!("invalid block type"))? {
204 BlockType::Free => self.process_free(block)?,
205 BlockType::Reserved => self.process_reserved(block)?,
206 BlockType::Header => self.process_header(block)?,
207 BlockType::NodeValue => self.process_node(block)?,
208 BlockType::IntValue => self.process_property::<Int>(block, buffer)?,
209 BlockType::UintValue => self.process_property::<Uint>(block, buffer)?,
210 BlockType::DoubleValue => self.process_property::<Double>(block, buffer)?,
211 BlockType::ArrayValue => self.process_property::<Array<Unknown>>(block, buffer)?,
212 BlockType::BufferValue => self.process_property::<Buffer>(block, buffer)?,
213 BlockType::BoolValue => self.process_property::<Bool>(block, buffer)?,
214 BlockType::LinkValue => link_blocks.push(block),
215 BlockType::Extent => self.process_extent(block, buffer)?,
216 BlockType::Name => self.process_name(block, buffer)?,
217 BlockType::Tombstone => self.process_tombstone(block)?,
218 BlockType::StringReference => {
219 string_references.push(self.process_string_reference(block)?);
220 }
221 }
222 }
223
224 for block in string_references.drain(..) {
225 let index = block.index;
226 let dereferenced = self.expand_string_reference(block)?;
227 self.final_dereferenced_strings.insert(index, dereferenced);
228 }
229
230 for block in link_blocks.into_iter() {
233 self.process_property::<Link>(block, buffer)?
234 }
235
236 let (mut new_nodes, mut new_properties) = self.make_valid_node_tree(BlockIndex::ROOT)?;
237 for (node, id) in new_nodes.drain(..) {
238 self.final_nodes.insert(id, node);
239 }
240 for (property, id) in new_properties.drain(..) {
241 self.final_properties.insert(id, property);
242 }
243
244 self.record_unused_metrics();
245 Ok(self)
246 }
247
248 pub fn data(self) -> Data {
249 Data::build(self.final_nodes, self.final_properties)
250 }
251
252 pub fn metrics(self) -> Metrics {
253 self.metrics
254 }
255
256 fn record_unused_metrics(&mut self) {
258 for (_, node) in self.nodes.drain() {
259 if let Some(metrics) = node.metrics {
260 self.metrics.record(&metrics, BlockStatus::NotUsed);
261 }
262 }
263 for (_, name) in self.names.drain() {
264 self.metrics.record(&name.metrics, BlockStatus::NotUsed);
265 }
266 for (_, property) in self.properties.drain() {
267 self.metrics.record(&property.metrics, BlockStatus::NotUsed);
268 }
269 for (_, extent) in self.extents.drain() {
270 self.metrics.record(&extent.metrics, BlockStatus::NotUsed);
271 }
272 }
273
274 fn use_node(&mut self, node_id: BlockIndex) -> Result<ScannedNode, Error> {
275 let mut node = self
276 .nodes
277 .remove(&node_id)
278 .ok_or_else(|| format_err!("No node at index {}", node_id))?;
279 match node.metrics {
280 None => {
281 if node_id != BlockIndex::ROOT {
282 return Err(format_err!("Invalid node (no metrics) at index {}", node_id));
283 }
284 }
285 Some(metrics) => {
286 self.metrics.record(&metrics, BlockStatus::Used);
288 node.metrics = Some(metrics); }
290 }
291 Ok(node)
292 }
293
294 fn use_property(&mut self, property_id: BlockIndex) -> Result<ScannedProperty, Error> {
295 let property = self
296 .properties
297 .remove(&property_id)
298 .ok_or_else(|| format_err!("No property at index {}", property_id))?;
299 self.metrics.record(&property.metrics, BlockStatus::Used);
300 Ok(property)
301 }
302
303 fn use_owned_name(&mut self, name_id: BlockIndex) -> Result<String, Error> {
306 match self.names.remove(&name_id) {
307 Some(name) => {
308 self.metrics.record(&name.metrics, BlockStatus::Used);
309 Ok(name.name)
310 }
311 None => match self.final_dereferenced_strings.get(&name_id) {
312 Some(value) => {
313 Ok(value.clone())
316 }
317 None => Err(format_err!("No string at index {}", name_id)),
318 },
319 }
320 }
321
322 fn lookup_name_or_string_reference(&mut self, name_id: BlockIndex) -> Result<String, Error> {
325 match self.names.get(&name_id) {
326 Some(name) => {
327 self.metrics.record(&name.metrics, BlockStatus::Used);
328 Ok(name.name.clone())
329 }
330 None => match self.final_dereferenced_strings.get(&name_id) {
331 Some(value) => {
332 Ok(value.clone())
335 }
336 None => Err(format_err!("No string at index {}", name_id)),
337 },
338 }
339 }
340
341 fn process_free(&mut self, block: ScannedBlock<'_, Unknown>) -> Result<(), Error> {
352 self.metrics.process(block)?;
355 Ok(())
356 }
357
358 fn process_header(&mut self, block: ScannedBlock<'_, Unknown>) -> Result<(), Error> {
359 self.metrics.process(block)?;
360 Ok(())
361 }
362
363 fn process_tombstone(&mut self, block: ScannedBlock<'_, Unknown>) -> Result<(), Error> {
364 self.metrics.process(block)?;
365 Ok(())
366 }
367
368 fn process_reserved(&mut self, block: ScannedBlock<'_, Unknown>) -> Result<(), Error> {
369 self.metrics.process(block)?;
370 Ok(())
371 }
372
373 fn process_extent(
374 &mut self,
375 block: ScannedBlock<'_, Unknown>,
376 buffer: &[u8],
377 ) -> Result<(), Error> {
378 check_zero_bits(buffer, &block, 40, 63)?;
379 let extent = block.clone().cast::<Extent>().unwrap();
380 let next = extent.next_extent();
381 let data = extent.contents()?.to_vec();
382 self.extents
383 .insert(block.index(), ScannedExtent { next, data, metrics: Metrics::analyze(block)? });
384 Ok(())
385 }
386
387 fn process_name(
388 &mut self,
389 block: ScannedBlock<'_, Unknown>,
390 buffer: &[u8],
391 ) -> Result<(), Error> {
392 check_zero_bits(buffer, &block, 28, 63)?;
393 let name_block = block.clone().cast::<Name>().unwrap();
394 let name = name_block.contents()?.to_string();
395 self.names.insert(block.index(), ScannedName { name, metrics: Metrics::analyze(block)? });
396 Ok(())
397 }
398
399 fn process_node(&mut self, block: ScannedBlock<'_, Unknown>) -> Result<(), Error> {
400 let node_block = block.clone().cast::<inspect_format::Node>().unwrap();
401 let parent = node_block.parent_index();
402 let id = node_block.index();
403 let name = node_block.name_index();
404 let mut node;
405 let metrics = Some(Metrics::analyze(block)?);
406 if let Some(placeholder) = self.nodes.remove(&id) {
407 node = placeholder;
409 node.validated = true;
410 node.parent = parent;
411 node.name = name;
412 node.metrics = metrics;
413 } else {
414 node = ScannedNode {
415 validated: true,
416 name,
417 parent,
418 children: HashSet::new(),
419 properties: HashSet::new(),
420 metrics,
421 }
422 }
423 self.nodes.insert(id, node);
424 self.add_to_parent(parent, id, |node| &mut node.children);
425 Ok(())
426 }
427
428 fn add_to_parent<F: FnOnce(&mut ScannedNode) -> &mut HashSet<BlockIndex>>(
429 &mut self,
430 parent: BlockIndex,
431 id: BlockIndex,
432 get_the_hashset: F, ) {
434 self.nodes.entry(parent).or_insert_with(|| ScannedNode {
435 validated: false,
436 name: BlockIndex::EMPTY,
437 parent: BlockIndex::ROOT,
438 children: HashSet::new(),
439 properties: HashSet::new(),
440 metrics: None,
441 });
442 if let Some(parent_node) = self.nodes.get_mut(&parent) {
443 get_the_hashset(parent_node).insert(id);
444 }
445 }
446
447 fn process_string_reference(
448 &mut self,
449 block: ScannedBlock<'_, Unknown>,
450 ) -> Result<ScannedStringReference, Error> {
451 let string_ref = block.clone().cast::<StringRef>().unwrap();
452 let scanned = ScannedStringReference {
453 index: block.index(),
454 value: string_ref.inline_data()?.to_vec(),
455 length: string_ref.total_length(),
456 next_extent: string_ref.next_extent(),
457 };
458
459 self.metrics.process(block)?;
460 Ok(scanned)
461 }
462
463 fn process_property<K>(
464 &mut self,
465 block: ScannedBlock<'_, Unknown>,
466 buffer: &[u8],
467 ) -> Result<(), Error>
468 where
469 K: ValueBlockKind + Clone,
470 ScannedPayload: BuildScannedPayload<K>,
471 {
472 if block.block_type() == Some(BlockType::ArrayValue) {
473 check_zero_bits(buffer, &block, 80, 127)?;
474 }
475 let property_block = block.clone().cast::<K>().unwrap();
476 let id = property_block.index();
477 let parent = property_block.parent_index();
478 let name = property_block.name_index();
479 let payload = ScannedPayload::build(property_block, self)?;
480 let property = ScannedProperty { name, parent, payload, metrics: Metrics::analyze(block)? };
481 self.properties.insert(id, property);
482 self.add_to_parent(parent, id, |node| &mut node.properties);
483 Ok(())
484 }
485
486 #[allow(clippy::type_complexity)]
489 fn make_valid_node_tree(
490 &mut self,
491 id: BlockIndex,
492 ) -> Result<(Vec<(Node, BlockIndex)>, Vec<(Property, BlockIndex)>), Error> {
493 let scanned_node = self.use_node(id)?;
494 if !scanned_node.validated {
495 return Err(format_err!("No node at {}", id));
496 }
497 let mut nodes_in_tree = vec![];
498 let mut properties_under = vec![];
499 for node_id in scanned_node.children.iter() {
500 let (mut nodes_of, mut properties_of) = self.make_valid_node_tree(*node_id)?;
501 nodes_in_tree.append(&mut nodes_of);
502 properties_under.append(&mut properties_of);
503 }
504 for property_id in scanned_node.properties.iter() {
505 properties_under.push((self.make_valid_property(*property_id)?, *property_id));
506 }
507 let name = if id == BlockIndex::ROOT {
508 ROOT_NAME.to_owned()
509 } else {
510 self.use_owned_name(scanned_node.name)?
511 };
512 let this_node = Node {
513 name,
514 parent: scanned_node.parent,
515 children: scanned_node.children.clone(),
516 properties: scanned_node.properties.clone(),
517 };
518 nodes_in_tree.push((this_node, id));
519 Ok((nodes_in_tree, properties_under))
520 }
521
522 fn make_valid_property(&mut self, id: BlockIndex) -> Result<Property, Error> {
523 let scanned_property = self.use_property(id)?;
524 let name = self.use_owned_name(scanned_property.name)?;
525 let payload = self.make_valid_payload(scanned_property.payload)?;
526 Ok(Property { id, name, parent: scanned_property.parent, payload })
527 }
528
529 fn make_valid_payload(&mut self, payload: ScannedPayload) -> Result<Payload, Error> {
530 Ok(match payload {
531 ScannedPayload::Int(data) => Payload::Int(data),
532 ScannedPayload::Uint(data) => Payload::Uint(data),
533 ScannedPayload::Double(data) => Payload::Double(data),
534 ScannedPayload::Bool(data) => Payload::Bool(data),
535 ScannedPayload::IntArray(data, format) => Payload::IntArray(data, format),
536 ScannedPayload::UintArray(data, format) => Payload::UintArray(data, format),
537 ScannedPayload::DoubleArray(data, format) => Payload::DoubleArray(data, format),
538 ScannedPayload::StringArray(indexes) => Payload::StringArray(
539 indexes
540 .iter()
541 .map(|i| {
542 if *i == BlockIndex::EMPTY {
543 return "".into();
544 }
545 self.final_dereferenced_strings.get(i).unwrap().clone()
546 })
547 .collect(),
548 ),
549 ScannedPayload::Bytes { length, link } => {
550 Payload::Bytes(self.make_valid_vector(length, link)?)
551 }
552 ScannedPayload::String { length, link } => {
553 Payload::String(if let Some(length) = length {
554 std::str::from_utf8(&self.make_valid_vector(length, link)?)?.to_owned()
555 } else {
556 self.final_dereferenced_strings.get(&link).unwrap().clone()
557 })
558 }
559 ScannedPayload::Link { disposition, scanned_tree } => {
560 Payload::Link { disposition, parsed_data: scanned_tree.data() }
561 }
562 })
563 }
564
565 fn expand_string_reference(
566 &mut self,
567 mut block: ScannedStringReference,
568 ) -> Result<String, Error> {
569 let length_of_inlined = block.value.len();
570 if block.next_extent != BlockIndex::EMPTY {
571 block.value.append(
572 &mut self.make_valid_vector(block.length - length_of_inlined, block.next_extent)?,
573 );
574 }
575
576 Ok(String::from_utf8(block.value)?)
577 }
578
579 fn make_valid_vector(&mut self, length: usize, link: BlockIndex) -> Result<Vec<u8>, Error> {
580 let mut dest = vec![];
581 let mut length_remaining = length;
582 let mut next_link = link;
583 while length_remaining > 0 {
584 let mut extent = self
586 .extents
587 .remove(&next_link)
588 .ok_or_else(|| format_err!("No extent at {}", next_link))?;
589 let copy_len = min(extent.data.len(), length_remaining);
590 extent.metrics.set_data_bytes(copy_len);
591 self.metrics.record(&extent.metrics, BlockStatus::Used);
592 dest.extend_from_slice(&extent.data[..copy_len]);
593 length_remaining -= copy_len;
594 next_link = extent.next;
595 }
596 Ok(dest)
597 }
598}
599
600#[derive(Debug)]
601struct ScannedNode {
602 validated: bool,
609 name: BlockIndex,
610 parent: BlockIndex,
611 children: HashSet<BlockIndex>,
612 properties: HashSet<BlockIndex>,
613 metrics: Option<BlockMetrics>,
614}
615
616#[derive(Debug)]
617struct ScannedProperty {
618 name: BlockIndex,
619 parent: BlockIndex,
620 payload: ScannedPayload,
621 metrics: BlockMetrics,
622}
623
624#[derive(Debug)]
625struct ScannedStringReference {
626 index: BlockIndex,
627 value: Vec<u8>,
628 length: usize,
629 next_extent: BlockIndex,
630}
631
632#[derive(Debug)]
633struct ScannedName {
634 name: String,
635 metrics: BlockMetrics,
636}
637
638#[derive(Debug)]
639struct ScannedExtent {
640 next: BlockIndex,
641 data: Vec<u8>,
642 metrics: BlockMetrics,
643}
644
645#[derive(Debug)]
646enum ScannedPayload {
647 String {
648 length: Option<usize>,
651 link: BlockIndex,
652 },
653 Bytes {
654 length: usize,
655 link: BlockIndex,
656 },
657 Int(i64),
658 Uint(u64),
659 Double(f64),
660 Bool(bool),
661 IntArray(Vec<i64>, ArrayFormat),
662 UintArray(Vec<u64>, ArrayFormat),
663 DoubleArray(Vec<f64>, ArrayFormat),
664 StringArray(Vec<BlockIndex>),
665 Link {
666 disposition: LinkNodeDisposition,
667 scanned_tree: Box<Scanner>,
668 },
669}
670
671trait BuildScannedPayload<K> {
672 fn build(block: ScannedBlock<'_, K>, _scanner: &mut Scanner) -> Result<ScannedPayload, Error>;
673}
674
675impl BuildScannedPayload<Int> for ScannedPayload {
676 fn build(block: ScannedBlock<'_, Int>, _scanner: &mut Scanner) -> Result<Self, Error> {
677 Ok(Self::Int(block.value()))
678 }
679}
680
681impl BuildScannedPayload<Uint> for ScannedPayload {
682 fn build(block: ScannedBlock<'_, Uint>, _scanner: &mut Scanner) -> Result<Self, Error> {
683 Ok(Self::Uint(block.value()))
684 }
685}
686
687impl BuildScannedPayload<Double> for ScannedPayload {
688 fn build(block: ScannedBlock<'_, Double>, _scanner: &mut Scanner) -> Result<Self, Error> {
689 Ok(Self::Double(block.value()))
690 }
691}
692
693impl BuildScannedPayload<Bool> for ScannedPayload {
694 fn build(block: ScannedBlock<'_, Bool>, _scanner: &mut Scanner) -> Result<Self, Error> {
695 Ok(Self::Bool(block.value()))
696 }
697}
698
699impl BuildScannedPayload<Buffer> for ScannedPayload {
700 fn build(block: ScannedBlock<'_, Buffer>, _scanner: &mut Scanner) -> Result<Self, Error> {
701 let format = block.format().ok_or_else(|| format_err!("invalid format"))?;
702 let link = block.extent_index();
703 Ok(match format {
704 PropertyFormat::String => {
705 let length = Some(block.total_length());
706 ScannedPayload::String { length, link }
707 }
708 PropertyFormat::Bytes => {
709 let length = block.total_length();
710 ScannedPayload::Bytes { length, link }
711 }
712 PropertyFormat::StringReference => ScannedPayload::String { link, length: None },
713 })
714 }
715}
716
717impl BuildScannedPayload<Array<Unknown>> for ScannedPayload {
718 fn build(
719 block: ScannedBlock<'_, Array<Unknown>>,
720 _scanner: &mut Scanner,
721 ) -> Result<Self, Error> {
722 let entry_type =
723 block.entry_type().ok_or_else(|| format_err!("unknown array entry type"))?;
724 let array_format = block.format().ok_or_else(|| format_err!("unknown array format"))?;
725 let slots = block.slots();
726 match entry_type {
727 BlockType::IntValue => {
728 let block = block.cast_array::<Int>().unwrap();
729 let numbers: Result<Vec<i64>, _> = (0..slots)
730 .map(|i| block.get(i).ok_or_else(|| format_err!("no entry at index: {i}")))
731 .collect();
732 Ok(ScannedPayload::IntArray(numbers?, array_format))
733 }
734 BlockType::UintValue => {
735 let block = block.cast_array::<Uint>().unwrap();
736 let numbers: Result<Vec<u64>, _> = (0..slots)
737 .map(|i| block.get(i).ok_or_else(|| format_err!("no entry at index: {i}")))
738 .collect();
739 Ok(ScannedPayload::UintArray(numbers?, array_format))
740 }
741 BlockType::DoubleValue => {
742 let block = block.cast_array::<Double>().unwrap();
743 let numbers: Result<Vec<f64>, _> = (0..slots)
744 .map(|i| block.get(i).ok_or_else(|| format_err!("no entry at index: {i}")))
745 .collect();
746 Ok(ScannedPayload::DoubleArray(numbers?, array_format))
747 }
748 BlockType::StringReference => {
749 let block = block.cast_array::<StringRef>().unwrap();
750 let indexes: Result<Vec<BlockIndex>, _> = (0..slots)
751 .map(|i| {
752 block
753 .get_string_index_at(i)
754 .ok_or_else(|| format_err!("no entry at index: {i}"))
755 })
756 .collect();
757 Ok(ScannedPayload::StringArray(indexes?))
758 }
759 illegal_type => {
760 Err(format_err!("No way I should see {:?} for ArrayEntryType", illegal_type))
761 }
762 }
763 }
764}
765
766impl BuildScannedPayload<Link> for ScannedPayload {
767 fn build(block: ScannedBlock<'_, Link>, scanner: &mut Scanner) -> Result<Self, Error> {
768 let child_name = scanner
769 .lookup_name_or_string_reference(block.content_index())
770 .context(format_err!("Child name not found for LinkValue block {}.", block.index()))?;
771 let child_trees = scanner
772 .child_trees
773 .as_mut()
774 .ok_or_else(|| format_err!("LinkValue encountered without child tree."))?;
775 let child_tree = child_trees.remove(&child_name).ok_or_else(|| {
776 format_err!(
777 "Lazy node not found for LinkValue block {} with name {}.",
778 block.index(),
779 child_name
780 )
781 })?;
782 Ok(ScannedPayload::Link {
783 disposition: block
784 .link_node_disposition()
785 .ok_or_else(|| format_err!("invalid disposition"))?,
786 scanned_tree: Box::new(Scanner::try_from(child_tree)?),
787 })
788 }
789}
790
791#[cfg(test)]
792mod tests {
793 use super::*;
794 use crate::*;
795 use fidl_diagnostics_validate::*;
796 use fuchsia_inspect::reader::snapshot::BackingBuffer;
797 use inspect_format::{
798 Block, BlockAccessorExt, BlockAccessorMutExt, HeaderFields, PayloadFields, ReadBytes,
799 constants,
800 };
801 use num_traits::ToPrimitive;
802
803 const MAX_BLOCK_BITS: usize = constants::MAX_ORDER_SIZE * BITS_PER_BYTE;
805
806 fn copy_into(source: &[u8], dest: &mut [u8], offset: usize) {
807 dest[offset..offset + source.len()].copy_from_slice(source);
808 }
809
810 fn try_byte(
814 buffer: &mut [u8],
815 (index, offset): (usize, usize),
816 value: u8,
817 predicted: Option<&str>,
818 ) {
819 let location = index * 16 + offset;
820 let previous = buffer[location];
821 buffer[location] = value;
822 let actual = data::Scanner::try_from(buffer as &[u8]).map(|d| d.data().to_string());
823
824 match (&predicted, &actual) {
825 (None, Err(actual)) => {
826 println!("With ({index},{offset}) -> {value}, got expected error {actual:?}");
827 }
828 (None, Ok(actual)) => {
829 println!(
830 "BAD: With ({},{}) -> {}, expected error but got string {:?}",
831 index, offset, value, actual
832 );
833 }
834 (Some(_), Err(actual)) => {
835 println!(
836 "BAD: With ({index},{offset}) -> {value}, got unexpected error {actual:?}"
837 );
838 }
839 (Some(predicted), Ok(actual)) => {
840 if predicted == actual {
841 println!(
842 "With ({},{}) -> {}, got expected string {:?}",
843 index, offset, value, predicted
844 );
845 } else {
846 println!(
847 "BAD: With ({},{}) -> {}, expected string {:?} but got {:?}",
848 index, offset, value, predicted, actual
849 );
850 println!("Raw data: {:?}", data::Scanner::try_from(buffer as &[u8]))
851 }
852 }
853 }
854 assert_eq!(predicted, actual.as_ref().ok().map(|s| &s[..]));
855 buffer[location] = previous;
856 }
857
858 fn put_header<T: ReadBytes>(header: &Block<&mut T, Unknown>, buffer: &mut [u8], index: usize) {
859 copy_into(&HeaderFields::value(header).to_le_bytes(), buffer, index * 16);
860 }
861
862 fn put_payload<T: ReadBytes>(
863 payload: &Block<&mut T, Unknown>,
864 buffer: &mut [u8],
865 index: usize,
866 ) {
867 copy_into(&PayloadFields::value(payload).to_le_bytes(), buffer, index * 16 + 8);
868 }
869
870 #[fuchsia::test]
871 fn test_scanning_string_reference() {
872 let mut buffer = [0u8; 4096];
873 const NODE: BlockIndex = BlockIndex::new(3);
874 const NUMBER_NAME: BlockIndex = BlockIndex::new(4);
875 const NUMBER_EXTENT: BlockIndex = BlockIndex::new(5);
876
877 let mut container = [0u8; 16];
879 let mut header = container.block_at_mut(BlockIndex::EMPTY);
880 HeaderFields::set_order(&mut header, 0);
881 HeaderFields::set_block_type(&mut header, BlockType::Header.to_u8().unwrap());
882 HeaderFields::set_header_magic(&mut header, constants::HEADER_MAGIC_NUMBER);
883 HeaderFields::set_header_version(&mut header, constants::HEADER_VERSION_NUMBER);
884 put_header(&header, &mut buffer, (*BlockIndex::HEADER).try_into().unwrap());
885
886 HeaderFields::set_order(&mut header, 0);
888 HeaderFields::set_block_type(&mut header, BlockType::NodeValue.to_u8().unwrap());
889 HeaderFields::set_value_name_index(&mut header, *NUMBER_NAME);
890 HeaderFields::set_value_parent_index(&mut header, *BlockIndex::HEADER);
891 put_header(&header, &mut buffer, (*NODE).try_into().unwrap());
892
893 HeaderFields::set_order(&mut header, 0);
895 HeaderFields::set_block_type(&mut header, BlockType::StringReference.to_u8().unwrap());
896 HeaderFields::set_extent_next_index(&mut header, *NUMBER_EXTENT);
897 put_header(&header, &mut buffer, (*NUMBER_NAME).try_into().unwrap());
898 copy_into(&[6, 0, 0, 0], &mut buffer, (*NUMBER_NAME * 16 + 8).try_into().unwrap());
899 copy_into(b"numb", &mut buffer, (*NUMBER_NAME * 16 + 12).try_into().unwrap());
900 let mut container = [0u8; 16];
901 let mut number_extent = container.block_at_mut(BlockIndex::EMPTY);
902 HeaderFields::set_order(&mut number_extent, 0);
903 HeaderFields::set_block_type(&mut number_extent, BlockType::Extent.to_u8().unwrap());
904 HeaderFields::set_extent_next_index(&mut number_extent, 0);
905 put_header(&number_extent, &mut buffer, (*NUMBER_EXTENT).try_into().unwrap());
906 copy_into(b"er", &mut buffer, (*NUMBER_EXTENT * 16 + 8).try_into().unwrap());
907
908 try_byte(&mut buffer, (16, 0), 0, Some("root ->\n> number ->"));
909 }
910
911 #[fuchsia::test]
912 fn test_scanning_logic() {
913 let mut buffer = [0u8; 4096];
914 const HEADER: usize = 0;
916 {
917 let mut container = [0u8; 16];
918 let mut header = container.block_at_mut(BlockIndex::EMPTY);
919 HeaderFields::set_order(&mut header, 0);
920 HeaderFields::set_block_type(&mut header, BlockType::Header.to_u8().unwrap());
921 HeaderFields::set_header_magic(&mut header, constants::HEADER_MAGIC_NUMBER);
922 HeaderFields::set_header_version(&mut header, constants::HEADER_VERSION_NUMBER);
923 put_header(&header, &mut buffer, HEADER);
924 }
925 const ROOT: usize = 1;
926 {
927 let mut container = [0u8; 16];
928 let mut header = container.block_at_mut(BlockIndex::EMPTY);
929 HeaderFields::set_order(&mut header, 0);
930 HeaderFields::set_block_type(&mut header, BlockType::NodeValue.to_u8().unwrap());
931 HeaderFields::set_value_name_index(&mut header, 2);
932 HeaderFields::set_value_parent_index(&mut header, 0);
933 put_header(&header, &mut buffer, ROOT);
934 }
935
936 const ROOT_NAME: usize = 2;
938 {
939 let mut container = [0u8; 16];
940 let mut header = container.block_at_mut(BlockIndex::EMPTY);
941 HeaderFields::set_order(&mut header, 0);
942 HeaderFields::set_block_type(&mut header, BlockType::Name.to_u8().unwrap());
943 HeaderFields::set_name_length(&mut header, 4);
944 put_header(&header, &mut buffer, ROOT_NAME);
945 }
946 copy_into(b"node", &mut buffer, ROOT_NAME * 16 + 8);
947 try_byte(&mut buffer, (16, 0), 0, Some("root ->\n> node ->"));
948 try_byte(&mut buffer, (HEADER, 7), 0, None);
950 try_byte(&mut buffer, (ROOT, 1), 1, Some("root ->"));
952 try_byte(&mut buffer, (ROOT, 5), 1, None);
954 try_byte(&mut buffer, (HEADER, 8), 1, None);
956 try_byte(&mut buffer, (HEADER, 8), 2, Some("root ->\n> node ->"));
958
959 const NUMBER: usize = 4;
961 let mut container = [0u8; 16];
962 let mut number_header = container.block_at_mut(BlockIndex::EMPTY);
963 HeaderFields::set_order(&mut number_header, 0);
964 HeaderFields::set_block_type(&mut number_header, BlockType::IntValue.to_u8().unwrap());
965 HeaderFields::set_value_name_index(&mut number_header, 3);
966 HeaderFields::set_value_parent_index(&mut number_header, 1);
967 put_header(&number_header, &mut buffer, NUMBER);
968 const NUMBER_NAME: usize = 3;
969 {
970 let mut container = [0u8; 16];
971 let mut header = container.block_at_mut(BlockIndex::EMPTY);
972 HeaderFields::set_order(&mut header, 0);
973 HeaderFields::set_block_type(&mut header, BlockType::Name.to_u8().unwrap());
974 HeaderFields::set_name_length(&mut header, 6);
975 put_header(&header, &mut buffer, NUMBER_NAME);
976 copy_into(b"number", &mut buffer, NUMBER_NAME * 16 + 8);
977 }
978
979 try_byte(&mut buffer, (HEADER, 8), 2, Some("root ->\n> node ->\n> > number: Int(0)"));
980 try_byte(&mut buffer, (NUMBER, 1), 5, Some("root ->\n> node ->\n> > number: Uint(0)"));
981 try_byte(&mut buffer, (NUMBER, 1), 6, Some("root ->\n> node ->\n> > number: Double(0.0)"));
982 try_byte(&mut buffer, (NUMBER, 1), 7, Some("root ->\n> node ->\n> > number: String(\"\")"));
983 try_byte(&mut buffer, (NUMBER, 1), 0xb0, None);
985 try_byte(&mut buffer, (NUMBER, 1), 0xf, None);
987 HeaderFields::set_order(&mut number_header, 2);
988 HeaderFields::set_block_type(&mut number_header, BlockType::ArrayValue.to_u8().unwrap());
989 put_header(&number_header, &mut buffer, NUMBER);
990 try_byte(&mut buffer, (128, 0), 0, None);
992 try_byte(
994 &mut buffer,
995 (NUMBER, 8),
996 0x04,
997 Some("root ->\n> node ->\n> > number: IntArray([], Default)"),
998 );
999 try_byte(
1000 &mut buffer,
1001 (NUMBER, 8),
1002 0x05,
1003 Some("root ->\n> node ->\n> > number: UintArray([], Default)"),
1004 );
1005 try_byte(
1006 &mut buffer,
1007 (NUMBER, 8),
1008 0x06,
1009 Some("root ->\n> node ->\n> > number: DoubleArray([], Default)"),
1010 );
1011 try_byte(
1013 &mut buffer,
1014 (NUMBER, 8),
1015 0x14,
1016 Some("root ->\n> node ->\n> > number: IntArray([], LinearHistogram)"),
1017 );
1018 try_byte(
1019 &mut buffer,
1020 (NUMBER, 8),
1021 0x24,
1022 Some("root ->\n> node ->\n> > number: IntArray([], ExponentialHistogram)"),
1023 );
1024 try_byte(&mut buffer, (NUMBER, 8), 0x34, None);
1025 try_byte(&mut buffer, (NUMBER, 8), BlockType::ArrayValue.to_u8().unwrap(), None);
1027 buffer[NUMBER * 16 + 8] = 4; buffer[NUMBER * 16 + 9] = 2; try_byte(
1030 &mut buffer,
1031 (NUMBER, 16),
1032 42,
1033 Some("root ->\n> node ->\n> > number: IntArray([42, 0], Default)"),
1034 );
1035 try_byte(
1036 &mut buffer,
1037 (NUMBER, 24),
1038 42,
1039 Some("root ->\n> node ->\n> > number: IntArray([0, 42], Default)"),
1040 );
1041 }
1042
1043 #[fuchsia::test]
1044 async fn test_to_string_order() -> Result<(), Error> {
1045 let int0 = Property {
1048 name: "int0".into(),
1049 id: 2.into(),
1050 parent: 1.into(),
1051 payload: Payload::Int(0),
1052 }
1053 .to_string("");
1054 let int1_struct = Property {
1055 name: "int1".into(),
1056 id: 2.into(),
1057 parent: 1.into(),
1058 payload: Payload::Int(1),
1059 };
1060 let int1 = int1_struct.to_string("");
1061 assert_ne!(int0, int1);
1062 let uint0 = Property {
1063 name: "uint0".into(),
1064 id: 2.into(),
1065 parent: 1.into(),
1066 payload: Payload::Uint(0),
1067 }
1068 .to_string("");
1069 assert_ne!(int0, uint0);
1070 let int0_different_name = Property {
1071 name: "int0_different_name".into(),
1072 id: 2.into(),
1073 parent: 1.into(),
1074 payload: Payload::Int(0),
1075 }
1076 .to_string("");
1077 assert_ne!(int0, int0_different_name);
1078 let uint0_different_ids = Property {
1079 name: "uint0".into(),
1080 id: 3.into(),
1081 parent: 4.into(),
1082 payload: Payload::Uint(0),
1083 }
1084 .to_string("");
1085 assert_eq!(uint0, uint0_different_ids);
1086 let int1_different_prefix = int1_struct.to_string("foo");
1087 assert_ne!(int1, int1_different_prefix);
1088 let mut puppet1 = puppet::tests::local_incomplete_puppet().await?;
1091 let mut child1_action = create_node!(parent:0, id:1, name:"child1");
1092 let mut child2_action = create_node!(parent:0, id:2, name:"child2");
1093 let mut property1_action =
1094 create_numeric_property!(parent:0, id:1, name:"prop1", value: Value::IntT(1));
1095 let mut property2_action =
1096 create_numeric_property!(parent:0, id:2, name:"prop2", value: Value::IntT(2));
1097 puppet1.apply(&mut child1_action).await?;
1098 puppet1.apply(&mut child2_action).await?;
1099 let mut puppet2 = puppet::tests::local_incomplete_puppet().await?;
1100 puppet2.apply(&mut child2_action).await?;
1101 puppet2.apply(&mut child1_action).await?;
1102 assert_eq!(puppet1.read_data().await?.to_string(), puppet2.read_data().await?.to_string());
1103 puppet1.apply(&mut property1_action).await?;
1104 puppet1.apply(&mut property2_action).await?;
1105 puppet2.apply(&mut property2_action).await?;
1106 puppet2.apply(&mut property1_action).await?;
1107 assert_eq!(puppet1.read_data().await?.to_string(), puppet2.read_data().await?.to_string());
1108 puppet1 = puppet::tests::local_incomplete_puppet().await?;
1110 puppet2 = puppet::tests::local_incomplete_puppet().await?;
1111 let mut subchild2_action = create_node!(parent:1, id:2, name:"child2");
1112 puppet1.apply(&mut child1_action).await?;
1113 puppet2.apply(&mut child1_action).await?;
1114 puppet1.apply(&mut child2_action).await?;
1115 puppet2.apply(&mut subchild2_action).await?;
1116 assert_ne!(puppet1.read_data().await?.to_string(), puppet2.read_data().await?.to_string());
1117 let mut subproperty2_action =
1119 create_numeric_property!(parent:1, id:2, name:"prop2", value: Value::IntT(1));
1120 puppet1.apply(&mut child1_action).await?;
1121 puppet2.apply(&mut child1_action).await?;
1122 puppet1.apply(&mut property2_action).await?;
1123 puppet2.apply(&mut subproperty2_action).await?;
1124 Ok(())
1125 }
1126
1127 #[fuchsia::test]
1128 fn test_bit_ops() -> Result<(), Error> {
1129 assert_eq!(low_bits(0xff, 3), 7);
1130 assert_eq!(low_bits(0x04, 3), 4);
1131 assert_eq!(low_bits(0xf8, 3), 0);
1132 assert_eq!(low_bits(0xab, 99), 0xab);
1133 assert_eq!(low_bits(0xff, 0), 0);
1134 assert_eq!(high_bits(0xff, 3), 0xe0);
1135 assert_eq!(high_bits(0x20, 3), 0x20);
1136 assert_eq!(high_bits(0x1f, 3), 0);
1137 assert_eq!(high_bits(0xab, 99), 0xab);
1138 assert_eq!(high_bits(0xff, 0), 0);
1139 Ok(())
1140 }
1141
1142 #[fuchsia::test]
1143 fn test_zero_bits() -> Result<(), Error> {
1144 let mut buffer = [0u8; 48];
1145 for byte in buffer.iter_mut().take(16) {
1146 *byte = 0xff;
1147 }
1148 for byte in buffer.iter_mut().skip(32) {
1149 *byte = 0xff;
1150 }
1151 {
1152 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1153 let block = backing_buffer.block_at(1.into());
1154 assert!(check_zero_bits(&buffer, &block, 1, 0).is_err());
1155 assert!(check_zero_bits(&buffer, &block, 0, 0).is_ok());
1156 assert!(check_zero_bits(&buffer, &block, 0, MAX_BLOCK_BITS).is_ok());
1157 }
1158 buffer[1 + 16] = 1;
1162 {
1165 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1166 let block = backing_buffer.block_at(1.into());
1167 assert!(check_zero_bits(&buffer, &block, 8, 8).is_err());
1168 assert!(check_zero_bits(&buffer, &block, 8, MAX_BLOCK_BITS).is_err());
1169 assert!(check_zero_bits(&buffer, &block, 9, MAX_BLOCK_BITS).is_ok());
1170 }
1171 buffer[2 + 16] = 0x80;
1172 {
1175 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1176 let block = backing_buffer.block_at(1.into());
1177 assert!(check_zero_bits(&buffer, &block, 9, MAX_BLOCK_BITS).is_err());
1178 assert!(check_zero_bits(&buffer, &block, 9, 22).is_ok());
1179 assert!(check_zero_bits(&buffer, &block, 24, MAX_BLOCK_BITS).is_ok());
1180 assert!(check_zero_bits(&buffer, &block, 24, 63).is_ok());
1181 }
1182 buffer[2 + 16] = 0x20;
1183 {
1185 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1186 let block = backing_buffer.block_at(1.into());
1187 assert!(check_zero_bits(&buffer, &block, 16, 20).is_ok());
1188 assert!(check_zero_bits(&buffer, &block, 21, 21).is_err());
1189 assert!(check_zero_bits(&buffer, &block, 22, 63).is_ok());
1190 }
1191 buffer[7 + 16] = 0x80;
1192 {
1194 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1195 let block = backing_buffer.block_at(1.into());
1196 assert!(check_zero_bits(&buffer, &block, 22, 63).is_err());
1197 assert!(check_zero_bits(&buffer, &block, 22, 62).is_ok());
1198 }
1199 buffer[3 + 16] = 0x10;
1200 {
1203 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1204 let block = backing_buffer.block_at(1.into());
1205 assert!(check_zero_bits(&buffer, &block, 22, 62).is_err());
1206 }
1207 buffer[3 + 16] = 0;
1208 buffer[4 + 16] = 0x10;
1209 {
1210 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1211 let block = backing_buffer.block_at(1.into());
1212 assert!(check_zero_bits(&buffer, &block, 22, 62).is_err());
1213 }
1214 buffer[4 + 16] = 0;
1215 buffer[5 + 16] = 0x10;
1216 {
1217 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1218 let block = backing_buffer.block_at(1.into());
1219 assert!(check_zero_bits(&buffer, &block, 22, 62).is_err());
1220 }
1221 buffer[5 + 16] = 0;
1222 buffer[6 + 16] = 0x10;
1223 {
1224 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1225 let block = backing_buffer.block_at(1.into());
1226 assert!(check_zero_bits(&buffer, &block, 22, 62).is_err());
1227 }
1228 buffer[1 + 16] = 0x81;
1229 {
1232 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1233 let block = backing_buffer.block_at(1.into());
1234 assert!(check_zero_bits(&buffer, &block, 9, 14).is_ok());
1235 assert!(check_zero_bits(&buffer, &block, 8, 14).is_err());
1236 assert!(check_zero_bits(&buffer, &block, 9, 15).is_err());
1237 }
1238 Ok(())
1239 }
1240
1241 #[fuchsia::test]
1242 fn test_reserved_fields() {
1243 let mut buffer = [0u8; 4096];
1244 const HEADER: usize = 0;
1246 {
1247 let mut container = [0u8; 16];
1248 let mut header = container.block_at_mut(BlockIndex::EMPTY);
1249 HeaderFields::set_order(&mut header, 0);
1250 HeaderFields::set_block_type(&mut header, BlockType::Header.to_u8().unwrap());
1251 HeaderFields::set_header_magic(&mut header, constants::HEADER_MAGIC_NUMBER);
1252 HeaderFields::set_header_version(&mut header, constants::HEADER_VERSION_NUMBER);
1253 put_header(&header, &mut buffer, HEADER);
1254 }
1255 const VALUE: usize = 1;
1256 let mut container = [0u8; 16];
1257 let mut value_header = container.block_at_mut(BlockIndex::EMPTY);
1258 HeaderFields::set_order(&mut value_header, 0);
1259 HeaderFields::set_block_type(&mut value_header, BlockType::NodeValue.to_u8().unwrap());
1260 HeaderFields::set_value_name_index(&mut value_header, 2);
1261 HeaderFields::set_value_parent_index(&mut value_header, 0);
1262 put_header(&value_header, &mut buffer, VALUE);
1263 const VALUE_NAME: usize = 2;
1265 {
1266 let mut buf = [0; 16];
1267 let mut header = buf.block_at_mut(0.into());
1268 HeaderFields::set_order(&mut header, 0);
1269 HeaderFields::set_block_type(&mut header, BlockType::Name.to_u8().unwrap());
1270 HeaderFields::set_name_length(&mut header, 5);
1271 put_header(&header, &mut buffer, VALUE_NAME);
1272 }
1273 copy_into(b"value", &mut buffer, VALUE_NAME * 16 + 8);
1274 const EXTENT: usize = 3;
1276 {
1277 let mut container = [0u8; 16];
1278 let mut header = container.block_at_mut(BlockIndex::EMPTY);
1279 HeaderFields::set_order(&mut header, 0);
1280 HeaderFields::set_block_type(&mut header, BlockType::Extent.to_u8().unwrap());
1281 HeaderFields::set_extent_next_index(&mut header, 0);
1282 put_header(&header, &mut buffer, EXTENT);
1283 }
1284 try_byte(&mut buffer, (16, 0), 0, Some("root ->\n> value ->"));
1286 try_byte(&mut buffer, (6, 7), 42, Some("root ->\n> value ->"));
1291 try_byte(&mut buffer, (VALUE_NAME, 7), 42, None);
1293 try_byte(&mut buffer, (EXTENT, 6), 42, None);
1295 HeaderFields::set_block_type(&mut value_header, BlockType::ArrayValue.to_u8().unwrap());
1296 put_header(&value_header, &mut buffer, VALUE);
1297 {
1298 let mut container = [0u8; 16];
1299 let mut array_subheader = container.block_at_mut(BlockIndex::EMPTY);
1300 PayloadFields::set_array_entry_type(
1301 &mut array_subheader,
1302 BlockType::IntValue.to_u8().unwrap(),
1303 );
1304 PayloadFields::set_array_flags(
1305 &mut array_subheader,
1306 ArrayFormat::Default.to_u8().unwrap(),
1307 );
1308 put_payload(&array_subheader, &mut buffer, VALUE);
1309 }
1310 try_byte(&mut buffer, (16, 0), 0, Some("root ->\n> value: IntArray([], Default)"));
1311 try_byte(&mut buffer, (VALUE, 12), 42, None);
1313 HeaderFields::set_block_type(&mut value_header, BlockType::IntValue.to_u8().unwrap());
1314 put_header(&value_header, &mut buffer, VALUE);
1315 try_byte(&mut buffer, (VALUE, 12), 42, Some("root ->\n> value: Int(180388626436)"));
1317 }
1318}