72 [[deprecated(
"Use InterfaceDescription for initializing the Interface")]]
73 Handle(
const std::string & prefix_name,
const std::string & interface_name,
double * value_ptr)
75 interface_name_(interface_name),
82 const std::string & prefix_name,
const std::string & interface_name,
83 const std::string & data_type =
"double",
const std::string & initial_value =
"")
85 interface_name_(interface_name),
90 if (data_type_ == hardware_interface::HandleDataType::DOUBLE)
94 value_ = initial_value.empty() ? std::numeric_limits<double>::quiet_NaN()
96 value_ptr_ = std::get_if<double>(&value_);
98 catch (
const std::invalid_argument & err)
100 throw std::invalid_argument(
103 "Invalid initial value : '{}' parsed for interface : '{}' with type : '{}'"),
104 initial_value, handle_name_, data_type_.to_string()));
107 else if (data_type_ == hardware_interface::HandleDataType::FLOAT32)
111 value_ptr_ =
nullptr;
112 value_ = initial_value.empty()
113 ? std::numeric_limits<float>::quiet_NaN()
116 catch (
const std::invalid_argument & err)
118 throw std::invalid_argument(
120 FMT_COMPILE(
"Invalid initial value: '{}' parsed for interface: '{}' with type: '{}'"),
121 initial_value, handle_name_, data_type_.to_string()));
124 else if (data_type_ == hardware_interface::HandleDataType::BOOL)
128 value_ptr_ =
nullptr;
131 catch (
const std::invalid_argument & err)
133 throw std::invalid_argument(
135 FMT_COMPILE(
"Invalid initial value: '{}' parsed for interface: '{}' with type: '{}'"),
136 initial_value, handle_name_, data_type_.to_string()));
139 else if (data_type_ == hardware_interface::HandleDataType::UINT8)
143 value_ptr_ =
nullptr;
144 value_ = initial_value.empty()
145 ?
static_cast<uint8_t
>(std::numeric_limits<uint8_t>::max())
146 :
static_cast<uint8_t
>(hardware_interface::stoui8(initial_value));
148 catch (
const std::invalid_argument & err)
150 throw std::invalid_argument(
152 FMT_COMPILE(
"Invalid initial value: '{}' parsed for interface: '{}' with type: '{}'"),
153 initial_value, handle_name_, data_type_.to_string()));
156 else if (data_type_ == hardware_interface::HandleDataType::INT8)
160 value_ptr_ =
nullptr;
161 value_ = initial_value.empty()
162 ?
static_cast<int8_t
>(std::numeric_limits<int8_t>::max())
163 :
static_cast<int8_t
>(hardware_interface::stoi8(initial_value));
165 catch (
const std::invalid_argument & err)
167 throw std::invalid_argument(
169 FMT_COMPILE(
"Invalid initial value: '{}' parsed for interface: '{}' with type: '{}'"),
170 initial_value, handle_name_, data_type_.to_string()));
173 else if (data_type_ == hardware_interface::HandleDataType::UINT16)
177 value_ptr_ =
nullptr;
178 value_ = initial_value.empty()
179 ?
static_cast<uint16_t
>(std::numeric_limits<uint16_t>::max())
180 :
static_cast<uint16_t
>(hardware_interface::stoui16(initial_value));
182 catch (
const std::invalid_argument & err)
184 throw std::invalid_argument(
186 FMT_COMPILE(
"Invalid initial value: '{}' parsed for interface: '{}' with type: '{}'"),
187 initial_value, handle_name_, data_type_.to_string()));
190 else if (data_type_ == hardware_interface::HandleDataType::INT16)
194 value_ptr_ =
nullptr;
195 value_ = initial_value.empty()
196 ?
static_cast<int16_t
>(std::numeric_limits<int16_t>::max())
197 :
static_cast<int16_t
>(hardware_interface::stoi16(initial_value));
199 catch (
const std::invalid_argument & err)
201 throw std::invalid_argument(
203 FMT_COMPILE(
"Invalid initial value: '{}' parsed for interface: '{}' with type: '{}'"),
204 initial_value, handle_name_, data_type_.to_string()));
207 else if (data_type_ == hardware_interface::HandleDataType::UINT32)
211 value_ptr_ =
nullptr;
212 value_ = initial_value.empty()
213 ?
static_cast<uint32_t
>(std::numeric_limits<uint32_t>::max())
214 :
static_cast<uint32_t
>(hardware_interface::stoui32(initial_value));
216 catch (
const std::invalid_argument & err)
218 throw std::invalid_argument(
220 FMT_COMPILE(
"Invalid initial value: '{}' parsed for interface: '{}' with type: '{}'"),
221 initial_value, handle_name_, data_type_.to_string()));
224 else if (data_type_ == hardware_interface::HandleDataType::INT32)
228 value_ptr_ =
nullptr;
229 value_ = initial_value.empty()
230 ?
static_cast<int32_t
>(std::numeric_limits<int32_t>::max())
231 :
static_cast<int32_t
>(hardware_interface::stoi32(initial_value));
233 catch (
const std::invalid_argument & err)
235 throw std::invalid_argument(
237 FMT_COMPILE(
"Invalid initial value: '{}' parsed for interface: '{}' with type: '{}'"),
238 initial_value, handle_name_, data_type_.to_string()));
243 throw std::runtime_error(
245 FMT_COMPILE(
"Invalid data type: '{}' for interface: {}. Check supported types."),
246 data_type, handle_name_));
252 interface_description.get_prefix_name(), interface_description.get_interface_name(),
253 interface_description.get_data_type_string(),
258 [[deprecated(
"Use InterfaceDescription for initializing the Interface")]]
260 explicit Handle(
const std::string & interface_name)
261 : interface_name_(interface_name), handle_name_(
"/" + interface_name_), value_ptr_(
nullptr)
265 [[deprecated(
"Use InterfaceDescription for initializing the Interface")]]
267 explicit Handle(
const char * interface_name)
268 : interface_name_(interface_name), handle_name_(
"/" + interface_name_), value_ptr_(
nullptr)
283 Handle(
Handle && other)
noexcept { swap(*
this, other); }
294 inline operator bool()
const {
return value_ptr_ !=
nullptr; }
296 const std::string & get_name()
const {
return handle_name_; }
298 const std::string & get_interface_name()
const {
return interface_name_; }
301 "Replaced by get_name method, which is semantically more correct")]]
const std::string &
302 get_full_name()
const
307 const std::string & get_prefix_name()
const {
return prefix_name_; }
310 "Use std::optional<T> get_optional() instead to retrieve the value. This method will be "
311 "removed by the ROS 2 Kilted Kaiju release.")]]
312 double get_value()
const
314 std::shared_lock<std::shared_mutex> lock(handle_mutex_, std::try_to_lock);
315 if (!lock.owns_lock())
317 return std::numeric_limits<double>::quiet_NaN();
321 THROW_ON_NULLPTR(value_ptr_);
336 template <
typename T =
double>
339 std::shared_lock<std::shared_mutex> lock(handle_mutex_, std::try_to_lock);
340 return get_optional<T>(lock);
353 template <
typename T =
double>
354 [[nodiscard]] std::optional<T>
get_optional(std::shared_lock<std::shared_mutex> & lock)
const
356 if (!lock.owns_lock())
362 if constexpr (std::is_same_v<T, double>)
366 case HandleDataType::DOUBLE:
367 THROW_ON_NULLPTR(value_ptr_);
369 case HandleDataType::BOOL:
370 case HandleDataType::FLOAT32:
371 case HandleDataType::UINT8:
372 case HandleDataType::INT8:
373 case HandleDataType::UINT16:
374 case HandleDataType::INT16:
375 case HandleDataType::UINT32:
376 case HandleDataType::INT32:
377 throw std::runtime_error(
380 "Data type: '{}' will not be casted to double for interface: {}. Use "
381 "get_optional<{}>() instead."),
382 data_type_.to_string(), get_name(), data_type_.to_string()));
384 throw std::runtime_error(
386 FMT_COMPILE(
"Data type: '{}' cannot be casted to double for interface: {}"),
387 data_type_.to_string(), get_name()));
392 return std::get<T>(value_);
394 catch (
const std::bad_variant_access & err)
396 throw std::runtime_error(
398 FMT_COMPILE(
"Invalid data type : '{}' access for interface : {} expected : '{}'"),
399 get_type_name<T>(), get_name(), data_type_.to_string()));
415 template <
typename T>
417 "Use std::optional<T> get_optional() instead to retrieve the value. This method will be "
418 "removed by the ROS 2 Kilted Kaiju release.")]] [[nodiscard]]
bool
421 std::shared_lock<std::shared_mutex> lock(handle_mutex_, std::try_to_lock);
422 if (!lock.owns_lock())
428 if constexpr (std::is_same_v<T, double>)
431 THROW_ON_NULLPTR(value_ptr_);
438 value = std::get<T>(value_);
440 catch (
const std::bad_variant_access & err)
442 throw std::runtime_error(
444 FMT_COMPILE(
"Invalid data type : '{}' access for interface : {} expected : '{}'"),
445 get_type_name<T>(), get_name(), data_type_.to_string()));
465 typename T,
typename = std::enable_if_t<
466 !std::is_same_v<std::decay_t<T>, std::shared_lock<std::shared_mutex>>>>
467 [[nodiscard]]
bool get_value(T & value,
bool wait_for_lock)
const
471 std::shared_lock<std::shared_mutex> lock(handle_mutex_);
472 return get_value(lock, value);
476 std::shared_lock<std::shared_mutex> lock(handle_mutex_, std::try_to_lock);
477 return get_value(lock, value);
492 template <
typename T>
493 [[nodiscard]]
bool set_value(
const T & value,
bool wait_for_lock)
497 std::unique_lock<std::shared_mutex> lock(handle_mutex_);
502 std::unique_lock<std::shared_mutex> lock(handle_mutex_, std::try_to_lock);
518 template <
typename T>
521 std::unique_lock<std::shared_mutex> lock(handle_mutex_, std::try_to_lock);
537 template <
typename T>
538 [[nodiscard]]
bool set_value(std::unique_lock<std::shared_mutex> & lock,
const T & value)
540 if (!lock.owns_lock())
546 if constexpr (std::is_same_v<T, double>)
549 THROW_ON_NULLPTR(value_ptr_);
554 if (!std::holds_alternative<T>(value_))
556 throw std::runtime_error(
558 FMT_COMPILE(
"Invalid data type : '{}' access for interface : {} expected : '{}'"),
559 get_type_name<T>(), get_name(), data_type_.to_string()));
567 std::shared_mutex & get_mutex()
const {
return handle_mutex_; }
569 HandleDataType get_data_type()
const {
return data_type_; }
574 bool is_valid()
const
576 return (value_ptr_ !=
nullptr) || !std::holds_alternative<std::monostate>(value_);
589 template <
typename T>
590 [[nodiscard]]
bool get_value(std::shared_lock<std::shared_mutex> & lock, T & value)
const
592 if (!lock.owns_lock())
598 if constexpr (std::is_same_v<T, double>)
602 case HandleDataType::DOUBLE:
603 THROW_ON_NULLPTR(value_ptr_);
606 case HandleDataType::BOOL:
607 case HandleDataType::FLOAT32:
608 case HandleDataType::UINT8:
609 case HandleDataType::INT8:
610 case HandleDataType::UINT16:
611 case HandleDataType::INT16:
612 case HandleDataType::UINT32:
613 case HandleDataType::INT32:
614 throw std::runtime_error(
617 "Data type: '{}' will not be casted to double for interface: {}. Use "
618 "get_optional<{}>() instead."),
619 data_type_.to_string(), get_name(), data_type_.to_string()));
621 throw std::runtime_error(
623 FMT_COMPILE(
"Data type: '{}' cannot be casted to double for interface: {}"),
624 data_type_.to_string(), get_name()));
629 value = std::get<T>(value_);
632 catch (
const std::bad_variant_access & err)
634 throw std::runtime_error(
636 FMT_COMPILE(
"Invalid data type: '{}' access for interface: {} expected: '{}'"),
637 get_type_name<T>(), get_name(), data_type_.to_string()));
642 void copy(
const Handle & other)
noexcept
644 std::scoped_lock lock(other.handle_mutex_, handle_mutex_);
646 interface_name_ = other.interface_name_;
647 handle_name_ = other.handle_name_;
648 value_ = other.value_;
649 data_type_ = other.data_type_;
650 if (std::holds_alternative<std::monostate>(value_))
652 value_ptr_ = other.value_ptr_;
656 value_ptr_ = std::get_if<double>(&value_);
660 void swap(Handle & first, Handle & second)
noexcept
662 std::scoped_lock lock(first.handle_mutex_, second.handle_mutex_);
663 std::swap(first.prefix_name_, second.prefix_name_);
664 std::swap(first.interface_name_, second.interface_name_);
665 std::swap(first.handle_name_, second.handle_name_);
666 std::swap(first.value_, second.value_);
667 std::swap(first.data_type_, second.data_type_);
668 std::swap(first.value_ptr_, second.value_ptr_);
674 std::string interface_name_;
675 std::string handle_name_;
680 double * value_ptr_ =
nullptr;
682 mutable std::shared_mutex handle_mutex_;