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>>();
    }
}