rsl 1.2.0
ROS Support Library
Loading...
Searching...
No Matches
parameter_validators.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <rsl/algorithm.hpp>
4#include <rsl/export.hpp>
7
8#include <rcl_interfaces/msg/set_parameters_result.hpp>
9#include <rclcpp/parameter.hpp>
10#include <tl_expected/expected.hpp>
11
12#include <fmt/ranges.h>
13#include <type_traits>
14
15namespace rsl {
16
22namespace detail {
23template <typename T>
24[[nodiscard]] auto stringify(T const& value) -> std::string {
25 if constexpr (std::is_floating_point_v<T>) return fmt::format("{:g}", value);
26 return fmt::format("{}", value);
27}
28
29template <typename T>
30[[nodiscard]] auto join_stringified(std::vector<T> const& values) -> std::string {
31 std::vector<std::string> tokens;
32 tokens.reserve(values.size());
33 for (auto const& value : values) tokens.push_back(stringify(value));
34 return fmt::format("{}", fmt::join(tokens, ", "));
35}
36
37template <typename T, typename Fn>
38[[nodiscard]] auto size_compare(rclcpp::Parameter const& parameter, size_t const size,
39 std::string const& predicate_description,
40 Fn const& predicate) -> tl::expected<void, std::string> {
41 static constexpr auto format_string = "Length of parameter '{}' is '{}' but must be {} '{}'";
42 switch (parameter.get_type()) {
43 case rclcpp::ParameterType::PARAMETER_STRING:
44 if (auto value = parameter.get_value<std::string>(); !predicate(value.size(), size))
45 return tl::unexpected(fmt::format(format_string, parameter.get_name(), value.size(),
46 predicate_description, size));
47 break;
48 default:
49 if (auto value = parameter.get_value<std::vector<T>>(); !predicate(value.size(), size))
50 return tl::unexpected(fmt::format(format_string, parameter.get_name(), value.size(),
51 predicate_description, size));
52 }
53 return {};
54}
55
56template <typename T, typename Fn>
57[[nodiscard]] auto compare(rclcpp::Parameter const& parameter, T const& value,
58 std::string const& predicate_description,
59 Fn const& predicate) -> tl::expected<void, std::string> {
60 if (auto const param_value = parameter.get_value<T>(); !predicate(param_value, value))
61 return tl::unexpected(fmt::format("Parameter '{}' with the value '{}' must be {} '{}'",
62 parameter.get_name(), stringify(param_value),
63 predicate_description, stringify(value)));
64 return {};
65}
66} // namespace detail
77template <typename T>
78[[nodiscard]] auto unique(rclcpp::Parameter const& parameter) -> tl::expected<void, std::string> {
79 if (is_unique(parameter.get_value<std::vector<T>>())) return {};
80 return tl::unexpected(
81 fmt::format("Parameter '{}' must only contain unique values", parameter.get_name()));
82}
83
90template <typename T>
91[[nodiscard]] auto subset_of(rclcpp::Parameter const& parameter, std::vector<T> const& valid_values)
92 -> tl::expected<void, std::string> {
93 auto const& values = parameter.get_value<std::vector<T>>();
94 for (auto const& value : values)
95 if (!contains(valid_values, value))
96 return tl::unexpected(
97 fmt::format("Entry '{}' in parameter '{}' is not in the set '{{{}}}'", value,
98 parameter.get_name(), fmt::join(valid_values, ", ")));
99 return {};
100}
101
108template <typename T>
109[[nodiscard]] auto fixed_size(rclcpp::Parameter const& parameter, size_t const size) {
110 return detail::size_compare<T>(parameter, size, "equal to", std::equal_to<>());
111}
112
119template <typename T>
120[[nodiscard]] auto size_gt(rclcpp::Parameter const& parameter, size_t const size) {
121 return detail::size_compare<T>(parameter, size, "greater than", std::greater<>());
122}
123
130template <typename T>
131[[nodiscard]] auto size_lt(rclcpp::Parameter const& parameter, size_t const size) {
132 return detail::size_compare<T>(parameter, size, "less than", std::less<>());
133}
134
142template <typename T>
143[[nodiscard]] auto not_empty(rclcpp::Parameter const& parameter)
144 -> tl::expected<void, std::string> {
145 switch (parameter.get_type()) {
146 case rclcpp::ParameterType::PARAMETER_STRING:
147 if (auto param_value = parameter.get_value<std::string>(); param_value.empty())
148 return tl::unexpected(
149 fmt::format("Parameter '{}' cannot be empty", parameter.get_name()));
150 break;
151 default:
152 if (auto param_value = parameter.get_value<std::vector<T>>(); param_value.empty())
153 return tl::unexpected(
154 fmt::format("Parameter '{}' cannot be empty", parameter.get_name()));
155 }
156 return {};
157}
158
165template <typename T>
166[[nodiscard]] auto element_bounds(rclcpp::Parameter const& parameter, T const& lower,
167 T const& upper) -> tl::expected<void, std::string> {
168 auto const& param_value = parameter.get_value<std::vector<T>>();
169 for (auto val : param_value)
170 if (val < lower || val > upper)
171 return tl::unexpected(
172 fmt::format("Value '{}' in parameter '{}' must be within bounds '[{}, {}]'",
173 detail::stringify(val), parameter.get_name(), detail::stringify(lower),
174 detail::stringify(upper)));
175 return {};
176}
177
184template <typename T>
185[[nodiscard]] auto lower_element_bounds(rclcpp::Parameter const& parameter,
186 T const& lower) -> tl::expected<void, std::string> {
187 auto const& param_value = parameter.get_value<std::vector<T>>();
188 for (auto val : param_value)
189 if (val < lower)
190 return tl::unexpected(fmt::format(
191 "Value '{}' in parameter '{}' must be above lower bound of '{}'",
192 detail::stringify(val), parameter.get_name(), detail::stringify(lower)));
193 return {};
194}
195
202template <typename T>
203[[nodiscard]] auto upper_element_bounds(rclcpp::Parameter const& parameter,
204 T const& upper) -> tl::expected<void, std::string> {
205 auto const& param_value = parameter.get_value<std::vector<T>>();
206 for (auto val : param_value)
207 if (val > upper)
208 return tl::unexpected(fmt::format(
209 "Value '{}' in parameter '{}' must be below upper bound of '{}'",
210 detail::stringify(val), parameter.get_name(), detail::stringify(upper)));
211 return {};
212}
213
220template <typename T>
221[[nodiscard]] auto bounds(rclcpp::Parameter const& parameter, T const& lower,
222 T const& upper) -> tl::expected<void, std::string> {
223 auto const& param_value = parameter.get_value<T>();
224 if (param_value < lower || param_value > upper)
225 return tl::unexpected(
226 fmt::format("Parameter '{}' with the value '{}' must be within bounds '[{}, {}]'",
227 parameter.get_name(), detail::stringify(param_value),
228 detail::stringify(lower), detail::stringify(upper)));
229 return {};
230}
231
238template <typename T>
239[[deprecated("Replace with rsl::gt_eq"), nodiscard]] auto lower_bounds(
240 rclcpp::Parameter const& parameter, T const& value) {
241 return detail::compare(parameter, value, "above lower bound of", std::greater_equal<T>());
242}
243
250template <typename T>
251[[deprecated("Replace with rsl::lt_eq"), nodiscard]] auto upper_bounds(
252 rclcpp::Parameter const& parameter, T const& value) {
253 return detail::compare(parameter, value, "below upper bound of", std::less_equal<T>());
254}
255
262template <typename T>
263[[nodiscard]] auto lt(rclcpp::Parameter const& parameter, T const& value) {
264 return detail::compare(parameter, value, "less than", std::less<T>());
265}
266
273template <typename T>
274[[nodiscard]] auto gt(rclcpp::Parameter const& parameter, T const& value) {
275 return detail::compare(parameter, value, "greater than", std::greater<T>());
276}
277
284template <typename T>
285[[nodiscard]] auto lt_eq(rclcpp::Parameter const& parameter, T const& value) {
286 return detail::compare(parameter, value, "less than or equal to", std::less_equal<T>());
287}
288
295template <typename T>
296[[nodiscard]] auto gt_eq(rclcpp::Parameter const& parameter, T const& value) {
297 return detail::compare(parameter, value, "greater than or equal to", std::greater_equal<T>());
298}
299
306template <typename T>
307[[nodiscard]] auto one_of(rclcpp::Parameter const& parameter,
308 std::vector<T> const& collection) -> tl::expected<void, std::string> {
309 auto const& param_value = parameter.get_value<T>();
310 if (contains(collection, param_value)) return {};
311 return tl::unexpected(fmt::format(
312 "Parameter '{}' with the value '{}' is not in the set '{{{}}}'", parameter.get_name(),
313 detail::stringify(param_value), detail::join_stringified(collection)));
314}
315
319[[nodiscard]] RSL_EXPORT auto to_parameter_result_msg(tl::expected<void, std::string> const& result)
320 -> rcl_interfaces::msg::SetParametersResult;
321
322} // namespace rsl
auto contains(Collection const &collection, typename Collection::const_reference value)
Determine if a collection contains a value. Example usage:
Definition algorithm.hpp:19
auto is_unique(Collection collection)
Determine if all elements in a collection are unique. Example usage:
Definition algorithm.hpp:37
auto fixed_size(rclcpp::Parameter const &parameter, size_t const size)
Is the array size of parameter equal to passed in size?
Definition parameter_validators.hpp:109
auto lower_element_bounds(rclcpp::Parameter const &parameter, T const &lower) -> tl::expected< void, std::string >
Are all elements of parameter greater than lower bound?
Definition parameter_validators.hpp:185
auto bounds(rclcpp::Parameter const &parameter, T const &lower, T const &upper) -> tl::expected< void, std::string >
Is parameter within bounds (inclusive)?
Definition parameter_validators.hpp:221
auto gt_eq(rclcpp::Parameter const &parameter, T const &value)
Is parameter greater than or equal to some value?
Definition parameter_validators.hpp:296
auto subset_of(rclcpp::Parameter const &parameter, std::vector< T > const &valid_values) -> tl::expected< void, std::string >
Are the values in parameter a subset of the valid values?
Definition parameter_validators.hpp:91
auto unique(rclcpp::Parameter const &parameter) -> tl::expected< void, std::string >
Is every element of rclcpp::Parameter unique?
Definition parameter_validators.hpp:78
auto one_of(rclcpp::Parameter const &parameter, std::vector< T > const &collection) -> tl::expected< void, std::string >
Is the parameter value one of a set of values?
Definition parameter_validators.hpp:307
auto size_lt(rclcpp::Parameter const &parameter, size_t const size)
Is the array size of parameter less than passed in size?
Definition parameter_validators.hpp:131
auto upper_element_bounds(rclcpp::Parameter const &parameter, T const &upper) -> tl::expected< void, std::string >
Are all elements of parameter less than some upper bound?
Definition parameter_validators.hpp:203
auto element_bounds(rclcpp::Parameter const &parameter, T const &lower, T const &upper) -> tl::expected< void, std::string >
Are all elements of parameter within the bounds (inclusive)?
Definition parameter_validators.hpp:166
auto not_empty(rclcpp::Parameter const &parameter) -> tl::expected< void, std::string >
Is the size of the value passed in not zero?
Definition parameter_validators.hpp:143
RSL_EXPORT auto to_parameter_result_msg(tl::expected< void, std::string > const &result) -> rcl_interfaces::msg::SetParametersResult
Convert the result of a validator function into a SetParametersResult msg.
auto lower_bounds(rclcpp::Parameter const &parameter, T const &value)
Is parameter within some lower bound (same as gt_eq)?
Definition parameter_validators.hpp:239
auto lt(rclcpp::Parameter const &parameter, T const &value)
Is parameter less than some value?
Definition parameter_validators.hpp:263
auto size_gt(rclcpp::Parameter const &parameter, size_t const size)
Is the array size of parameter greater than passed in size?
Definition parameter_validators.hpp:120
auto gt(rclcpp::Parameter const &parameter, T const &value)
Is parameter greater than some value?
Definition parameter_validators.hpp:274
auto lt_eq(rclcpp::Parameter const &parameter, T const &value)
Is parameter less than or equal to some value?
Definition parameter_validators.hpp:285
auto upper_bounds(rclcpp::Parameter const &parameter, T const &value)
Is parameter within some upper bound (same as lt_eq)?
Definition parameter_validators.hpp:251