1use super::{Data, LazyNode, Metrics, Node, Payload, Property, ROOT_NAME};
6use crate::metrics::{BlockMetrics, BlockStatus};
7use anyhow::{bail, format_err, Context, Error};
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 constants, Block, BlockAccessorExt, BlockAccessorMutExt, HeaderFields, PayloadFields,
788 ReadBytes,
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 if predicted.is_none() {
813 if actual.is_err() {
814 println!("With ({index},{offset}) -> {value}, got expected error {actual:?}");
815 } else {
816 println!(
817 "BAD: With ({},{}) -> {}, expected error but got string {:?}",
818 index,
819 offset,
820 value,
821 actual.as_ref().unwrap()
822 );
823 }
824 } else if actual.is_err() {
825 println!("BAD: With ({index},{offset}) -> {value}, got unexpected error {actual:?}");
826 } else if actual.as_ref().ok().map(|s| &s[..]) == predicted {
827 println!(
828 "With ({},{}) -> {}, got expected string {:?}",
829 index,
830 offset,
831 value,
832 predicted.unwrap()
833 );
834 } else {
835 println!(
836 "BAD: With ({},{}) -> {}, expected string {:?} but got {:?}",
837 index,
838 offset,
839 value,
840 predicted.unwrap(),
841 actual.as_ref().unwrap()
842 );
843 println!("Raw data: {:?}", data::Scanner::try_from(buffer as &[u8]))
844 }
845 assert_eq!(predicted, actual.as_ref().ok().map(|s| &s[..]));
846 buffer[location] = previous;
847 }
848
849 fn put_header<T: ReadBytes>(header: &Block<&mut T, Unknown>, buffer: &mut [u8], index: usize) {
850 copy_into(&HeaderFields::value(header).to_le_bytes(), buffer, index * 16);
851 }
852
853 fn put_payload<T: ReadBytes>(
854 payload: &Block<&mut T, Unknown>,
855 buffer: &mut [u8],
856 index: usize,
857 ) {
858 copy_into(&PayloadFields::value(payload).to_le_bytes(), buffer, index * 16 + 8);
859 }
860
861 #[fuchsia::test]
862 fn test_scanning_string_reference() {
863 let mut buffer = [0u8; 4096];
864 const NODE: BlockIndex = BlockIndex::new(3);
865 const NUMBER_NAME: BlockIndex = BlockIndex::new(4);
866 const NUMBER_EXTENT: BlockIndex = BlockIndex::new(5);
867
868 let mut container = [0u8; 16];
870 let mut header = container.block_at_mut(BlockIndex::EMPTY);
871 HeaderFields::set_order(&mut header, 0);
872 HeaderFields::set_block_type(&mut header, BlockType::Header.to_u8().unwrap());
873 HeaderFields::set_header_magic(&mut header, constants::HEADER_MAGIC_NUMBER);
874 HeaderFields::set_header_version(&mut header, constants::HEADER_VERSION_NUMBER);
875 put_header(&header, &mut buffer, (*BlockIndex::HEADER).try_into().unwrap());
876
877 HeaderFields::set_order(&mut header, 0);
879 HeaderFields::set_block_type(&mut header, BlockType::NodeValue.to_u8().unwrap());
880 HeaderFields::set_value_name_index(&mut header, *NUMBER_NAME);
881 HeaderFields::set_value_parent_index(&mut header, *BlockIndex::HEADER);
882 put_header(&header, &mut buffer, (*NODE).try_into().unwrap());
883
884 HeaderFields::set_order(&mut header, 0);
886 HeaderFields::set_block_type(&mut header, BlockType::StringReference.to_u8().unwrap());
887 HeaderFields::set_extent_next_index(&mut header, *NUMBER_EXTENT);
888 put_header(&header, &mut buffer, (*NUMBER_NAME).try_into().unwrap());
889 copy_into(&[6, 0, 0, 0], &mut buffer, (*NUMBER_NAME * 16 + 8).try_into().unwrap());
890 copy_into(b"numb", &mut buffer, (*NUMBER_NAME * 16 + 12).try_into().unwrap());
891 let mut container = [0u8; 16];
892 let mut number_extent = container.block_at_mut(BlockIndex::EMPTY);
893 HeaderFields::set_order(&mut number_extent, 0);
894 HeaderFields::set_block_type(&mut number_extent, BlockType::Extent.to_u8().unwrap());
895 HeaderFields::set_extent_next_index(&mut number_extent, 0);
896 put_header(&number_extent, &mut buffer, (*NUMBER_EXTENT).try_into().unwrap());
897 copy_into(b"er", &mut buffer, (*NUMBER_EXTENT * 16 + 8).try_into().unwrap());
898
899 try_byte(&mut buffer, (16, 0), 0, Some("root ->\n> number ->"));
900 }
901
902 #[fuchsia::test]
903 fn test_scanning_logic() {
904 let mut buffer = [0u8; 4096];
905 const HEADER: usize = 0;
907 {
908 let mut container = [0u8; 16];
909 let mut header = container.block_at_mut(BlockIndex::EMPTY);
910 HeaderFields::set_order(&mut header, 0);
911 HeaderFields::set_block_type(&mut header, BlockType::Header.to_u8().unwrap());
912 HeaderFields::set_header_magic(&mut header, constants::HEADER_MAGIC_NUMBER);
913 HeaderFields::set_header_version(&mut header, constants::HEADER_VERSION_NUMBER);
914 put_header(&header, &mut buffer, HEADER);
915 }
916 const ROOT: usize = 1;
917 {
918 let mut container = [0u8; 16];
919 let mut header = container.block_at_mut(BlockIndex::EMPTY);
920 HeaderFields::set_order(&mut header, 0);
921 HeaderFields::set_block_type(&mut header, BlockType::NodeValue.to_u8().unwrap());
922 HeaderFields::set_value_name_index(&mut header, 2);
923 HeaderFields::set_value_parent_index(&mut header, 0);
924 put_header(&header, &mut buffer, ROOT);
925 }
926
927 const ROOT_NAME: usize = 2;
929 {
930 let mut container = [0u8; 16];
931 let mut header = container.block_at_mut(BlockIndex::EMPTY);
932 HeaderFields::set_order(&mut header, 0);
933 HeaderFields::set_block_type(&mut header, BlockType::Name.to_u8().unwrap());
934 HeaderFields::set_name_length(&mut header, 4);
935 put_header(&header, &mut buffer, ROOT_NAME);
936 }
937 copy_into(b"node", &mut buffer, ROOT_NAME * 16 + 8);
938 try_byte(&mut buffer, (16, 0), 0, Some("root ->\n> node ->"));
939 try_byte(&mut buffer, (HEADER, 7), 0, None);
941 try_byte(&mut buffer, (ROOT, 1), 1, Some("root ->"));
943 try_byte(&mut buffer, (ROOT, 5), 1, None);
945 try_byte(&mut buffer, (HEADER, 8), 1, None);
947 try_byte(&mut buffer, (HEADER, 8), 2, Some("root ->\n> node ->"));
949
950 const NUMBER: usize = 4;
952 let mut container = [0u8; 16];
953 let mut number_header = container.block_at_mut(BlockIndex::EMPTY);
954 HeaderFields::set_order(&mut number_header, 0);
955 HeaderFields::set_block_type(&mut number_header, BlockType::IntValue.to_u8().unwrap());
956 HeaderFields::set_value_name_index(&mut number_header, 3);
957 HeaderFields::set_value_parent_index(&mut number_header, 1);
958 put_header(&number_header, &mut buffer, NUMBER);
959 const NUMBER_NAME: usize = 3;
960 {
961 let mut container = [0u8; 16];
962 let mut header = container.block_at_mut(BlockIndex::EMPTY);
963 HeaderFields::set_order(&mut header, 0);
964 HeaderFields::set_block_type(&mut header, BlockType::Name.to_u8().unwrap());
965 HeaderFields::set_name_length(&mut header, 6);
966 put_header(&header, &mut buffer, NUMBER_NAME);
967 copy_into(b"number", &mut buffer, NUMBER_NAME * 16 + 8);
968 }
969
970 try_byte(&mut buffer, (HEADER, 8), 2, Some("root ->\n> node ->\n> > number: Int(0)"));
971 try_byte(&mut buffer, (NUMBER, 1), 5, Some("root ->\n> node ->\n> > number: Uint(0)"));
972 try_byte(&mut buffer, (NUMBER, 1), 6, Some("root ->\n> node ->\n> > number: Double(0.0)"));
973 try_byte(&mut buffer, (NUMBER, 1), 7, Some("root ->\n> node ->\n> > number: String(\"\")"));
974 try_byte(&mut buffer, (NUMBER, 1), 0xb0, None);
976 try_byte(&mut buffer, (NUMBER, 1), 0xf, None);
978 HeaderFields::set_order(&mut number_header, 2);
979 HeaderFields::set_block_type(&mut number_header, BlockType::ArrayValue.to_u8().unwrap());
980 put_header(&number_header, &mut buffer, NUMBER);
981 try_byte(&mut buffer, (128, 0), 0, None);
983 try_byte(
985 &mut buffer,
986 (NUMBER, 8),
987 0x04,
988 Some("root ->\n> node ->\n> > number: IntArray([], Default)"),
989 );
990 try_byte(
991 &mut buffer,
992 (NUMBER, 8),
993 0x05,
994 Some("root ->\n> node ->\n> > number: UintArray([], Default)"),
995 );
996 try_byte(
997 &mut buffer,
998 (NUMBER, 8),
999 0x06,
1000 Some("root ->\n> node ->\n> > number: DoubleArray([], Default)"),
1001 );
1002 try_byte(
1004 &mut buffer,
1005 (NUMBER, 8),
1006 0x14,
1007 Some("root ->\n> node ->\n> > number: IntArray([], LinearHistogram)"),
1008 );
1009 try_byte(
1010 &mut buffer,
1011 (NUMBER, 8),
1012 0x24,
1013 Some("root ->\n> node ->\n> > number: IntArray([], ExponentialHistogram)"),
1014 );
1015 try_byte(&mut buffer, (NUMBER, 8), 0x34, None);
1016 try_byte(&mut buffer, (NUMBER, 8), BlockType::ArrayValue.to_u8().unwrap(), None);
1018 buffer[NUMBER * 16 + 8] = 4; buffer[NUMBER * 16 + 9] = 2; try_byte(
1021 &mut buffer,
1022 (NUMBER, 16),
1023 42,
1024 Some("root ->\n> node ->\n> > number: IntArray([42, 0], Default)"),
1025 );
1026 try_byte(
1027 &mut buffer,
1028 (NUMBER, 24),
1029 42,
1030 Some("root ->\n> node ->\n> > number: IntArray([0, 42], Default)"),
1031 );
1032 }
1033
1034 #[fuchsia::test]
1035 async fn test_to_string_order() -> Result<(), Error> {
1036 let int0 = Property {
1039 name: "int0".into(),
1040 id: 2.into(),
1041 parent: 1.into(),
1042 payload: Payload::Int(0),
1043 }
1044 .to_string("");
1045 let int1_struct = Property {
1046 name: "int1".into(),
1047 id: 2.into(),
1048 parent: 1.into(),
1049 payload: Payload::Int(1),
1050 };
1051 let int1 = int1_struct.to_string("");
1052 assert_ne!(int0, int1);
1053 let uint0 = Property {
1054 name: "uint0".into(),
1055 id: 2.into(),
1056 parent: 1.into(),
1057 payload: Payload::Uint(0),
1058 }
1059 .to_string("");
1060 assert_ne!(int0, uint0);
1061 let int0_different_name = Property {
1062 name: "int0_different_name".into(),
1063 id: 2.into(),
1064 parent: 1.into(),
1065 payload: Payload::Int(0),
1066 }
1067 .to_string("");
1068 assert_ne!(int0, int0_different_name);
1069 let uint0_different_ids = Property {
1070 name: "uint0".into(),
1071 id: 3.into(),
1072 parent: 4.into(),
1073 payload: Payload::Uint(0),
1074 }
1075 .to_string("");
1076 assert_eq!(uint0, uint0_different_ids);
1077 let int1_different_prefix = int1_struct.to_string("foo");
1078 assert_ne!(int1, int1_different_prefix);
1079 let mut puppet1 = puppet::tests::local_incomplete_puppet().await?;
1082 let mut child1_action = create_node!(parent:0, id:1, name:"child1");
1083 let mut child2_action = create_node!(parent:0, id:2, name:"child2");
1084 let mut property1_action =
1085 create_numeric_property!(parent:0, id:1, name:"prop1", value: Value::IntT(1));
1086 let mut property2_action =
1087 create_numeric_property!(parent:0, id:2, name:"prop2", value: Value::IntT(2));
1088 puppet1.apply(&mut child1_action).await?;
1089 puppet1.apply(&mut child2_action).await?;
1090 let mut puppet2 = puppet::tests::local_incomplete_puppet().await?;
1091 puppet2.apply(&mut child2_action).await?;
1092 puppet2.apply(&mut child1_action).await?;
1093 assert_eq!(puppet1.read_data().await?.to_string(), puppet2.read_data().await?.to_string());
1094 puppet1.apply(&mut property1_action).await?;
1095 puppet1.apply(&mut property2_action).await?;
1096 puppet2.apply(&mut property2_action).await?;
1097 puppet2.apply(&mut property1_action).await?;
1098 assert_eq!(puppet1.read_data().await?.to_string(), puppet2.read_data().await?.to_string());
1099 puppet1 = puppet::tests::local_incomplete_puppet().await?;
1101 puppet2 = puppet::tests::local_incomplete_puppet().await?;
1102 let mut subchild2_action = create_node!(parent:1, id:2, name:"child2");
1103 puppet1.apply(&mut child1_action).await?;
1104 puppet2.apply(&mut child1_action).await?;
1105 puppet1.apply(&mut child2_action).await?;
1106 puppet2.apply(&mut subchild2_action).await?;
1107 assert_ne!(puppet1.read_data().await?.to_string(), puppet2.read_data().await?.to_string());
1108 let mut subproperty2_action =
1110 create_numeric_property!(parent:1, id:2, name:"prop2", value: Value::IntT(1));
1111 puppet1.apply(&mut child1_action).await?;
1112 puppet2.apply(&mut child1_action).await?;
1113 puppet1.apply(&mut property2_action).await?;
1114 puppet2.apply(&mut subproperty2_action).await?;
1115 Ok(())
1116 }
1117
1118 #[fuchsia::test]
1119 fn test_bit_ops() -> Result<(), Error> {
1120 assert_eq!(low_bits(0xff, 3), 7);
1121 assert_eq!(low_bits(0x04, 3), 4);
1122 assert_eq!(low_bits(0xf8, 3), 0);
1123 assert_eq!(low_bits(0xab, 99), 0xab);
1124 assert_eq!(low_bits(0xff, 0), 0);
1125 assert_eq!(high_bits(0xff, 3), 0xe0);
1126 assert_eq!(high_bits(0x20, 3), 0x20);
1127 assert_eq!(high_bits(0x1f, 3), 0);
1128 assert_eq!(high_bits(0xab, 99), 0xab);
1129 assert_eq!(high_bits(0xff, 0), 0);
1130 Ok(())
1131 }
1132
1133 #[fuchsia::test]
1134 fn test_zero_bits() -> Result<(), Error> {
1135 let mut buffer = [0u8; 48];
1136 for byte in buffer.iter_mut().take(16) {
1137 *byte = 0xff;
1138 }
1139 for byte in buffer.iter_mut().skip(32) {
1140 *byte = 0xff;
1141 }
1142 {
1143 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1144 let block = backing_buffer.block_at(1.into());
1145 assert!(check_zero_bits(&buffer, &block, 1, 0).is_err());
1146 assert!(check_zero_bits(&buffer, &block, 0, 0).is_ok());
1147 assert!(check_zero_bits(&buffer, &block, 0, MAX_BLOCK_BITS).is_ok());
1148 }
1149 buffer[1 + 16] = 1;
1153 {
1156 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1157 let block = backing_buffer.block_at(1.into());
1158 assert!(check_zero_bits(&buffer, &block, 8, 8).is_err());
1159 assert!(check_zero_bits(&buffer, &block, 8, MAX_BLOCK_BITS).is_err());
1160 assert!(check_zero_bits(&buffer, &block, 9, MAX_BLOCK_BITS).is_ok());
1161 }
1162 buffer[2 + 16] = 0x80;
1163 {
1166 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1167 let block = backing_buffer.block_at(1.into());
1168 assert!(check_zero_bits(&buffer, &block, 9, MAX_BLOCK_BITS).is_err());
1169 assert!(check_zero_bits(&buffer, &block, 9, 22).is_ok());
1170 assert!(check_zero_bits(&buffer, &block, 24, MAX_BLOCK_BITS).is_ok());
1171 assert!(check_zero_bits(&buffer, &block, 24, 63).is_ok());
1172 }
1173 buffer[2 + 16] = 0x20;
1174 {
1176 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1177 let block = backing_buffer.block_at(1.into());
1178 assert!(check_zero_bits(&buffer, &block, 16, 20).is_ok());
1179 assert!(check_zero_bits(&buffer, &block, 21, 21).is_err());
1180 assert!(check_zero_bits(&buffer, &block, 22, 63).is_ok());
1181 }
1182 buffer[7 + 16] = 0x80;
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, 22, 63).is_err());
1188 assert!(check_zero_bits(&buffer, &block, 22, 62).is_ok());
1189 }
1190 buffer[3 + 16] = 0x10;
1191 {
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, 62).is_err());
1197 }
1198 buffer[3 + 16] = 0;
1199 buffer[4 + 16] = 0x10;
1200 {
1201 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1202 let block = backing_buffer.block_at(1.into());
1203 assert!(check_zero_bits(&buffer, &block, 22, 62).is_err());
1204 }
1205 buffer[4 + 16] = 0;
1206 buffer[5 + 16] = 0x10;
1207 {
1208 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1209 let block = backing_buffer.block_at(1.into());
1210 assert!(check_zero_bits(&buffer, &block, 22, 62).is_err());
1211 }
1212 buffer[5 + 16] = 0;
1213 buffer[6 + 16] = 0x10;
1214 {
1215 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1216 let block = backing_buffer.block_at(1.into());
1217 assert!(check_zero_bits(&buffer, &block, 22, 62).is_err());
1218 }
1219 buffer[1 + 16] = 0x81;
1220 {
1223 let backing_buffer = BackingBuffer::from(buffer.to_vec());
1224 let block = backing_buffer.block_at(1.into());
1225 assert!(check_zero_bits(&buffer, &block, 9, 14).is_ok());
1226 assert!(check_zero_bits(&buffer, &block, 8, 14).is_err());
1227 assert!(check_zero_bits(&buffer, &block, 9, 15).is_err());
1228 }
1229 Ok(())
1230 }
1231
1232 #[fuchsia::test]
1233 fn test_reserved_fields() {
1234 let mut buffer = [0u8; 4096];
1235 const HEADER: usize = 0;
1237 {
1238 let mut container = [0u8; 16];
1239 let mut header = container.block_at_mut(BlockIndex::EMPTY);
1240 HeaderFields::set_order(&mut header, 0);
1241 HeaderFields::set_block_type(&mut header, BlockType::Header.to_u8().unwrap());
1242 HeaderFields::set_header_magic(&mut header, constants::HEADER_MAGIC_NUMBER);
1243 HeaderFields::set_header_version(&mut header, constants::HEADER_VERSION_NUMBER);
1244 put_header(&header, &mut buffer, HEADER);
1245 }
1246 const VALUE: usize = 1;
1247 let mut container = [0u8; 16];
1248 let mut value_header = container.block_at_mut(BlockIndex::EMPTY);
1249 HeaderFields::set_order(&mut value_header, 0);
1250 HeaderFields::set_block_type(&mut value_header, BlockType::NodeValue.to_u8().unwrap());
1251 HeaderFields::set_value_name_index(&mut value_header, 2);
1252 HeaderFields::set_value_parent_index(&mut value_header, 0);
1253 put_header(&value_header, &mut buffer, VALUE);
1254 const VALUE_NAME: usize = 2;
1256 {
1257 let mut buf = [0; 16];
1258 let mut header = buf.block_at_mut(0.into());
1259 HeaderFields::set_order(&mut header, 0);
1260 HeaderFields::set_block_type(&mut header, BlockType::Name.to_u8().unwrap());
1261 HeaderFields::set_name_length(&mut header, 5);
1262 put_header(&header, &mut buffer, VALUE_NAME);
1263 }
1264 copy_into(b"value", &mut buffer, VALUE_NAME * 16 + 8);
1265 const EXTENT: usize = 3;
1267 {
1268 let mut container = [0u8; 16];
1269 let mut header = container.block_at_mut(BlockIndex::EMPTY);
1270 HeaderFields::set_order(&mut header, 0);
1271 HeaderFields::set_block_type(&mut header, BlockType::Extent.to_u8().unwrap());
1272 HeaderFields::set_extent_next_index(&mut header, 0);
1273 put_header(&header, &mut buffer, EXTENT);
1274 }
1275 try_byte(&mut buffer, (16, 0), 0, Some("root ->\n> value ->"));
1277 try_byte(&mut buffer, (6, 7), 42, Some("root ->\n> value ->"));
1282 try_byte(&mut buffer, (VALUE_NAME, 7), 42, None);
1284 try_byte(&mut buffer, (EXTENT, 6), 42, None);
1286 HeaderFields::set_block_type(&mut value_header, BlockType::ArrayValue.to_u8().unwrap());
1287 put_header(&value_header, &mut buffer, VALUE);
1288 {
1289 let mut container = [0u8; 16];
1290 let mut array_subheader = container.block_at_mut(BlockIndex::EMPTY);
1291 PayloadFields::set_array_entry_type(
1292 &mut array_subheader,
1293 BlockType::IntValue.to_u8().unwrap(),
1294 );
1295 PayloadFields::set_array_flags(
1296 &mut array_subheader,
1297 ArrayFormat::Default.to_u8().unwrap(),
1298 );
1299 put_payload(&array_subheader, &mut buffer, VALUE);
1300 }
1301 try_byte(&mut buffer, (16, 0), 0, Some("root ->\n> value: IntArray([], Default)"));
1302 try_byte(&mut buffer, (VALUE, 12), 42, None);
1304 HeaderFields::set_block_type(&mut value_header, BlockType::IntValue.to_u8().unwrap());
1305 put_header(&value_header, &mut buffer, VALUE);
1306 try_byte(&mut buffer, (VALUE, 12), 42, Some("root ->\n> value: Int(180388626436)"));
1308 }
1309}