blob: 45a2e46d538a1952c24374f3ed0b5af5807b12cf [file] [log] [blame]
// 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 {
diagnostics_data::{InspectData, InspectHandleName},
diagnostics_hierarchy::{ArrayContent, DiagnosticsHierarchy, Property},
nom::HexDisplay,
num_traits::Bounded,
std::{
fmt,
ops::{Add, AddAssign, MulAssign},
},
};
const INDENT: usize = 2;
const HEX_DISPLAY_CHUNK_SIZE: usize = 16;
pub fn format<W>(w: &mut W, path: &str, diagnostics_hierarchy: DiagnosticsHierarchy) -> fmt::Result
where
W: fmt::Write,
{
writeln!(w, "{}:", path)?;
output_hierarchy(w, &diagnostics_hierarchy, 1)
}
pub fn output_schema<W>(w: &mut W, schema: &InspectData) -> fmt::Result
where
W: fmt::Write,
{
writeln!(w, "{}:", schema.moniker)?;
writeln!(w, " metadata:")?;
if let Some(errors) = &schema.metadata.errors {
writeln!(w, " errors = {}", errors.join(", "))?;
}
if let Some(name) = &schema.metadata.name {
match name {
InspectHandleName::Filename(f) => {
writeln!(w, " filename = {}", f)?;
}
InspectHandleName::Name(n) => {
writeln!(w, " name = {}", n)?;
}
}
}
write!(w, " component_url = ")?;
match &schema.metadata.component_url {
Some(url) => writeln!(w, "{}", url)?,
None => writeln!(w, "null")?,
}
writeln!(w, " timestamp = {}", schema.metadata.timestamp)?;
match &schema.payload {
Some(hierarchy) => {
writeln!(w, " payload:")?;
output_hierarchy(w, &hierarchy, 2)
}
None => writeln!(w, " payload: null"),
}
}
fn output_hierarchy<W>(
w: &mut W,
diagnostics_hierarchy: &DiagnosticsHierarchy,
indent: usize,
) -> fmt::Result
where
W: fmt::Write,
{
let name_indent = " ".repeat(INDENT * indent);
let value_indent = " ".repeat(INDENT * (indent + 1));
writeln!(w, "{}{}:", name_indent, diagnostics_hierarchy.name)?;
for property in &diagnostics_hierarchy.properties {
match property {
Property::String(name, value) => writeln!(w, "{}{} = {}", value_indent, name, value)?,
Property::Int(name, value) => writeln!(w, "{}{} = {}", value_indent, name, value)?,
Property::Uint(name, value) => writeln!(w, "{}{} = {}", value_indent, name, value)?,
Property::Double(name, value) => {
writeln!(w, "{}{} = {:.6}", value_indent, name, value)?
}
Property::Bytes(name, array) => {
let byte_str = array.to_hex(HEX_DISPLAY_CHUNK_SIZE);
writeln!(w, "{}{} = Binary:\n{}", value_indent, name, byte_str.trim())?;
}
Property::Bool(name, value) => writeln!(w, "{}{} = {}", value_indent, name, value)?,
Property::IntArray(name, array) => output_array(w, &value_indent, &name, &array)?,
Property::UintArray(name, array) => output_array(w, &value_indent, &name, &array)?,
Property::DoubleArray(name, array) => output_array(w, &value_indent, &name, &array)?,
Property::StringList(name, list) => {
writeln!(w, "{}{} = {:?}", value_indent, name, list)?;
}
}
}
for child in &diagnostics_hierarchy.children {
output_hierarchy(w, child, indent + 1)?;
}
Ok(())
}
fn output_array<T, W>(
w: &mut W,
value_indent: &str,
name: &str,
array: &ArrayContent<T>,
) -> fmt::Result
where
W: fmt::Write,
T: AddAssign + MulAssign + Copy + Add<Output = T> + fmt::Display + NumberFormat + Bounded,
{
write!(w, "{}{} = [", value_indent, name)?;
match array {
ArrayContent::Values(values) => {
for (i, value) in values.iter().enumerate() {
write!(w, "{}", value)?;
if i < values.len() - 1 {
write!(w, ", ")?;
}
}
}
ArrayContent::Buckets(buckets) => {
for (i, bucket) in buckets.iter().enumerate() {
write!(
w,
"[{},{})={}",
bucket.floor.format(),
bucket.ceiling.format(),
bucket.count.format()
)?;
if i < buckets.len() - 1 {
write!(w, ", ")?;
}
}
}
};
writeln!(w, "]")
}
trait NumberFormat {
fn format(&self) -> String;
}
impl NumberFormat for i64 {
fn format(&self) -> String {
match *self {
std::i64::MAX => "<max>".to_string(),
std::i64::MIN => "<min>".to_string(),
x => format!("{}", x),
}
}
}
impl NumberFormat for u64 {
fn format(&self) -> String {
match *self {
std::u64::MAX => "<max>".to_string(),
x => format!("{}", x),
}
}
}
impl NumberFormat for f64 {
fn format(&self) -> String {
if *self == std::f64::MAX || *self == std::f64::INFINITY {
"inf".to_string()
} else if *self == std::f64::MIN || *self == std::f64::NEG_INFINITY {
"-inf".to_string()
} else {
format!("{}", self)
}
}
}