blob: 3fad27ad68b86a2d0387e2018617734c957040be [file] [log] [blame]
// Copyright 2018 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.
#ifndef LIB_INSPECT_CPP_VMO_TYPES_H_
#define LIB_INSPECT_CPP_VMO_TYPES_H_
#include <lib/fit/function.h>
#include <lib/fit/thread_safety.h>
#include <lib/fpromise/promise.h>
#include <lib/inspect/cpp/vmo/block.h>
#include <lib/stdcompat/optional.h>
#include <lib/stdcompat/span.h>
#include <lib/stdcompat/string_view.h>
#include <lib/stdcompat/variant.h>
#include <zircon/assert.h>
#include <zircon/compiler.h>
#include <zircon/types.h>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <mutex>
#include <string>
#include <type_traits>
#include <vector>
namespace inspect {
class Node;
class Inspector;
using LazyNodeCallbackFn = fit::function<fpromise::promise<Inspector>()>;
using AtomicUpdateCallbackFn = fit::function<void(Node&)>;
using RecordChildCallbackFn = fit::function<void(Node&)>;
// StringReference is a type that can be used as a name of a Node in the Inspect API.
// Each StringReference will have a single allocation in the appropriate VMO.
// StringReferences are lazy-node safe.
//
// StringReferences can be statically declared as a constant in namespace-scope.
// Example:
//
// `namespace {`
// `const StringReference kTimestamp("timestamp");`
// `} // namespace`
//
// Or,
// `static const StringReference kTimestamp("timestamp");`
class StringReference final {
public:
StringReference(StringReference&&) = default;
StringReference(const StringReference&) = default;
// Create a new `StringReference` for the given value.
//
// StringReference treats the data as borrowed; the caller is responsible for lifetime
// management. `data` must live as long as the StringReference. `data` must be null
// terminated.
explicit StringReference(const char* data);
// Access the data referenced by `this`.
cpp17::string_view Data() const;
// Access the state ID of the StringReference.
uint64_t ID() const;
private:
StringReference() = delete;
const cpp17::string_view data_;
const uint64_t reference_id_;
};
// `BorrowedStringValue` is a non-owning polymorphic type that allows the discrimination between
// single-use StringReference-as-names and user-declared StringReferences that have
// a re-usable state ID. This allows us to not do the work associated with maintaining
// the state ID when unnecessary.
using BorrowedStringValue = cpp17::variant<cpp17::string_view, StringReference>;
namespace internal {
class State;
// Base class for ValueHolder types, which approximate std::any.
struct BaseHolder {
virtual ~BaseHolder() = default;
};
// Holder for an arbitrary type.
template <typename T>
struct ValueHolder final : public BaseHolder {
explicit ValueHolder(T val) : value(std::move(val)) {}
~ValueHolder() override = default;
T value;
};
// A property containing a templated numeric type. All methods wrap the
// corresponding functionality on |State|, and concrete
// implementations are available only for int64_t, uint64_t and double.
template <typename T>
class NumericProperty final {
public:
// Construct a default numeric metric. Operations on this metric are
// no-ops.
NumericProperty() = default;
~NumericProperty();
// Allow moving, disallow copying.
NumericProperty(const NumericProperty& other) = delete;
NumericProperty(NumericProperty&& other) = default;
NumericProperty& operator=(const NumericProperty& other) = delete;
NumericProperty& operator=(NumericProperty&& other) noexcept;
// Set the value of this numeric metric to the given value.
void Set(T value);
// Add the given value to the value of this numeric metric.
void Add(T value);
// Subtract the given value from the value of this numeric metric.
void Subtract(T value);
// Return true if this metric is stored in a buffer. False otherwise.
explicit operator bool() const { return state_ != nullptr; }
private:
friend class ::inspect::internal::State;
NumericProperty(std::shared_ptr<internal::State> state, internal::BlockIndex name,
internal::BlockIndex value)
: state_(std::move(state)), name_index_(name), value_index_(value) {}
// Reference to the state containing this metric.
std::shared_ptr<internal::State> state_;
// Index of the name block in the state.
internal::BlockIndex name_index_;
// Index of the value block in the state.
internal::BlockIndex value_index_;
};
// A value containing an array of numeric types. All methods wrap the
// corresponding functionality on |State|, and concrete
// implementations are available only for int64_t, uint64_t and double.
template <typename T>
class ArrayValue final {
public:
// Construct a default array value. Operations on this value are
// no-ops.
ArrayValue() = default;
~ArrayValue();
// Allow moving, disallow copying.
ArrayValue(const ArrayValue& other) = delete;
ArrayValue(ArrayValue&& other) = default;
ArrayValue& operator=(const ArrayValue& other) = delete;
ArrayValue& operator=(ArrayValue&& other) noexcept;
// Set the value of the given index of this array.
void Set(size_t index, T value);
// Add the given value to the value of this numeric metric.
template <typename X = T,
typename = std::enable_if_t<!std::is_same<X, BorrowedStringValue>::value>>
void Add(size_t index, T value);
// Subtract the given value from the value of this numeric metric.
template <typename X = T,
typename = std::enable_if_t<!std::is_same<X, BorrowedStringValue>::value>>
void Subtract(size_t index, T value);
// Return true if this metric is stored in a buffer. False otherwise.
explicit operator bool() const { return state_ != nullptr; }
private:
friend class ::inspect::internal::State;
ArrayValue(std::shared_ptr<internal::State> state, internal::BlockIndex name,
internal::BlockIndex value)
: state_(std::move(state)), name_index_(name), value_index_(value) {}
// Reference to the state containing this value.
std::shared_ptr<internal::State> state_;
// Index of the name block in the state.
internal::BlockIndex name_index_;
// Index of the value block in the state.
internal::BlockIndex value_index_;
};
template <typename T>
class LinearHistogram final {
public:
// Create a default histogram.
// Operations on the metric will have no effect.
LinearHistogram() = default;
// Movable but not copyable.
LinearHistogram(const LinearHistogram& other) = delete;
LinearHistogram(LinearHistogram&& other) = default;
LinearHistogram& operator=(const LinearHistogram& other) = delete;
LinearHistogram& operator=(LinearHistogram&& other) = default;
// Insert the given value once to the correct bucket of the histogram.
void Insert(T value) { Insert(value, 1); }
// Insert the given value |count| times to the correct bucket of the
// histogram.
void Insert(T value, T count) { array_.Add(GetIndexForValue(value), count); }
private:
friend class ::inspect::Node;
// First slots are floor, step_size, and underflow.
static const size_t kBucketOffset = 3;
// Get the number of buckets, which excludes the two parameter slots and the
// two overflow slots.
size_t BucketCount() { return array_size_ - 4; }
// Calculates the correct array index to store the given value.
size_t GetIndexForValue(T value) {
if (array_size_ == 0) {
return 0;
}
size_t ret = kBucketOffset - 1;
T current_floor = floor_;
for (; value >= current_floor && ret < array_size_ - 1; current_floor += step_size_, ret++) {
}
return ret;
}
// Internal constructor wrapping an array.
LinearHistogram(T floor, T step_size, size_t array_size, ArrayValue<T> array)
: floor_(floor), step_size_(step_size), array_size_(array_size), array_(std::move(array)) {
ZX_ASSERT(array_size_ > 4);
array_.Set(0, floor_);
array_.Set(1, step_size_);
}
T floor_ = 0;
T step_size_ = 0;
size_t array_size_ = 0;
ArrayValue<T> array_;
};
template <typename T>
class ExponentialHistogram final {
public:
// Create a default histogram.
// Operations on the metric will have no effect.
ExponentialHistogram() = default;
// Movable but not copyable.
ExponentialHistogram(const ExponentialHistogram& other) = delete;
ExponentialHistogram(ExponentialHistogram&& other) = default;
ExponentialHistogram& operator=(const ExponentialHistogram& other) = delete;
ExponentialHistogram& operator=(ExponentialHistogram&& other) = default;
// Insert the given value once to the correct bucket of the histogram.
void Insert(T value) { Insert(value, 1); }
// Insert the given value |count| times to the correct bucket of the
// histogram.
void Insert(T value, T count) { array_.Add(GetIndexForValue(value), count); }
private:
friend class ::inspect::Node;
// First slots are floor, initial_step, step_multiplier, and underflow.
static const size_t kBucketOffset = 4;
// Get the number of buckets, which excludes the two parameter slots and the
// two overflow slots.
size_t BucketCount() { return array_size_ - 5; }
// Calculates the correct array index to store the given value.
size_t GetIndexForValue(T value) {
if (array_size_ == 0) {
return 0;
}
T current_floor = floor_;
T current_step = initial_step_;
size_t ret = kBucketOffset - 1;
while (value >= current_floor && ret < array_size_ - 1) {
current_floor = floor_ + current_step;
current_step *= step_multiplier_;
ret++;
}
return ret;
}
// Internal constructor wrapping a VMO type.
ExponentialHistogram(T floor, T initial_step, T step_multiplier, size_t array_size,
ArrayValue<T> array)
: floor_(floor),
initial_step_(initial_step),
step_multiplier_(step_multiplier),
array_size_(array_size),
array_(std::move(array)) {
ZX_ASSERT(array_size_ > 5);
array_.Set(0, floor_);
array_.Set(1, initial_step_);
array_.Set(2, step_multiplier_);
}
T floor_ = 0;
T initial_step_ = 0;
T step_multiplier_ = 0;
size_t array_size_ = 0;
ArrayValue<T> array_;
};
// A property containing a string value.
// All methods wrap the corresponding functionality on |State|.
template <typename T>
class Property final {
public:
// Construct a default property. Operations on this property are
// no-ops.
Property() = default;
~Property();
// Allow moving, disallow copying.
Property(const Property& other) = delete;
Property(Property&& other) = default;
Property& operator=(const Property& other) = delete;
Property& operator=(Property&& other) noexcept;
// Return true if this property is stored in a buffer. False otherwise.
explicit operator bool() const { return state_ != nullptr; }
// Set the value of this property.
void Set(const T& value);
private:
friend class ::inspect::internal::State;
Property(std::shared_ptr<internal::State> state, internal::BlockIndex name,
internal::BlockIndex value)
: state_(std::move(state)), name_index_(name), value_index_(value) {}
// Reference to the state containing this property.
std::shared_ptr<internal::State> state_;
// Index of the name block in the state.
internal::BlockIndex name_index_;
// Index of the value block in the state.
internal::BlockIndex value_index_;
};
} // namespace internal
using IntProperty = internal::NumericProperty<int64_t>;
using UintProperty = internal::NumericProperty<uint64_t>;
using DoubleProperty = internal::NumericProperty<double>;
using BoolProperty = internal::Property<bool>;
using IntArray = internal::ArrayValue<int64_t>;
using UintArray = internal::ArrayValue<uint64_t>;
using DoubleArray = internal::ArrayValue<double>;
using StringArray = internal::ArrayValue<BorrowedStringValue>;
using LinearIntHistogram = internal::LinearHistogram<int64_t>;
using LinearUintHistogram = internal::LinearHistogram<uint64_t>;
using LinearDoubleHistogram = internal::LinearHistogram<double>;
using ExponentialIntHistogram = internal::ExponentialHistogram<int64_t>;
using ExponentialUintHistogram = internal::ExponentialHistogram<uint64_t>;
using ExponentialDoubleHistogram = internal::ExponentialHistogram<double>;
using StringProperty = internal::Property<std::string>;
using ByteVectorProperty = internal::Property<std::vector<uint8_t>>;
// Links specify a location that can be read as a continuation of an Inspect hierarchy.
class Link final {
public:
// Construct a default link.
Link() = default;
~Link();
// Allow moving, disallow copying.
Link(const Link& other) = delete;
Link(Link&& other) = default;
Link& operator=(const Link& other) = delete;
Link& operator=(Link&& other) noexcept;
// Return true if this node is stored in a buffer. False otherwise.
explicit operator bool() const { return state_ != nullptr; }
private:
friend class ::inspect::internal::State;
Link(std::shared_ptr<internal::State> state, internal::BlockIndex name,
internal::BlockIndex value, internal::BlockIndex content)
: state_(std::move(state)), name_index_(name), value_index_(value), content_index_(content) {}
// Remove from `state_` and invalidate `state_`.
// This needs to be done on destruction and move.
void DeallocateFromVmo();
// Reference to the state containing this value.
std::shared_ptr<internal::State> state_;
// Index of the name block in the state.
internal::BlockIndex name_index_;
// Index of the value block in the state.
internal::BlockIndex value_index_;
// Index of the content block in the state.
internal::BlockIndex content_index_;
};
// A LazyNode has a value that is dynamically set by a callback.
class LazyNode final {
public:
// Construct a default LazyNode.
LazyNode() = default;
~LazyNode();
// Allow moving, disallow copying.
LazyNode(const LazyNode& other) = delete;
LazyNode(LazyNode&& other) = default;
LazyNode& operator=(const LazyNode& other) = delete;
LazyNode& operator=(LazyNode&& other) noexcept;
// Return true if this value is represented in a buffer. False otherwise.
explicit operator bool() const { return state_ != nullptr; }
private:
friend class ::inspect::internal::State;
LazyNode(std::shared_ptr<internal::State> state, std::string content_value, Link link)
: state_(std::move(state)),
content_value_(std::move(content_value)),
link_(std::move(link)) {}
// Remove from `state_` and invalidate `state_`.
// This needs to be done on destruction and move.
void DeallocateFromVmo();
// Reference to the state containing this value.
std::shared_ptr<internal::State> state_;
// The value stored in the contents of the Link for this node. Used as a key for removal when
// deleted.
std::string content_value_;
// The Link node that references this LazyNode.
Link link_;
};
namespace internal {
enum StringReferenceWrapperDiscriminant {
isStringLiteral,
isStringReference,
};
class InnerValueList final {
public:
InnerValueList() = default;
// Disallow copy and assign.
InnerValueList(const InnerValueList&) = delete;
InnerValueList(InnerValueList&& other) = delete;
InnerValueList& operator=(const InnerValueList&) = delete;
InnerValueList& operator=(InnerValueList&& other) = delete;
// Emplaces a value in this ValueList.
template <typename T>
void emplace(T value) {
std::lock_guard<std::mutex> lock(mutex_);
values_.emplace_back(std::make_unique<internal::ValueHolder<T>>(std::move(value)));
}
void clear() {
std::lock_guard<std::mutex> lock(mutex_);
values_.clear();
}
private:
mutable std::mutex mutex_;
// The list of values.
std::vector<std::unique_ptr<internal::BaseHolder>> values_ FIT_GUARDED(mutex_);
};
} // namespace internal
// A ValueList is a holder for arbitrary values that do not need to be explicitly named or modified
// after creation.
//
// This class is not thread-safe, and it requires external synchronization if accessed from multiple
// threads.
//
// Example:
// struct Item {
// // The inspect::Node for this item.
// Node node;
//
// // List of unnamed values that should be retained for this item.
// ValueList values;
//
// Item(Node* parent, const std::string& name, int value) {
// node = parent->CreateChild(name);
// // Expose the value, but enlist it in the ValueList so it doesn't need a name.
// node.CreateInt("value", value, &values);
// // "Stats" computes and stores some stats under the node it is given. Keep this in the
// // ValueList as well since it doesn't need a name.
// values.emplace(Stats(this, node.CreateChild("stats")));
// }
// }
class ValueList final {
public:
ValueList() { list_ = std::make_shared<internal::InnerValueList>(); }
// Disallow copy and assign.
// ValueList(const ValueList&) = delete;
// ValueList(ValueList&& other) = delete;
// ValueList& operator=(const ValueList&) = delete;
// ValueList& operator=(ValueList&& other) = delete;
// Emplaces a value in this ValueList.
template <typename T>
void emplace(T value) {
list_->emplace(std::move(value));
}
void clear() { list_->clear(); }
private:
std::shared_ptr<internal::InnerValueList> list_;
};
// A node under which properties, metrics, and other nodes may be nested.
// All methods wrap the corresponding functionality on |State|.
class Node final {
public:
// Construct a default node. Operations on this node are
// no-ops.
Node() = default;
~Node();
// Allow moving, disallow copying.
Node(const Node& other) = delete;
Node(Node&& other) = default;
Node& operator=(const Node& other) = delete;
Node& operator=(Node&& other) noexcept;
// Create a new |Node| with the given name that is a child of this node.
// If this node is not stored in a buffer, the created node will
// also not be stored in a buffer.
Node CreateChild(BorrowedStringValue name) __WARN_UNUSED_RESULT;
// Same as CreateChild, but emplaces the value in the given container.
//
// The type of |list| must have method emplace(Node).
// inspect::ValueList is recommended for most use cases.
template <typename T>
void CreateChild(BorrowedStringValue name, T* list) {
list->emplace(CreateChild(name));
}
/// Associates the lifetime of the given value with the node lifetime.
template <typename T>
void Record(T value) {
value_list_.emplace(std::move(value));
}
// Create a new |Node| with the given name that is a child of this node.
// The new child lifetime will be the same as the parent node.
void RecordChild(BorrowedStringValue name, RecordChildCallbackFn callback);
// Create a new |IntProperty| with the given name that is a child of this node.
// If this node is not stored in a buffer, the created metric will
// also not be stored in a buffer.
IntProperty CreateInt(BorrowedStringValue name, int64_t value) __WARN_UNUSED_RESULT;
// Create a new |IntProperty| with the given name that is a child of this node.
// The new property lifetime will be the same as the parent node.
void RecordInt(BorrowedStringValue name, int64_t value);
// Same as CreateInt, but emplaces the value in the given container.
//
// The type of |list| must have method emplace(IntProperty).
// inspect::ValueList is recommended for most use cases.
template <typename T>
void CreateInt(BorrowedStringValue name, int64_t value, T* list) {
list->emplace(CreateInt(name, value));
}
// Create a new |UintProperty| with the given name that is a child of this node.
// If this node is not stored in a buffer, the created metric will
// also not be stored in a buffer.
UintProperty CreateUint(BorrowedStringValue name, uint64_t value) __WARN_UNUSED_RESULT;
// Create a new |UintProperty| with the given name that is a child of this node.
// The new property lifetime will be the same as the parent node.
void RecordUint(BorrowedStringValue name, uint64_t value);
// Same as CreateUint, but emplaces the value in the given container.
//
// The type of |list| must have method emplace(UintProperty).
// inspect::ValueList is recommended for most use cases.
template <typename T>
void CreateUint(BorrowedStringValue name, uint64_t value, T* list) {
list->emplace(CreateUint(name, value));
}
// Create a new |DoubleProperty| with the given name that is a child of this node.
// If this node is not stored in a buffer, the created metric will
// also not be stored in a buffer.
DoubleProperty CreateDouble(BorrowedStringValue name, double value) __WARN_UNUSED_RESULT;
// Create a new |DoubleProperty| with the given name that is a child of this node.
// The new property lifetime will be the same as the parent node.
void RecordDouble(BorrowedStringValue name, double value);
// Same as CreateDouble, but emplaces the value in the given container.
//
// The type of |list| must have method emplace(DoubleProperty).
// inspect::ValueList is recommended for most use cases.
template <typename T>
void CreateDouble(BorrowedStringValue name, double value, T* list) {
list->emplace(CreateDouble(name, value));
}
// Create a new |BoolProperty| with the given name that is a child of this node.
// If this node is not stored in a buffer, the created metric will
// also not be stored in a buffer.
BoolProperty CreateBool(BorrowedStringValue name, bool value) __WARN_UNUSED_RESULT;
// Create a new |BoolProperty| with the given name that is a child of this node.
// The new property lifetime will be the same as the parent node.
void RecordBool(BorrowedStringValue name, bool value);
// Same as CreateBool, but emplaces the value in the given container.
//
// The type of |list| must have method emplace(BoolProperty).
// inspect::ValueList is recommended for most use cases.
template <typename T>
void CreateBool(BorrowedStringValue name, bool value, T* list) {
list->emplace(CreateBool(name, value));
}
// Create a new |StringProperty| with the given name and value that is a child of this node.
// If this node is not stored in a buffer, the created property will
// also not be stored in a buffer.
StringProperty CreateString(BorrowedStringValue name,
const std::string& value) __WARN_UNUSED_RESULT;
// Create a new |StringProperty| with the given name that is a child of this node.
// The new property lifetime will be the same as the parent node.
void RecordString(BorrowedStringValue name, const std::string& value);
// Same as CreateString, but emplaces the value in the given container.
//
// The type of |list| must have method emplace(StringProperty).
// inspect::ValueList is recommended for most use cases.
template <typename T>
void CreateString(BorrowedStringValue name, const std::string& value, T* list) {
list->emplace(CreateString(name, value));
}
// Create a new |ByteVectorProperty| with the given name and value that is a child of this node.
// If this node is not stored in a buffer, the created property will
// also not be stored in a buffer.
ByteVectorProperty CreateByteVector(BorrowedStringValue name,
cpp20::span<const uint8_t> value) __WARN_UNUSED_RESULT;
// Create a new |ByteVectorProperty| with the given name that is a child of this node.
// The new property lifetime will be the same as the parent node.
void RecordByteVector(BorrowedStringValue name, cpp20::span<const uint8_t> value);
// Same as CreateByteVector, but emplaces the value in the given container.
//
// The type of |list| must have method emplace(ByteVectorProperty).
// inspect::ValueList is recommended for most use cases.
template <typename T>
void CreateByteVector(BorrowedStringValue name, cpp20::span<const uint8_t> value, T* list) {
list->emplace(CreateByteVector(name, value));
}
// Create a new |IntArray| with the given name and slots that is a child of this node.
// If this node is not stored in a buffer, the created value will
// also not be stored in a buffer.
IntArray CreateIntArray(BorrowedStringValue name, size_t slots) __WARN_UNUSED_RESULT;
// Create a new |UintArray| with the given name and slots that is a child of this node.
// If this node is not stored in a buffer, the created value will
// also not be stored in a buffer.
UintArray CreateUintArray(BorrowedStringValue name, size_t slots) __WARN_UNUSED_RESULT;
// Create a new |DoubleArray| with the given name and slots that is a child of this node.
// If this node is not stored in a buffer, the created value will
// also not be stored in a buffer.
DoubleArray CreateDoubleArray(BorrowedStringValue name, size_t slots) __WARN_UNUSED_RESULT;
// Create a new |StringArray| with the given name and slots that is a child of this node.
// If this node is not stored in a buffer, the created value will
// also not be stored in a buffer.
StringArray CreateStringArray(BorrowedStringValue name, size_t slots) __WARN_UNUSED_RESULT;
// Create a new |LinearIntHistogram| with the given name and format that is a child of this
// node. If this node is not stored in a buffer, the created value will also not be stored in
// a buffer.
LinearIntHistogram CreateLinearIntHistogram(BorrowedStringValue name, int64_t floor,
int64_t step_size,
size_t buckets) __WARN_UNUSED_RESULT;
// Create a new |LinearUintHistogram| with the given name and format that is a child of this
// node. If this node is not stored in a buffer, the created value will also not be stored in
// a buffer.
LinearUintHistogram CreateLinearUintHistogram(BorrowedStringValue name, uint64_t floor,
uint64_t step_size,
size_t buckets) __WARN_UNUSED_RESULT;
// Create a new |LinearDoubleHistogram| with the given name and format that is a child of this
// node. If this node is not stored in a buffer, the created value will also not be stored in
// a buffer.
LinearDoubleHistogram CreateLinearDoubleHistogram(BorrowedStringValue name, double floor,
double step_size,
size_t buckets) __WARN_UNUSED_RESULT;
// Create a new |ExponentialIntHistogram| with the given name and format that is a child of this
// node. If this node is not stored in a buffer, the created value will also not be stored in
// a buffer.
ExponentialIntHistogram CreateExponentialIntHistogram(BorrowedStringValue name, int64_t floor,
int64_t initial_step,
int64_t step_multiplier,
size_t buckets) __WARN_UNUSED_RESULT;
// Create a new |ExponentialUintHistogram| with the given name and format that is a child of this
// node. If this node is not stored in a buffer, the created value will also not be stored in
// a buffer.
ExponentialUintHistogram CreateExponentialUintHistogram(BorrowedStringValue name, uint64_t floor,
uint64_t initial_step,
uint64_t step_multiplier,
size_t buckets) __WARN_UNUSED_RESULT;
// Create a new |ExponentialDoubleHistogram| with the given name and format that is a child of
// this node. If this node is not stored in a buffer, the created value will also not be
// stored in a buffer.
ExponentialDoubleHistogram CreateExponentialDoubleHistogram(BorrowedStringValue name,
double floor, double initial_step,
double step_multiplier,
size_t buckets) __WARN_UNUSED_RESULT;
// Create a new |LazyNode| with the given name that is populated by the given callback on demand.
//
// The passed |callback| will live as long as the returned LazyNode, and will not be called
// concurrently by multiple threads.
//
// For example:
// auto a = root.CreateChild("a");
// a.CreateLazyNode("b", [] {
// Inspector insp;
// ValueList values;
// insp.GetRoot().CreateInt("val", 2, &values);
// return fpromise::make_ok_result(insp);
// });
//
// Output:
// root:
// a:
// b:
// val = 2
LazyNode CreateLazyNode(BorrowedStringValue name,
LazyNodeCallbackFn callback) __WARN_UNUSED_RESULT;
// Create a new |LazyNode| with the given name that is a child of this node.
// The new child lifetime will be the same as the parent node.
void RecordLazyNode(BorrowedStringValue name, LazyNodeCallbackFn callback);
// Same as CreateLazyNode, but emplaces the value in the given container.
//
// The type of |list| must have method emplace(LazyNode).
// inspect::ValueList is recommended for most use cases.
template <typename F, typename T>
void CreateLazyNode(BorrowedStringValue name, F callback, T* list) {
list->emplace(CreateLazyNode(name, std::move(callback)));
}
// Create a new |LazyNode| with the given name that is a child of this node.
// The new child lifetime will be the same as the parent node.
void RecordLazyValues(BorrowedStringValue name, LazyNodeCallbackFn callback);
// Create a new |LazyNode| whose children and properties are added to this node on demand.
//
// The passed |callback| will live as long as the returned LazyNode, and will not be called
// concurrently by multiple threads.
//
// The name is only used if inflating the tree callback fails.
//
// WARNING: It is the caller's responsibility to avoid name collisions with other properties
// on this node.
//
// For example:
// auto a = root.CreateChild("a");
// a.CreateLazy("b", [] {
// Inspector insp;
// ValueList values;
// insp.GetRoot().CreateInt("val", 2).enlist(&values);
// return fpromise::make_ok_promise(insp);
// });
//
// Output:
// root:
// a:
// val = 2
//
// Alternatively:
//
// a.CreateLazyNode("b", [] {
// return fpromise::make_error_promise();
// });
//
// Possible output:
// root:
// a:
// b [Failed to open link]
LazyNode CreateLazyValues(BorrowedStringValue name,
LazyNodeCallbackFn callback) __WARN_UNUSED_RESULT;
// Same as CreateLazyValues, but emplaces the value in the given container.
//
// The type of |list| must have method emplace(LazyNode).
// inspect::ValueList is recommended for most use cases.
template <typename F, typename T>
void CreateLazyValues(BorrowedStringValue name, F callback, T* list) {
list->emplace(CreateLazyValues(name, std::move(callback)));
}
// Runs |callback| on this node.
//
// All operations performed by |callback| are guaranteed to appear in the same generation when
// reading Inspect data.
void AtomicUpdate(AtomicUpdateCallbackFn callback);
// Return true if this node is stored in a buffer. False otherwise.
explicit operator bool() const { return state_ != nullptr; }
// Create a unique name for children of this node.
//
// The returned strings are guaranteed to be at least unique within the context of this Node,
// except in the case that this is a default no-op node, in which case this always returns the
// empty string.
std::string UniqueName(const std::string& prefix);
private:
friend class ::inspect::internal::State;
Node(std::shared_ptr<internal::State> state, internal::BlockIndex name,
internal::BlockIndex value)
: state_(std::move(state)), name_index_(name), value_index_(value) {}
// Reference to the state containing this metric.
std::shared_ptr<internal::State> state_;
// Index of the name block in the state.
internal::BlockIndex name_index_;
// Index of the value block in the state.
internal::BlockIndex value_index_;
// Internally stored values owned by this Node.
//
// Shared pointers are used so Node is copyable.
ValueList value_list_;
};
} // namespace inspect
#endif // LIB_INSPECT_CPP_VMO_TYPES_H_