diff --git a/r2r_tracing/src/lib.rs b/r2r_tracing/src/lib.rs index ced4e92..b9ae86a 100644 --- a/r2r_tracing/src/lib.rs +++ b/r2r_tracing/src/lib.rs @@ -12,5 +12,8 @@ pub use rclcpp_tracepoints::*; mod r2r_tracepoints; pub use r2r_tracepoints::*; +mod tracing_id; +pub use tracing_id::TracingId; + mod macros; use macros::tracepoint_fn; diff --git a/r2r_tracing/src/rclcpp_tracepoints.rs b/r2r_tracing/src/rclcpp_tracepoints.rs index 55b4e5c..25b8554 100644 --- a/r2r_tracing/src/rclcpp_tracepoints.rs +++ b/r2r_tracing/src/rclcpp_tracepoints.rs @@ -1,4 +1,4 @@ -use crate::tracepoint_fn; +use crate::{tracepoint_fn, TracingId}; use r2r_rcl::{rcl_node_t, rcl_service_t, rcl_subscription_t, rcl_timer_t}; #[cfg(feature = "tracing")] @@ -104,18 +104,18 @@ pub fn trace_service_callback_added(service: *const rcl_service_t, callback_id: /// Tracepoint to allow associating the timer callback identified by `callback_id` with its `rcl_timer_t` handle. /// /// Tracepoint: `ros2::rclcpp_timer_callback_added` -pub fn trace_timer_callback_added(timer: *const rcl_timer_t, callback_id: usize) { +pub fn trace_timer_callback_added(timer: TracingId, callback_id: usize) { unsafe { - tp::ros_trace_rclcpp_timer_callback_added(timer.cast(), c_void!(callback_id)); + tp::ros_trace_rclcpp_timer_callback_added(timer.c_void(), c_void!(callback_id)); } } /// Tracepoint to allow associating the `timer` with a `node`. /// /// Tracepoint: `ros2::rclcpp_timer_link_node` -pub fn trace_timer_link_node(timer: *const rcl_timer_t, node: *const rcl_node_t) { +pub fn trace_timer_link_node(timer: TracingId, node: TracingId) { unsafe { - tp::ros_trace_rclcpp_timer_link_node(timer.cast(), node.cast()); + tp::ros_trace_rclcpp_timer_link_node(timer.c_void(), node.c_void()); } } diff --git a/r2r_tracing/src/tracing_id.rs b/r2r_tracing/src/tracing_id.rs new file mode 100644 index 0000000..950f4db --- /dev/null +++ b/r2r_tracing/src/tracing_id.rs @@ -0,0 +1,77 @@ +/// Unique identifier for tracing purposes +#[derive(Debug)] +pub struct TracingId { + /// Pointer to the object used as a unique ID. + /// Safety: Do NOT dereference the pointer. + #[cfg(feature = "tracing")] + id: *const T, + + /// Marker for the type. Needed when `tracing` feature is disabled. + #[cfg(not(feature = "tracing"))] + _marker: std::marker::PhantomData, +} + +impl TracingId { + /// Creates new `TracingId` from the pointer. + /// + /// # Safety + /// The pointer is used as a unique ID so users must ensure that they never create `TracingId` + /// with same address for different objects. + /// + /// The pointer does not need to point to valid memory. + pub const unsafe fn new(_id: *const T) -> Self { + Self { + #[cfg(feature = "tracing")] + id: _id, + #[cfg(not(feature = "tracing"))] + _marker: std::marker::PhantomData, + } + } + + /// Erase the generic type of the ID. + #[must_use] + pub fn forget_type(self) -> TracingId { + #[cfg(not(feature = "tracing"))] + unsafe { + // Safety: The ID cannot be obtained back without the `tracing` feature. + TracingId::new(std::ptr::null()) + } + #[cfg(feature = "tracing")] + unsafe { + // Safety: self contains valid ID. + TracingId::new(self.c_void()) + } + } + + /// Obtain the address representing the ID. + /// + /// # Safety + /// Do NOT dereference the pointer. + #[cfg(feature = "tracing")] + pub(crate) const unsafe fn c_void(self) -> *const std::ffi::c_void { + self.id.cast::() + } +} + +/// Deriving Clone for `TracingId` would only derive it only conditionally based on whether the +/// `T` is `Clone` or not. But TracingId is independent of T. +impl Clone for TracingId { + fn clone(&self) -> Self { + *self + } +} + +/// Deriving Copy for `TracingId` would only derive it only conditionally based on whether the +/// `T` is `Copy` or not. But TracingId is independent of T. +impl Copy for TracingId {} + +/// # Safety +/// +/// The address is never dereferenced and is used only as a unique ID so it is safe to send to another thread. +unsafe impl Send for TracingId {} + +/// # Safety +/// +/// The `TracingId` does not allow interior mutability because the pointer is never dereferenced. +/// It is safe to use across multiple threads. +unsafe impl Sync for TracingId {}