mirror of
https://github.com/zeek/zeek.git
synced 2025-10-14 20:48:21 +00:00
653 lines
19 KiB
C++
653 lines
19 KiB
C++
#pragma once
|
|
|
|
#include <cassert>
|
|
#include <memory>
|
|
#include <type_traits>
|
|
|
|
#include "zeek/Expr.h"
|
|
#include "zeek/Frame.h"
|
|
#include "zeek/OpaqueVal.h"
|
|
#include "zeek/Reporter.h"
|
|
|
|
#include "broker/config.hh"
|
|
#include "broker/data.hh"
|
|
|
|
namespace zeek {
|
|
|
|
/// A 64-bit timestamp with nanosecond precision.
|
|
using BrokerTimespan = std::chrono::duration<int64_t, std::nano>;
|
|
|
|
class ODesc;
|
|
|
|
} // namespace zeek
|
|
|
|
namespace zeek::Broker {
|
|
|
|
class Manager;
|
|
|
|
} // namespace zeek::Broker
|
|
|
|
namespace zeek::threading {
|
|
|
|
struct Value;
|
|
struct Field;
|
|
|
|
} // namespace zeek::threading
|
|
|
|
namespace zeek::Broker::detail {
|
|
|
|
class StoreHandleVal;
|
|
|
|
extern OpaqueTypePtr opaque_of_data_type;
|
|
extern OpaqueTypePtr opaque_of_set_iterator;
|
|
extern OpaqueTypePtr opaque_of_table_iterator;
|
|
extern OpaqueTypePtr opaque_of_vector_iterator;
|
|
extern OpaqueTypePtr opaque_of_record_iterator;
|
|
|
|
/**
|
|
* Convert a broker port protocol to a zeek port protocol.
|
|
*/
|
|
TransportProto to_zeek_port_proto(broker::port::protocol tp);
|
|
|
|
/**
|
|
* Create a Broker::Data value from a Zeek value.
|
|
* @param v the Zeek value to convert to a Broker data value.
|
|
* @return a Broker::Data value, where the optional field is set if the conversion
|
|
* was possible, else it is unset.
|
|
*/
|
|
RecordValPtr make_data_val(Val* v);
|
|
|
|
/**
|
|
* Create a Broker::Data value from a Broker data value.
|
|
* @param d the Broker value to wrap in an opaque type.
|
|
* @return a Broker::Data value that wraps the Broker value.
|
|
*/
|
|
RecordValPtr make_data_val(broker::data d);
|
|
|
|
/**
|
|
* Get the type of Broker data that Broker::Data wraps.
|
|
* @param v a Broker::Data value.
|
|
* @param frame used to get location info upon error.
|
|
* @return a Broker::DataType value.
|
|
*/
|
|
EnumValPtr get_data_type(RecordVal* v, zeek::detail::Frame* frame);
|
|
|
|
/**
|
|
* Convert a Zeek value to a Broker data value.
|
|
* @param v a Zeek value.
|
|
* @return a Broker data value if the Zeek value could be converted to one.
|
|
*/
|
|
std::optional<broker::data> val_to_data(const Val* v);
|
|
|
|
/**
|
|
* Convert a Broker data value to a Zeek value.
|
|
* @param d a Broker data value.
|
|
* @param type the expected type of the value to return.
|
|
* @return a pointer to a new Zeek value or a nullptr if the conversion was not
|
|
* possible.
|
|
*/
|
|
ValPtr data_to_val(broker::data& d, Type* type);
|
|
|
|
/**
|
|
* Convert a zeek::threading::Field to a Broker data value.
|
|
* @param f a zeek::threading::Field.
|
|
* @return a Broker data value if the zeek::threading::Field could be converted to one.
|
|
*/
|
|
broker::data threading_field_to_data(const threading::Field* f);
|
|
|
|
/**
|
|
* Convert a Broker data value to a zeek::threading::Value.
|
|
* @param d a Broker data value.
|
|
* @return a pointer to a new zeek::threading::Value or a nullptr if the conversion was not
|
|
* possible.
|
|
*/
|
|
threading::Field* data_to_threading_field(broker::data d);
|
|
|
|
/**
|
|
* A Zeek value which wraps a Broker data value.
|
|
*/
|
|
class DataVal : public OpaqueVal {
|
|
public:
|
|
DataVal(broker::data arg_data) : OpaqueVal(opaque_of_data_type), data(std::move(arg_data)) {}
|
|
|
|
void ValDescribe(ODesc* d) const override;
|
|
|
|
ValPtr castTo(zeek::Type* t);
|
|
bool canCastTo(zeek::Type* t) const;
|
|
|
|
// Returns the Zeek type that scripts use to represent a Broker data
|
|
// instance. This may be wrapping the opaque value inside another
|
|
// type.
|
|
static const TypePtr& ScriptDataType();
|
|
|
|
broker::data data;
|
|
|
|
protected:
|
|
DataVal() : OpaqueVal(opaque_of_data_type) {}
|
|
|
|
DECLARE_OPAQUE_VALUE(zeek::Broker::detail::DataVal)
|
|
};
|
|
|
|
/**
|
|
* Visitor for retrieving type names a Broker data value.
|
|
*/
|
|
struct type_name_getter {
|
|
using result_type = const char*;
|
|
|
|
result_type operator()(broker::none) { return "NONE"; } // FIXME: what's the right thing to return here?
|
|
|
|
result_type operator()(bool) { return "bool"; }
|
|
|
|
result_type operator()(uint64_t) { return "uint64_t"; }
|
|
|
|
result_type operator()(int64_t) { return "int64_t"; }
|
|
|
|
result_type operator()(double) { return "double"; }
|
|
|
|
result_type operator()(const std::string&) { return "string"; }
|
|
|
|
result_type operator()(const broker::address&) { return "address"; }
|
|
|
|
result_type operator()(const broker::subnet&) { return "subnet"; }
|
|
|
|
result_type operator()(const broker::port&) { return "port"; }
|
|
|
|
result_type operator()(const broker::timestamp&) { return "time"; }
|
|
|
|
result_type operator()(const broker::timespan&) { return "interval"; }
|
|
|
|
result_type operator()(const broker::enum_value&) { return "enum"; }
|
|
|
|
result_type operator()(const broker::set&) { return "set"; }
|
|
|
|
result_type operator()(const broker::table&) { return "table"; }
|
|
|
|
result_type operator()(const broker::vector&) {
|
|
assert(tag == zeek::TYPE_VECTOR || tag == zeek::TYPE_RECORD);
|
|
return tag == zeek::TYPE_VECTOR ? "vector" : "record";
|
|
}
|
|
|
|
zeek::TypeTag tag;
|
|
};
|
|
|
|
/**
|
|
* Retrieve Broker data value associated with a Broker::Data Zeek value.
|
|
* @param v a Broker::Data value.
|
|
* @param f used to get location information on error.
|
|
* @return a reference to the wrapped Broker data value. A runtime interpreter
|
|
* exception is thrown if the optional opaque value of \a v is not set.
|
|
*/
|
|
broker::data& opaque_field_to_data(zeek::RecordVal* v, zeek::detail::Frame* f);
|
|
|
|
/**
|
|
* Retrieve variant data from a Broker data value.
|
|
* @tparam T a type that the variant may contain.
|
|
* @param d a Broker data value to get variant data out of.
|
|
* @param tag a Zeek tag which corresponds to T (just used for error reporting).
|
|
* @param f used to get location information on error.
|
|
* @return a reference to the requested type in the variant Broker data.
|
|
* A runtime interpret exception is thrown if trying to access a type which
|
|
* is not currently stored in the Broker data.
|
|
*/
|
|
template<typename T>
|
|
T& require_data_type(broker::data& d, zeek::TypeTag tag, zeek::detail::Frame* f) {
|
|
auto ptr = broker::get_if<T>(&d);
|
|
if ( ! ptr )
|
|
zeek::reporter->RuntimeError(f->GetCallLocation(), "data is of type '%s' not of type '%s'",
|
|
visit(type_name_getter{tag}, d), zeek::type_name(tag));
|
|
|
|
return *ptr;
|
|
}
|
|
|
|
/**
|
|
* @see require_data_type() and opaque_field_to_data().
|
|
*/
|
|
template<typename T>
|
|
inline T& require_data_type(zeek::RecordVal* v, zeek::TypeTag tag, zeek::detail::Frame* f) {
|
|
return require_data_type<T>(opaque_field_to_data(v, f), tag, f);
|
|
}
|
|
|
|
// Copying data into iterator vals is not the fastest approach, but safer...
|
|
|
|
class SetIterator : public zeek::OpaqueVal {
|
|
public:
|
|
SetIterator(zeek::RecordVal* v, zeek::TypeTag tag, zeek::detail::Frame* f)
|
|
: zeek::OpaqueVal(opaque_of_set_iterator),
|
|
dat(require_data_type<broker::set>(v, zeek::TYPE_TABLE, f)),
|
|
it(dat.begin()) {}
|
|
|
|
broker::set dat;
|
|
broker::set::iterator it;
|
|
|
|
protected:
|
|
SetIterator() : zeek::OpaqueVal(opaque_of_set_iterator) {}
|
|
|
|
DECLARE_OPAQUE_VALUE(zeek::Broker::detail::SetIterator)
|
|
};
|
|
|
|
class TableIterator : public zeek::OpaqueVal {
|
|
public:
|
|
TableIterator(zeek::RecordVal* v, zeek::TypeTag tag, zeek::detail::Frame* f)
|
|
: zeek::OpaqueVal(opaque_of_table_iterator),
|
|
dat(require_data_type<broker::table>(v, zeek::TYPE_TABLE, f)),
|
|
it(dat.begin()) {}
|
|
|
|
broker::table dat;
|
|
broker::table::iterator it;
|
|
|
|
protected:
|
|
TableIterator() : zeek::OpaqueVal(opaque_of_table_iterator) {}
|
|
|
|
DECLARE_OPAQUE_VALUE(zeek::Broker::detail::TableIterator)
|
|
};
|
|
|
|
class VectorIterator : public zeek::OpaqueVal {
|
|
public:
|
|
VectorIterator(zeek::RecordVal* v, zeek::TypeTag tag, zeek::detail::Frame* f)
|
|
: zeek::OpaqueVal(opaque_of_vector_iterator),
|
|
dat(require_data_type<broker::vector>(v, zeek::TYPE_VECTOR, f)),
|
|
it(dat.begin()) {}
|
|
|
|
broker::vector dat;
|
|
broker::vector::iterator it;
|
|
|
|
protected:
|
|
VectorIterator() : zeek::OpaqueVal(opaque_of_vector_iterator) {}
|
|
|
|
DECLARE_OPAQUE_VALUE(zeek::Broker::detail::VectorIterator)
|
|
};
|
|
|
|
class RecordIterator : public zeek::OpaqueVal {
|
|
public:
|
|
RecordIterator(zeek::RecordVal* v, zeek::TypeTag tag, zeek::detail::Frame* f)
|
|
: zeek::OpaqueVal(opaque_of_record_iterator),
|
|
dat(require_data_type<broker::vector>(v, zeek::TYPE_RECORD, f)),
|
|
it(dat.begin()) {}
|
|
|
|
broker::vector dat;
|
|
broker::vector::iterator it;
|
|
|
|
protected:
|
|
RecordIterator() : zeek::OpaqueVal(opaque_of_record_iterator) {}
|
|
|
|
DECLARE_OPAQUE_VALUE(zeek::Broker::detail::RecordIterator)
|
|
};
|
|
|
|
} // namespace zeek::Broker::detail
|
|
|
|
namespace zeek {
|
|
|
|
class BrokerListView;
|
|
|
|
/**
|
|
* Non-owning reference (view) to a Broker data value.
|
|
*/
|
|
class BrokerDataView {
|
|
public:
|
|
friend class zeek::Broker::detail::DataVal;
|
|
friend class zeek::Broker::detail::SetIterator;
|
|
friend class zeek::Broker::detail::TableIterator;
|
|
friend class zeek::Broker::detail::VectorIterator;
|
|
friend class zeek::Broker::detail::RecordIterator;
|
|
|
|
BrokerDataView() = delete;
|
|
|
|
BrokerDataView(const BrokerDataView&) noexcept = default;
|
|
|
|
explicit BrokerDataView(broker::data* value) noexcept : value_(value) { assert(value != nullptr); }
|
|
|
|
/**
|
|
* Checks whether the value represents the `nil` value.
|
|
*/
|
|
[[nodiscard]] bool IsNil() const noexcept { return broker::is<broker::none>(*value_); }
|
|
|
|
/**
|
|
* Checks whether the value is a Boolean.
|
|
*/
|
|
[[nodiscard]] bool IsBool() const noexcept { return broker::is<bool>(*value_); }
|
|
|
|
/**
|
|
* Converts the value to a Boolean.
|
|
*/
|
|
[[nodiscard]] bool ToBool(bool fallback = 0) const noexcept {
|
|
if ( auto val = broker::get_if<bool>(value_); val ) {
|
|
return *val;
|
|
}
|
|
return fallback;
|
|
}
|
|
|
|
/**
|
|
* Checks whether the value is a string.
|
|
*/
|
|
[[nodiscard]] bool IsString() const noexcept { return broker::is<std::string>(*value_); }
|
|
|
|
/**
|
|
* Converts the value to a string.
|
|
*/
|
|
[[nodiscard]] std::string_view ToString() const noexcept {
|
|
if ( auto val = broker::get_if<std::string>(value_); val ) {
|
|
return *val;
|
|
}
|
|
return std::string_view{};
|
|
}
|
|
|
|
/**
|
|
* Checks whether the value is an integer.
|
|
*/
|
|
[[nodiscard]] bool IsInteger() const noexcept { return broker::is<broker::integer>(*value_); }
|
|
|
|
/**
|
|
* Converts the value to an integer.
|
|
*/
|
|
[[nodiscard]] int64_t ToInteger(int64_t fallback = 0) const noexcept {
|
|
if ( auto val = broker::get_if<broker::integer>(value_); val ) {
|
|
return *val;
|
|
}
|
|
return fallback;
|
|
}
|
|
|
|
/**
|
|
* Checks whether the value is a count.
|
|
*/
|
|
[[nodiscard]] bool IsCount() const noexcept { return broker::is<broker::count>(*value_); }
|
|
|
|
/**
|
|
* Converts the value to a count.
|
|
*/
|
|
[[nodiscard]] uint64_t ToCount(uint64_t fallback = 0) const noexcept {
|
|
if ( auto val = broker::get_if<broker::count>(value_); val ) {
|
|
return *val;
|
|
}
|
|
return fallback;
|
|
}
|
|
|
|
/**
|
|
* Checks whether the value is a real (double).
|
|
*/
|
|
[[nodiscard]] bool IsReal() const noexcept { return broker::is<broker::real>(*value_); }
|
|
|
|
/**
|
|
* Converts the value to a real (double).
|
|
*/
|
|
[[nodiscard]] double ToReal(double fallback = 0) const noexcept {
|
|
if ( auto val = broker::get_if<broker::real>(value_); val ) {
|
|
return *val;
|
|
}
|
|
return fallback;
|
|
}
|
|
|
|
/**
|
|
* Checks whether the value is a list.
|
|
*/
|
|
[[nodiscard]] bool IsList() const noexcept { return broker::is<broker::vector>(*value_); }
|
|
|
|
/**
|
|
* Converts the value to a list.
|
|
* @pre IsList()
|
|
*/
|
|
[[nodiscard]] BrokerListView ToList() noexcept;
|
|
|
|
/**
|
|
* Tries to convert this view to a Zeek value.
|
|
* @returns a Zeek value or nullptr if the conversion failed.
|
|
*/
|
|
[[nodiscard]] ValPtr ToVal(Type* type);
|
|
|
|
/**
|
|
* Renders the value as a string.
|
|
*/
|
|
friend std::string to_string(const BrokerDataView& data) { return broker::to_string(*data.value_); }
|
|
|
|
private:
|
|
broker::data* value_;
|
|
};
|
|
|
|
/**
|
|
* Convenience function to check whether a list of Broker data values are all of type `count`.
|
|
*/
|
|
template<typename... Args>
|
|
[[nodiscard]] bool are_all_counts(BrokerDataView arg, Args&&... args) {
|
|
return arg.IsCount() && (args.IsCount() && ...);
|
|
}
|
|
|
|
/**
|
|
* Convenience function to check whether a list of Broker data values are all of type `integer`.
|
|
*/
|
|
template<typename... Args>
|
|
[[nodiscard]] auto to_count(BrokerDataView arg, Args&&... args) {
|
|
return std::tuple{arg.ToCount(), args.ToCount()...};
|
|
}
|
|
|
|
/**
|
|
* Non-owning reference (view) to a Broker list value.
|
|
*/
|
|
class BrokerListView {
|
|
public:
|
|
BrokerListView() = delete;
|
|
|
|
BrokerListView(const BrokerListView&) noexcept = default;
|
|
|
|
explicit BrokerListView(broker::vector* values) noexcept : values_(values) { assert(values != nullptr); }
|
|
|
|
/**
|
|
* Returns a view to the first element.
|
|
* @pre Size() > 0
|
|
*/
|
|
[[nodiscard]] BrokerDataView Front() const { return BrokerDataView{std::addressof(values_->front())}; }
|
|
|
|
/**
|
|
* Returns a view to the last element.
|
|
* @pre Size() > 0
|
|
*/
|
|
[[nodiscard]] BrokerDataView Back() const { return BrokerDataView{std::addressof(values_->back())}; }
|
|
|
|
/**
|
|
* Returns a view to the element at the given index.
|
|
* @pre index < Size()
|
|
*/
|
|
[[nodiscard]] BrokerDataView operator[](size_t index) const {
|
|
return BrokerDataView{std::addressof((*values_)[index])};
|
|
}
|
|
|
|
/**
|
|
* Returns the number of elements in the list.
|
|
*/
|
|
[[nodiscard]] size_t Size() const noexcept { return values_->size(); }
|
|
|
|
/**
|
|
* Checks whether the list is empty.
|
|
*/
|
|
[[nodiscard]] size_t IsEmpty() const noexcept { return values_->empty(); }
|
|
|
|
private:
|
|
broker::vector* values_;
|
|
};
|
|
|
|
class BrokerDataAccess;
|
|
|
|
class BrokerListBuilder;
|
|
|
|
/**
|
|
* Owning wrapper for a Broker data value.
|
|
*/
|
|
class BrokerData {
|
|
public:
|
|
friend class BrokerDataAccess;
|
|
friend class BrokerListBuilder;
|
|
friend class zeek::Broker::Manager;
|
|
friend class zeek::Broker::detail::StoreHandleVal;
|
|
|
|
BrokerData() = default;
|
|
|
|
template<class DataType, class = std::enable_if_t<std::is_same_v<DataType, broker::data>>>
|
|
explicit BrokerData(DataType value) : value_(std::move(value)) {
|
|
// Note: we use enable_if here to avoid nasty implicit conversions of broker::data.
|
|
}
|
|
|
|
BrokerDataView AsView() noexcept { return BrokerDataView{std::addressof(value_)}; }
|
|
|
|
/**
|
|
* Attempts to parse a Zeek value into a Broker value. On success, the Broker
|
|
* value is stored in this object.
|
|
* @returns `true` if the conversion succeeded, `false` otherwise.
|
|
*/
|
|
[[nodiscard]] bool Convert(const Val* value);
|
|
|
|
/**
|
|
* @copydoc Convert(const Val*)
|
|
*/
|
|
[[nodiscard]] bool Convert(const ValPtr& value) { return Convert(value.get()); }
|
|
|
|
/**
|
|
* Converts this value to a Zeek record.
|
|
*/
|
|
[[nodiscard]] RecordValPtr ToRecordVal() &&;
|
|
|
|
/**
|
|
* Convenience function for converting a Zeek value to a Broker value and then
|
|
* to a Zeek record.
|
|
*/
|
|
[[nodiscard]] static RecordValPtr ToRecordVal(const Val* value);
|
|
|
|
/**
|
|
* @copydoc ToRecordVal(const Val*)
|
|
*/
|
|
[[nodiscard]] static RecordValPtr ToRecordVal(const ValPtr& value) { return ToRecordVal(value.get()); }
|
|
|
|
/**
|
|
* Creates a Broker value from a string.
|
|
*/
|
|
[[nodiscard]] static BrokerData FromString(const char* cstr, size_t len) {
|
|
return BrokerData{broker::data{std::string{cstr, len}}};
|
|
}
|
|
|
|
/**
|
|
* Renders the value as a string.
|
|
*/
|
|
friend std::string to_string(const BrokerData& data) { return broker::to_string(data.value_); }
|
|
|
|
private:
|
|
broker::data value_;
|
|
};
|
|
|
|
/**
|
|
* Utility class for building a BrokerData containing a list of values.
|
|
*/
|
|
class BrokerListBuilder {
|
|
public:
|
|
friend class zeek::Broker::Manager;
|
|
|
|
/**
|
|
* Reserves space for up to `n` elements.
|
|
*/
|
|
void Reserve(size_t n) { values_.reserve(n); }
|
|
|
|
/**
|
|
* Tries to convert a Zeek value into a Broker value and adds it to the list on success.
|
|
*/
|
|
[[nodiscard]] bool Add(const Val* value);
|
|
|
|
/**
|
|
* @copydoc Add(const Val*)
|
|
*/
|
|
[[nodiscard]] bool Add(const ValPtr& value) { return Add(value.get()); }
|
|
|
|
/**
|
|
* Adds `value` as a Broker `count` to the list, automatically converting it if necessary.
|
|
*/
|
|
template<typename T>
|
|
void AddCount(T value) {
|
|
if constexpr ( std::is_enum_v<T> ) {
|
|
AddCount(static_cast<std::underlying_type_t<T>>(value));
|
|
}
|
|
else {
|
|
static_assert(std::is_integral_v<T> && ! std::is_same_v<bool, T>);
|
|
static_assert(std::is_unsigned_v<T>);
|
|
static_assert(sizeof(T) <= sizeof(broker::count));
|
|
values_.emplace_back(static_cast<broker::count>(value));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds `value` as a Broker `integer` to the list, automatically converting it if necessary.
|
|
*/
|
|
template<typename T>
|
|
void AddInteger(T value) {
|
|
if constexpr ( std::is_enum_v<T> ) {
|
|
AddInteger(static_cast<std::underlying_type_t<T>>(value));
|
|
}
|
|
else {
|
|
static_assert(std::is_integral_v<T> && ! std::is_same_v<bool, T>);
|
|
static_assert(std::is_signed_v<T>);
|
|
static_assert(sizeof(T) <= sizeof(broker::integer));
|
|
values_.emplace_back(static_cast<broker::integer>(value));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Appends `value` to the end of the list.
|
|
*/
|
|
void Add(uint64_t value) { values_.emplace_back(static_cast<broker::count>(value)); }
|
|
|
|
/**
|
|
* Appends `value` to the end of the list.
|
|
*/
|
|
void Add(int64_t value) { values_.emplace_back(static_cast<broker::integer>(value)); }
|
|
|
|
/**
|
|
* Appends `value` to the end of the list.
|
|
*/
|
|
void Add(double value) { values_.emplace_back(value); }
|
|
|
|
/**
|
|
* Appends `value` to the end of the list.
|
|
*/
|
|
void Add(bool value) { values_.emplace_back(value); }
|
|
|
|
/**
|
|
* Appends `value` to the end of the list.
|
|
*/
|
|
void Add(std::string value) { values_.emplace_back(std::move(value)); }
|
|
|
|
/**
|
|
* Appends a string to the end of the list.
|
|
* @param cstr The characters to append.
|
|
* @param len The number of characters to append.
|
|
*/
|
|
void Add(const char* cstr, size_t len) { values_.emplace_back(std::string{cstr, len}); }
|
|
|
|
/**
|
|
* Appends `value` to the end of the list.
|
|
*/
|
|
void Add(BrokerData value) { values_.emplace_back(std::move(value.value_)); }
|
|
|
|
/**
|
|
* Appends all elements from `builder` to the end of the list as a single element.
|
|
*/
|
|
void Add(BrokerListBuilder&& builder) { values_.emplace_back(std::move(builder.values_)); }
|
|
|
|
/**
|
|
* Appends the `nil` value to the end of the list.
|
|
*/
|
|
void AddNil() { values_.emplace_back(); }
|
|
|
|
/**
|
|
* Adds a list of values to the list (as a single element).
|
|
*/
|
|
template<class... Ts>
|
|
void AddList(Ts&&... values) {
|
|
BrokerListBuilder sub;
|
|
(sub.Add(std::forward<Ts>(values)), ...);
|
|
values_.emplace_back(std::move(sub.values_));
|
|
}
|
|
|
|
/**
|
|
* Builds a `BrokerData` containing the list of values.
|
|
*/
|
|
BrokerData Build() && { return BrokerData{broker::data{std::move(values_)}}; }
|
|
|
|
private:
|
|
broker::vector values_;
|
|
};
|
|
|
|
} // namespace zeek
|