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