use std::{any::Any, sync::MutexGuard};
use crate::{log_error, rcl_bindings::*, InnerGuardConditionHandle, RclrsError, ToResult};
pub trait RclPrimitive: Send + Sync {
unsafe fn execute(&mut self, ready: ReadyKind, payload: &mut dyn Any)
-> Result<(), RclrsError>;
fn kind(&self) -> RclPrimitiveKind;
fn handle(&self) -> RclPrimitiveHandle<'_>;
}
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum RclPrimitiveKind {
Subscription,
GuardCondition,
Timer,
Client,
Service,
Event,
ActionServer,
ActionClient,
}
#[derive(Debug)]
pub enum RclPrimitiveHandle<'a> {
Subscription(MutexGuard<'a, rcl_subscription_t>),
GuardCondition(MutexGuard<'a, InnerGuardConditionHandle>),
Timer(MutexGuard<'a, rcl_timer_t>),
Client(MutexGuard<'a, rcl_client_t>),
Service(MutexGuard<'a, rcl_service_t>),
Event(MutexGuard<'a, rcl_event_t>),
ActionServer(MutexGuard<'a, rcl_action_server_t>),
ActionClient(MutexGuard<'a, rcl_action_client_t>),
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ReadyKind {
Basic,
ActionServer(ActionServerReady),
ActionClient(ActionClientReady),
}
impl ReadyKind {
pub fn from_ptr<T>(ptr: *const T) -> Option<Self> {
if ptr.is_null() {
None
} else {
Some(Self::Basic)
}
}
pub fn for_basic(self) -> Result<(), RclrsError> {
match self {
Self::Basic => Ok(()),
_ => Err(RclrsError::InvalidReadyInformation {
expected: Self::Basic,
received: self,
}),
}
}
pub fn for_action_server(self) -> Result<ActionServerReady, RclrsError> {
match self {
Self::ActionServer(ready) => Ok(ready),
_ => Err(RclrsError::InvalidReadyInformation {
expected: Self::ActionServer(Default::default()),
received: self,
}),
}
}
pub fn for_action_client(self) -> Result<ActionClientReady, RclrsError> {
match self {
Self::ActionClient(ready) => Ok(ready),
_ => Err(RclrsError::InvalidReadyInformation {
expected: Self::ActionClient(Default::default()),
received: self,
}),
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct ActionServerReady {
pub goal_request: bool,
pub cancel_request: bool,
pub result_request: bool,
pub goal_expired: bool,
}
impl Default for ActionServerReady {
fn default() -> Self {
Self {
goal_request: false,
cancel_request: false,
result_request: false,
goal_expired: false,
}
}
}
impl ActionServerReady {
pub(crate) unsafe fn check(
wait_set: &rcl_wait_set_t,
action_server: MutexGuard<rcl_action_server_t>,
) -> Option<ReadyKind> {
let mut ready = ActionServerReady::default();
let r = unsafe {
rcl_action_server_wait_set_get_entities_ready(
wait_set,
&*action_server,
&mut ready.goal_request,
&mut ready.cancel_request,
&mut ready.result_request,
&mut ready.goal_expired,
)
};
if let Err(err) = r.ok() {
log_error!(
"ActionServerReady.check",
"Error while checking readiness for action server: {err}",
);
}
if ready.any_ready() {
Some(ReadyKind::ActionServer(ready))
} else {
None
}
}
pub fn any_ready(&self) -> bool {
self.goal_request || self.cancel_request || self.result_request || self.goal_expired
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct ActionClientReady {
pub feedback: bool,
pub status: bool,
pub goal_response: bool,
pub cancel_response: bool,
pub result_response: bool,
}
impl ActionClientReady {
pub(crate) unsafe fn check(
wait_set: &rcl_wait_set_t,
action_client: MutexGuard<rcl_action_client_t>,
) -> Option<ReadyKind> {
let mut ready = ActionClientReady::default();
let r = unsafe {
rcl_action_client_wait_set_get_entities_ready(
wait_set,
&*action_client,
&mut ready.feedback,
&mut ready.status,
&mut ready.goal_response,
&mut ready.cancel_response,
&mut ready.result_response,
)
};
if let Err(err) = r.ok() {
log_error!(
"ActionClientReady.check",
"Error while checking readiness for action client: {err}",
);
}
if ready.any_ready() {
Some(ReadyKind::ActionClient(ready))
} else {
None
}
}
pub fn any_ready(&self) -> bool {
self.feedback
|| self.status
|| self.goal_response
|| self.cancel_response
|| self.result_response
}
}
impl Default for ActionClientReady {
fn default() -> Self {
Self {
feedback: false,
status: false,
goal_response: false,
cancel_response: false,
result_response: false,
}
}
}