rclrs/publisher/loaned_message.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
use std::ops::{Deref, DerefMut};
use rosidl_runtime_rs::RmwMessage;
use crate::{rcl_bindings::*, Publisher, RclrsError, ToResult};
/// A message that is owned by the middleware, loaned for publishing.
///
/// It dereferences to a `&mut T`.
///
/// This type is returned by [`Publisher::borrow_loaned_message()`], see the documentation of
/// that function for more information.
///
/// The loan is returned by dropping the message or [publishing it][1].
///
/// [1]: LoanedMessage::publish
pub struct LoanedMessage<'a, T>
where
T: RmwMessage,
{
pub(super) msg_ptr: *mut T,
pub(super) publisher: &'a Publisher<T>,
}
impl<T> Deref for LoanedMessage<'_, T>
where
T: RmwMessage,
{
type Target = T;
fn deref(&self) -> &Self::Target {
// SAFETY: msg_ptr is a valid pointer, obtained through rcl_borrow_loaned_message.
unsafe { &*self.msg_ptr }
}
}
impl<T> DerefMut for LoanedMessage<'_, T>
where
T: RmwMessage,
{
fn deref_mut(&mut self) -> &mut Self::Target {
// SAFETY: msg_ptr is a valid pointer, obtained through rcl_borrow_loaned_message.
unsafe { &mut *self.msg_ptr }
}
}
impl<T> Drop for LoanedMessage<'_, T>
where
T: RmwMessage,
{
fn drop(&mut self) {
// Check whether the loan was already returned with
// rcl_publish_loaned_message()
if !self.msg_ptr.is_null() {
unsafe {
// SAFETY: These two pointers are valid, and the msg_ptr is not used afterwards.
rcl_return_loaned_message_from_publisher(
&*self.publisher.handle.rcl_publisher.lock().unwrap(),
self.msg_ptr as *mut _,
)
.ok()
.unwrap()
}
}
}
}
// SAFETY: The functions accessing this type, including drop(), shouldn't care about the thread
// they are running in. Therefore, this type can be safely sent to another thread.
unsafe impl<T> Send for LoanedMessage<'_, T> where T: RmwMessage {}
// SAFETY: There is no interior mutability in this type. All mutation happens through &mut references.
unsafe impl<T> Sync for LoanedMessage<'_, T> where T: RmwMessage {}
impl<T> LoanedMessage<'_, T>
where
T: RmwMessage,
{
/// Publishes the loaned message, falling back to regular publishing if needed.
pub fn publish(mut self) -> Result<(), RclrsError> {
unsafe {
// SAFETY: These two pointers are valid, and the msg_ptr is not used afterwards.
rcl_publish_loaned_message(
&*self.publisher.handle.rcl_publisher.lock().unwrap(),
self.msg_ptr as *mut _,
std::ptr::null_mut(),
)
.ok()?;
}
// Set the msg_ptr to null, as a signal to the drop impl that this
// loan was already returned.
self.msg_ptr = std::ptr::null_mut();
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn traits() {
use crate::test_helpers::*;
assert_send::<LoanedMessage<test_msgs::msg::rmw::BoundedSequences>>();
assert_sync::<LoanedMessage<test_msgs::msg::rmw::BoundedSequences>>();
}
}