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(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 =
276 self.nodes.remove(&node_id).ok_or(format_err!("No node at index {}", node_id))?;
277 match node.metrics {
278 None => {
279 if node_id != BlockIndex::ROOT {
280 return Err(format_err!("Invalid node (no metrics) at index {}", node_id));
281 }
282 }
283 Some(metrics) => {
284 self.metrics.record(&metrics, BlockStatus::Used);
286 node.metrics = Some(metrics); }
288 }
289 Ok(node)
290 }
291
292 fn use_property(&mut self, property_id: BlockIndex) -> Result<ScannedProperty, Error> {
293 let property = self
294 .properties
295 .remove(&property_id)
296 .ok_or(format_err!("No property at index {}", property_id))?;
297 self.metrics.record(&property.metrics, BlockStatus::Used);
298 Ok(property)
299 }
300
301 fn use_owned_name(&mut self, name_id: BlockIndex) -> Result<String, Error> {
304 match self.names.remove(&name_id) {
305 Some(name) => {
306 self.metrics.record(&name.metrics, BlockStatus::Used);
307 Ok(name.name)
308 }
309 None => match self.final_dereferenced_strings.get(&name_id) {
310 Some(value) => {
311 Ok(value.clone())
314 }
315 None => Err(format_err!("No string at index {}", name_id)),
316 },
317 }
318 }
319
320 fn lookup_name_or_string_reference(&mut self, name_id: BlockIndex) -> Result<String, Error> {
323 match self.names.get(&name_id) {
324 Some(name) => {
325 self.metrics.record(&name.metrics, BlockStatus::Used);
326 Ok(name.name.clone())
327 }
328 None => match self.final_dereferenced_strings.get(&name_id) {
329 Some(value) => {
330 Ok(value.clone())
333 }
334 None => Err(format_err!("No string at index {}", name_id)),
335 },
336 }
337 }
338
339 fn process_free(&mut self, block: ScannedBlock<'_, Unknown>) -> Result<(), Error> {
350 self.metrics.process(block)?;
353 Ok(())
354 }
355
356 fn process_header(&mut self, block: ScannedBlock<'_, Unknown>) -> Result<(), Error> {
357 self.metrics.process(block)?;
358 Ok(())
359 }
360
361 fn process_tombstone(&mut self, block: ScannedBlock<'_, Unknown>) -> Result<(), Error> {
362 self.metrics.process(block)?;
363 Ok(())
364 }
365
366 fn process_reserved(&mut self, block: ScannedBlock<'_, Unknown>) -> Result<(), Error> {
367 self.metrics.process(block)?;
368 Ok(())
369 }
370
371 fn process_extent(
372 &mut self,
373 block: ScannedBlock<'_, Unknown>,
374 buffer: &[u8],
375 ) -> Result<(), Error> {
376 check_zero_bits(buffer, &block, 40, 63)?;
377 let extent = block.clone().cast::<Extent>().unwrap();
378 let next = extent.next_extent();
379 let data = extent.contents()?.to_vec();
380 self.extents
381 .insert(block.index(), ScannedExtent { next, data, metrics: Metrics::analyze(block)? });
382 Ok(())
383 }
384
385 fn process_name(
386 &mut self,
387 block: ScannedBlock<'_, Unknown>,
388 buffer: &[u8],
389 ) -> Result<(), Error> {
390 check_zero_bits(buffer, &block, 28, 63)?;
391 let name_block = block.clone().cast::<Name>().unwrap();
392 let name = name_block.contents()?.to_string();
393 self.names.insert(block.index(), ScannedName { name, metrics: Metrics::analyze(block)? });
394 Ok(())
395 }
396
397 fn process_node(&mut self, block: ScannedBlock<'_, Unknown>) -> Result<(), Error> {
398 let node_block = block.clone().cast::<inspect_format::Node>().unwrap();
399 let parent = node_block.parent_index();
400 let id = node_block.index();
401 let name = node_block.name_index();
402 let mut node;
403 let metrics = Some(Metrics::analyze(block)?);
404 if let Some(placeholder) = self.nodes.remove(&id) {
405 node = placeholder;
407 node.validated = true;
408 node.parent = parent;
409 node.name = name;
410 node.metrics = metrics;
411 } else {
412 node = ScannedNode {
413 validated: true,
414 name,
415 parent,
416 children: HashSet::new(),
417 properties: HashSet::new(),
418 metrics,
419 }
420 }
421 self.nodes.insert(id, node);
422 self.add_to_parent(parent, id, |node| &mut node.children);
423 Ok(())
424 }
425
426 fn add_to_parent<F: FnOnce(&mut ScannedNode) -> &mut HashSet<BlockIndex>>(
427 &mut self,
428 parent: BlockIndex,
429 id: BlockIndex,
430 get_the_hashset: F, ) {
432 self.nodes.entry(parent).or_insert_with(|| ScannedNode {
433 validated: false,
434 name: BlockIndex::EMPTY,
435 parent: BlockIndex::ROOT,
436 children: HashSet::new(),
437 properties: HashSet::new(),
438 metrics: None,
439 });
440 if let Some(parent_node) = self.nodes.get_mut(&parent) {
441 get_the_hashset(parent_node).insert(id);
442 }
443 }
444
445 fn process_string_reference(
446 &mut self,
447 block: ScannedBlock<'_, Unknown>,
448 ) -> Result<ScannedStringReference, Error> {
449 let string_ref = block.clone().cast::<StringRef>().unwrap();
450 let scanned = ScannedStringReference {
451 index: block.index(),
452 value: string_ref.inline_data()?.to_vec(),
453 length: string_ref.total_length(),
454 next_extent: string_ref.next_extent(),
455 };
456
457 self.metrics.process(block)?;
458 Ok(scanned)
459 }
460
461 fn process_property<K>(
462 &mut self,
463 block: ScannedBlock<'_, Unknown>,
464 buffer: &[u8],
465 ) -> Result<(), Error>
466 where
467 K: ValueBlockKind + Clone,
468 ScannedPayload: BuildScannedPayload<K>,
469 {
470 if block.block_type() == Some(BlockType::ArrayValue) {
471 check_zero_bits(buffer, &block, 80, 127)?;
472 }
473 let property_block = block.clone().cast::<K>().unwrap();
474 let id = property_block.index();
475 let parent = property_block.parent_index();
476 let name = property_block.name_index();
477 let payload = ScannedPayload::build(property_block, self)?;
478 let property = ScannedProperty { name, parent, payload, metrics: Metrics::analyze(block)? };
479 self.properties.insert(id, property);
480 self.add_to_parent(parent, id, |node| &mut node.properties);
481 Ok(())
482 }
483
484 #[allow(clippy::type_complexity)]
487 fn make_valid_node_tree(
488 &mut self,
489 id: BlockIndex,
490 ) -> Result<(Vec<(Node, BlockIndex)>, Vec<(Property, BlockIndex)>), Error> {
491 let scanned_node = self.use_node(id)?;
492 if !scanned_node.validated {
493 return Err(format_err!("No node at {}", id));
494 }
495 let mut nodes_in_tree = vec![];
496 let mut properties_under = vec![];
497 for node_id in scanned_node.children.iter() {
498 let (mut nodes_of, mut properties_of) = self.make_valid_node_tree(*node_id)?;
499 nodes_in_tree.append(&mut nodes_of);
500 properties_under.append(&mut properties_of);
501 }
502 for property_id in scanned_node.properties.iter() {
503 properties_under.push((self.make_valid_property(*property_id)?, *property_id));
504 }
505 let name = if id == BlockIndex::ROOT {
506 ROOT_NAME.to_owned()
507 } else {
508 self.use_owned_name(scanned_node.name)?
509 };
510 let this_node = Node {
511 name,
512 parent: scanned_node.parent,
513 children: scanned_node.children.clone(),
514 properties: scanned_node.properties.clone(),
515 };
516 nodes_in_tree.push((this_node, id));
517 Ok((nodes_in_tree, properties_under))
518 }
519
520 fn make_valid_property(&mut self, id: BlockIndex) -> Result<Property, Error> {
521 let scanned_property = self.use_property(id)?;
522 let name = self.use_owned_name(scanned_property.name)?;
523 let payload = self.make_valid_payload(scanned_property.payload)?;
524 Ok(Property { id, name, parent: scanned_property.parent, payload })
525 }
526
527 fn make_valid_payload(&mut self, payload: ScannedPayload) -> Result<Payload, Error> {
528 Ok(match payload {
529 ScannedPayload::Int(data) => Payload::Int(data),
530 ScannedPayload::Uint(data) => Payload::Uint(data),
531 ScannedPayload::Double(data) => Payload::Double(data),
532 ScannedPayload::Bool(data) => Payload::Bool(data),
533 ScannedPayload::IntArray(data, format) => Payload::IntArray(data, format),
534 ScannedPayload::UintArray(data, format) => Payload::UintArray(data, format),
535 ScannedPayload::DoubleArray(data, format) => Payload::DoubleArray(data, format),
536 ScannedPayload::StringArray(indexes) => Payload::StringArray(
537 indexes
538 .iter()
539 .map(|i| {
540 if *i == BlockIndex::EMPTY {
541 return "".into();
542 }
543 self.final_dereferenced_strings.get(i).unwrap().clone()
544 })
545 .collect(),
546 ),
547 ScannedPayload::Bytes { length, link } => {
548 Payload::Bytes(self.make_valid_vector(length, link)?)
549 }
550 ScannedPayload::String { length, link } => {
551 Payload::String(if let Some(length) = length {
552 std::str::from_utf8(&self.make_valid_vector(length, link)?)?.to_owned()
553 } else {
554 self.final_dereferenced_strings.get(&link).unwrap().clone()
555 })
556 }
557 ScannedPayload::Link { disposition, scanned_tree } => {
558 Payload::Link { disposition, parsed_data: scanned_tree.data() }
559 }
560 })
561 }
562
563 fn expand_string_reference(
564 &mut self,
565 mut block: ScannedStringReference,
566 ) -> Result<String, Error> {
567 let length_of_inlined = block.value.len();
568 if block.next_extent != BlockIndex::EMPTY {
569 block.value.append(
570 &mut self.make_valid_vector(block.length - length_of_inlined, block.next_extent)?,
571 );
572 }
573
574 Ok(String::from_utf8(block.value)?)
575 }
576
577 fn make_valid_vector(&mut self, length: usize, link: BlockIndex) -> Result<Vec<u8>, Error> {
578 let mut dest = vec![];
579 let mut length_remaining = length;
580 let mut next_link = link;
581 while length_remaining > 0 {
582 let mut extent =
584 self.extents.remove(&next_link).ok_or(format_err!("No extent at {}", next_link))?;
585 let copy_len = min(extent.data.len(), length_remaining);
586 extent.metrics.set_data_bytes(copy_len);
587 self.metrics.record(&extent.metrics, BlockStatus::Used);
588 dest.extend_from_slice(&extent.data[..copy_len]);
589 length_remaining -= copy_len;
590 next_link = extent.next;
591 }
592 Ok(dest)
593 }
594}
595
596#[derive(Debug)]
597struct ScannedNode {
598 validated: bool,
605 name: BlockIndex,
606 parent: BlockIndex,
607 children: HashSet<BlockIndex>,
608 properties: HashSet<BlockIndex>,
609 metrics: Option<BlockMetrics>,
610}
611
612#[derive(Debug)]
613struct ScannedProperty {
614 name: BlockIndex,
615 parent: BlockIndex,
616 payload: ScannedPayload,
617 metrics: BlockMetrics,
618}
619
620#[derive(Debug)]
621struct ScannedStringReference {
622 index: BlockIndex,
623 value: Vec<u8>,
624 length: usize,
625 next_extent: BlockIndex,
626}
627
628#[derive(Debug)]
629struct ScannedName {
630 name: String,
631 metrics: BlockMetrics,
632}
633
634#[derive(Debug)]
635struct ScannedExtent {
636 next: BlockIndex,
637 data: Vec<u8>,
638 metrics: BlockMetrics,
639}
640
641#[derive(Debug)]
642enum ScannedPayload {
643 String {
644 length: Option<usize>,
647 link: BlockIndex,
648 },
649 Bytes {
650 length: usize,
651 link: BlockIndex,
652 },
653 Int(i64),
654 Uint(u64),
655 Double(f64),
656 Bool(bool),
657 IntArray(Vec<i64>, ArrayFormat),
658 UintArray(Vec<u64>, ArrayFormat),
659 DoubleArray(Vec<f64>, ArrayFormat),
660 StringArray(Vec<BlockIndex>),
661 Link {
662 disposition: LinkNodeDisposition,
663 scanned_tree: Box<Scanner>,
664 },
665}
666
667trait BuildScannedPayload<K> {
668 fn build(block: ScannedBlock<'_, K>, _scanner: &mut Scanner) -> Result<ScannedPayload, Error>;
669}
670
671impl BuildScannedPayload<Int> for ScannedPayload {
672 fn build(block: ScannedBlock<'_, Int>, _scanner: &mut Scanner) -> Result<Self, Error> {
673 Ok(Self::Int(block.value()))
674 }
675}
676
677impl BuildScannedPayload<Uint> for ScannedPayload {
678 fn build(block: ScannedBlock<'_, Uint>, _scanner: &mut Scanner) -> Result<Self, Error> {
679 Ok(Self::Uint(block.value()))
680 }
681}
682
683impl BuildScannedPayload<Double> for ScannedPayload {
684 fn build(block: ScannedBlock<'_, Double>, _scanner: &mut Scanner) -> Result<Self, Error> {
685 Ok(Self::Double(block.value()))
686 }
687}
688
689impl BuildScannedPayload<Bool> for ScannedPayload {
690 fn build(block: ScannedBlock<'_, Bool>, _scanner: &mut Scanner) -> Result<Self, Error> {
691 Ok(Self::Bool(block.value()))
692 }
693}
694
695impl BuildScannedPayload<Buffer> for ScannedPayload {
696 fn build(block: ScannedBlock<'_, Buffer>, _scanner: &mut Scanner) -> Result<Self, Error> {
697 let format = block.format().ok_or(format_err!("invalid format"))?;
698 let link = block.extent_index();
699 Ok(match format {
700 PropertyFormat::String => {
701 let length = Some(block.total_length());
702 ScannedPayload::String { length, link }
703 }
704 PropertyFormat::Bytes => {
705 let length = block.total_length();
706 ScannedPayload::Bytes { length, link }
707 }
708 PropertyFormat::StringReference => ScannedPayload::String { link, length: None },
709 })
710 }
711}
712
713impl BuildScannedPayload<Array<Unknown>> for ScannedPayload {
714 fn build(
715 block: ScannedBlock<'_, Array<Unknown>>,
716 _scanner: &mut Scanner,
717 ) -> Result<Self, Error> {
718 let entry_type = block.entry_type().ok_or(format_err!("unknown array entry type"))?;
719 let array_format = block.format().ok_or(format_err!("unknown array format"))?;
720 let slots = block.slots();
721 match entry_type {
722 BlockType::IntValue => {
723 let block = block.cast_array::<Int>().unwrap();
724 let numbers: Result<Vec<i64>, _> = (0..slots)
725 .map(|i| block.get(i).ok_or(format_err!("no entry at index: {i}")))
726 .collect();
727 Ok(ScannedPayload::IntArray(numbers?, array_format))
728 }
729 BlockType::UintValue => {
730 let block = block.cast_array::<Uint>().unwrap();
731 let numbers: Result<Vec<u64>, _> = (0..slots)
732 .map(|i| block.get(i).ok_or(format_err!("no entry at index: {i}")))
733 .collect();
734 Ok(ScannedPayload::UintArray(numbers?, array_format))
735 }
736 BlockType::DoubleValue => {
737 let block = block.cast_array::<Double>().unwrap();
738 let numbers: Result<Vec<f64>, _> = (0..slots)
739 .map(|i| block.get(i).ok_or(format_err!("no entry at index: {i}")))
740 .collect();
741 Ok(ScannedPayload::DoubleArray(numbers?, array_format))
742 }
743 BlockType::StringReference => {
744 let block = block.cast_array::<StringRef>().unwrap();
745 let indexes: Result<Vec<BlockIndex>, _> = (0..slots)
746 .map(|i| {
747 block.get_string_index_at(i).ok_or(format_err!("no entry at index: {i}"))
748 })
749 .collect();
750 Ok(ScannedPayload::StringArray(indexes?))
751 }
752 illegal_type => {
753 Err(format_err!("No way I should see {:?} for ArrayEntryType", illegal_type))
754 }
755 }
756 }
757}
758
759impl BuildScannedPayload<Link> for ScannedPayload {
760 fn build(block: ScannedBlock<'_, Link>, scanner: &mut Scanner) -> Result<Self, Error> {
761 let child_name = scanner
762 .lookup_name_or_string_reference(block.content_index())
763 .context(format_err!("Child name not found for LinkValue block {}.", block.index()))?;
764 let child_trees = scanner
765 .child_trees
766 .as_mut()
767 .ok_or(format_err!("LinkValue encountered without child tree."))?;
768 let child_tree = child_trees.remove(&child_name).ok_or(format_err!(
769 "Lazy node not found for LinkValue block {} with name {}.",
770 block.index(),
771 child_name
772 ))?;
773 Ok(ScannedPayload::Link {
774 disposition: block.link_node_disposition().ok_or(format_err!("invalid disposition"))?,
775 scanned_tree: Box::new(Scanner::try_from(child_tree)?),
776 })
777 }
778}
779
780#[cfg(test)]
781mod tests {
782 use super::*;
783 use crate::*;
784 use fidl_diagnostics_validate::*;
785 use fuchsia_inspect::reader::snapshot::BackingBuffer;
786 use inspect_format::{
787 Block, BlockAccessorExt, BlockAccessorMutExt, HeaderFields, PayloadFields, ReadBytes,
788 constants,
789 };
790 use num_traits::ToPrimitive;
791
792 const MAX_BLOCK_BITS: usize = constants::MAX_ORDER_SIZE * BITS_PER_BYTE;
794
795 fn copy_into(source: &[u8], dest: &mut [u8], offset: usize) {
796 dest[offset..offset + source.len()].copy_from_slice(source);
797 }
798
799 fn try_byte(
803 buffer: &mut [u8],
804 (index, offset): (usize, usize),
805 value: u8,
806 predicted: Option<&str>,
807 ) {
808 let location = index * 16 + offset;
809 let previous = buffer[location];
810 buffer[location] = value;
811 let actual = data::Scanner::try_from(buffer as &[u8]).map(|d| d.data().to_string());
812
813 match (&predicted, &actual) {
814 (None, Err(actual)) => {
815 println!("With ({index},{offset}) -> {value}, got expected error {actual:?}");
816 }
817 (None, Ok(actual)) => {
818 println!(
819 "BAD: With ({},{}) -> {}, expected error but got string {:?}",
820 index, offset, value, actual
821 );
822 }
823 (Some(_), Err(actual)) => {
824 println!(
825 "BAD: With ({index},{offset}) -> {value}, got unexpected error {actual:?}"
826 );
827 }
828 (Some(predicted), Ok(actual)) => {
829 if predicted == actual {
830 println!(
831 "With ({},{}) -> {}, got expected string {:?}",
832 index, offset, value, predicted
833 );
834 } else {
835 println!(
836 "BAD: With ({},{}) -> {}, expected string {:?} but got {:?}",
837 index, offset, value, predicted, actual
838 );
839 println!("Raw data: {:?}", data::Scanner::try_from(buffer as &[u8]))
840 }
841 }
842 }
843 assert_eq!(predicted, actual.as_ref().ok().map(|s| &s[..]));
844 buffer[location] = previous;
845 }
846
847 fn put_header<T: ReadBytes>(header: &Block<&mut T, Unknown>, buffer: &mut [u8], index: usize) {
848 copy_into(&HeaderFields::value(header).to_le_bytes(), buffer, index * 16);
849 }
850
851 fn put_payload<T: ReadBytes>(
852 payload: &Block<&mut T, Unknown>,
853 buffer: &mut [u8],
854 index: usize,
855 ) {
856 copy_into(&PayloadFields::value(payload).to_le_bytes(), buffer, index * 16 + 8);
857 }
858
859 #[fuchsia::test]
860 fn test_scanning_string_reference() {
861 let mut buffer = [0u8; 4096];
862 const NODE: BlockIndex = BlockIndex::new(3);
863 const NUMBER_NAME: BlockIndex = BlockIndex::new(4);
864 const NUMBER_EXTENT: BlockIndex = BlockIndex::new(5);
865
866 let mut container = [0u8; 16];
868 let mut header = container.block_at_mut(BlockIndex::EMPTY);
869 HeaderFields::set_order(&mut header, 0);
870 HeaderFields::set_block_type(&mut header, BlockType::Header.to_u8().unwrap());
871 HeaderFields::set_header_magic(&mut header, constants::HEADER_MAGIC_NUMBER);
872 HeaderFields::set_header_version(&mut header, constants::HEADER_VERSION_NUMBER);
873 put_header(&header, &mut buffer, (*BlockIndex::HEADER).try_into().unwrap());
874
875 HeaderFields::set_order(&mut header, 0);
877 HeaderFields::set_block_type(&mut header, BlockType::NodeValue.to_u8().unwrap());
878 HeaderFields::set_value_name_index(&mut header, *NUMBER_NAME);
879 HeaderFields::set_value_parent_index(&mut header, *BlockIndex::HEADER);
880 put_header(&header, &mut buffer, (*NODE).try_into().unwrap());
881
882 HeaderFields::set_order(&mut header, 0);
884 HeaderFields::set_block_type(&mut header, BlockType::StringReference.to_u8().unwrap());
885 HeaderFields::set_extent_next_index(&mut header, *NUMBER_EXTENT);
886 put_header(&header, &mut buffer, (*NUMBER_NAME).try_into().unwrap());
887 copy_into(&[6, 0, 0, 0], &mut buffer, (*NUMBER_NAME * 16 + 8).try_into().unwrap());
888 copy_into(b"numb", &mut buffer, (*NUMBER_NAME * 16 + 12).try_into().unwrap());
889 let mut container = [0u8; 16];
890 let mut number_extent = container.block_at_mut(BlockIndex::EMPTY);
891 HeaderFields::set_order(&mut number_extent, 0);
892 HeaderFields::set_block_type(&mut number_extent, BlockType::Extent.to_u8().unwrap());
893 HeaderFields::set_extent_next_index(&mut number_extent, 0);
894 put_header(&number_extent, &mut buffer, (*NUMBER_EXTENT).try_into().unwrap());
895 copy_into(b"er", &mut buffer, (*NUMBER_EXTENT * 16 + 8).try_into().unwrap());
896
897 try_byte(&mut buffer, (16, 0), 0, Some("root ->\n> number ->"));
898 }
899
900 #[fuchsia::test]
901 fn test_scanning_logic() {
902 let mut buffer = [0u8; 4096];
903 const HEADER: usize = 0;
905 {
906 let mut container = [0u8; 16];
907 let mut header = container.block_at_mut(BlockIndex::EMPTY);
908 HeaderFields::set_order(&mut header, 0);
909 HeaderFields::set_block_type(&mut header, BlockType::Header.to_u8().unwrap());
910 HeaderFields::set_header_magic(&mut header, constants::HEADER_MAGIC_NUMBER);
911 HeaderFields::set_header_version(&mut header, constants::HEADER_VERSION_NUMBER);
912 put_header(&header, &mut buffer, HEADER);
913 }
914 const ROOT: usize = 1;
915 {
916 let mut container = [0u8; 16];
917 let mut header = container.block_at_mut(BlockIndex::EMPTY);
918 HeaderFields::set_order(&mut header, 0);
919 HeaderFields::set_block_type(&mut header, BlockType::NodeValue.to_u8().unwrap());
920 HeaderFields::set_value_name_index(&mut header, 2);
921 HeaderFields::set_value_parent_index(&mut header, 0);
922 put_header(&header, &mut buffer, ROOT);
923 }
924
925 const ROOT_NAME: usize = 2;
927 {
928 let mut container = [0u8; 16];
929 let mut header = container.block_at_mut(BlockIndex::EMPTY);
930 HeaderFields::set_order(&mut header, 0);
931 HeaderFields::set_block_type(&mut header, BlockType::Name.to_u8().unwrap());
932 HeaderFields::set_name_length(&mut header, 4);
933 put_header(&header, &mut buffer, ROOT_NAME);
934 }
935 copy_into(b"node", &mut buffer, ROOT_NAME * 16 + 8);
936 try_byte(&mut buffer, (16, 0), 0, Some("root ->\n> node ->"));
937 try_byte(&mut buffer, (HEADER, 7), 0, None);
939 try_byte(&mut buffer, (ROOT, 1), 1, Some("root ->"));
941 try_byte(&mut buffer, (ROOT, 5), 1, None);
943 try_byte(&mut buffer, (HEADER, 8), 1, None);
945 try_byte(&mut buffer, (HEADER, 8), 2, Some("root ->\n> node ->"));
947
948 const NUMBER: usize = 4;
950 let mut container = [0u8; 16];
951 let mut number_header = container.block_at_mut(BlockIndex::EMPTY);
952 HeaderFields::set_order(&mut number_header, 0);
953 HeaderFields::set_block_type(&mut number_header, BlockType::IntValue.to_u8().unwrap());
954 HeaderFields::set_value_name_index(&mut number_header, 3);
955 HeaderFields::set_value_parent_index(&mut number_header, 1);
956 put_header(&number_header, &mut buffer, NUMBER);
957 const NUMBER_NAME: usize = 3;
958 {
959 let mut container = [0u8; 16];
960 let mut header = container.block_at_mut(BlockIndex::EMPTY);
961 HeaderFields::set_order(&mut header, 0);
962 HeaderFields::set_block_type(&mut header, BlockType::Name.to_u8().unwrap());
963 HeaderFields::set_name_length(&mut header, 6);
964 put_header(&header, &mut buffer, NUMBER_NAME);
965 copy_into(b"number", &mut buffer, NUMBER_NAME * 16 + 8);
966 }
967
968 try_byte(&mut buffer, (HEADER, 8), 2, Some("root ->\n> node ->\n> > number: Int(0)"));
969 try_byte(&mut buffer, (NUMBER, 1), 5, Some("root ->\n> node ->\n> > number: Uint(0)"));
970 try_byte(&mut buffer, (NUMBER, 1), 6, Some("root ->\n> node ->\n> > number: Double(0.0)"));
971 try_byte(&mut buffer, (NUMBER, 1), 7, Some("root ->\n> node ->\n> > number: String(\"\")"));
972 try_byte(&mut buffer, (NUMBER, 1), 0xb0, None);
974 try_byte(&mut buffer, (NUMBER, 1), 0xf, None);
976 HeaderFields::set_order(&mut number_header, 2);
977 HeaderFields::set_block_type(&mut number_header, BlockType::ArrayValue.to_u8().unwrap());
978 put_header(&number_header, &mut buffer, NUMBER);
979 try_byte(&mut buffer, (128, 0), 0, None);
981 try_byte(
983 &mut buffer,
984 (NUMBER, 8),
985 0x04,
986 Some("root ->\n> node ->\n> > number: IntArray([], Default)"),
987 );
988 try_byte(
989 &mut buffer,
990 (NUMBER, 8),
991 0x05,
992 Some("root ->\n> node ->\n> > number: UintArray([], Default)"),
993 );
994 try_byte(
995 &mut buffer,
996 (NUMBER, 8),
997 0x06,
998 Some("root ->\n> node ->\n> > number: DoubleArray([], Default)"),
999 );
1000 try_byte(
1002 &mut buffer,
1003 (NUMBER, 8),
1004 0x14,
1005 Some("root ->\n> node ->\n> > number: IntArray([], LinearHistogram)"),
1006 );
1007 try_byte(
1008 &mut buffer,
1009 (NUMBER, 8),
1010 0x24,
1011 Some("root ->\n> node ->\n> > number: IntArray([], ExponentialHistogram)"),
1012 );
1013 try_byte(&mut buffer, (NUMBER, 8), 0x34, None);
1014 try_byte(&mut buffer, (NUMBER, 8), BlockType::ArrayValue.to_u8().unwrap(), None);
1016 buffer[NUMBER * 16 + 8] = 4; buffer[NUMBER * 16 + 9] = 2; try_byte(
1019 &mut buffer,
1020 (NUMBER, 16),
1021 42,
1022 Some("root ->\n> node ->\n> > number: IntArray([42, 0], Default)"),
1023 );
1024 try_byte(
1025 &mut buffer,
1026 (NUMBER, 24),
1027 42,
1028 Some("root ->\n> node ->\n> > number: IntArray([0, 42], Default)"),
1029 );
1030 }
1031
1032 #[fuchsia::test]
1033 async fn test_to_string_order() -> Result<(), Error> {
1034 let int0 = Property {
1037 name: "int0".into(),
1038 id: 2.into(),
1039 parent: 1.into(),
1040 payload: Payload::Int(0),
1041 }
1042 .to_string("");
1043 let int1_struct = Property {
1044 name: "int1".into(),
1045 id: 2.into(),
1046 parent: 1.into(),
1047 payload: Payload::Int(1),
1048 };
1049 let int1 = int1_struct.to_string("");
1050 assert_ne!(int0, int1);
1051 let uint0 = Property {
1052 name: "uint0".into(),
1053 id: 2.into(),
1054 parent: 1.into(),
1055 payload: Payload::Uint(0),
1056 }
1057 .to_string("");
1058 assert_ne!(int0, uint0);
1059 let int0_different_name = Property {
1060 name: "int0_different_name".into(),
1061 id: 2.into(),
1062 parent: 1.into(),
1063 payload: Payload::Int(0),
1064 }
1065 .to_string("");
1066 assert_ne!(int0, int0_different_name);
1067 let uint0_different_ids = Property {
1068 name: "uint0".into(),
1069 id: 3.into(),
1070 parent: 4.into(),
1071 payload: Payload::Uint(0),
1072 }
1073 .to_string("");
1074 assert_eq!(uint0, uint0_different_ids);
1075 let int1_different_prefix = int1_struct.to_string("foo");
1076 assert_ne!(int1, int1_different_prefix);
1077 let mut puppet1 = puppet::tests::local_incomplete_puppet().await?;
1080 let mut child1_action = create_node!(parent:0, id:1, name:"child1");
1081 let mut child2_action = create_node!(parent:0, id:2, name:"child2");
1082 let mut property1_action =
1083 create_numeric_property!(parent:0, id:1, name:"prop1", value: Value::IntT(1));
1084 let mut property2_action =
1085 create_numeric_property!(parent:0, id:2, name:"prop2", value: Value::IntT(2));
1086 puppet1.apply(&mut child1_action).await?;
1087 puppet1.apply(&mut child2_action).await?;
1088 let mut puppet2 = puppet::tests::local_incomplete_puppet().await?;
1089 puppet2.apply(&mut child2_action).await?;
1090 puppet2.apply(&mut child1_action).await?;
1091 assert_eq!(puppet1.read_data().await?.to_string(), puppet2.read_data().await?.to_string());
1092 puppet1.apply(&mut property1_action).await?;
1093 puppet1.apply(&mut property2_action).await?;
1094 puppet2.apply(&mut property2_action).await?;
1095 puppet2.apply(&mut property1_action).await?;
1096 assert_eq!(puppet1.read_data().await?.to_string(), puppet2.read_data().await?.to_string());
1097 puppet1 = puppet::tests::local_incomplete_puppet().await?;
1099 puppet2 = puppet::tests::local_incomplete_puppet().await?;
1100 let mut subchild2_action = create_node!(parent:1, id:2, name:"child2");
1101 puppet1.apply(&mut child1_action).await?;
1102 puppet2.apply(&mut child1_action).await?;
1103 puppet1.apply(&mut child2_action).await?;
1104 puppet2.apply(&mut subchild2_action).await?;
1105 assert_ne!(puppet1.read_data().await?.to_string(), puppet2.read_data().await?.to_string());
1106 let mut subproperty2_action =
1108 create_numeric_property!(parent:1, id:2, name:"prop2", value: Value::IntT(1));
1109 puppet1.apply(&mut child1_action).await?;
1110 puppet2.apply(&mut child1_action).await?;
1111 puppet1.apply(&mut property2_action).await?;
1112 puppet2.apply(&mut subproperty2_action).await?;
1113 Ok(())
1114 }
1115
1116 #[fuchsia::test]
1117 fn test_bit_ops() -> Result<(), Error> {
1118 assert_eq!(low_bits(0xff, 3), 7);
1119 assert_eq!(low_bits(0x04, 3), 4);
1120 assert_eq!(low_bits(0xf8, 3), 0);
1121 assert_eq!(low_bits(0xab, 99), 0xab);
1122 assert_eq!(low_bits(0xff, 0), 0);
1123 assert_eq!(high_bits(0xff, 3), 0xe0);
1124 assert_eq!(high_bits(0x20, 3), 0x20);
1125 assert_eq!(high_bits(0x1f, 3), 0);
1126 assert_eq!(high_bits(0xab, 99), 0xab);
1127 assert_eq!(high_bits(0xff, 0), 0);
1128 Ok(())
1129 }
1130
1131 #[fuchsia::test]
1132 fn test_zero_bits() -> Result<(), Error> {
1133 let mut buffer = [0u8; 48];
1134 for byte in buffer.iter_mut().take(16) {
1135 *byte = 0xff;
1136 }
1137 for byte in buffer.iter_mut().skip(32) {
1138 *byte = 0xff;
1139 }
1140 {
1141 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1142 let block = backing_buffer.block_at(1.into());
1143 assert!(check_zero_bits(&buffer, &block, 1, 0).is_err());
1144 assert!(check_zero_bits(&buffer, &block, 0, 0).is_ok());
1145 assert!(check_zero_bits(&buffer, &block, 0, MAX_BLOCK_BITS).is_ok());
1146 }
1147 buffer[1 + 16] = 1;
1151 {
1154 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1155 let block = backing_buffer.block_at(1.into());
1156 assert!(check_zero_bits(&buffer, &block, 8, 8).is_err());
1157 assert!(check_zero_bits(&buffer, &block, 8, MAX_BLOCK_BITS).is_err());
1158 assert!(check_zero_bits(&buffer, &block, 9, MAX_BLOCK_BITS).is_ok());
1159 }
1160 buffer[2 + 16] = 0x80;
1161 {
1164 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1165 let block = backing_buffer.block_at(1.into());
1166 assert!(check_zero_bits(&buffer, &block, 9, MAX_BLOCK_BITS).is_err());
1167 assert!(check_zero_bits(&buffer, &block, 9, 22).is_ok());
1168 assert!(check_zero_bits(&buffer, &block, 24, MAX_BLOCK_BITS).is_ok());
1169 assert!(check_zero_bits(&buffer, &block, 24, 63).is_ok());
1170 }
1171 buffer[2 + 16] = 0x20;
1172 {
1174 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1175 let block = backing_buffer.block_at(1.into());
1176 assert!(check_zero_bits(&buffer, &block, 16, 20).is_ok());
1177 assert!(check_zero_bits(&buffer, &block, 21, 21).is_err());
1178 assert!(check_zero_bits(&buffer, &block, 22, 63).is_ok());
1179 }
1180 buffer[7 + 16] = 0x80;
1181 {
1183 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1184 let block = backing_buffer.block_at(1.into());
1185 assert!(check_zero_bits(&buffer, &block, 22, 63).is_err());
1186 assert!(check_zero_bits(&buffer, &block, 22, 62).is_ok());
1187 }
1188 buffer[3 + 16] = 0x10;
1189 {
1192 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1193 let block = backing_buffer.block_at(1.into());
1194 assert!(check_zero_bits(&buffer, &block, 22, 62).is_err());
1195 }
1196 buffer[3 + 16] = 0;
1197 buffer[4 + 16] = 0x10;
1198 {
1199 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1200 let block = backing_buffer.block_at(1.into());
1201 assert!(check_zero_bits(&buffer, &block, 22, 62).is_err());
1202 }
1203 buffer[4 + 16] = 0;
1204 buffer[5 + 16] = 0x10;
1205 {
1206 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1207 let block = backing_buffer.block_at(1.into());
1208 assert!(check_zero_bits(&buffer, &block, 22, 62).is_err());
1209 }
1210 buffer[5 + 16] = 0;
1211 buffer[6 + 16] = 0x10;
1212 {
1213 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1214 let block = backing_buffer.block_at(1.into());
1215 assert!(check_zero_bits(&buffer, &block, 22, 62).is_err());
1216 }
1217 buffer[1 + 16] = 0x81;
1218 {
1221 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1222 let block = backing_buffer.block_at(1.into());
1223 assert!(check_zero_bits(&buffer, &block, 9, 14).is_ok());
1224 assert!(check_zero_bits(&buffer, &block, 8, 14).is_err());
1225 assert!(check_zero_bits(&buffer, &block, 9, 15).is_err());
1226 }
1227 Ok(())
1228 }
1229
1230 #[fuchsia::test]
1231 fn test_reserved_fields() {
1232 let mut buffer = [0u8; 4096];
1233 const HEADER: usize = 0;
1235 {
1236 let mut container = [0u8; 16];
1237 let mut header = container.block_at_mut(BlockIndex::EMPTY);
1238 HeaderFields::set_order(&mut header, 0);
1239 HeaderFields::set_block_type(&mut header, BlockType::Header.to_u8().unwrap());
1240 HeaderFields::set_header_magic(&mut header, constants::HEADER_MAGIC_NUMBER);
1241 HeaderFields::set_header_version(&mut header, constants::HEADER_VERSION_NUMBER);
1242 put_header(&header, &mut buffer, HEADER);
1243 }
1244 const VALUE: usize = 1;
1245 let mut container = [0u8; 16];
1246 let mut value_header = container.block_at_mut(BlockIndex::EMPTY);
1247 HeaderFields::set_order(&mut value_header, 0);
1248 HeaderFields::set_block_type(&mut value_header, BlockType::NodeValue.to_u8().unwrap());
1249 HeaderFields::set_value_name_index(&mut value_header, 2);
1250 HeaderFields::set_value_parent_index(&mut value_header, 0);
1251 put_header(&value_header, &mut buffer, VALUE);
1252 const VALUE_NAME: usize = 2;
1254 {
1255 let mut buf = [0; 16];
1256 let mut header = buf.block_at_mut(0.into());
1257 HeaderFields::set_order(&mut header, 0);
1258 HeaderFields::set_block_type(&mut header, BlockType::Name.to_u8().unwrap());
1259 HeaderFields::set_name_length(&mut header, 5);
1260 put_header(&header, &mut buffer, VALUE_NAME);
1261 }
1262 copy_into(b"value", &mut buffer, VALUE_NAME * 16 + 8);
1263 const EXTENT: usize = 3;
1265 {
1266 let mut container = [0u8; 16];
1267 let mut header = container.block_at_mut(BlockIndex::EMPTY);
1268 HeaderFields::set_order(&mut header, 0);
1269 HeaderFields::set_block_type(&mut header, BlockType::Extent.to_u8().unwrap());
1270 HeaderFields::set_extent_next_index(&mut header, 0);
1271 put_header(&header, &mut buffer, EXTENT);
1272 }
1273 try_byte(&mut buffer, (16, 0), 0, Some("root ->\n> value ->"));
1275 try_byte(&mut buffer, (6, 7), 42, Some("root ->\n> value ->"));
1280 try_byte(&mut buffer, (VALUE_NAME, 7), 42, None);
1282 try_byte(&mut buffer, (EXTENT, 6), 42, None);
1284 HeaderFields::set_block_type(&mut value_header, BlockType::ArrayValue.to_u8().unwrap());
1285 put_header(&value_header, &mut buffer, VALUE);
1286 {
1287 let mut container = [0u8; 16];
1288 let mut array_subheader = container.block_at_mut(BlockIndex::EMPTY);
1289 PayloadFields::set_array_entry_type(
1290 &mut array_subheader,
1291 BlockType::IntValue.to_u8().unwrap(),
1292 );
1293 PayloadFields::set_array_flags(
1294 &mut array_subheader,
1295 ArrayFormat::Default.to_u8().unwrap(),
1296 );
1297 put_payload(&array_subheader, &mut buffer, VALUE);
1298 }
1299 try_byte(&mut buffer, (16, 0), 0, Some("root ->\n> value: IntArray([], Default)"));
1300 try_byte(&mut buffer, (VALUE, 12), 42, None);
1302 HeaderFields::set_block_type(&mut value_header, BlockType::IntValue.to_u8().unwrap());
1303 put_header(&value_header, &mut buffer, VALUE);
1304 try_byte(&mut buffer, (VALUE, 12), 42, Some("root ->\n> value: Int(180388626436)"));
1306 }
1307}