From 88e86e6786eadae76ce8450d0d79b2a35680214d Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Fri, 1 Nov 2024 16:35:34 +0100 Subject: [PATCH 1/5] [#498] Introduce CustomPayloadMarker --- .../posix/tests/unix_datagram_socket_tests.rs | 1 - .../ffi/src/api/publish_subscribe_header.rs | 33 ++------ iceoryx2-ffi/ffi/src/api/publisher.rs | 6 +- iceoryx2-ffi/ffi/src/api/service_builder.rs | 6 +- iceoryx2/src/port/publisher.rs | 75 ++++++++++++------- iceoryx2/src/port/subscriber.rs | 6 +- .../src/service/builder/publish_subscribe.rs | 9 ++- .../src/service/header/publish_subscribe.rs | 13 ++-- iceoryx2/tests/publisher_tests.rs | 5 +- .../tests/service_publish_subscribe_tests.rs | 8 +- 10 files changed, 84 insertions(+), 78 deletions(-) diff --git a/iceoryx2-bb/posix/tests/unix_datagram_socket_tests.rs b/iceoryx2-bb/posix/tests/unix_datagram_socket_tests.rs index 173b007fa..9f504a262 100644 --- a/iceoryx2-bb/posix/tests/unix_datagram_socket_tests.rs +++ b/iceoryx2-bb/posix/tests/unix_datagram_socket_tests.rs @@ -14,7 +14,6 @@ use iceoryx2_bb_container::semantic_string::SemanticString; use iceoryx2_bb_posix::barrier::*; use iceoryx2_bb_posix::config::*; use iceoryx2_bb_posix::creation_mode::*; -use iceoryx2_bb_posix::directory::Directory; use iceoryx2_bb_posix::file::*; use iceoryx2_bb_posix::file_descriptor::*; use iceoryx2_bb_posix::socket_ancillary::*; diff --git a/iceoryx2-ffi/ffi/src/api/publish_subscribe_header.rs b/iceoryx2-ffi/ffi/src/api/publish_subscribe_header.rs index 374a463ed..c7b591779 100644 --- a/iceoryx2-ffi/ffi/src/api/publish_subscribe_header.rs +++ b/iceoryx2-ffi/ffi/src/api/publish_subscribe_header.rs @@ -154,7 +154,7 @@ pub unsafe extern "C" fn iox2_publish_subscribe_header_publisher_id( *id_handle_ptr = (*storage_ptr).as_handle(); } -/// Returns the payloads type size. +/// Returns the number of bytes of the payload /// /// # Arguments /// @@ -165,35 +165,16 @@ pub unsafe extern "C" fn iox2_publish_subscribe_header_publisher_id( /// /// * `header_handle` is valid and non-null #[no_mangle] -pub unsafe extern "C" fn iox2_publish_subscribe_header_payload_type_size( +pub unsafe extern "C" fn iox2_publish_subscribe_header_number_of_bytes( header_handle: iox2_publish_subscribe_header_h_ref, -) -> usize { +) -> u64 { header_handle.assert_non_null(); let header = &mut *header_handle.as_type(); - header.value.as_ref().payload_type_layout().size() + // In the typed Rust API it is the number of elements and the element is a + // CustomPayloadMarker. But this translates to the number of bytes whenever CustomPayloadMarker + // is used. + header.value.as_ref().number_of_elements() } - -/// Returns the payloads type alignment. -/// -/// # Arguments -/// -/// * `handle` is valid, non-null and was initialized with -/// [`iox2_sample_header()`](crate::iox2_sample_header) -/// -/// # Safety -/// -/// * `header_handle` is valid and non-null -#[no_mangle] -pub unsafe extern "C" fn iox2_publish_subscribe_header_payload_type_alignment( - header_handle: iox2_publish_subscribe_header_h_ref, -) -> usize { - header_handle.assert_non_null(); - - let header = &mut *header_handle.as_type(); - - header.value.as_ref().payload_type_layout().align() -} - // END C API diff --git a/iceoryx2-ffi/ffi/src/api/publisher.rs b/iceoryx2-ffi/ffi/src/api/publisher.rs index 7989d3de6..142b68e45 100644 --- a/iceoryx2-ffi/ffi/src/api/publisher.rs +++ b/iceoryx2-ffi/ffi/src/api/publisher.rs @@ -192,7 +192,7 @@ unsafe fn send_copy( // loan_slice_uninit(1) <= 1 is correct here since it defines the number of // slice elements not bytes. The element was set via TypeDetails and has a // defined size and alignment. - let mut sample = match publisher.loan_slice_uninit(1) { + let mut sample = match publisher.loan_custom_payload(1) { Ok(sample) => sample, Err(e) => return e.into_c_int(), }; @@ -383,7 +383,7 @@ pub unsafe extern "C" fn iox2_publisher_loan( let publisher = &mut *publisher_handle.as_type(); match publisher.service_type { - iox2_service_type_e::IPC => match publisher.value.as_ref().ipc.loan_slice_uninit(1) { + iox2_service_type_e::IPC => match publisher.value.as_ref().ipc.loan_custom_payload(1) { Ok(sample) => { let (sample_struct_ptr, deleter) = init_sample_struct_ptr(sample_struct_ptr); (*sample_struct_ptr).init( @@ -396,7 +396,7 @@ pub unsafe extern "C" fn iox2_publisher_loan( } Err(error) => error.into_c_int(), }, - iox2_service_type_e::LOCAL => match publisher.value.as_ref().local.loan_slice_uninit(1) { + iox2_service_type_e::LOCAL => match publisher.value.as_ref().local.loan_custom_payload(1) { Ok(sample) => { let (sample_struct_ptr, deleter) = init_sample_struct_ptr(sample_struct_ptr); (*sample_struct_ptr).init( diff --git a/iceoryx2-ffi/ffi/src/api/service_builder.rs b/iceoryx2-ffi/ffi/src/api/service_builder.rs index f03ccd556..b60a00b86 100644 --- a/iceoryx2-ffi/ffi/src/api/service_builder.rs +++ b/iceoryx2-ffi/ffi/src/api/service_builder.rs @@ -15,7 +15,7 @@ use crate::api::{iox2_service_type_e, AssertNonNullHandle, HandleToType}; use iceoryx2::prelude::*; -use iceoryx2::service::builder::publish_subscribe::CustomHeaderMarker; +use iceoryx2::service::builder::publish_subscribe::{CustomHeaderMarker, CustomPayloadMarker}; use iceoryx2::service::builder::{ event::Builder as ServiceBuilderEvent, publish_subscribe::Builder as ServiceBuilderPubSub, Builder as ServiceBuilderBase, @@ -29,8 +29,8 @@ use core::mem::MaybeUninit; // BEGIN types definition pub(super) type UserHeaderFfi = CustomHeaderMarker; -pub(super) type PayloadFfi = [u8]; -pub(super) type UninitPayloadFfi = [MaybeUninit]; +pub(super) type PayloadFfi = [CustomPayloadMarker]; +pub(super) type UninitPayloadFfi = [MaybeUninit]; pub(super) union ServiceBuilderUnionNested { pub(super) base: ManuallyDrop>, diff --git a/iceoryx2/src/port/publisher.rs b/iceoryx2/src/port/publisher.rs index 9ef12e57a..61858c9e2 100644 --- a/iceoryx2/src/port/publisher.rs +++ b/iceoryx2/src/port/publisher.rs @@ -108,6 +108,7 @@ use crate::port::update_connections::{ConnectionFailure, UpdateConnections}; use crate::port::DegrationAction; use crate::raw_sample::RawSampleMut; use crate::sample_mut_uninit::SampleMutUninit; +use crate::service::builder::publish_subscribe::CustomPayloadMarker; use crate::service::config_scheme::{connection_config, data_segment_config}; use crate::service::dynamic_config::publish_subscribe::{PublisherDetails, SubscriberDetails}; use crate::service::header::publish_subscribe::Header; @@ -738,14 +739,6 @@ impl .sample_layout(number_of_elements) } - fn payload_layout(&self, number_of_elements: usize) -> Layout { - self.data_segment - .subscriber_connections - .static_config - .message_type_details - .payload_layout(number_of_elements) - } - fn user_header_ptr(&self, header: *const Header) -> *const u8 { self.data_segment .subscriber_connections @@ -837,12 +830,7 @@ impl let user_header_ptr = self.user_header_ptr(header_ptr) as *mut UserHeader; let payload_ptr = self.payload_ptr(header_ptr) as *mut MaybeUninit; - unsafe { - header_ptr.write(Header::new( - self.data_segment.port_id, - Layout::new::(), - )) - }; + unsafe { header_ptr.write(Header::new(self.data_segment.port_id, 1)) }; let sample = unsafe { RawSampleMut::new_unchecked(header_ptr, user_header_ptr, payload_ptr) }; @@ -988,24 +976,13 @@ impl let user_header_ptr = self.user_header_ptr(header_ptr) as *mut UserHeader; let payload_ptr = self.payload_ptr(header_ptr) as *mut MaybeUninit; - unsafe { - header_ptr.write(Header::new( - self.data_segment.port_id, - self.payload_layout(slice_len), - )) - }; - - let slice_len_adjusted_to_payload_type_details = - self.payload_size * slice_len / core::mem::size_of::(); + unsafe { header_ptr.write(Header::new(self.data_segment.port_id, slice_len as _)) }; let sample = unsafe { RawSampleMut::new_unchecked( header_ptr, user_header_ptr, - core::slice::from_raw_parts_mut( - payload_ptr, - slice_len_adjusted_to_payload_type_details, - ), + core::slice::from_raw_parts_mut(payload_ptr, slice_len), ) }; @@ -1018,6 +995,50 @@ impl ) } } + +impl + Publisher +{ + #[doc(hidden)] + pub unsafe fn loan_custom_payload( + &self, + slice_len: usize, + ) -> Result< + SampleMutUninit], UserHeader>, + PublisherLoanError, + > { + let max_slice_len = self.data_segment.config.max_slice_len; + if max_slice_len < slice_len { + fail!(from self, with PublisherLoanError::ExceedsMaxLoanSize, + "Unable to loan slice with {} elements since it would exceed the max supported slice length of {}.", + slice_len, max_slice_len); + } + + let sample_layout = self.sample_layout(slice_len); + let chunk = self.allocate(sample_layout)?; + let header_ptr = chunk.data_ptr as *mut Header; + let user_header_ptr = self.user_header_ptr(header_ptr) as *mut UserHeader; + let payload_ptr = self.payload_ptr(header_ptr) as *mut MaybeUninit; + + let slice_len = self.payload_size * slice_len; + + unsafe { header_ptr.write(Header::new(self.data_segment.port_id, slice_len as _)) }; + + let sample = unsafe { + RawSampleMut::new_unchecked( + header_ptr, + user_header_ptr, + core::slice::from_raw_parts_mut(payload_ptr, slice_len), + ) + }; + + Ok(SampleMutUninit::< + Service, + [MaybeUninit], + UserHeader, + >::new(&self.data_segment, sample, chunk.offset)) + } +} //////////////////////// // END: sliced API //////////////////////// diff --git a/iceoryx2/src/port/subscriber.rs b/iceoryx2/src/port/subscriber.rs index 6626a5aa5..585ac3694 100644 --- a/iceoryx2/src/port/subscriber.rs +++ b/iceoryx2/src/port/subscriber.rs @@ -447,9 +447,7 @@ impl let header_ptr = absolute_address as *const Header; let user_header_ptr = self.user_header_ptr(header_ptr).cast(); let payload_ptr = self.payload_ptr(header_ptr).cast(); - - let payload_layout = unsafe { (*header_ptr).payload_type_layout() }; - let number_of_elements = payload_layout.size() / core::mem::size_of::(); + let number_of_elements = unsafe { (*header_ptr).number_of_elements() }; Sample { details, @@ -457,7 +455,7 @@ impl RawSample::::new_slice_unchecked( header_ptr, user_header_ptr, - core::slice::from_raw_parts(payload_ptr, number_of_elements), + core::slice::from_raw_parts(payload_ptr, number_of_elements as _), ) }, } diff --git a/iceoryx2/src/service/builder/publish_subscribe.rs b/iceoryx2/src/service/builder/publish_subscribe.rs index 5acd0cbaa..c2ee1143b 100644 --- a/iceoryx2/src/service/builder/publish_subscribe.rs +++ b/iceoryx2/src/service/builder/publish_subscribe.rs @@ -40,6 +40,11 @@ use super::{OpenDynamicStorageFailure, ServiceState}; #[doc(hidden)] pub struct CustomHeaderMarker {} +#[repr(C)] +#[derive(Debug)] +#[doc(hidden)] +pub struct CustomPayloadMarker {} + /// Errors that can occur when an existing [`MessagingPattern::PublishSubscribe`] [`Service`] shall be opened. #[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)] pub enum PublishSubscribeOpenError { @@ -716,7 +721,9 @@ impl } } -impl Builder<[u8], UserHeader, ServiceType> { +impl + Builder<[CustomPayloadMarker], UserHeader, ServiceType> +{ #[doc(hidden)] pub unsafe fn __internal_set_payload_type_details(mut self, value: &TypeDetail) -> Self { self.override_payload_type = Some(value.clone()); diff --git a/iceoryx2/src/service/header/publish_subscribe.rs b/iceoryx2/src/service/header/publish_subscribe.rs index 210397012..885632181 100644 --- a/iceoryx2/src/service/header/publish_subscribe.rs +++ b/iceoryx2/src/service/header/publish_subscribe.rs @@ -30,7 +30,6 @@ //! # Ok(()) //! # } //! ``` -use std::alloc::Layout; use crate::port::port_identifiers::UniquePublisherId; @@ -40,14 +39,14 @@ use crate::port::port_identifiers::UniquePublisherId; #[repr(C)] pub struct Header { publisher_port_id: UniquePublisherId, - payload_type_layout: Layout, + number_of_elements: u64, } impl Header { - pub(crate) fn new(publisher_port_id: UniquePublisherId, payload_type_layout: Layout) -> Self { + pub(crate) fn new(publisher_port_id: UniquePublisherId, number_of_elements: u64) -> Self { Self { publisher_port_id, - payload_type_layout, + number_of_elements, } } @@ -56,8 +55,8 @@ impl Header { self.publisher_port_id } - /// Returns the [`Layout`] of the corresponding payload. - pub fn payload_type_layout(&self) -> Layout { - self.payload_type_layout + /// Returns the amount of elements of the payload. + pub fn number_of_elements(&self) -> u64 { + self.number_of_elements } } diff --git a/iceoryx2/tests/publisher_tests.rs b/iceoryx2/tests/publisher_tests.rs index 326234887..eeb92c16f 100644 --- a/iceoryx2/tests/publisher_tests.rs +++ b/iceoryx2/tests/publisher_tests.rs @@ -18,6 +18,7 @@ mod publisher { use iceoryx2::port::publisher::{PublisherCreateError, PublisherLoanError}; use iceoryx2::prelude::*; + use iceoryx2::service::builder::publish_subscribe::CustomPayloadMarker; use iceoryx2::service::port_factory::publisher::UnableToDeliverStrategy; use iceoryx2::service::static_config::message_type_details::{TypeDetail, TypeVariant}; use iceoryx2::service::{service_name::ServiceName, Service}; @@ -404,14 +405,14 @@ mod publisher { let service = unsafe { node.service_builder(&service_name) - .publish_subscribe::<[u8]>() + .publish_subscribe::<[CustomPayloadMarker]>() .__internal_set_payload_type_details(&type_detail) .create()? }; let sut = service.publisher_builder().create()?; - let sample = sut.loan_slice(1)?; + let sample = unsafe { sut.loan_custom_payload(1)? }; assert_that!(sample.payload(), len TYPE_SIZE_OVERRIDE); diff --git a/iceoryx2/tests/service_publish_subscribe_tests.rs b/iceoryx2/tests/service_publish_subscribe_tests.rs index d3e935f51..2210abf95 100644 --- a/iceoryx2/tests/service_publish_subscribe_tests.rs +++ b/iceoryx2/tests/service_publish_subscribe_tests.rs @@ -21,9 +21,9 @@ mod service_publish_subscribe { use iceoryx2::port::subscriber::SubscriberCreateError; use iceoryx2::port::update_connections::UpdateConnections; use iceoryx2::prelude::*; - use iceoryx2::service::builder::publish_subscribe::CustomHeaderMarker; use iceoryx2::service::builder::publish_subscribe::PublishSubscribeCreateError; use iceoryx2::service::builder::publish_subscribe::PublishSubscribeOpenError; + use iceoryx2::service::builder::publish_subscribe::{CustomHeaderMarker, CustomPayloadMarker}; use iceoryx2::service::messaging_pattern::MessagingPattern; use iceoryx2::service::port_factory::publisher::UnableToDeliverStrategy; use iceoryx2::service::static_config::message_type_details::{TypeDetail, TypeVariant}; @@ -2611,7 +2611,7 @@ mod service_publish_subscribe { let _sut = unsafe { node.service_builder(&service_name) - .publish_subscribe::<[u8]>() + .publish_subscribe::<[CustomPayloadMarker]>() .__internal_set_payload_type_details(&TypeDetail::__internal_new::( TypeVariant::FixedSize, )) @@ -2704,7 +2704,7 @@ mod service_publish_subscribe { let sut2 = unsafe { node.service_builder(&service_name) - .publish_subscribe::<[u8]>() + .publish_subscribe::<[CustomPayloadMarker]>() .__internal_set_payload_type_details(&TypeDetail::__internal_new::( TypeVariant::FixedSize, )) @@ -2715,7 +2715,7 @@ mod service_publish_subscribe { let sut3 = unsafe { node.service_builder(&service_name) - .publish_subscribe::<[u8]>() + .publish_subscribe::<[CustomPayloadMarker]>() .__internal_set_payload_type_details(&TypeDetail::__internal_new::( TypeVariant::FixedSize, )) From d50afad6d50e7b6b94c24beccff0f7d568e2fea2 Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Fri, 1 Nov 2024 18:00:32 +0100 Subject: [PATCH 2/5] [#498] Separate the CustomPayloadType API from the normal safe API --- .../include/iox2/header_publish_subscribe.hpp | 4 +- .../cxx/src/header_publish_subscribe.cpp | 7 +- .../ffi/src/api/publish_subscribe_header.rs | 12 +-- iceoryx2/src/port/publisher.rs | 73 ++++++++++-------- iceoryx2/src/port/subscriber.rs | 54 +++++++++++++- iceoryx2/src/sample_mut_uninit.rs | 2 +- .../src/service/builder/publish_subscribe.rs | 2 +- .../static_config/message_type_details.rs | 2 +- iceoryx2/tests/publisher_tests.rs | 51 ++++++++++++- .../tests/service_publish_subscribe_tests.rs | 74 +++++++++++++++++++ iceoryx2/tests/subscriber_tests.rs | 27 +++++++ 11 files changed, 259 insertions(+), 49 deletions(-) diff --git a/iceoryx2-ffi/cxx/include/iox2/header_publish_subscribe.hpp b/iceoryx2-ffi/cxx/include/iox2/header_publish_subscribe.hpp index ac29d5ed7..a548ea9a8 100644 --- a/iceoryx2-ffi/cxx/include/iox2/header_publish_subscribe.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/header_publish_subscribe.hpp @@ -30,8 +30,8 @@ class HeaderPublishSubscribe { /// Returns the [`UniquePublisherId`] of the source [`Publisher`]. auto publisher_id() const -> UniquePublisherId; - /// Returns the [`Layout`] of the corresponding payload. - auto payload_type_layout() const -> iox::Layout; + /// Returns the number of [`Payload`] elements in the received [`Sample`]. + auto number_of_elements() const -> uint64_t; private: template diff --git a/iceoryx2-ffi/cxx/src/header_publish_subscribe.cpp b/iceoryx2-ffi/cxx/src/header_publish_subscribe.cpp index d8c0389af..3ac5932ec 100644 --- a/iceoryx2-ffi/cxx/src/header_publish_subscribe.cpp +++ b/iceoryx2-ffi/cxx/src/header_publish_subscribe.cpp @@ -51,10 +51,7 @@ auto HeaderPublishSubscribe::publisher_id() const -> UniquePublisherId { return UniquePublisherId { id_handle }; } -auto HeaderPublishSubscribe::payload_type_layout() const -> iox::Layout { - auto size = iox2_publish_subscribe_header_payload_type_size(&m_handle); - auto alignment = iox2_publish_subscribe_header_payload_type_alignment(&m_handle); - - return iox::Layout::create(size, alignment).expect("Payload layout is always valid."); +auto HeaderPublishSubscribe::number_of_elements() const -> uint64_t { + return iox2_publish_subscribe_header_number_of_elements(&m_handle); } } // namespace iox2 diff --git a/iceoryx2-ffi/ffi/src/api/publish_subscribe_header.rs b/iceoryx2-ffi/ffi/src/api/publish_subscribe_header.rs index c7b591779..fe18c5e7d 100644 --- a/iceoryx2-ffi/ffi/src/api/publish_subscribe_header.rs +++ b/iceoryx2-ffi/ffi/src/api/publish_subscribe_header.rs @@ -154,7 +154,12 @@ pub unsafe extern "C" fn iox2_publish_subscribe_header_publisher_id( *id_handle_ptr = (*storage_ptr).as_handle(); } -/// Returns the number of bytes of the payload +/// Returns the number of elements of the payload. +/// The element size is defined via this call when creating a new service +/// [`crate::iox2_service_builder_pub_sub_set_payload_type_details()`]. +/// So if the payload is defined with alignment 8 and size 16 and this function returns 5. It +/// means that the payload consists of 5 elements of size 16 and every element is 8 byte aligned. +/// Therefore, the payload pointer points to a memory region with 5 * 16 = 80 bytes. /// /// # Arguments /// @@ -165,16 +170,13 @@ pub unsafe extern "C" fn iox2_publish_subscribe_header_publisher_id( /// /// * `header_handle` is valid and non-null #[no_mangle] -pub unsafe extern "C" fn iox2_publish_subscribe_header_number_of_bytes( +pub unsafe extern "C" fn iox2_publish_subscribe_header_number_of_elements( header_handle: iox2_publish_subscribe_header_h_ref, ) -> u64 { header_handle.assert_non_null(); let header = &mut *header_handle.as_type(); - // In the typed Rust API it is the number of elements and the element is a - // CustomPayloadMarker. But this translates to the number of bytes whenever CustomPayloadMarker - // is used. header.value.as_ref().number_of_elements() } // END C API diff --git a/iceoryx2/src/port/publisher.rs b/iceoryx2/src/port/publisher.rs index 61858c9e2..d580d0443 100644 --- a/iceoryx2/src/port/publisher.rs +++ b/iceoryx2/src/port/publisher.rs @@ -116,6 +116,7 @@ use crate::service::naming_scheme::{ data_segment_name, extract_publisher_id_from_connection, extract_subscriber_id_from_connection, }; use crate::service::port_factory::publisher::{LocalPublisherConfig, UnableToDeliverStrategy}; +use crate::service::static_config::message_type_details::TypeVariant; use crate::service::static_config::publish_subscribe::{self}; use crate::service::{self, ServiceState}; use crate::{config, sample_mut::SampleMut}; @@ -139,6 +140,7 @@ use iceoryx2_cal::zero_copy_connection::{ ZeroCopyConnection, ZeroCopyCreationError, ZeroCopySendError, ZeroCopySender, }; use iceoryx2_pal_concurrency_sync::iox_atomic::{IoxAtomicBool, IoxAtomicU64, IoxAtomicUsize}; +use std::any::TypeId; use std::cell::UnsafeCell; use std::fmt::Debug; use std::sync::atomic::Ordering; @@ -529,7 +531,11 @@ impl DataSegment { /// Sending endpoint of a publish-subscriber based communication. #[derive(Debug)] -pub struct Publisher { +pub struct Publisher< + Service: service::Service, + Payload: Debug + ?Sized + 'static, + UserHeader: Debug, +> { pub(crate) data_segment: Arc>, dynamic_publisher_handle: Option, payload_size: usize, @@ -756,6 +762,15 @@ impl .payload_ptr_from_header(header.cast()) .cast() } + + fn payload_type_variant(&self) -> TypeVariant { + self.data_segment + .subscriber_connections + .static_config + .message_type_details + .payload + .variant + } } //////////////////////// @@ -962,6 +977,18 @@ impl &self, slice_len: usize, ) -> Result], UserHeader>, PublisherLoanError> + { + // required since Rust does not support generic specializations or negative traits + debug_assert!(TypeId::of::() != TypeId::of::()); + + unsafe { self.loan_slice_uninit_impl(slice_len, slice_len) } + } + + unsafe fn loan_slice_uninit_impl( + &self, + slice_len: usize, + underlying_number_of_slice_elements: usize, + ) -> Result], UserHeader>, PublisherLoanError> { let max_slice_len = self.data_segment.config.max_slice_len; if max_slice_len < slice_len { @@ -982,7 +1009,7 @@ impl RawSampleMut::new_unchecked( header_ptr, user_header_ptr, - core::slice::from_raw_parts_mut(payload_ptr, slice_len), + core::slice::from_raw_parts_mut(payload_ptr, underlying_number_of_slice_elements), ) }; @@ -999,6 +1026,13 @@ impl impl Publisher { + /// # Safety + /// + /// * slice_len != 1 only when payload TypeVariant == Dynamic + /// * The number_of_elements in the [`Header`](crate::service::header::publish_subscribe::Header) + /// is set to `slice_len` + /// * The [`SampleMutUninit`] will contain `slice_len` * `MessageTypeDetails::payload.size` + /// elements of type [`CustomPayloadMarker`]. #[doc(hidden)] pub unsafe fn loan_custom_payload( &self, @@ -1007,36 +1041,13 @@ impl SampleMutUninit], UserHeader>, PublisherLoanError, > { - let max_slice_len = self.data_segment.config.max_slice_len; - if max_slice_len < slice_len { - fail!(from self, with PublisherLoanError::ExceedsMaxLoanSize, - "Unable to loan slice with {} elements since it would exceed the max supported slice length of {}.", - slice_len, max_slice_len); - } - - let sample_layout = self.sample_layout(slice_len); - let chunk = self.allocate(sample_layout)?; - let header_ptr = chunk.data_ptr as *mut Header; - let user_header_ptr = self.user_header_ptr(header_ptr) as *mut UserHeader; - let payload_ptr = self.payload_ptr(header_ptr) as *mut MaybeUninit; - - let slice_len = self.payload_size * slice_len; - - unsafe { header_ptr.write(Header::new(self.data_segment.port_id, slice_len as _)) }; - - let sample = unsafe { - RawSampleMut::new_unchecked( - header_ptr, - user_header_ptr, - core::slice::from_raw_parts_mut(payload_ptr, slice_len), - ) - }; + // TypeVariant::Dynamic == slice and only here it makes sense to loan more than one element + debug_assert!( + slice_len == 1 + || (slice_len != 1 && self.payload_type_variant() == TypeVariant::Dynamic) + ); - Ok(SampleMutUninit::< - Service, - [MaybeUninit], - UserHeader, - >::new(&self.data_segment, sample, chunk.offset)) + self.loan_slice_uninit_impl(slice_len, self.payload_size * slice_len) } } //////////////////////// diff --git a/iceoryx2/src/port/subscriber.rs b/iceoryx2/src/port/subscriber.rs index 585ac3694..af5d1000a 100644 --- a/iceoryx2/src/port/subscriber.rs +++ b/iceoryx2/src/port/subscriber.rs @@ -31,6 +31,7 @@ //! # } //! ``` +use std::any::TypeId; use std::cell::UnsafeCell; use std::fmt::Debug; use std::marker::PhantomData; @@ -46,6 +47,7 @@ use iceoryx2_cal::{shared_memory::*, zero_copy_connection::*}; use crate::port::DegrationAction; use crate::sample::SampleDetails; +use crate::service::builder::publish_subscribe::CustomPayloadMarker; use crate::service::dynamic_config::publish_subscribe::{PublisherDetails, SubscriberDetails}; use crate::service::header::publish_subscribe::Header; use crate::service::port_factory::subscriber::SubscriberConfig; @@ -102,7 +104,11 @@ impl std::error::Error for SubscriberCreateError {} /// The receiving endpoint of a publish-subscribe communication. #[derive(Debug)] -pub struct Subscriber { +pub struct Subscriber< + Service: service::Service, + Payload: Debug + ?Sized + 'static, + UserHeader: Debug, +> { dynamic_subscriber_handle: Option, publisher_connections: PublisherConnections, to_be_removed_connections: UnsafeCell>>>, @@ -423,6 +429,8 @@ impl pub fn receive( &self, ) -> Result>, SubscriberReceiveError> { + debug_assert!(TypeId::of::() != TypeId::of::()); + Ok(self.receive_impl()?.map(|(details, absolute_address)| { let header_ptr = absolute_address as *const Header; let user_header_ptr = self.user_header_ptr(header_ptr).cast(); @@ -443,6 +451,8 @@ impl pub fn receive( &self, ) -> Result>, SubscriberReceiveError> { + debug_assert!(TypeId::of::() != TypeId::of::()); + Ok(self.receive_impl()?.map(|(details, absolute_address)| { let header_ptr = absolute_address as *const Header; let user_header_ptr = self.user_header_ptr(header_ptr).cast(); @@ -462,3 +472,45 @@ impl })) } } + +impl + Subscriber +{ + /// # Safety + /// + /// * The number_of_elements in the [`Header`](crate::service::header::publish_subscribe::Header) + /// corresponds to the payload type details that where overridden in + /// `MessageTypeDetails::payload.size`. Meaning, when the payload.size == 8 and the number + /// of elements if 5, it means that the sample will contain a slice of 8 * 5 = 40 + /// [`CustomPayloadMarker`]s. + #[doc(hidden)] + pub unsafe fn receive_custom_payload( + &self, + ) -> Result>, SubscriberReceiveError> + { + Ok(self.receive_impl()?.map(|(details, absolute_address)| { + let header_ptr = absolute_address as *const Header; + let user_header_ptr = self.user_header_ptr(header_ptr).cast(); + let payload_ptr = self.payload_ptr(header_ptr).cast(); + let number_of_elements = unsafe { (*header_ptr).number_of_elements() }; + let number_of_bytes = number_of_elements as usize + * self + .static_config + .publish_subscribe() + .message_type_details + .payload + .size; + + Sample { + details, + ptr: unsafe { + RawSample::::new_slice_unchecked( + header_ptr, + user_header_ptr, + core::slice::from_raw_parts(payload_ptr, number_of_bytes), + ) + }, + } + })) + } +} diff --git a/iceoryx2/src/sample_mut_uninit.rs b/iceoryx2/src/sample_mut_uninit.rs index e4d23950c..83003c13a 100644 --- a/iceoryx2/src/sample_mut_uninit.rs +++ b/iceoryx2/src/sample_mut_uninit.rs @@ -114,7 +114,7 @@ use crate::{ /// /// The generic parameter `Payload` is actually [`core::mem::MaybeUninit`]. pub struct SampleMutUninit { - sample: SampleMut, + pub(crate) sample: SampleMut, } impl diff --git a/iceoryx2/src/service/builder/publish_subscribe.rs b/iceoryx2/src/service/builder/publish_subscribe.rs index c2ee1143b..7eae4ff59 100644 --- a/iceoryx2/src/service/builder/publish_subscribe.rs +++ b/iceoryx2/src/service/builder/publish_subscribe.rs @@ -43,7 +43,7 @@ pub struct CustomHeaderMarker {} #[repr(C)] #[derive(Debug)] #[doc(hidden)] -pub struct CustomPayloadMarker {} +pub struct CustomPayloadMarker(u8); /// Errors that can occur when an existing [`MessagingPattern::PublishSubscribe`] [`Service`] shall be opened. #[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)] diff --git a/iceoryx2/src/service/static_config/message_type_details.rs b/iceoryx2/src/service/static_config/message_type_details.rs index 3efa1fe9f..57924140a 100644 --- a/iceoryx2/src/service/static_config/message_type_details.rs +++ b/iceoryx2/src/service/static_config/message_type_details.rs @@ -17,7 +17,7 @@ use serde::{Deserialize, Serialize}; /// Defines if the type is a slice with a runtime-size ([`TypeVariant::Dynamic`]) /// or if its a type that satisfies [`Sized`] ([`TypeVariant::FixedSize`]). -#[derive(Default, Debug, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)] +#[derive(Default, Debug, Clone, Copy, Eq, Hash, PartialEq, Serialize, Deserialize)] pub enum TypeVariant { #[default] /// A type notated by [`#[repr(C)]`](https://doc.rust-lang.org/reference/type-layout.html#reprc). diff --git a/iceoryx2/tests/publisher_tests.rs b/iceoryx2/tests/publisher_tests.rs index eeb92c16f..db55b141b 100644 --- a/iceoryx2/tests/publisher_tests.rs +++ b/iceoryx2/tests/publisher_tests.rs @@ -394,8 +394,7 @@ mod publisher { } #[test] - fn publisher_with_overridden_payload_details_adjusts_slice_len() -> TestResult<()> - { + fn publisher_with_custom_payload_details_adjusts_slice_len() -> TestResult<()> { const TYPE_SIZE_OVERRIDE: usize = 128; let service_name = generate_name()?; let config = generate_isolated_config(); @@ -419,6 +418,54 @@ mod publisher { Ok(()) } + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn publisher_with_custom_payload_details_panics_when_calling_loan_slice_uninit() { + const TYPE_SIZE_OVERRIDE: usize = 128; + let service_name = generate_name().unwrap(); + let config = generate_isolated_config(); + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let mut type_detail = TypeDetail::__internal_new::(TypeVariant::FixedSize); + type_detail.size = TYPE_SIZE_OVERRIDE; + + let service = unsafe { + node.service_builder(&service_name) + .publish_subscribe::<[CustomPayloadMarker]>() + .__internal_set_payload_type_details(&type_detail) + .create() + .unwrap() + }; + + let sut = service.publisher_builder().create().unwrap(); + + // panics here + let _sample = sut.loan_slice_uninit(1); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn custom_fixed_size_payload_panics_when_loaning_more_than_one_element() { + set_log_level(LogLevel::Error); + let service_name = generate_name().unwrap(); + let config = generate_isolated_config(); + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let type_details = TypeDetail::__internal_new::(TypeVariant::FixedSize); + + let service = unsafe { + node.service_builder(&service_name) + .publish_subscribe::<[CustomPayloadMarker]>() + .__internal_set_payload_type_details(&type_details) + .create() + .unwrap() + }; + + let sut = service.publisher_builder().create().unwrap(); + + let _sample = unsafe { sut.loan_custom_payload(2) }; + } + #[instantiate_tests()] mod ipc {} diff --git a/iceoryx2/tests/service_publish_subscribe_tests.rs b/iceoryx2/tests/service_publish_subscribe_tests.rs index 2210abf95..355594b92 100644 --- a/iceoryx2/tests/service_publish_subscribe_tests.rs +++ b/iceoryx2/tests/service_publish_subscribe_tests.rs @@ -2902,6 +2902,80 @@ mod service_publish_subscribe { assert_that!(*sample, eq 456); } + #[test] + fn communication_with_custom_payload_works() { + set_log_level(LogLevel::Error); + const NUMBER_OF_ELEMENTS: usize = 1; + let service_name = generate_name(); + let config = generate_isolated_config(); + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let mut type_details = TypeDetail::__internal_new::(TypeVariant::FixedSize); + type_details.size = 1024; + type_details.alignment = 1024; + + let sut = unsafe { + node.service_builder(&service_name) + .publish_subscribe::<[CustomPayloadMarker]>() + .__internal_set_payload_type_details(&type_details) + .create() + .unwrap() + }; + + let publisher = sut.publisher_builder().create().unwrap(); + let subscriber = sut.subscriber_builder().create().unwrap(); + + let sample = unsafe { publisher.loan_custom_payload(NUMBER_OF_ELEMENTS).unwrap() }; + assert_that!(sample.payload(), len type_details.size); + assert_that!((sample.payload().as_ptr() as usize % type_details.alignment), eq 0); + assert_that!(sample.header().number_of_elements(), eq NUMBER_OF_ELEMENTS as u64); + + unsafe { sample.assume_init().send().unwrap() }; + + let sample = unsafe { subscriber.receive_custom_payload().unwrap().unwrap() }; + assert_that!(sample.payload(), len type_details.size); + assert_that!((sample.payload().as_ptr() as usize % type_details.alignment), eq 0); + assert_that!(sample.header().number_of_elements(), eq NUMBER_OF_ELEMENTS as u64); + } + + #[test] + fn communication_with_custom_slice_payload_works() { + set_log_level(LogLevel::Error); + const NUMBER_OF_ELEMENTS: usize = 7; + let service_name = generate_name(); + let config = generate_isolated_config(); + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let mut type_details = TypeDetail::__internal_new::(TypeVariant::Dynamic); + type_details.size = 2048; + type_details.alignment = 2048; + + let sut = unsafe { + node.service_builder(&service_name) + .publish_subscribe::<[CustomPayloadMarker]>() + .__internal_set_payload_type_details(&type_details) + .create() + .unwrap() + }; + + let publisher = sut + .publisher_builder() + .max_slice_len(NUMBER_OF_ELEMENTS) + .create() + .unwrap(); + let subscriber = sut.subscriber_builder().create().unwrap(); + + let sample = unsafe { publisher.loan_custom_payload(NUMBER_OF_ELEMENTS).unwrap() }; + assert_that!(sample.payload(), len type_details.size * NUMBER_OF_ELEMENTS); + assert_that!((sample.payload().as_ptr() as usize % type_details.alignment), eq 0); + assert_that!(sample.header().number_of_elements(), eq NUMBER_OF_ELEMENTS as u64); + + unsafe { sample.assume_init().send().unwrap() }; + + let sample = unsafe { subscriber.receive_custom_payload().unwrap().unwrap() }; + assert_that!(sample.payload(), len type_details.size * NUMBER_OF_ELEMENTS); + assert_that!((sample.payload().as_ptr() as usize % type_details.alignment), eq 0); + assert_that!(sample.header().number_of_elements(), eq NUMBER_OF_ELEMENTS as u64); + } + #[instantiate_tests()] mod ipc {} diff --git a/iceoryx2/tests/subscriber_tests.rs b/iceoryx2/tests/subscriber_tests.rs index 273743c37..1fed1494e 100644 --- a/iceoryx2/tests/subscriber_tests.rs +++ b/iceoryx2/tests/subscriber_tests.rs @@ -12,6 +12,8 @@ #[generic_tests::define] mod subscriber { + use iceoryx2::service::builder::publish_subscribe::CustomPayloadMarker; + use iceoryx2::service::static_config::message_type_details::{TypeDetail, TypeVariant}; use std::collections::HashSet; use iceoryx2::{ @@ -69,6 +71,31 @@ mod subscriber { } } + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn subscriber_with_custom_payload_details_panics_when_calling_receive() { + const TYPE_SIZE_OVERRIDE: usize = 128; + let service_name = generate_name(); + let config = generate_isolated_config(); + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let mut type_detail = TypeDetail::__internal_new::(TypeVariant::FixedSize); + type_detail.size = TYPE_SIZE_OVERRIDE; + + let service = unsafe { + node.service_builder(&service_name) + .publish_subscribe::<[CustomPayloadMarker]>() + .__internal_set_payload_type_details(&type_detail) + .create() + .unwrap() + }; + + let sut = service.subscriber_builder().create().unwrap(); + + // panics here + let _sample = sut.receive(); + } + #[instantiate_tests()] mod ipc {} From 4eaa0bf8e5019dd60cd99f3ba9391cdc11dc22c2 Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Fri, 1 Nov 2024 18:06:12 +0100 Subject: [PATCH 3/5] [#498] Adjust C API --- iceoryx2-ffi/ffi/src/api/subscriber.rs | 28 ++++++++++++++------------ iceoryx2/src/port/publisher.rs | 5 +---- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/iceoryx2-ffi/ffi/src/api/subscriber.rs b/iceoryx2-ffi/ffi/src/api/subscriber.rs index af0ab03e0..e041c6ad1 100644 --- a/iceoryx2-ffi/ffi/src/api/subscriber.rs +++ b/iceoryx2-ffi/ffi/src/api/subscriber.rs @@ -273,7 +273,7 @@ pub unsafe extern "C" fn iox2_subscriber_receive( let subscriber = &mut *subscriber_handle.as_type(); match subscriber.service_type { - iox2_service_type_e::IPC => match subscriber.value.as_ref().ipc.receive() { + iox2_service_type_e::IPC => match subscriber.value.as_ref().ipc.receive_custom_payload() { Ok(Some(sample)) => { let (sample_struct_ptr, deleter) = init_sample_struct_ptr(sample_struct_ptr); (*sample_struct_ptr).init( @@ -286,19 +286,21 @@ pub unsafe extern "C" fn iox2_subscriber_receive( Ok(None) => (), Err(error) => return error.into_c_int(), }, - iox2_service_type_e::LOCAL => match subscriber.value.as_ref().local.receive() { - Ok(Some(sample)) => { - let (sample_struct_ptr, deleter) = init_sample_struct_ptr(sample_struct_ptr); - (*sample_struct_ptr).init( - subscriber.service_type, - SampleUnion::new_local(sample), - deleter, - ); - *sample_handle_ptr = (*sample_struct_ptr).as_handle(); + iox2_service_type_e::LOCAL => { + match subscriber.value.as_ref().local.receive_custom_payload() { + Ok(Some(sample)) => { + let (sample_struct_ptr, deleter) = init_sample_struct_ptr(sample_struct_ptr); + (*sample_struct_ptr).init( + subscriber.service_type, + SampleUnion::new_local(sample), + deleter, + ); + *sample_handle_ptr = (*sample_struct_ptr).as_handle(); + } + Ok(None) => (), + Err(error) => return error.into_c_int(), } - Ok(None) => (), - Err(error) => return error.into_c_int(), - }, + } } IOX2_OK diff --git a/iceoryx2/src/port/publisher.rs b/iceoryx2/src/port/publisher.rs index d580d0443..ce4b9fb37 100644 --- a/iceoryx2/src/port/publisher.rs +++ b/iceoryx2/src/port/publisher.rs @@ -1042,10 +1042,7 @@ impl PublisherLoanError, > { // TypeVariant::Dynamic == slice and only here it makes sense to loan more than one element - debug_assert!( - slice_len == 1 - || (slice_len != 1 && self.payload_type_variant() == TypeVariant::Dynamic) - ); + debug_assert!(slice_len == 1 || self.payload_type_variant() == TypeVariant::Dynamic); self.loan_slice_uninit_impl(slice_len, self.payload_size * slice_len) } From f05cfb41389a24fb6b75f13a395cf1059833ee75 Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Fri, 1 Nov 2024 18:29:37 +0100 Subject: [PATCH 4/5] [#498] Add more detailed documentation --- doc/release-notes/iceoryx2-unreleased.md | 9 +++++++++ iceoryx2/src/port/subscriber.rs | 10 +++++----- iceoryx2/src/sample_mut_uninit.rs | 2 +- iceoryx2/src/service/header/publish_subscribe.rs | 10 +++++++++- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/doc/release-notes/iceoryx2-unreleased.md b/doc/release-notes/iceoryx2-unreleased.md index 8f095bd7d..d1ec9d3d0 100644 --- a/doc/release-notes/iceoryx2-unreleased.md +++ b/doc/release-notes/iceoryx2-unreleased.md @@ -38,6 +38,7 @@ * Rename `NodeEvent` into `WaitEvent` [#390](https://github.com/eclipse-iceoryx/iceoryx2/issues/390) * Bazel support for the Rust crates [#349](https://github.com/eclipse-iceoryx/iceoryx2/issues/349) * Remove ACL dependency [#457](https://github.com/eclipse-iceoryx/iceoryx2/issues/457) +* Publish Subscribe Header contains number of elements contained in a `Sample` [#498](https://github.com/eclipse-iceoryx/iceoryx2/issues/498) ### Workflow @@ -72,3 +73,11 @@ // ... } ``` + +2. Removed `payload_type_layout` from pub/sub header. + + ```rust + // old + let sample = publisher.loan()?; + sample.header().payload_type_layout(); + ``` diff --git a/iceoryx2/src/port/subscriber.rs b/iceoryx2/src/port/subscriber.rs index af5d1000a..e1767eb63 100644 --- a/iceoryx2/src/port/subscriber.rs +++ b/iceoryx2/src/port/subscriber.rs @@ -429,8 +429,6 @@ impl pub fn receive( &self, ) -> Result>, SubscriberReceiveError> { - debug_assert!(TypeId::of::() != TypeId::of::()); - Ok(self.receive_impl()?.map(|(details, absolute_address)| { let header_ptr = absolute_address as *const Header; let user_header_ptr = self.user_header_ptr(header_ptr).cast(); @@ -480,9 +478,11 @@ impl /// /// * The number_of_elements in the [`Header`](crate::service::header::publish_subscribe::Header) /// corresponds to the payload type details that where overridden in - /// `MessageTypeDetails::payload.size`. Meaning, when the payload.size == 8 and the number - /// of elements if 5, it means that the sample will contain a slice of 8 * 5 = 40 - /// [`CustomPayloadMarker`]s. + /// `MessageTypeDetails::payload.size`. + /// If the `payload.size == 8` a value for number_of_elements of 5 means that there are + /// 5 elements of size 8 stored in the [`Sample`]. + /// * When the payload.size == 8 and the number of elements if 5, it means that the sample + /// will contain a slice of 8 * 5 = 40 [`CustomPayloadMarker`]s or 40 bytes. #[doc(hidden)] pub unsafe fn receive_custom_payload( &self, diff --git a/iceoryx2/src/sample_mut_uninit.rs b/iceoryx2/src/sample_mut_uninit.rs index 83003c13a..e4d23950c 100644 --- a/iceoryx2/src/sample_mut_uninit.rs +++ b/iceoryx2/src/sample_mut_uninit.rs @@ -114,7 +114,7 @@ use crate::{ /// /// The generic parameter `Payload` is actually [`core::mem::MaybeUninit`]. pub struct SampleMutUninit { - pub(crate) sample: SampleMut, + sample: SampleMut, } impl diff --git a/iceoryx2/src/service/header/publish_subscribe.rs b/iceoryx2/src/service/header/publish_subscribe.rs index 885632181..5de1d6508 100644 --- a/iceoryx2/src/service/header/publish_subscribe.rs +++ b/iceoryx2/src/service/header/publish_subscribe.rs @@ -55,7 +55,15 @@ impl Header { self.publisher_port_id } - /// Returns the amount of elements of the payload. + /// Returns how many elements are stored inside the sample's payload. + /// + /// # Details when using + /// [`CustomPayloadMarker`](crate::service::builder::publish_subscribe::CustomPayloadMarker) + /// + /// In this case the number of elements relates to the element defined in the + /// [`MessageTypeDetails`](crate::service::static_config::message_type_details::MessageTypeDetails). + /// When the element has a `payload.size == 40` and the `Sample::payload().len() == 120` it + /// means that it contains 3 elements (3 * 40 == 120). pub fn number_of_elements(&self) -> u64 { self.number_of_elements } From 6deb81b58c4ca3d3f5231ae8327faed8ff52d775 Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Sat, 2 Nov 2024 07:23:33 +0100 Subject: [PATCH 5/5] [#498] Rewrite code for clarity --- doc/release-notes/iceoryx2-unreleased.md | 8 +------- iceoryx2/tests/subscriber_tests.rs | 4 +++- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/doc/release-notes/iceoryx2-unreleased.md b/doc/release-notes/iceoryx2-unreleased.md index d1ec9d3d0..8362aa404 100644 --- a/doc/release-notes/iceoryx2-unreleased.md +++ b/doc/release-notes/iceoryx2-unreleased.md @@ -74,10 +74,4 @@ } ``` -2. Removed `payload_type_layout` from pub/sub header. - - ```rust - // old - let sample = publisher.loan()?; - sample.header().payload_type_layout(); - ``` +2. Removed `payload_type_layout()` from `publish_subscribe::Header`. diff --git a/iceoryx2/tests/subscriber_tests.rs b/iceoryx2/tests/subscriber_tests.rs index 1fed1494e..996e2d578 100644 --- a/iceoryx2/tests/subscriber_tests.rs +++ b/iceoryx2/tests/subscriber_tests.rs @@ -74,7 +74,9 @@ mod subscriber { #[test] #[should_panic] #[cfg(debug_assertions)] - fn subscriber_with_custom_payload_details_panics_when_calling_receive() { + fn subscriber_with_custom_payload_details_panics_when_calling_non_custom_receive< + Sut: Service, + >() { const TYPE_SIZE_OVERRIDE: usize = 128; let service_name = generate_name(); let config = generate_isolated_config();