use std::{
any::Any,
sync::{Arc, Mutex},
};
use crate::{
rcl_bindings::*, ContextHandle, RclPrimitive, RclPrimitiveHandle, RclPrimitiveKind, RclrsError,
ReadyKind, ToResult, Waitable, WaitableLifecycle,
};
pub struct GuardCondition {
handle: Arc<GuardConditionHandle>,
#[allow(unused)]
lifecycle: WaitableLifecycle,
}
unsafe impl Send for rcl_guard_condition_t {}
unsafe impl Send for InnerGuardConditionHandle {}
impl GuardCondition {
pub fn trigger(&self) -> Result<(), RclrsError> {
if let Some(handle) = self.handle.rcl_guard_condition.lock().unwrap().owned_mut() {
unsafe {
rcl_trigger_guard_condition(handle).ok()?;
}
} else {
return Err(RclrsError::UnownedGuardCondition);
}
Ok(())
}
pub(crate) fn new(
context: &Arc<ContextHandle>,
callback: Option<Box<dyn FnMut() + Send + Sync>>,
) -> (Arc<Self>, Waitable) {
let rcl_guard_condition = {
let mut guard_condition = unsafe { rcl_get_zero_initialized_guard_condition() };
let mut rcl_context = context.rcl_context.lock().unwrap();
unsafe {
rcl_guard_condition_init(
&mut guard_condition,
&mut *rcl_context,
rcl_guard_condition_get_default_options(),
);
}
Mutex::new(InnerGuardConditionHandle::Owned(guard_condition))
};
let handle = Arc::new(GuardConditionHandle {
rcl_guard_condition,
context_handle: Arc::clone(&context),
});
let (waitable, lifecycle) = Waitable::new(
Box::new(GuardConditionExecutable {
handle: Arc::clone(&handle),
callback,
}),
None,
);
(Arc::new(Self { handle, lifecycle }), waitable)
}
pub(crate) unsafe fn from_rcl(
context: &Arc<ContextHandle>,
rcl_guard_condition: *const rcl_guard_condition_t,
owner: Box<dyn Any>,
callback: Option<Box<dyn FnMut() + Send + Sync>>,
) -> (Self, Waitable) {
let rcl_guard_condition = Mutex::new(InnerGuardConditionHandle::Unowned {
handle: rcl_guard_condition,
owner,
});
let handle = Arc::new(GuardConditionHandle {
rcl_guard_condition,
context_handle: Arc::clone(&context),
});
let (waitable, lifecycle) = Waitable::new(
Box::new(GuardConditionExecutable {
handle: Arc::clone(&handle),
callback,
}),
None,
);
(Self { handle, lifecycle }, waitable)
}
}
struct GuardConditionHandle {
rcl_guard_condition: Mutex<InnerGuardConditionHandle>,
#[allow(dead_code)]
context_handle: Arc<ContextHandle>,
}
#[derive(Debug)]
pub enum InnerGuardConditionHandle {
Owned(rcl_guard_condition_t),
Unowned {
handle: *const rcl_guard_condition_t,
owner: Box<dyn Any>,
},
}
impl InnerGuardConditionHandle {
pub fn owned(&self) -> Option<&rcl_guard_condition_t> {
match self {
Self::Owned(handle) => Some(handle),
_ => None,
}
}
pub fn owned_mut(&mut self) -> Option<&mut rcl_guard_condition_t> {
match self {
Self::Owned(handle) => Some(handle),
_ => None,
}
}
pub fn use_handle<Out>(&self, f: impl FnOnce(&rcl_guard_condition_t) -> Out) -> Out {
match self {
Self::Owned(handle) => f(handle),
Self::Unowned { handle, .. } => f(unsafe {
handle.as_ref().unwrap()
}),
}
}
}
impl Drop for GuardConditionHandle {
fn drop(&mut self) {
if let InnerGuardConditionHandle::Owned(rcl_guard_condition) =
&mut *self.rcl_guard_condition.lock().unwrap()
{
unsafe {
rcl_guard_condition_fini(rcl_guard_condition);
}
}
}
}
struct GuardConditionExecutable {
handle: Arc<GuardConditionHandle>,
callback: Option<Box<dyn FnMut() + Send + Sync>>,
}
impl RclPrimitive for GuardConditionExecutable {
unsafe fn execute(&mut self, ready: ReadyKind, _: &mut dyn Any) -> Result<(), RclrsError> {
ready.for_basic()?;
if let Some(callback) = &mut self.callback {
callback();
}
Ok(())
}
fn kind(&self) -> RclPrimitiveKind {
RclPrimitiveKind::GuardCondition
}
fn handle(&self) -> RclPrimitiveHandle<'_> {
RclPrimitiveHandle::GuardCondition(self.handle.rcl_guard_condition.lock().unwrap())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn traits() {
use crate::test_helpers::*;
assert_send::<GuardCondition>();
assert_sync::<GuardCondition>();
}
}