Program Listing for File parameter.cpp¶
↰ Return to documentation for file (foxglove/src/server/parameter.cpp
)
#include <foxglove-c/foxglove-c.h>
#include <foxglove/error.hpp>
#include <foxglove/server/parameter.hpp>
#include <cstring>
#include <stdexcept>
namespace foxglove {
ParameterValueView::Value ParameterValueView::value() const {
// Accessing union members is safe, because the tag serves as a valid
// discriminator.
switch (impl_->tag) {
case FOXGLOVE_PARAMETER_VALUE_TAG_NUMBER:
return impl_->data.number; // NOLINT(cppcoreguidelines-pro-type-union-access)
case FOXGLOVE_PARAMETER_VALUE_TAG_BOOLEAN:
return impl_->data.boolean; // NOLINT(cppcoreguidelines-pro-type-union-access)
case FOXGLOVE_PARAMETER_VALUE_TAG_STRING: {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
const foxglove_string* string = &impl_->data.string;
return std::string_view(string->data, string->len);
}
case FOXGLOVE_PARAMETER_VALUE_TAG_ARRAY: {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
const foxglove_parameter_value_array* array = &impl_->data.array;
std::vector<ParameterValueView> result;
result.reserve(array->len);
for (size_t i = 0; i < array->len; ++i) {
auto value = ParameterValueView(&array->values[i]);
result.emplace_back(value);
}
return result;
}
case FOXGLOVE_PARAMETER_VALUE_TAG_DICT: {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
const foxglove_parameter_value_dict* dict = &impl_->data.dict;
std::map<std::string, ParameterValueView> result;
for (size_t i = 0; i < dict->len; ++i) {
const auto& entry = dict->entries[i];
auto key = std::string(entry.key.data, entry.key.len);
result.emplace(key, ParameterValueView(entry.value));
}
return result;
}
default:
throw std::runtime_error("Unknown parameter value tag");
}
}
ParameterValue ParameterValueView::clone() const {
foxglove_parameter_value* ptr = foxglove_parameter_value_clone(impl_);
if (ptr == nullptr) {
throw std::runtime_error("allocation failed");
}
return ParameterValue(ptr);
}
void ParameterValue::Deleter::operator()(foxglove_parameter_value* ptr) const noexcept {
foxglove_parameter_value_free(ptr);
}
ParameterValue::ParameterValue(foxglove_parameter_value* ptr)
: impl_(ptr) {}
ParameterValue::ParameterValue(double value)
: impl_(nullptr) {
foxglove_parameter_value* ptr = foxglove_parameter_value_create_number(value);
if (ptr == nullptr) {
throw std::runtime_error("allocation failed");
}
impl_.reset(ptr);
}
ParameterValue::ParameterValue(bool value)
: impl_(nullptr) {
foxglove_parameter_value* ptr = foxglove_parameter_value_create_boolean(value);
if (ptr == nullptr) {
throw std::runtime_error("allocation failed");
}
impl_.reset(ptr);
}
ParameterValue::ParameterValue(std::string_view value)
: impl_(nullptr) {
foxglove_parameter_value* ptr = nullptr;
auto error = foxglove_parameter_value_create_string(&ptr, {value.data(), value.length()});
if (error != foxglove_error::FOXGLOVE_ERROR_OK) {
throw std::runtime_error(foxglove_error_to_cstr(error));
}
impl_.reset(ptr);
}
ParameterValue::ParameterValue(std::vector<ParameterValue> values)
: impl_(nullptr) {
foxglove_parameter_value_array* array_ptr = foxglove_parameter_value_array_create(values.size());
if (array_ptr == nullptr) {
throw std::runtime_error("allocation failed");
}
for (auto& value : values) {
foxglove_parameter_value* value_ptr = value.release();
auto error = foxglove_parameter_value_array_push(array_ptr, value_ptr);
if (error != foxglove_error::FOXGLOVE_ERROR_OK) {
foxglove_parameter_value_array_free(array_ptr);
throw std::runtime_error(foxglove_error_to_cstr(error));
}
}
foxglove_parameter_value* ptr = foxglove_parameter_value_create_array(array_ptr);
if (ptr == nullptr) {
throw std::runtime_error("allocation failed");
}
impl_.reset(ptr);
}
ParameterValue::ParameterValue(std::map<std::string, ParameterValue> value)
: impl_(nullptr) {
foxglove_parameter_value_dict* dict_ptr = foxglove_parameter_value_dict_create(value.size());
if (dict_ptr == nullptr) {
throw std::runtime_error("allocation failed");
}
for (auto& pair : value) {
std::string_view key = pair.first;
foxglove_parameter_value* value_ptr = pair.second.release();
auto error =
foxglove_parameter_value_dict_insert(dict_ptr, {key.data(), key.length()}, value_ptr);
if (error != foxglove_error::FOXGLOVE_ERROR_OK) {
foxglove_parameter_value_dict_free(dict_ptr);
throw std::runtime_error(foxglove_error_to_cstr(error));
}
}
foxglove_parameter_value* ptr = foxglove_parameter_value_create_dict(dict_ptr);
if (ptr == nullptr) {
throw std::runtime_error("allocation failed");
}
impl_.reset(ptr);
}
ParameterValueView ParameterValue::view() const noexcept {
return ParameterValueView(impl_.get());
}
foxglove_parameter_value* ParameterValue::release() noexcept {
return impl_.release();
}
std::string_view ParameterView::name() const noexcept {
const auto& name = impl_->name;
return {name.data, name.len};
}
ParameterType ParameterView::type() const noexcept {
return static_cast<ParameterType>(impl_->type);
}
std::optional<ParameterValueView> ParameterView::value() const noexcept {
if (impl_->value == nullptr) {
return {};
}
return ParameterValueView(impl_->value);
}
Parameter ParameterView::clone() const {
foxglove_parameter* ptr = foxglove_parameter_clone(impl_);
if (ptr == nullptr) {
throw std::runtime_error("allocation failed");
}
return Parameter(ptr);
}
FoxgloveResult<std::vector<std::byte>> ParameterView::getByteArray() const {
size_t len = 0;
auto error = foxglove_parameter_get_byte_array_decoded_size(impl_, &len);
if (error != foxglove_error::FOXGLOVE_ERROR_OK) {
return foxglove::unexpected(FoxgloveError(error));
}
std::vector<std::byte> bytes;
bytes.resize(len);
error =
foxglove_parameter_decode_byte_array(impl_, reinterpret_cast<uint8_t*>(bytes.data()), &len);
if (error != foxglove_error::FOXGLOVE_ERROR_OK) {
return foxglove::unexpected(FoxgloveError(error));
}
bytes.resize(len);
return bytes;
}
void Parameter::Deleter::operator()(foxglove_parameter* ptr) const noexcept {
foxglove_parameter_free(ptr);
}
Parameter::Parameter(foxglove_parameter* param)
: impl_(param) {}
Parameter::Parameter(std::string_view name)
: impl_(nullptr) {
foxglove_parameter* ptr = nullptr;
auto error = foxglove_parameter_create_empty(&ptr, {name.data(), name.length()});
if (error != foxglove_error::FOXGLOVE_ERROR_OK) {
throw std::runtime_error(foxglove_error_to_cstr(error));
}
impl_.reset(ptr);
}
Parameter::Parameter(std::string_view name, bool value)
: impl_(nullptr) {
foxglove_parameter* ptr = nullptr;
auto error = foxglove_parameter_create_boolean(&ptr, {name.data(), name.length()}, value);
if (error != foxglove_error::FOXGLOVE_ERROR_OK) {
throw std::runtime_error(foxglove_error_to_cstr(error));
}
impl_.reset(ptr);
}
Parameter::Parameter(std::string_view name, double value)
: impl_(nullptr) {
foxglove_parameter* ptr = nullptr;
auto error = foxglove_parameter_create_float64(&ptr, {name.data(), name.length()}, value);
if (error != foxglove_error::FOXGLOVE_ERROR_OK) {
throw std::runtime_error(foxglove_error_to_cstr(error));
}
impl_.reset(ptr);
}
Parameter::Parameter(std::string_view name, std::string_view value)
: impl_(nullptr) {
foxglove_parameter* ptr = nullptr;
auto error = foxglove_parameter_create_string(
&ptr, {name.data(), name.length()}, {value.data(), value.length()}
);
if (error != foxglove_error::FOXGLOVE_ERROR_OK) {
throw std::runtime_error(foxglove_error_to_cstr(error));
}
impl_.reset(ptr);
}
Parameter::Parameter(std::string_view name, const uint8_t* data, size_t data_length)
: impl_(nullptr) {
foxglove_parameter* ptr = nullptr;
auto error =
foxglove_parameter_create_byte_array(&ptr, {name.data(), name.length()}, {data, data_length});
if (error != foxglove_error::FOXGLOVE_ERROR_OK) {
throw std::runtime_error(foxglove_error_to_cstr(error));
}
impl_.reset(ptr);
}
Parameter::Parameter(std::string_view name, const std::vector<double>& values)
: impl_(nullptr) {
foxglove_parameter* ptr = nullptr;
auto error = foxglove_parameter_create_float64_array(
&ptr, {name.data(), name.length()}, values.data(), values.size()
);
if (error != foxglove_error::FOXGLOVE_ERROR_OK) {
throw std::runtime_error(foxglove_error_to_cstr(error));
}
impl_.reset(ptr);
}
Parameter::Parameter(std::string_view name, std::map<std::string, ParameterValue> values)
: Parameter::Parameter(name, ParameterType::None, ParameterValue(std::move(values))) {}
Parameter::Parameter(std::string_view name, ParameterType type, ParameterValue&& value)
: impl_(nullptr) {
// Explicit move to make the linter happy.
foxglove_parameter_value* value_ptr = std::move(value).release();
foxglove_parameter* ptr = nullptr;
auto error = foxglove_parameter_create(
&ptr, {name.data(), name.length()}, static_cast<foxglove_parameter_type>(type), value_ptr
);
if (error != foxglove_error::FOXGLOVE_ERROR_OK) {
throw std::runtime_error(foxglove_error_to_cstr(error));
}
impl_.reset(ptr);
}
ParameterView Parameter::view() const noexcept {
return ParameterView(impl_.get());
}
foxglove_parameter* Parameter::release() noexcept {
return impl_.release();
}
ParameterArrayView::ParameterArrayView(const foxglove_parameter_array* ptr)
: impl_(ptr) {}
std::vector<ParameterView> ParameterArrayView::parameters() const {
std::vector<ParameterView> params;
params.reserve(impl_->len);
for (auto i = 0; i < impl_->len; ++i) {
params.emplace_back(ParameterView(&impl_->parameters[i]));
}
return params;
}
void ParameterArray::Deleter::operator()(foxglove_parameter_array* ptr) const noexcept {
foxglove_parameter_array_free(ptr);
}
// We're consuming the contents of the vector, even though we're not moving it.
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
ParameterArray::ParameterArray(std::vector<Parameter>&& params)
: impl_(nullptr) {
foxglove_parameter_array* array_ptr = foxglove_parameter_array_create(params.size());
if (array_ptr == nullptr) {
throw std::runtime_error("allocation failed");
}
for (auto& param : params) {
auto error = foxglove_parameter_array_push(array_ptr, param.release());
if (error != foxglove_error::FOXGLOVE_ERROR_OK) {
foxglove_parameter_array_free(array_ptr);
throw std::runtime_error(foxglove_error_to_cstr(error));
}
}
impl_.reset(array_ptr);
}
ParameterArrayView ParameterArray::view() const noexcept {
return ParameterArrayView(impl_.get());
}
foxglove_parameter_array* ParameterArray::release() noexcept {
return impl_.release();
}
} // namespace foxglove