blob: ff94f086c8fd5b82f4d0654f164d6034de9c15d0 [file] [log] [blame]
// Copyright 2020 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.
#![cfg(test)]
mod quick_start_before {
// [START quick_start_before_decl]
struct Yak {
// TODO: Overflow risk at high altitudes?
hair_length: u16, // Current hair length in mm
credit_card_no: String, // Super secret
}
impl Yak {
pub fn new() -> Self {
Self { hair_length: 5, credit_card_no: "<secret>".to_string() }
}
pub fn shave(&mut self) {
self.hair_length = 0;
}
}
// [END quick_start_before_decl]
#[test]
fn init() {
// [START quick_start_before_init]
let mut yak = Yak::new();
yak.shave();
// [END quick_start_before_init]
let _ = yak.credit_card_no; // Prevent unused warning
assert_eq!(yak.hair_length, 0);
}
}
mod quick_start_after {
use fuchsia_inspect::{assert_inspect_tree, NumericProperty};
// [START quick_start_after_decl]
use fuchsia_inspect_derive::{
IValue, // A RAII smart pointer that can be attached to inspect
Inspect, // The core trait and derive-macro
WithInspect, // Provides `.with_inspect(..)`
};
#[derive(Inspect)]
struct Yak {
#[inspect(rename = "hair_length_mm")] // Clarify that it's millimeters
hair_length: IValue<u16>, // Encapsulate primitive in IValue
#[inspect(skip)] // Credit card number should NOT be exposed
credit_card_no: String,
shaved_counter: fuchsia_inspect::UintProperty, // Write-only counter
inspect_node: fuchsia_inspect::Node, // Inspect node of this Yak, optional
}
impl Yak {
pub fn new() -> Self {
Self {
hair_length: IValue::new(5), // Or if you prefer, `5.into()`
credit_card_no: "<secret>".to_string(),
// Inspect nodes and properties should be default-initialized
shaved_counter: fuchsia_inspect::UintProperty::default(),
inspect_node: fuchsia_inspect::Node::default(),
}
}
pub fn shave(&mut self) {
self.hair_length.iset(0); // Set the source value AND update the inspect property
self.shaved_counter.add(1u64); // Increment counter
}
}
// [END quick_start_after_decl]
#[allow(dead_code)]
impl Yak {
fn credit_card_no(&self) -> &str {
&self.credit_card_no
}
}
#[test]
fn init() -> Result<(), fuchsia_inspect_derive::AttachError> {
let inspector = fuchsia_inspect::Inspector::new();
// [START quick_start_after_init]
// Initialization
let mut yak = Yak::new()
.with_inspect(/* parent node */ inspector.root(), /* name */ "my_yak")?;
assert_inspect_tree!(inspector, root: {
my_yak: { hair_length_mm: 5u64, shaved_counter: 0u64 }
});
// Mutation
yak.shave();
assert_inspect_tree!(inspector, root: {
my_yak: { hair_length_mm: 0u64, shaved_counter: 1u64 }
});
// Destruction
std::mem::drop(yak);
assert_inspect_tree!(inspector, root: {});
// [END quick_start_after_init]
Ok(())
}
}
mod derive_inspect {
use fuchsia_inspect::{assert_inspect_tree, Node};
use fuchsia_inspect_derive::{AttachError, IValue, Inspect, WithInspect};
use std::cell::RefCell;
// [START inspect_node_present_decl]
#[derive(Inspect)]
struct Yak {
name: IValue<String>,
age: IValue<u16>,
inspect_node: fuchsia_inspect::Node, // NOTE: Node is present
}
// Yak is represented as a node with `name` and `age` properties.
// [END inspect_node_present_decl]
impl Yak {
fn new() -> Self {
Self {
name: "Lil Sebastian".to_string().into(),
age: 3.into(),
inspect_node: Node::default(),
}
}
}
// [START inspect_node_absent_decl]
#[derive(Inspect)]
struct YakName {
title: IValue<String>, // E.g. "Lil"
full_name: IValue<String>, // E.g. "Sebastian"
// NOTE: Node is absent
}
// YakName has no separate node. Instead, the `title` and `full_name`
// properties are attached directly to the parent node.
// [END inspect_node_absent_decl]
// [START inspect_forward_decl]
#[derive(Inspect)]
struct Wrapper {
// key is not included, because inspect has been forwarded.
_key: String,
#[inspect(forward)]
inner: RefCell<Inner>,
}
#[derive(Inspect)]
struct Inner {
name: IValue<String>,
age: IValue<u16>,
inspect_node: fuchsia_inspect::Node,
}
// Wrapper is represented as a node with `name` and `age` properties.
// [END inspect_forward_decl]
enum Horse {
Icelandic,
#[allow(dead_code)]
Arabian,
}
impl Inspect for &mut Horse {
fn iattach(self, _parent: &Node, _name: impl AsRef<str>) -> Result<(), AttachError> {
// Exercise
Ok(())
}
}
// [START inspect_nested_decl]
// Stable is represented as a node with two child nodes `yak` and `horse`
#[derive(Inspect)]
struct Stable {
yak: Yak, // Yak derives Inspect
horse: Horse, // Horse implements Inspect manually
inspect_node: fuchsia_inspect::Node,
}
// [END inspect_nested_decl]
impl Stable {
fn new() -> Self {
Self { yak: Yak::new(), horse: Horse::Icelandic, inspect_node: Node::default() }
}
}
#[test]
fn attach_yak() -> Result<(), AttachError> {
let inspector = fuchsia_inspect::Inspector::new();
// [START inspect_node_present_init]
let yak = Yak::new().with_inspect(inspector.root(), "my_yak")?;
assert_inspect_tree!(inspector, root: { my_yak: { name: "Lil Sebastian", age: 3u64 }});
// [END inspect_node_present_init]
let _ = yak; // Suppress unused warning
Ok(())
}
#[test]
fn attach_stable() -> Result<(), AttachError> {
let inspector = fuchsia_inspect::Inspector::new();
// [START inspect_nested_init]
// Stable owns a Yak, which also implements Inspect.
let stable = Stable::new().with_inspect(inspector.root(), "stable")?;
assert_inspect_tree!(inspector,
root: { stable: { yak: { name: "Lil Sebastian", age: 3u64 }}});
// [END inspect_nested_init]
let _ = stable; // Suppress unused warning
Ok(())
}
}
mod smart_pointers {
use fuchsia_inspect::assert_inspect_tree;
use fuchsia_inspect_derive::{AttachError, IValue, WithInspect};
#[test]
fn ivalue_demo() -> Result<(), AttachError> {
let inspector = fuchsia_inspect::Inspector::new();
// [START smart_pointers_ivalue]
let mut number = IValue::new(1337u16) // IValue is an IOwned smart pointer
.with_inspect(inspector.root(), "my_number")?; // Attach to inspect tree
// Dereference the value behind the IValue, without mutating
assert_eq!(*number, 1337u16);
{
// Mutate value behind an IOwned smart pointer, using a scope guard
let mut number_guard = number.as_mut();
*number_guard = 1338;
*number_guard += 1;
// Inspect state not yet updated
assert_inspect_tree!(inspector, root: { my_number: 1337u64 });
}
// When the guard goes out of scope, the inspect state is updated
assert_inspect_tree!(inspector, root: { my_number: 1339u64 });
number.iset(1340); // Sets the source value AND updates inspect
assert_inspect_tree!(inspector, root: { my_number: 1340u64 });
let inner = number.into_inner(); // Detaches from inspect tree...
assert_eq!(inner, 1340u16); // ...and returns the inner value.
// [END smart_pointers_ivalue]
assert_inspect_tree!(inspector, root: {});
Ok(())
}
}
mod unit {
use fuchsia_inspect::assert_inspect_tree;
use fuchsia_inspect_derive::{AttachError, IValue, WithInspect};
use fuchsia_inspect_derive::Unit;
// [START unit_plain_decl]
// Represented as a Node with two properties, `x` and `y`, of type UintProperty
#[derive(Unit)]
struct Point {
x: f32,
y: f32,
}
// [END unit_plain_decl]
// [START unit_nested_decl]
// Represented as a Node with two child nodes `top_left` and `bottom_right`
#[derive(Unit)]
struct Rect {
#[inspect(rename = "top_left")]
tl: Point,
#[inspect(rename = "bottom_right")]
br: Point,
}
// [END unit_nested_decl]
#[test]
fn unit_demo() -> Result<(), AttachError> {
let inspector = fuchsia_inspect::Inspector::new();
// [START unit_nested_init]
let rect_original = Rect { tl: Point { x: -3.0, y: 5.0 }, br: Point { x: 2.0, y: -1.5 } };
let rect = IValue::new(rect_original) // IValue wraps Rect, because it implements `Unit`
.with_inspect(inspector.root(), "rectangle")?;
assert_inspect_tree!(inspector, root: { rectangle: {
top_left: { x: -3f64, y: 5f64 },
bottom_right: { x: 2f64, y: -1.5f64 },
}});
// [END unit_nested_init]
std::mem::drop(rect);
assert_inspect_tree!(inspector, root: {});
Ok(())
}
}