15 #include "rclcpp/subscription_base.hpp"
22 #include <unordered_map>
25 #include "rcpputils/scope_exit.hpp"
27 #include "rclcpp/detail/cpp_callback_trampoline.hpp"
28 #include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
29 #include "rclcpp/exceptions.hpp"
30 #include "rclcpp/expand_topic_or_service_name.hpp"
31 #include "rclcpp/experimental/intra_process_manager.hpp"
32 #include "rclcpp/logging.hpp"
33 #include "rclcpp/node_interfaces/node_base_interface.hpp"
34 #include "rclcpp/event_handler.hpp"
37 #include "rmw/error_handling.h"
38 #include "rmw/impl/cpp/demangle.hpp"
41 #include "rosidl_dynamic_typesupport/types.h"
45 SubscriptionBase::SubscriptionBase(
47 const rosidl_message_type_support_t & type_support_handle,
48 const std::string & topic_name,
51 bool use_default_callbacks,
53 : node_base_(node_base),
54 node_handle_(node_base_->get_shared_rcl_node_handle()),
56 use_intra_process_(false),
57 intra_process_subscription_id_(0),
58 event_callbacks_(event_callbacks),
59 type_support_(type_support_handle),
60 delivered_message_kind_(delivered_message_kind)
62 auto custom_deletor = [node_handle = this->node_handle_](
rcl_subscription_t * rcl_subs)
67 "Error in destruction of rcl subscription handle: %s",
68 rcl_get_error_string().str);
74 subscription_handle_ = std::shared_ptr<rcl_subscription_t>(
79 subscription_handle_.get(),
83 &subscription_options);
86 auto rcl_node_handle = node_handle_.get();
94 rclcpp::exceptions::throw_from_rcl_error(ret,
"could not create subscription");
102 if (!use_intra_process_) {
105 auto ipm = weak_ipm_.lock();
110 "Intra process manager died before than a subscription.");
113 ipm->remove_subscription(intra_process_subscription_id_);
127 if (event_callbacks.deadline_callback) {
128 this->add_event_handler(
129 event_callbacks.deadline_callback,
130 RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED);
135 "Failed to add event handler for deadline; not supported");
139 if (event_callbacks.liveliness_callback) {
140 this->add_event_handler(
141 event_callbacks.liveliness_callback,
142 RCL_SUBSCRIPTION_LIVELINESS_CHANGED);
147 "Failed to add event handler for liveliness; not supported");
150 QOSRequestedIncompatibleQoSCallbackType incompatible_qos_cb;
151 if (event_callbacks.incompatible_qos_callback) {
152 incompatible_qos_cb = event_callbacks.incompatible_qos_callback;
153 }
else if (use_default_callbacks) {
155 incompatible_qos_cb = [
this](QOSRequestedIncompatibleQoSInfo & info) {
156 this->default_incompatible_qos_callback(info);
161 if (incompatible_qos_cb) {
162 this->add_event_handler(incompatible_qos_cb, RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS);
167 "Failed to add event handler for incompatible qos; not supported");
170 IncompatibleTypeCallbackType incompatible_type_cb;
171 if (event_callbacks.incompatible_type_callback) {
172 incompatible_type_cb = event_callbacks.incompatible_type_callback;
173 }
else if (use_default_callbacks) {
175 incompatible_type_cb = [
this](IncompatibleTypeInfo & info) {
176 this->default_incompatible_type_callback(info);
180 if (incompatible_type_cb) {
181 this->add_event_handler(incompatible_type_cb, RCL_SUBSCRIPTION_INCOMPATIBLE_TYPE);
186 "Failed to add event handler for incompatible type; not supported");
190 if (event_callbacks.message_lost_callback) {
191 this->add_event_handler(
192 event_callbacks.message_lost_callback,
193 RCL_SUBSCRIPTION_MESSAGE_LOST);
198 "Failed to add event handler for message lost; not supported");
202 if (event_callbacks.matched_callback) {
203 this->add_event_handler(
204 event_callbacks.matched_callback,
205 RCL_SUBSCRIPTION_MATCHED);
210 "Failed to add event handler for matched; not supported");
220 std::shared_ptr<rcl_subscription_t>
221 SubscriptionBase::get_subscription_handle()
223 return subscription_handle_;
226 std::shared_ptr<const rcl_subscription_t>
227 SubscriptionBase::get_subscription_handle()
const
229 return subscription_handle_;
233 std::unordered_map<rcl_subscription_event_type_t, std::shared_ptr<rclcpp::EventHandlerBase>> &
236 return event_handlers_;
244 auto msg = std::string(
"failed to get qos settings: ") + rcl_get_error_string().str;
246 throw std::runtime_error(msg);
256 this->get_subscription_handle().get(),
261 TRACETOOLS_TRACEPOINT(rclcpp_take,
static_cast<const void *
>(message_out));
265 rclcpp::exceptions::throw_from_rcl_error(ret);
283 this->get_subscription_handle().get(),
287 TRACETOOLS_TRACEPOINT(
293 rclcpp::exceptions::throw_from_rcl_error(ret);
298 const rosidl_message_type_support_t &
299 SubscriptionBase::get_message_type_support_handle()
const
301 return type_support_;
307 return delivered_message_kind_ == rclcpp::DeliveredMessageKind::SERIALIZED_MESSAGE;
313 return delivered_message_kind_;
319 size_t inter_process_publisher_count = 0;
322 subscription_handle_.get(),
323 &inter_process_publisher_count);
326 rclcpp::exceptions::throw_from_rcl_error(status,
"failed to get get publisher count");
328 return inter_process_publisher_count;
333 uint64_t intra_process_subscription_id,
334 IntraProcessManagerWeakPtr weak_ipm)
336 intra_process_subscription_id_ = intra_process_subscription_id;
337 weak_ipm_ = std::move(weak_ipm);
338 use_intra_process_ =
true;
353 "Loaned messages are only safe with const ref subscription callbacks. "
354 "If you are using any other kind of subscriptions, "
355 "set the ROS_DISABLE_LOANED_MESSAGES environment variable to 1 (the default).");
360 rclcpp::Waitable::SharedPtr
364 if (!use_intra_process_) {
368 auto ipm = weak_ipm_.lock();
370 throw std::runtime_error(
371 "SubscriptionBase::get_intra_process_waitable() called "
372 "after destruction of intra process manager");
376 return ipm->get_subscription_intra_process(intra_process_subscription_id_);
380 SubscriptionBase::default_incompatible_qos_callback(
381 rclcpp::QOSRequestedIncompatibleQoSInfo & event)
const
383 std::string policy_name = qos_policy_name_from_kind(event.last_policy_kind);
386 "New publisher discovered on topic '%s', offering incompatible QoS. "
387 "No messages will be sent to it. "
388 "Last incompatible policy: %s",
390 policy_name.c_str());
394 SubscriptionBase::default_incompatible_type_callback(
395 [[maybe_unused]] rclcpp::IncompatibleTypeInfo & event)
const
399 "Incompatible type on topic '%s', no messages will be sent to it.",
get_topic_name());
403 SubscriptionBase::matches_any_intra_process_publishers(
const rmw_gid_t * sender_gid)
const
405 if (!use_intra_process_) {
408 auto ipm = weak_ipm_.lock();
410 throw std::runtime_error(
411 "intra process publisher check called "
412 "after destruction of intra process manager");
414 return ipm->matches_any_publishers(sender_gid);
419 void * pointer_to_subscription_part,
422 if (
nullptr == pointer_to_subscription_part) {
423 throw std::invalid_argument(
"pointer_to_subscription_part is unexpectedly nullptr");
425 if (
this == pointer_to_subscription_part) {
426 return subscription_in_use_by_wait_set_.exchange(in_use_state);
429 return intra_process_subscription_waitable_in_use_by_wait_set_.exchange(in_use_state);
431 for (
const auto & key_event_pair : event_handlers_) {
432 auto qos_event = key_event_pair.second;
433 if (qos_event.get() == pointer_to_subscription_part) {
434 return qos_events_in_use_by_wait_set_[qos_event.get()].exchange(in_use_state);
437 throw std::runtime_error(
"given pointer_to_subscription_part does not match any part");
440 std::vector<rclcpp::NetworkFlowEndpoint>
443 rcutils_allocator_t allocator = rcutils_get_default_allocator();
444 rcl_network_flow_endpoint_array_t network_flow_endpoint_array =
445 rcl_get_zero_initialized_network_flow_endpoint_array();
446 rcl_ret_t ret = rcl_subscription_get_network_flow_endpoints(
447 subscription_handle_.get(), &allocator, &network_flow_endpoint_array);
449 auto error_msg = std::string(
"Error obtaining network flows of subscription: ") +
450 rcl_get_error_string().str;
453 rcl_network_flow_endpoint_array_fini(&network_flow_endpoint_array))
455 error_msg += std::string(
". Also error cleaning up network flow array: ") +
456 rcl_get_error_string().str;
459 rclcpp::exceptions::throw_from_rcl_error(ret, error_msg);
462 std::vector<rclcpp::NetworkFlowEndpoint> network_flow_endpoint_vector;
463 network_flow_endpoint_vector.reserve(network_flow_endpoint_array.size);
464 for (
size_t i = 0; i < network_flow_endpoint_array.size; ++i) {
465 network_flow_endpoint_vector.emplace_back(
466 network_flow_endpoint_array.
467 network_flow_endpoint[i]);
470 ret = rcl_network_flow_endpoint_array_fini(&network_flow_endpoint_array);
472 rclcpp::exceptions::throw_from_rcl_error(ret,
"error cleaning up network flow array");
475 return network_flow_endpoint_vector;
480 rcl_event_callback_t callback,
481 const void * user_data)
484 subscription_handle_.get(),
489 using rclcpp::exceptions::throw_from_rcl_error;
490 throw_from_rcl_error(ret,
"failed to set the on new message callback for subscription");
508 const std::string & filter_expression,
509 const std::vector<std::string> & expression_parameters)
516 subscription_handle_.get(),
522 rclcpp::exceptions::throw_from_rcl_error(
523 ret,
"failed to init subscription content_filtered_topic option");
525 RCPPUTILS_SCOPE_EXIT(
528 subscription_handle_.get(), &options);
532 "Failed to fini subscription content_filtered_topic option: %s",
533 rcl_get_error_string().str);
539 subscription_handle_.get(),
543 rclcpp::exceptions::throw_from_rcl_error(ret,
"failed to set cft expression parameters");
555 subscription_handle_.get(),
559 rclcpp::exceptions::throw_from_rcl_error(ret,
"failed to get cft expression parameters");
562 RCPPUTILS_SCOPE_EXIT(
565 subscription_handle_.get(), &options);
569 "Failed to fini subscription content_filtered_topic option: %s",
570 rcl_get_error_string().str);
575 rmw_subscription_content_filter_options_t & content_filter_options =
576 options.rmw_subscription_content_filter_options;
579 for (
size_t i = 0; i < content_filter_options.expression_parameters.size; ++i) {
581 content_filter_options.expression_parameters.data[i]);
590 SubscriptionBase::take_dynamic_message(
594 throw std::runtime_error(
"Unimplemented");
602 std::lock_guard<std::recursive_mutex> lock(on_new_message_callback_mutex_);
603 if (on_new_message_callback_) {
612 std::lock_guard<std::recursive_mutex> lock(on_new_message_callback_mutex_);
613 if (on_new_message_callback_) {
615 rclcpp::detail::cpp_callback_trampoline<
616 decltype(on_new_message_callback_),
const void *,
size_t>,
617 static_cast<const void *
>(&on_new_message_callback_));
625 throw std::invalid_argument(
626 "The callback passed to set_on_new_message_callback "
631 [callback,
this](
size_t number_of_messages) {
633 callback(number_of_messages);
634 }
catch (
const std::exception & exception) {
637 "rclcpp::SubscriptionBase@" <<
this <<
638 " caught " << rmw::impl::cpp::demangle(exception) <<
639 " exception in user-provided callback for the 'on new message' callback: " <<
644 "rclcpp::SubscriptionBase@" <<
this <<
645 " caught unhandled exception in user-provided callback " <<
646 "for the 'on new message' callback");
650 std::lock_guard<std::recursive_mutex> lock(on_new_message_callback_mutex_);
656 rclcpp::detail::cpp_callback_trampoline<decltype(new_callback),
const void *,
size_t>,
657 static_cast<const void *
>(&new_callback));
660 on_new_message_callback_ = new_callback;
664 rclcpp::detail::cpp_callback_trampoline<
665 decltype(on_new_message_callback_),
const void *,
size_t>,
666 static_cast<const void *
>(&on_new_message_callback_));
672 std::lock_guard<std::recursive_mutex> lock(on_new_message_callback_mutex_);
674 if (on_new_message_callback_) {
676 on_new_message_callback_ =
nullptr;
682 const std::function<
void(
size_t)> & callback)
684 if (!use_intra_process_) {
687 "Calling set_on_new_intra_process_message_callback for subscription with IPC disabled");
692 throw std::invalid_argument(
693 "The callback passed to set_on_new_intra_process_message_callback "
700 std::function<void(
size_t,
int)> new_callback = [callback] (
size_t nr, int) {callback(nr);};
701 subscription_intra_process_->set_on_ready_callback(new_callback);
707 if (!use_intra_process_) {
710 "Calling clear_on_new_intra_process_message_callback for subscription with IPC disabled");
714 subscription_intra_process_->clear_on_ready_callback();
719 const std::function<
void(
size_t)> & callback,
722 if (event_handlers_.count(event_type) == 0) {
725 "Calling set_on_new_qos_event_callback for non registered subscription event_type");
730 throw std::invalid_argument(
731 "The callback passed to set_on_new_qos_event_callback "
738 std::function<void(
size_t,
int)> new_callback = [callback] (
size_t nr, int) {callback(nr);};
739 event_handlers_[event_type]->set_on_ready_callback(new_callback);
745 if (event_handlers_.count(event_type) == 0) {
748 "Calling clear_on_new_qos_event_callback for non registered event_type");
752 event_handlers_[event_type]->clear_on_ready_callback();
RCLCPP_PUBLIC Logger get_child(const std::string &suffix)
Return a logger that is a descendant of this logger.
Additional meta data about messages taken from subscriptions.
const rmw_message_info_t & get_rmw_message_info() const
Return the message info as the underlying rmw message info type.
Encapsulation of Quality of Service settings.
Object oriented version of rcl_serialized_message_t with destructor to avoid memory leaks.
rcl_serialized_message_t & get_rcl_serialized_message()
Get the underlying rcl_serialized_t handle.
RCLCPP_PUBLIC size_t get_publisher_count() const
Get matching publisher count.
RCLCPP_PUBLIC rclcpp::QoS get_actual_qos() const
Get the actual QoS settings, after the defaults have been determined.
RCLCPP_PUBLIC void set_on_new_message_callback(const std::function< void(size_t)> &callback)
Set a callback to be called when each new message is received.
RCLCPP_PUBLIC void clear_on_new_message_callback()
Unset the callback registered for new messages, if any.
RCLCPP_PUBLIC void set_on_new_qos_event_callback(const std::function< void(size_t)> &callback, rcl_subscription_event_type_t event_type)
Set a callback to be called when each new qos event instance occurs.
virtual RCLCPP_PUBLIC void enable_callbacks()
Enable the callbacks to be called.
RCLCPP_PUBLIC bool can_loan_messages() const
Check if subscription instance can loan messages.
static RCLCPP_PUBLIC bool event_type_is_supported(const rcl_subscription_event_type_t event_type)
Check if a subscription event type is supported by the active RMW implementation.
RCLCPP_PUBLIC bool is_cft_supported() const
Check if content filtered topic feature of the subscription instance is supported.
RCLCPP_PUBLIC rclcpp::Waitable::SharedPtr get_intra_process_waitable() const
Return the waitable for intra-process.
RCLCPP_PUBLIC std::vector< rclcpp::NetworkFlowEndpoint > get_network_flow_endpoints() const
Get network flow endpoints.
RCLCPP_PUBLIC void setup_intra_process(uint64_t intra_process_subscription_id, IntraProcessManagerWeakPtr weak_ipm)
Implemenation detail.
RCLCPP_PUBLIC DeliveredMessageKind get_delivered_message_kind() const
Return the delivered message kind.
RCLCPP_PUBLIC void set_on_new_intra_process_message_callback(const std::function< void(size_t)> &callback)
Set a callback to be called when each new intra-process message is received.
virtual RCLCPP_PUBLIC void disable_callbacks()
Disable callbacks from being called.
RCLCPP_PUBLIC void clear_on_new_qos_event_callback(rcl_subscription_event_type_t event_type)
Unset the callback registered for new qos events, if any.
RCLCPP_PUBLIC bool take_serialized(rclcpp::SerializedMessage &message_out, rclcpp::MessageInfo &message_info_out)
Take the next inter-process message, in its serialized form, from the subscription.
RCLCPP_PUBLIC bool take_type_erased(void *message_out, rclcpp::MessageInfo &message_info_out)
Take the next inter-process message from the subscription as a type erased pointer.
RCLCPP_PUBLIC bool exchange_in_use_by_wait_set_state(void *pointer_to_subscription_part, bool in_use_state)
Exchange state of whether or not a part of the subscription is used by a wait set.
RCLCPP_PUBLIC void set_content_filter(const std::string &filter_expression, const std::vector< std::string > &expression_parameters={})
Set the filter expression and expression parameters for the subscription.
virtual RCLCPP_PUBLIC ~SubscriptionBase()
Destructor.
RCLCPP_PUBLIC bool is_cft_enabled() const
Check if content filtered topic feature of the subscription instance is enabled.
RCLCPP_PUBLIC void bind_event_callbacks(const SubscriptionEventCallbacks &event_callbacks, bool use_default_callbacks)
Add event handlers for passed in event_callbacks.
RCLCPP_PUBLIC const std::unordered_map< rcl_subscription_event_type_t, std::shared_ptr< rclcpp::EventHandlerBase > > & get_event_handlers() const
Get all the QoS event handlers associated with this subscription.
RCLCPP_PUBLIC void clear_on_new_intra_process_message_callback()
Unset the callback registered for new intra-process messages, if any.
RCLCPP_PUBLIC rclcpp::ContentFilterOptions get_content_filter() const
Get the filter expression and expression parameters for the subscription.
RCLCPP_PUBLIC bool is_serialized() const
Return if the subscription is serialized.
RCLCPP_PUBLIC const char * get_topic_name() const
Get the topic that this subscription is subscribed on.
Pure virtual interface class for the NodeBase part of the Node API.
enum rcl_subscription_event_type_e rcl_subscription_event_type_t
Enumeration of all of the subscription events that may fire.
RCL_PUBLIC RCL_WARN_UNUSED bool rcl_subscription_event_type_is_supported(const rcl_subscription_event_type_t event_type)
Check if a subscription event type is supported by the active RMW implementation.
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
RCLCPP_PUBLIC std::string expand_topic_or_service_name(const std::string &name, const std::string &node_name, const std::string &namespace_, bool is_service=false)
Expand a topic or service name and throw if it is not valid.
RCLCPP_PUBLIC Logger get_node_logger(const rcl_node_t *node)
Return a named logger using an rcl_node_t.
DeliveredMessageKind
The kind of message that the subscription delivers in its callback, used by the executor.
RCLCPP_PUBLIC std::vector< const char * > get_c_vector_string(const std::vector< std::string > &strings_in)
Return the std::vector of C string from the given std::vector<std::string>.
RCLCPP_PUBLIC const char * get_c_string(const char *string_in)
Return the given string.
RCLCPP_PUBLIC Logger get_logger(const std::string &name)
Return a named logger.
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_node_get_name(const rcl_node_t *node)
Return the name of the node.
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_node_get_namespace(const rcl_node_t *node)
Return the namespace of the node.
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_node_get_logger_name(const rcl_node_t *node)
Return the logger name of the node.
Options available for a rcl subscription.
Structure which encapsulates a ROS Subscription.
Options to configure content filtered topic in the subscription.
std::string filter_expression
Filter expression is similar to the WHERE part of an SQL clause.
std::vector< std::string > expression_parameters
static QoSInitialization from_rmw(const rmw_qos_profile_t &rmw_qos)
Create a QoSInitialization from an existing rmw_qos_profile_t, using its history and depth.
Contains callbacks for non-message events that a Subscription can receive from the middleware.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_content_filter_options_fini(const rcl_subscription_t *subscription, rcl_subscription_content_filter_options_t *options)
Reclaim rcl_subscription_content_filter_options_t structure.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_init(rcl_subscription_t *subscription, const rcl_node_t *node, const rosidl_message_type_support_t *type_support, const char *topic_name, const rcl_subscription_options_t *options)
Initialize a ROS subscription.
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_subscription_get_topic_name(const rcl_subscription_t *subscription)
Get the topic name for the subscription.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_set_on_new_message_callback(const rcl_subscription_t *subscription, rcl_event_callback_t callback, const void *user_data)
Set the on new message callback function for the subscription.
RCL_PUBLIC bool rcl_subscription_can_loan_messages(const rcl_subscription_t *subscription)
Check if subscription instance can loan messages.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_fini(rcl_subscription_t *subscription, rcl_node_t *node)
Finalize a rcl_subscription_t.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_take(const rcl_subscription_t *subscription, void *ros_message, rmw_message_info_t *message_info, rmw_subscription_allocation_t *allocation)
Take a ROS message from a topic using a rcl subscription.
RCL_PUBLIC RCL_WARN_UNUSED rmw_ret_t rcl_subscription_get_publisher_count(const rcl_subscription_t *subscription, size_t *publisher_count)
Get the number of publishers matched to a subscription.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_take_serialized_message(const rcl_subscription_t *subscription, rcl_serialized_message_t *serialized_message, rmw_message_info_t *message_info, rmw_subscription_allocation_t *allocation)
Take a serialized raw message from a topic using a rcl subscription.
RCL_PUBLIC RCL_WARN_UNUSED rcl_subscription_content_filter_options_t rcl_get_zero_initialized_subscription_content_filter_options(void)
Return the zero initialized subscription content filter options.
RCL_PUBLIC RCL_WARN_UNUSED bool rcl_subscription_is_cft_enabled(const rcl_subscription_t *subscription)
Check if the content filtered topic feature is enabled in the subscription.
RCL_PUBLIC RCL_WARN_UNUSED const rmw_qos_profile_t * rcl_subscription_get_actual_qos(const rcl_subscription_t *subscription)
Get the actual qos settings of the subscription.
RCL_PUBLIC RCL_WARN_UNUSED rcl_subscription_t rcl_get_zero_initialized_subscription(void)
Return a rcl_subscription_t struct with members set to NULL.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_get_content_filter(const rcl_subscription_t *subscription, rcl_subscription_content_filter_options_t *options)
Retrieve the filter expression of the subscription.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_set_content_filter(const rcl_subscription_t *subscription, const rcl_subscription_content_filter_options_t *options)
Set the filter expression and expression parameters for the subscription.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_content_filter_options_init(const rcl_subscription_t *subscription, const char *filter_expression, size_t expression_parameters_argc, const char *expression_parameter_argv[], rcl_subscription_content_filter_options_t *options)
Initialize the content filter options for the given subscription options.
RCL_PUBLIC bool rcl_subscription_is_cft_supported(const rcl_subscription_t *subscription)
Check if subscription instance supports content filtering.
#define RCL_RET_SUBSCRIPTION_TAKE_FAILED
Failed to take a message from the subscription return code.
#define RCL_RET_OK
Success return code.
#define RCL_RET_TOPIC_NAME_INVALID
Topic name does not pass validation.
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.