fuchsia_inspect_contrib/log/
wrappers.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use super::WriteInspect;
use fuchsia_inspect::{ArrayProperty, Node, StringReference};
use std::marker::PhantomData;

/// Wrapper to log bytes in an `inspect_log!` or `inspect_insert!` macro.
///
/// This wrapper is defined because a default `WriteInspect` implementation isn't provided for
/// an array or slice of bytes. Such default implementation was left out so that the user has
/// to explicitly choose whether to log bytes slice as a string or a byte vector in Inspect.
pub struct InspectBytes<T: AsRef<[u8]>>(pub T);

impl<T: AsRef<[u8]>> WriteInspect for InspectBytes<T> {
    fn write_inspect(&self, writer: &Node, key: impl Into<StringReference>) {
        writer.record_bytes(key, self.0.as_ref());
    }
}

/// Wrapper to log a list of items in `inspect_log!` or `inspect_insert!` macro. Each item
/// in the list must be a type that implements `WriteInspect`
///
/// Example:
/// ```
/// let list = ["foo", "bar", "baz"];
/// inspect_insert!(node_writer, some_list: InspectList(&list));
/// ```
///
/// The above code snippet would create the following child under node_writer:
/// ```
/// some_list:
///   0: "foo"
///   1: "bar"
///   2: "baz"
/// ```
pub struct InspectList<'a, T>(pub &'a [T]);

impl<'a, T> WriteInspect for InspectList<'a, T>
where
    T: WriteInspect,
{
    fn write_inspect(&self, writer: &Node, key: impl Into<StringReference>) {
        let child = writer.create_child(key);
        for (i, val) in self.0.iter().enumerate() {
            val.write_inspect(&child, i.to_string());
        }

        writer.record(child);
    }
}

/// Wrapper around a list `[T]` and a closure function `F` that determines how to map
/// and log each value of `T` in `inspect_log!` or `inspect_insert!` macro.
///
/// Example:
/// ```
/// let list = ["foo", "bar", "baz"]
/// let list_mapped = InspectListClosure(&list, |node_writer, key, item| {
///     let mapped_item = format!("super{}", item);
///     inspect_insert!(node_writer, var key: mapped_item);
/// });
/// inspect_insert!(node_writer, some_list: list_mapped);
/// ```
///
/// The above code snippet would create the following child under node_writer:
/// ```
/// some_list:
///   0: "superfoo"
///   1: "superbar"
///   2: "superbaz"
/// ```
pub struct InspectListClosure<'a, T, F>(pub &'a [T], pub F)
where
    F: Fn(&Node, &str, &T);

impl<'a, T, F> WriteInspect for InspectListClosure<'a, T, F>
where
    F: Fn(&Node, &str, &T),
{
    fn write_inspect(&self, writer: &Node, key: impl Into<StringReference>) {
        let child = writer.create_child(key);
        for (i, val) in self.0.iter().enumerate() {
            self.1(&child, &i.to_string(), val);
        }

        writer.record(child);
    }
}

/// Wrapper to log uint array in an `inspect_log!` or `inspect_insert!` macro.
pub struct InspectUintArray<T: AsRef<[I]>, I: Into<u64> + Clone> {
    pub items: T,
    _phantom: PhantomData<I>,
}

impl<T: AsRef<[I]>, I: Into<u64> + Clone> InspectUintArray<T, I> {
    pub fn new(items: T) -> Self {
        Self { items, _phantom: PhantomData }
    }
}

impl<T: AsRef<[I]>, I: Into<u64> + Clone> WriteInspect for InspectUintArray<T, I> {
    fn write_inspect(&self, node: &Node, key: impl Into<StringReference>) {
        let iter = self.items.as_ref().iter();
        let inspect_array = node.create_uint_array(key, iter.len());
        for (i, c) in iter.enumerate() {
            inspect_array.set(i, (*c).clone());
        }
        node.record(inspect_array);
    }
}