fuchsia_inspect_contrib/nodes/
mod.rsuse std::{fmt, marker};
mod list;
mod lru_cache;
pub use list::BoundedListNode;
pub use lru_cache::LruCacheNode;
pub use zx::{BootTimeline, MonotonicTimeline};
use fuchsia_inspect::{InspectType, IntProperty, Node, Property, StringReference};
pub trait GetCurrentTime: zx::Timeline + Sized {
fn get_current_time() -> zx::Instant<Self>;
}
impl GetCurrentTime for zx::MonotonicTimeline {
fn get_current_time() -> zx::MonotonicInstant {
zx::MonotonicInstant::get()
}
}
impl GetCurrentTime for zx::BootTimeline {
fn get_current_time() -> zx::BootInstant {
zx::BootInstant::get()
}
}
pub struct CreateTimeResult<T> {
pub timestamp: zx::Instant<T>,
pub property: TimeProperty<T>,
}
pub trait NodeTimeExt<T: zx::Timeline> {
fn create_time(&self, name: impl Into<StringReference>) -> CreateTimeResult<T>;
fn create_time_at(
&self,
name: impl Into<StringReference>,
timestamp: zx::Instant<T>,
) -> TimeProperty<T>;
fn record_time(&self, name: impl Into<StringReference>) -> zx::Instant<T>;
}
impl<T> NodeTimeExt<T> for Node
where
T: zx::Timeline + GetCurrentTime,
{
fn create_time(&self, name: impl Into<StringReference>) -> CreateTimeResult<T> {
let timestamp = T::get_current_time();
CreateTimeResult { timestamp, property: self.create_time_at(name, timestamp) }
}
fn create_time_at(
&self,
name: impl Into<StringReference>,
timestamp: zx::Instant<T>,
) -> TimeProperty<T> {
TimeProperty {
inner: self.create_int(name, timestamp.into_nanos()),
_phantom: marker::PhantomData,
}
}
fn record_time(&self, name: impl Into<StringReference>) -> zx::Instant<T> {
let instant = T::get_current_time();
self.record_int(name, instant.into_nanos());
instant
}
}
#[derive(Debug)]
pub struct TimeProperty<T> {
pub(crate) inner: IntProperty,
_phantom: marker::PhantomData<T>,
}
impl<T> TimeProperty<T>
where
T: zx::Timeline + GetCurrentTime,
{
pub fn update(&self) {
self.set_at(T::get_current_time());
}
pub fn set_at(&self, timestamp: zx::Instant<T>) {
Property::set(&self.inner, timestamp.into_nanos());
}
}
pub type BootTimeProperty = TimeProperty<zx::BootTimeline>;
pub type MonotonicTimeProperty = TimeProperty<zx::MonotonicTimeline>;
impl<T: fmt::Debug + Send + Sync> InspectType for TimeProperty<T> {}
#[cfg(test)]
mod tests {
use super::*;
use diagnostics_assertions::{assert_data_tree, AnyProperty, PropertyAssertion};
use fuchsia_inspect::{DiagnosticsHierarchyGetter, Inspector};
use test_util::assert_lt;
#[fuchsia::test]
fn test_time_metadata_format() {
let inspector = Inspector::default();
let time_property = inspector
.root()
.create_time_at("time", zx::MonotonicInstant::from_nanos(123_456_700_000));
let t1 = validate_inspector_get_time(&inspector, 123_456_700_000i64);
time_property.set_at(zx::MonotonicInstant::from_nanos(333_005_000_000));
let t2 = validate_inspector_get_time(&inspector, 333_005_000_000i64);
time_property.set_at(zx::MonotonicInstant::from_nanos(333_444_000_000));
let t3 = validate_inspector_get_time(&inspector, 333_444_000_000i64);
assert_lt!(t1, t2);
assert_lt!(t2, t3);
}
#[fuchsia::test]
fn test_create_time_and_update() {
let inspector = Inspector::default();
let CreateTimeResult { timestamp: recorded_t1, property: time_property }: CreateTimeResult<
zx::MonotonicTimeline,
> = inspector.root().create_time("time");
let t1 = validate_inspector_get_time(&inspector, AnyProperty);
assert_eq!(recorded_t1.into_nanos(), t1);
time_property.update();
let t2 = validate_inspector_get_time(&inspector, AnyProperty);
time_property.update();
let t3 = validate_inspector_get_time(&inspector, AnyProperty);
assert_lt!(t1, t2);
assert_lt!(t2, t3);
}
#[fuchsia::test]
fn test_record_time() {
let before_time = zx::MonotonicInstant::get().into_nanos();
let inspector = Inspector::default();
NodeTimeExt::<zx::MonotonicTimeline>::record_time(inspector.root(), "time");
let after_time = validate_inspector_get_time(&inspector, AnyProperty);
assert_lt!(before_time, after_time);
}
#[fuchsia::test]
fn test_create_time_no_executor() {
let inspector = Inspector::default();
let _: CreateTimeResult<zx::MonotonicTimeline> = inspector.root().create_time("time");
}
#[fuchsia::test]
fn test_record_time_no_executor() {
let inspector = Inspector::default();
NodeTimeExt::<zx::MonotonicTimeline>::record_time(inspector.root(), "time");
}
fn validate_inspector_get_time<T>(inspector: &Inspector, expected: T) -> i64
where
T: PropertyAssertion<String> + 'static,
{
let hierarchy = inspector.get_diagnostics_hierarchy();
assert_data_tree!(hierarchy, root: { time: expected });
hierarchy.get_property("time").and_then(|t| t.int()).unwrap()
}
}