use core::fmt::Debug;
use core::marker::PhantomData;
use alloc::format;
use iceoryx2_bb_container::string::String;
use iceoryx2_bb_elementary::alignment::Alignment;
use iceoryx2_bb_elementary_traits::iceoryx_send::IceoryxSend;
use iceoryx2_bb_elementary_traits::zero_copy_send::ZeroCopySend;
use iceoryx2_bb_flatbuffers::{TypeName, is_binary_flatbuffer_schema};
use iceoryx2_bb_system_types::file_path::FilePath;
use iceoryx2_log::{fail, fatal_panic, warn};
use crate::identifiers::UniqueServiceId;
use crate::prelude::{AttributeSpecifier, AttributeVerifier};
use crate::service::builder::{
DynamicConfigCreationArgs, ServiceCreateError, ServiceOpenError, ServiceState,
StaticServiceResources,
};
use crate::service::dynamic_config::MessagingPatternSettings;
use crate::service::dynamic_config::request_response::DynamicConfigSettings;
use crate::service::port_factory::request_response;
use crate::service::resource::ServiceResource;
use crate::service::resource::request_response::{
RequestResponseResourceConfig, RequestResponseResources,
};
use crate::service::resource::type_definition::TypeDefinition;
use crate::service::static_config::StaticConfig;
use crate::service::static_config::message_type_details::TypeDetail;
use crate::service::static_config::messaging_pattern::MessagingPattern;
use crate::service::{Service, builder, dynamic_config};
use crate::service::{header, static_config};
use super::message_type_details::{MessageTypeDetails, TypeVariant};
use crate::service::marker::{CustomHeaderMarker, CustomPayloadMarker, Flatbuffer};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RequestResponseOpenError {
Interrupt,
DoesNotExist,
DoesNotSupportRequestedAmountOfClientRequestLoans,
DoesNotSupportRequestedAmountOfActiveRequestsPerClient,
DoesNotSupportRequestedResponseBufferSize,
DoesNotSupportRequestedAmountOfServers,
DoesNotSupportRequestedAmountOfClients,
DoesNotSupportRequestedAmountOfNodes,
DoesNotSupportRequestedAmountOfBorrowedResponsesPerPendingResponse,
ExceedsMaxNumberOfNodes,
HangsInCreation,
IncompatibleRequestOrResponseType,
IncompatibleAttributes,
IncompatibleMessagingPattern,
IncompatibleOverflowBehaviorForRequests,
IncompatibleOverflowBehaviorForResponses,
IncompatibleBehaviorForFireAndForgetRequests,
InsufficientPermissions,
InternalFailure,
IsMarkedForDestruction,
ServiceInCorruptedState,
UnableToCreateServiceTag,
VersionMismatch,
UnableToAcquireTypeDefinition,
InvalidTypeDefinition,
}
impl core::fmt::Display for RequestResponseOpenError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "RequestResponseOpenError::{self:?}")
}
}
impl core::error::Error for RequestResponseOpenError {}
impl From<ServiceState> for RequestResponseOpenError {
fn from(value: ServiceState) -> Self {
match value {
ServiceState::Interrupt => RequestResponseOpenError::Interrupt,
ServiceState::IncompatiblePayload => {
RequestResponseOpenError::IncompatibleRequestOrResponseType
}
ServiceState::IncompatibleMessagingPattern => {
RequestResponseOpenError::IncompatibleMessagingPattern
}
ServiceState::InsufficientPermissions => {
RequestResponseOpenError::InsufficientPermissions
}
ServiceState::HangsInCreation => RequestResponseOpenError::HangsInCreation,
ServiceState::Corrupted => RequestResponseOpenError::ServiceInCorruptedState,
ServiceState::InternalFailure => RequestResponseOpenError::InternalFailure,
ServiceState::VersionMismatch => RequestResponseOpenError::VersionMismatch,
}
}
}
impl From<ServiceOpenError> for RequestResponseOpenError {
fn from(value: ServiceOpenError) -> Self {
match value {
ServiceOpenError::InvalidTypeDefinition => {
RequestResponseOpenError::InvalidTypeDefinition
}
ServiceOpenError::DoesNotExist => RequestResponseOpenError::DoesNotExist,
ServiceOpenError::ExceedsMaxNumberOfNodes => {
RequestResponseOpenError::ExceedsMaxNumberOfNodes
}
ServiceOpenError::HangsInCreation => RequestResponseOpenError::HangsInCreation,
ServiceOpenError::IncompatibleMessagingPattern => {
RequestResponseOpenError::IncompatibleMessagingPattern
}
ServiceOpenError::IncompatiblePayload => {
RequestResponseOpenError::IncompatibleRequestOrResponseType
}
ServiceOpenError::InsufficientPermissions => {
RequestResponseOpenError::InsufficientPermissions
}
ServiceOpenError::InternalFailure => RequestResponseOpenError::InternalFailure,
ServiceOpenError::IsMarkedForDestruction => {
RequestResponseOpenError::IsMarkedForDestruction
}
ServiceOpenError::ServiceInCorruptedState => {
RequestResponseOpenError::ServiceInCorruptedState
}
ServiceOpenError::UnableToCreateServiceTag => {
RequestResponseOpenError::UnableToCreateServiceTag
}
ServiceOpenError::VersionMismatch => RequestResponseOpenError::VersionMismatch,
ServiceOpenError::Interrupt => RequestResponseOpenError::Interrupt,
ServiceOpenError::UnableToAcquireTypeDefinition => {
RequestResponseOpenError::UnableToAcquireTypeDefinition
}
}
}
}
impl From<RequestResponseOpenError> for ServiceOpenError {
fn from(value: RequestResponseOpenError) -> Self {
match value {
RequestResponseOpenError::InvalidTypeDefinition => ServiceOpenError::InvalidTypeDefinition,
RequestResponseOpenError::DoesNotExist => ServiceOpenError::DoesNotExist,
RequestResponseOpenError::ExceedsMaxNumberOfNodes => {
ServiceOpenError::ExceedsMaxNumberOfNodes
}
RequestResponseOpenError::HangsInCreation => ServiceOpenError::HangsInCreation,
RequestResponseOpenError::IncompatibleMessagingPattern => {
ServiceOpenError::IncompatibleMessagingPattern
}
RequestResponseOpenError::IncompatibleRequestOrResponseType => {
ServiceOpenError::IncompatiblePayload
}
RequestResponseOpenError::InsufficientPermissions => {
ServiceOpenError::InsufficientPermissions
}
RequestResponseOpenError::IsMarkedForDestruction => {
ServiceOpenError::IsMarkedForDestruction
}
RequestResponseOpenError::ServiceInCorruptedState => {
ServiceOpenError::ServiceInCorruptedState
}
RequestResponseOpenError::UnableToCreateServiceTag => {
ServiceOpenError::UnableToCreateServiceTag
}
RequestResponseOpenError::VersionMismatch => ServiceOpenError::VersionMismatch,
RequestResponseOpenError::Interrupt => ServiceOpenError::Interrupt,
RequestResponseOpenError::InternalFailure
| RequestResponseOpenError::DoesNotSupportRequestedAmountOfActiveRequestsPerClient
| RequestResponseOpenError::DoesNotSupportRequestedAmountOfBorrowedResponsesPerPendingResponse
| RequestResponseOpenError::DoesNotSupportRequestedAmountOfClientRequestLoans
| RequestResponseOpenError::DoesNotSupportRequestedAmountOfClients
| RequestResponseOpenError::DoesNotSupportRequestedAmountOfNodes
| RequestResponseOpenError::DoesNotSupportRequestedAmountOfServers
| RequestResponseOpenError::DoesNotSupportRequestedResponseBufferSize
| RequestResponseOpenError::IncompatibleAttributes
| RequestResponseOpenError::IncompatibleBehaviorForFireAndForgetRequests
| RequestResponseOpenError::IncompatibleOverflowBehaviorForRequests
| RequestResponseOpenError::IncompatibleOverflowBehaviorForResponses => ServiceOpenError::InternalFailure,
RequestResponseOpenError::UnableToAcquireTypeDefinition => ServiceOpenError::UnableToAcquireTypeDefinition
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RequestResponseCreateError {
Interrupt,
AlreadyExists,
InternalFailure,
IsBeingCreatedByAnotherInstance,
InsufficientPermissions,
HangsInCreation,
ServiceInCorruptedState,
UnableToCreateServiceTag,
ServiceConfigCouldNotBeCreated,
UnableToAcquireTypeDefinition,
InvalidTypeDefinition,
UnableToGenerateUniqueServiceId,
}
impl core::fmt::Display for RequestResponseCreateError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "RequestResponseCreateError::{self:?}")
}
}
impl core::error::Error for RequestResponseCreateError {}
impl From<ServiceState> for RequestResponseCreateError {
fn from(value: ServiceState) -> Self {
match value {
ServiceState::Interrupt => RequestResponseCreateError::Interrupt,
ServiceState::IncompatiblePayload
| ServiceState::IncompatibleMessagingPattern
| ServiceState::VersionMismatch => RequestResponseCreateError::AlreadyExists,
ServiceState::InsufficientPermissions => {
RequestResponseCreateError::InsufficientPermissions
}
ServiceState::HangsInCreation => RequestResponseCreateError::HangsInCreation,
ServiceState::Corrupted => RequestResponseCreateError::ServiceInCorruptedState,
ServiceState::InternalFailure => RequestResponseCreateError::InternalFailure,
}
}
}
impl From<ServiceCreateError> for RequestResponseCreateError {
fn from(value: ServiceCreateError) -> Self {
match value {
ServiceCreateError::AlreadyExists => RequestResponseCreateError::AlreadyExists,
ServiceCreateError::InsufficientPermissions => {
RequestResponseCreateError::InsufficientPermissions
}
ServiceCreateError::InternalFailure => RequestResponseCreateError::InternalFailure,
ServiceCreateError::IsBeingCreatedByAnotherInstance => {
RequestResponseCreateError::IsBeingCreatedByAnotherInstance
}
ServiceCreateError::ServiceConfigCouldNotBeCreated => {
RequestResponseCreateError::ServiceConfigCouldNotBeCreated
}
ServiceCreateError::ServiceInCorruptedState => {
RequestResponseCreateError::ServiceInCorruptedState
}
ServiceCreateError::UnableToCreateServiceTag => {
RequestResponseCreateError::UnableToCreateServiceTag
}
ServiceCreateError::Interrupt => RequestResponseCreateError::Interrupt,
ServiceCreateError::UnableToAcquireTypeDefinition => {
RequestResponseCreateError::UnableToAcquireTypeDefinition
}
ServiceCreateError::InvalidTypeDefinition => {
RequestResponseCreateError::InvalidTypeDefinition
}
ServiceCreateError::UnableToGenerateUniqueServiceId => {
RequestResponseCreateError::UnableToGenerateUniqueServiceId
}
}
}
}
impl From<RequestResponseCreateError> for ServiceCreateError {
fn from(value: RequestResponseCreateError) -> Self {
match value {
RequestResponseCreateError::AlreadyExists => ServiceCreateError::AlreadyExists,
RequestResponseCreateError::InsufficientPermissions => {
ServiceCreateError::InsufficientPermissions
}
RequestResponseCreateError::IsBeingCreatedByAnotherInstance => {
ServiceCreateError::IsBeingCreatedByAnotherInstance
}
RequestResponseCreateError::ServiceConfigCouldNotBeCreated => {
ServiceCreateError::ServiceConfigCouldNotBeCreated
}
RequestResponseCreateError::ServiceInCorruptedState => {
ServiceCreateError::ServiceInCorruptedState
}
RequestResponseCreateError::UnableToCreateServiceTag => {
ServiceCreateError::UnableToCreateServiceTag
}
RequestResponseCreateError::UnableToGenerateUniqueServiceId => {
ServiceCreateError::UnableToGenerateUniqueServiceId
}
_ => ServiceCreateError::InternalFailure,
}
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum RequestResponseOpenOrCreateError {
RequestResponseOpenError(RequestResponseOpenError),
RequestResponseCreateError(RequestResponseCreateError),
SystemInFlux,
}
impl From<ServiceState> for RequestResponseOpenOrCreateError {
fn from(value: ServiceState) -> Self {
RequestResponseOpenOrCreateError::RequestResponseOpenError(value.into())
}
}
impl From<RequestResponseOpenError> for RequestResponseOpenOrCreateError {
fn from(value: RequestResponseOpenError) -> Self {
RequestResponseOpenOrCreateError::RequestResponseOpenError(value)
}
}
impl From<RequestResponseCreateError> for RequestResponseOpenOrCreateError {
fn from(value: RequestResponseCreateError) -> Self {
RequestResponseOpenOrCreateError::RequestResponseCreateError(value)
}
}
impl core::fmt::Display for RequestResponseOpenOrCreateError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "RequestResponseOpenOrCreateError::{self:?}")
}
}
impl core::error::Error for RequestResponseOpenOrCreateError {}
#[derive(Debug, Default, Clone, Copy)]
struct Verify {
enable_safe_overflow_for_requests: bool,
enable_safe_overflow_for_responses: bool,
max_active_requests_per_client: bool,
max_loaned_requests: bool,
max_response_buffer_size: bool,
max_servers: bool,
max_clients: bool,
max_nodes: bool,
max_borrowed_responses_per_pending_response: bool,
enable_fire_and_forget_requests: bool,
}
#[derive(Debug)]
pub struct Builder<
RequestPayload: Debug + IceoryxSend + ?Sized,
RequestHeader: Debug + ZeroCopySend,
ResponsePayload: Debug + IceoryxSend + ?Sized,
ResponseHeader: Debug + ZeroCopySend,
ServiceType: Service,
> {
base: builder::BuilderWithServiceType<ServiceType>,
override_request_alignment: Option<usize>,
override_response_alignment: Option<usize>,
override_request_payload_type: Option<TypeDetail>,
override_response_payload_type: Option<TypeDetail>,
override_request_header_type: Option<TypeDetail>,
override_response_header_type: Option<TypeDetail>,
request_flatbuffer_schema_path: Option<FilePath>,
request_type_definition_name_hint: TypeName,
response_flatbuffer_schema_path: Option<FilePath>,
response_type_definition_name_hint: TypeName,
skip_type_definition_verification: bool,
verify: Verify,
_request_payload: PhantomData<RequestPayload>,
_request_header: PhantomData<RequestHeader>,
_response_payload: PhantomData<ResponsePayload>,
_response_header: PhantomData<ResponseHeader>,
}
impl<
RequestPayload: Debug + IceoryxSend + ?Sized,
RequestHeader: Debug + ZeroCopySend,
ResponsePayload: Debug + IceoryxSend + ?Sized,
ResponseHeader: Debug + ZeroCopySend,
ServiceType: Service,
> Clone for Builder<RequestPayload, RequestHeader, ResponsePayload, ResponseHeader, ServiceType>
{
fn clone(&self) -> Self {
Self {
base: self.base.clone(),
override_request_alignment: self.override_request_alignment,
override_response_alignment: self.override_response_alignment,
override_request_payload_type: self.override_request_payload_type,
override_response_payload_type: self.override_response_payload_type,
override_request_header_type: self.override_request_header_type,
override_response_header_type: self.override_response_header_type,
request_flatbuffer_schema_path: self.request_flatbuffer_schema_path,
response_flatbuffer_schema_path: self.response_flatbuffer_schema_path,
request_type_definition_name_hint: self.request_type_definition_name_hint,
response_type_definition_name_hint: self.response_type_definition_name_hint,
skip_type_definition_verification: self.skip_type_definition_verification,
verify: self.verify,
_request_payload: PhantomData,
_request_header: PhantomData,
_response_payload: PhantomData,
_response_header: PhantomData,
}
}
}
impl<
RequestPayload: Debug + IceoryxSend + ?Sized,
RequestHeader: Debug + ZeroCopySend,
ResponsePayload: Debug + IceoryxSend + ?Sized,
ResponseHeader: Debug + ZeroCopySend,
ServiceType: Service,
> Builder<RequestPayload, RequestHeader, ResponsePayload, ResponseHeader, ServiceType>
{
pub(crate) fn new(base: builder::BuilderWithServiceType<ServiceType>) -> Self {
Self {
base,
override_request_alignment: None,
override_response_alignment: None,
override_request_header_type: None,
override_request_payload_type: None,
override_response_header_type: None,
override_response_payload_type: None,
request_flatbuffer_schema_path: None,
response_flatbuffer_schema_path: None,
request_type_definition_name_hint: TypeName::new::<RequestPayload>(),
response_type_definition_name_hint: TypeName::new::<ResponsePayload>(),
skip_type_definition_verification: false,
verify: Verify::default(),
_request_payload: PhantomData,
_request_header: PhantomData,
_response_payload: PhantomData,
_response_header: PhantomData,
}
}
fn request_has_flatbuffer_payload(&self) -> bool {
use iceoryx2_bb_elementary_traits::type_name::TypeName;
match &self.override_request_payload_type {
Some(payload_type) => unsafe {
payload_type.type_name().as_str() == Flatbuffer::<()>::type_name()
},
None => unsafe {
<RequestPayload as iceoryx2_bb_elementary_traits::type_name::TypeName>::type_name()
== Flatbuffer::<()>::type_name()
},
}
}
fn response_has_flatbuffer_payload(&self) -> bool {
use iceoryx2_bb_elementary_traits::type_name::TypeName;
match &self.override_response_payload_type {
Some(payload_type) => unsafe {
payload_type.type_name().as_str() == Flatbuffer::<()>::type_name()
},
None => unsafe {
<ResponsePayload as iceoryx2_bb_elementary_traits::type_name::TypeName>::type_name()
== Flatbuffer::<()>::type_name()
},
}
}
fn config_details_mut(&mut self) -> &mut static_config::request_response::StaticConfig {
match self.base.service_config.messaging_pattern {
static_config::messaging_pattern::MessagingPattern::RequestResponse(ref mut v) => v,
_ => {
fatal_panic!(from self, "This should never happen! Accessing wrong messaging pattern in RequestResponse builder!");
}
}
}
fn config_details(&self) -> &static_config::request_response::StaticConfig {
match self.base.service_config.messaging_pattern {
static_config::messaging_pattern::MessagingPattern::RequestResponse(ref v) => v,
_ => {
fatal_panic!(from self, "This should never happen! Accessing wrong messaging pattern in RequestResponse builder!");
}
}
}
pub fn request_user_header<M: Debug + ZeroCopySend>(
self,
) -> Builder<RequestPayload, M, ResponsePayload, ResponseHeader, ServiceType> {
unsafe {
core::mem::transmute::<
Self,
Builder<RequestPayload, M, ResponsePayload, ResponseHeader, ServiceType>,
>(self)
}
}
pub fn response_user_header<M: Debug + ZeroCopySend>(
self,
) -> Builder<RequestPayload, RequestHeader, ResponsePayload, M, ServiceType> {
unsafe {
core::mem::transmute::<
Self,
Builder<RequestPayload, RequestHeader, ResponsePayload, M, ServiceType>,
>(self)
}
}
pub fn request_payload_alignment(mut self, alignment: Alignment) -> Self {
self.override_request_alignment = Some(alignment.value());
self
}
pub fn response_payload_alignment(mut self, alignment: Alignment) -> Self {
self.override_response_alignment = Some(alignment.value());
self
}
pub fn enable_safe_overflow_for_requests(mut self, value: bool) -> Self {
self.config_details_mut().enable_safe_overflow_for_requests = value;
self.verify.enable_safe_overflow_for_requests = true;
self
}
pub fn enable_safe_overflow_for_responses(mut self, value: bool) -> Self {
self.config_details_mut().enable_safe_overflow_for_responses = value;
self.verify.enable_safe_overflow_for_responses = true;
self
}
pub fn enable_fire_and_forget_requests(mut self, value: bool) -> Self {
self.config_details_mut().enable_fire_and_forget_requests = value;
self.verify.enable_fire_and_forget_requests = true;
self
}
pub fn max_active_requests_per_client(mut self, value: usize) -> Self {
self.config_details_mut().max_active_requests_per_client = value;
self.verify.max_active_requests_per_client = true;
self
}
pub fn max_loaned_requests(mut self, value: usize) -> Self {
self.config_details_mut().max_loaned_requests = value;
self.verify.max_loaned_requests = true;
self
}
pub fn max_response_buffer_size(mut self, value: usize) -> Self {
self.config_details_mut().max_response_buffer_size = value;
self.verify.max_response_buffer_size = true;
self
}
pub fn max_servers(mut self, value: usize) -> Self {
self.config_details_mut().max_servers = value;
self.verify.max_servers = true;
self
}
pub fn max_clients(mut self, value: usize) -> Self {
self.config_details_mut().max_clients = value;
self.verify.max_clients = true;
self
}
pub fn max_nodes(mut self, value: usize) -> Self {
self.config_details_mut().max_nodes = value;
self.verify.max_nodes = true;
self
}
pub fn max_borrowed_responses_per_pending_response(mut self, value: usize) -> Self {
self.config_details_mut()
.max_borrowed_responses_per_pending_response = value;
self.verify.max_borrowed_responses_per_pending_response = true;
self
}
fn adjust_configuration_to_meaningful_values(&mut self) {
let origin = format!("{self:?}");
let settings = self.base.service_config.request_response_mut();
if settings.max_response_buffer_size == 0 {
warn!(from origin,
"Setting the maximum size of the response buffer to 0 is not supported. Adjust it to 1, the smallest supported value.");
settings.max_response_buffer_size = 1;
}
if settings.max_active_requests_per_client == 0 {
warn!(from origin,
"Setting the maximum number of active requests to 0 is not supported. Adjust it to 1, the smallest supported value.");
settings.max_active_requests_per_client = 1;
}
if settings.max_servers == 0 {
warn!(from origin,
"Setting the maximum number of servers to 0 is not supported. Adjust it to 1, the smallest supported value.");
settings.max_servers = 1;
}
if settings.max_clients == 0 {
warn!(from origin,
"Setting the maximum number of clients to 0 is not supported. Adjust it to 1, the smallest supported value.");
settings.max_clients = 1;
}
if settings.max_nodes == 0 {
warn!(from origin,
"Setting the maximum number of nodes to 0 is not supported. Adjust it to 1, the smallest supported value.");
settings.max_nodes = 1;
}
if settings.max_borrowed_responses_per_pending_response == 0 {
warn!(from origin,
"Setting the maximum number of borrowed responses per pending response to 0 is not supported. Adjust it to 1, the smallest supported value.");
settings.max_borrowed_responses_per_pending_response = 1;
}
if settings.max_loaned_requests == 0 {
warn!(from origin,
"Setting the maximum loaned requests for clients to 0 is not supported. Adjust it to 1, the smallest supported value.");
settings.max_loaned_requests = 1;
}
}
fn verify_service_configuration(
&self,
msg: &str,
existing_service_config: &StaticConfig,
required_attributes: &AttributeVerifier,
) -> Result<(), RequestResponseOpenError> {
let required_service_config = &self.base.service_config;
let existing_attributes = existing_service_config.attributes();
if let Err(incompatible_key) = required_attributes.verify_requirements(existing_attributes)
{
fail!(from self, with RequestResponseOpenError::IncompatibleAttributes,
"{} due to incompatible service attribute key \"{}\". The following attributes {:?} are required but the service has the attributes {:?}.",
msg, incompatible_key, required_attributes, existing_attributes);
}
let required_configuration = required_service_config.request_response();
let existing_configuration = match &existing_service_config.messaging_pattern {
MessagingPattern::RequestResponse(v) => v,
p => {
fail!(from self, with RequestResponseOpenError::IncompatibleMessagingPattern,
"{} since a service with the messaging pattern {:?} exists but MessagingPattern::RequestResponse is required.",
msg, p);
}
};
if self.verify.enable_safe_overflow_for_requests
&& existing_configuration.enable_safe_overflow_for_requests
!= required_configuration.enable_safe_overflow_for_requests
{
fail!(from self, with RequestResponseOpenError::IncompatibleOverflowBehaviorForRequests,
"{} since the service has an incompatible safe overflow behavior for requests.",
msg);
}
if self.verify.enable_safe_overflow_for_responses
&& existing_configuration.enable_safe_overflow_for_responses
!= required_configuration.enable_safe_overflow_for_responses
{
fail!(from self, with RequestResponseOpenError::IncompatibleOverflowBehaviorForResponses,
"{} since the service has an incompatible safe overflow behavior for responses.",
msg);
}
if self.verify.enable_fire_and_forget_requests
&& existing_configuration.enable_fire_and_forget_requests
!= required_configuration.enable_fire_and_forget_requests
{
fail!(from self, with RequestResponseOpenError::IncompatibleBehaviorForFireAndForgetRequests,
"{} since the service has an incompatible behavior for fire and forget requests.",
msg);
}
if self.verify.max_active_requests_per_client
&& existing_configuration.max_active_requests_per_client
< required_configuration.max_active_requests_per_client
{
fail!(from self, with RequestResponseOpenError::DoesNotSupportRequestedAmountOfActiveRequestsPerClient,
"{} since the service supports only {} active requests per client but {} are required.",
msg, existing_configuration.max_active_requests_per_client, required_configuration.max_active_requests_per_client);
}
if self.verify.max_loaned_requests
&& existing_configuration.max_loaned_requests
< required_configuration.max_loaned_requests
{
fail!(from self, with RequestResponseOpenError::DoesNotSupportRequestedAmountOfClientRequestLoans,
"{} since the service supports only {} loaned requests per client but {} are required.",
msg, existing_configuration.max_loaned_requests, required_configuration.max_loaned_requests);
}
if self.verify.max_borrowed_responses_per_pending_response
&& existing_configuration.max_borrowed_responses_per_pending_response
< required_configuration.max_borrowed_responses_per_pending_response
{
fail!(from self, with RequestResponseOpenError::DoesNotSupportRequestedAmountOfBorrowedResponsesPerPendingResponse,
"{} since the service supports only {} borrowed responses per pending response but {} are required.",
msg, existing_configuration.max_borrowed_responses_per_pending_response, required_configuration.max_borrowed_responses_per_pending_response);
}
if self.verify.max_response_buffer_size
&& existing_configuration.max_response_buffer_size
< required_configuration.max_response_buffer_size
{
fail!(from self, with RequestResponseOpenError::DoesNotSupportRequestedResponseBufferSize,
"{} since the service supports a maximum response buffer size of {} but a size of {} is required.",
msg, existing_configuration.max_response_buffer_size, required_configuration.max_response_buffer_size);
}
if self.verify.max_servers
&& existing_configuration.max_servers < required_configuration.max_servers
{
fail!(from self, with RequestResponseOpenError::DoesNotSupportRequestedAmountOfServers,
"{} since the service supports at most {} servers but {} are required.",
msg, existing_configuration.max_servers, required_configuration.max_servers);
}
if self.verify.max_clients
&& existing_configuration.max_clients < required_configuration.max_clients
{
fail!(from self, with RequestResponseOpenError::DoesNotSupportRequestedAmountOfClients,
"{} since the service supports at most {} clients but {} are required.",
msg, existing_configuration.max_clients, required_configuration.max_clients);
}
if self.verify.max_nodes
&& existing_configuration.max_nodes < required_configuration.max_nodes
{
fail!(from self, with RequestResponseOpenError::DoesNotSupportRequestedAmountOfNodes,
"{} since the service supports at most {} nodes but {} are required.",
msg, existing_configuration.max_nodes, required_configuration.max_nodes);
}
Ok(())
}
fn is_service_available(
&self,
error_msg: &str,
) -> Result<Option<StaticServiceResources<ServiceType>>, ServiceState> {
let reqres_service_config = self.config_details();
match self.base.is_service_available(error_msg) {
Ok(Some((config, storage))) => {
if !reqres_service_config
.request_message_type_details
.is_compatible_to(&config.request_response().request_message_type_details)
{
fail!(from self, with ServiceState::IncompatiblePayload,
"{} since the services uses the request type \"{:?}\" which is not compatible to the requested type \"{:?}\".",
error_msg, &config.request_response().request_message_type_details,
reqres_service_config.request_message_type_details);
}
if !reqres_service_config
.response_message_type_details
.is_compatible_to(&config.request_response().response_message_type_details)
{
fail!(from self, with ServiceState::IncompatiblePayload,
"{} since the services uses the response type \"{:?}\" which is not compatible to the requested type \"{:?}\".",
error_msg, &config.request_response().response_message_type_details,
reqres_service_config.response_message_type_details);
}
Ok(Some((config, storage)))
}
Ok(None) => Ok(None),
Err(e) => Err(e),
}
}
fn create_impl(
&self,
attributes: &AttributeSpecifier,
) -> Result<
request_response::PortFactory<
ServiceType,
RequestPayload,
RequestHeader,
ResponsePayload,
ResponseHeader,
>,
RequestResponseCreateError,
> {
let msg = "Unable to create request response service";
let generate_dynamic_config = |service_config: &StaticConfig| {
let reqres_config = service_config.request_response();
let dynamic_config_setting = DynamicConfigSettings {
number_of_clients: reqres_config.max_clients,
number_of_servers: reqres_config.max_servers,
};
DynamicConfigCreationArgs {
messaging_pattern_settings: MessagingPatternSettings::RequestResponse(
dynamic_config_setting,
),
additional_size:
dynamic_config::request_response::DynamicConfig::<ServiceType::Bag>::memory_size(
&dynamic_config_setting,
),
max_number_of_nodes: reqres_config.max_nodes,
}
};
for (name, path) in [
("request", &self.request_flatbuffer_schema_path),
("response", &self.response_flatbuffer_schema_path),
] {
if let Some(schema_path) = path
&& !is_binary_flatbuffer_schema(&schema_path.file_name())
{
fail!(from self,
with RequestResponseCreateError::InvalidTypeDefinition,
"{msg} since the {name} type definition must be a binary flatbuffer schema and this file \"{}\" is something else.",
schema_path);
}
}
let service_state = self.base.create(
msg,
attributes,
|| self.is_service_available(msg),
|_| Ok(()),
generate_dynamic_config,
|service_config| {
RequestResponseResources::create(
service_config,
&RequestResponseResourceConfig::<ServiceType> {
request: TypeDefinition {
use_type_definition: self.request_has_flatbuffer_payload(),
schema_path: self.request_flatbuffer_schema_path,
type_name: self.request_type_definition_name_hint,
skip_type_definition_verification: false,
},
response: TypeDefinition {
use_type_definition: self.response_has_flatbuffer_payload(),
schema_path: self.response_flatbuffer_schema_path,
type_name: self.response_type_definition_name_hint,
skip_type_definition_verification: false,
},
shared_node: self.base.shared_node.clone(),
},
)
},
|_| {},
|service_config| {
UniqueServiceId::from_request_response_service::<ServiceType>(
service_config.name(),
self.base.shared_node.config(),
)
},
)?;
Ok(request_response::PortFactory::new(service_state))
}
fn open_impl(
&self,
required_attributes: &AttributeVerifier,
) -> Result<
request_response::PortFactory<
ServiceType,
RequestPayload,
RequestHeader,
ResponsePayload,
ResponseHeader,
>,
RequestResponseOpenError,
> {
let msg = "Unable to open request response service";
for (name, path) in [
("request", &self.request_flatbuffer_schema_path),
("response", &self.response_flatbuffer_schema_path),
] {
if let Some(schema_path) = path
&& !is_binary_flatbuffer_schema(&schema_path.file_name())
{
fail!(from self,
with RequestResponseOpenError::InvalidTypeDefinition,
"{msg} since the {name} type definition must be a binary flatbuffer schema and this file \"{}\" is something else.",
schema_path);
}
}
let service_state = self.base.open(
msg,
|| self.is_service_available(msg),
|existing_service_config| -> Result<(), RequestResponseOpenError> {
self.verify_service_configuration(msg, existing_service_config, required_attributes)
},
|service_config| {
RequestResponseResources::open(
service_config,
&RequestResponseResourceConfig::<ServiceType> {
request: TypeDefinition {
use_type_definition: self.request_has_flatbuffer_payload(),
schema_path: self.request_flatbuffer_schema_path,
type_name: self.request_type_definition_name_hint,
skip_type_definition_verification: self
.skip_type_definition_verification,
},
response: TypeDefinition {
use_type_definition: self.response_has_flatbuffer_payload(),
schema_path: self.response_flatbuffer_schema_path,
type_name: self.response_type_definition_name_hint,
skip_type_definition_verification: self
.skip_type_definition_verification,
},
shared_node: self.base.shared_node.clone(),
},
)
},
)?;
Ok(request_response::PortFactory::new(service_state))
}
fn open_or_create_impl(
mut self,
attributes: &AttributeVerifier,
) -> Result<
request_response::PortFactory<
ServiceType,
RequestPayload,
RequestHeader,
ResponsePayload,
ResponseHeader,
>,
RequestResponseOpenOrCreateError,
> {
let msg = "Unable to open or create request response service";
self.adjust_configuration_to_meaningful_values();
self.base.open_or_create(
msg,
attributes,
RequestResponseOpenOrCreateError::RequestResponseOpenError(
RequestResponseOpenError::InternalFailure,
),
RequestResponseOpenOrCreateError::SystemInFlux,
|attributes| self.open_impl(attributes),
|attributes| self.create_impl(attributes),
)
}
fn prepare_message_type(&mut self) {
if let Some(details) = &self.override_request_payload_type {
self.config_details_mut()
.request_message_type_details
.payload = *details;
}
if let Some(details) = &self.override_request_header_type {
self.config_details_mut()
.request_message_type_details
.user_header = *details;
}
if let Some(details) = &self.override_response_payload_type {
self.config_details_mut()
.response_message_type_details
.payload = *details;
}
if let Some(details) = &self.override_response_header_type {
self.config_details_mut()
.response_message_type_details
.user_header = *details;
}
if let Some(alignment) = self.override_request_alignment {
self.config_details_mut()
.request_message_type_details
.payload
.alignment = self
.config_details()
.request_message_type_details
.payload
.alignment
.max(alignment);
}
if let Some(alignment) = self.override_response_alignment {
self.config_details_mut()
.response_message_type_details
.payload
.alignment = self
.config_details()
.response_message_type_details
.payload
.alignment
.max(alignment);
}
}
}
impl<
RequestPayload: Debug + IceoryxSend,
RequestHeader: Debug + ZeroCopySend,
ResponsePayload: Debug + IceoryxSend,
ResponseHeader: Debug + ZeroCopySend,
ServiceType: Service,
> Builder<RequestPayload, RequestHeader, ResponsePayload, ResponseHeader, ServiceType>
{
fn prepare_message_type_details(&mut self) {
self.config_details_mut().request_message_type_details = MessageTypeDetails::from::<
header::request_response::RequestHeader,
RequestHeader,
RequestPayload,
>(TypeVariant::FixedSize);
self.config_details_mut().response_message_type_details = MessageTypeDetails::from::<
header::request_response::ResponseHeader,
ResponseHeader,
ResponsePayload,
>(TypeVariant::FixedSize);
self.prepare_message_type();
}
pub fn open_or_create(
self,
) -> Result<
request_response::PortFactory<
ServiceType,
RequestPayload,
RequestHeader,
ResponsePayload,
ResponseHeader,
>,
RequestResponseOpenOrCreateError,
> {
self.open_or_create_with_attributes(&AttributeVerifier::new())
}
pub fn open_or_create_with_attributes(
mut self,
verifier: &AttributeVerifier,
) -> Result<
request_response::PortFactory<
ServiceType,
RequestPayload,
RequestHeader,
ResponsePayload,
ResponseHeader,
>,
RequestResponseOpenOrCreateError,
> {
self.prepare_message_type_details();
self.open_or_create_impl(verifier)
}
pub fn open(
self,
) -> Result<
request_response::PortFactory<
ServiceType,
RequestPayload,
RequestHeader,
ResponsePayload,
ResponseHeader,
>,
RequestResponseOpenError,
> {
self.open_with_attributes(&AttributeVerifier::new())
}
pub fn open_with_attributes(
mut self,
verifier: &AttributeVerifier,
) -> Result<
request_response::PortFactory<
ServiceType,
RequestPayload,
RequestHeader,
ResponsePayload,
ResponseHeader,
>,
RequestResponseOpenError,
> {
self.prepare_message_type_details();
self.open_impl(verifier)
}
pub fn create(
self,
) -> Result<
request_response::PortFactory<
ServiceType,
RequestPayload,
RequestHeader,
ResponsePayload,
ResponseHeader,
>,
RequestResponseCreateError,
> {
self.create_with_attributes(&AttributeSpecifier::new())
}
pub fn create_with_attributes(
mut self,
attributes: &AttributeSpecifier,
) -> Result<
request_response::PortFactory<
ServiceType,
RequestPayload,
RequestHeader,
ResponsePayload,
ResponseHeader,
>,
RequestResponseCreateError,
> {
self.adjust_configuration_to_meaningful_values();
self.prepare_message_type_details();
self.create_impl(attributes)
}
}
impl<
RequestPayload: Debug + ZeroCopySend,
RequestHeader: Debug + ZeroCopySend,
ResponsePayload: Debug + IceoryxSend,
ResponseHeader: Debug + ZeroCopySend,
ServiceType: Service,
> Builder<[RequestPayload], RequestHeader, ResponsePayload, ResponseHeader, ServiceType>
{
fn prepare_message_type_details(&mut self) {
self.config_details_mut().request_message_type_details = MessageTypeDetails::from::<
header::request_response::RequestHeader,
RequestHeader,
RequestPayload,
>(TypeVariant::Dynamic);
self.config_details_mut().response_message_type_details = MessageTypeDetails::from::<
header::request_response::ResponseHeader,
ResponseHeader,
ResponsePayload,
>(TypeVariant::FixedSize);
self.prepare_message_type();
}
pub fn open_or_create(
self,
) -> Result<
request_response::PortFactory<
ServiceType,
[RequestPayload],
RequestHeader,
ResponsePayload,
ResponseHeader,
>,
RequestResponseOpenOrCreateError,
> {
self.open_or_create_with_attributes(&AttributeVerifier::new())
}
pub fn open_or_create_with_attributes(
mut self,
verifier: &AttributeVerifier,
) -> Result<
request_response::PortFactory<
ServiceType,
[RequestPayload],
RequestHeader,
ResponsePayload,
ResponseHeader,
>,
RequestResponseOpenOrCreateError,
> {
self.prepare_message_type_details();
self.open_or_create_impl(verifier)
}
pub fn open(
self,
) -> Result<
request_response::PortFactory<
ServiceType,
[RequestPayload],
RequestHeader,
ResponsePayload,
ResponseHeader,
>,
RequestResponseOpenError,
> {
self.open_with_attributes(&AttributeVerifier::new())
}
pub fn open_with_attributes(
mut self,
verifier: &AttributeVerifier,
) -> Result<
request_response::PortFactory<
ServiceType,
[RequestPayload],
RequestHeader,
ResponsePayload,
ResponseHeader,
>,
RequestResponseOpenError,
> {
self.prepare_message_type_details();
self.open_impl(verifier)
}
pub fn create(
self,
) -> Result<
request_response::PortFactory<
ServiceType,
[RequestPayload],
RequestHeader,
ResponsePayload,
ResponseHeader,
>,
RequestResponseCreateError,
> {
self.create_with_attributes(&AttributeSpecifier::new())
}
pub fn create_with_attributes(
mut self,
attributes: &AttributeSpecifier,
) -> Result<
request_response::PortFactory<
ServiceType,
[RequestPayload],
RequestHeader,
ResponsePayload,
ResponseHeader,
>,
RequestResponseCreateError,
> {
self.prepare_message_type_details();
self.create_impl(attributes)
}
}
impl<
RequestPayload: Debug + ZeroCopySend,
RequestHeader: Debug + ZeroCopySend,
ResponsePayload: Debug + ZeroCopySend,
ResponseHeader: Debug + ZeroCopySend,
ServiceType: Service,
> Builder<[RequestPayload], RequestHeader, [ResponsePayload], ResponseHeader, ServiceType>
{
fn prepare_message_type_details(&mut self) {
self.config_details_mut().request_message_type_details = MessageTypeDetails::from::<
header::request_response::RequestHeader,
RequestHeader,
RequestPayload,
>(TypeVariant::Dynamic);
self.config_details_mut().response_message_type_details = MessageTypeDetails::from::<
header::request_response::ResponseHeader,
ResponseHeader,
ResponsePayload,
>(TypeVariant::Dynamic);
self.prepare_message_type();
}
#[allow(clippy::type_complexity)] pub fn open_or_create(
self,
) -> Result<
request_response::PortFactory<
ServiceType,
[RequestPayload],
RequestHeader,
[ResponsePayload],
ResponseHeader,
>,
RequestResponseOpenOrCreateError,
> {
self.open_or_create_with_attributes(&AttributeVerifier::new())
}
#[allow(clippy::type_complexity)] pub fn open_or_create_with_attributes(
mut self,
verifier: &AttributeVerifier,
) -> Result<
request_response::PortFactory<
ServiceType,
[RequestPayload],
RequestHeader,
[ResponsePayload],
ResponseHeader,
>,
RequestResponseOpenOrCreateError,
> {
self.prepare_message_type_details();
self.open_or_create_impl(verifier)
}
#[allow(clippy::type_complexity)] pub fn open(
self,
) -> Result<
request_response::PortFactory<
ServiceType,
[RequestPayload],
RequestHeader,
[ResponsePayload],
ResponseHeader,
>,
RequestResponseOpenError,
> {
self.open_with_attributes(&AttributeVerifier::new())
}
#[allow(clippy::type_complexity)] pub fn open_with_attributes(
mut self,
verifier: &AttributeVerifier,
) -> Result<
request_response::PortFactory<
ServiceType,
[RequestPayload],
RequestHeader,
[ResponsePayload],
ResponseHeader,
>,
RequestResponseOpenError,
> {
self.prepare_message_type_details();
self.open_impl(verifier)
}
#[allow(clippy::type_complexity)] pub fn create(
self,
) -> Result<
request_response::PortFactory<
ServiceType,
[RequestPayload],
RequestHeader,
[ResponsePayload],
ResponseHeader,
>,
RequestResponseCreateError,
> {
self.create_with_attributes(&AttributeSpecifier::new())
}
#[allow(clippy::type_complexity)] pub fn create_with_attributes(
mut self,
attributes: &AttributeSpecifier,
) -> Result<
request_response::PortFactory<
ServiceType,
[RequestPayload],
RequestHeader,
[ResponsePayload],
ResponseHeader,
>,
RequestResponseCreateError,
> {
self.prepare_message_type_details();
self.create_impl(attributes)
}
}
impl<
RequestPayload: Debug + IceoryxSend,
RequestHeader: Debug + ZeroCopySend,
ResponsePayload: Debug + ZeroCopySend,
ResponseHeader: Debug + ZeroCopySend,
ServiceType: Service,
> Builder<RequestPayload, RequestHeader, [ResponsePayload], ResponseHeader, ServiceType>
{
fn prepare_message_type_details(&mut self) {
self.config_details_mut().request_message_type_details = MessageTypeDetails::from::<
header::request_response::RequestHeader,
RequestHeader,
RequestPayload,
>(TypeVariant::FixedSize);
self.config_details_mut().response_message_type_details = MessageTypeDetails::from::<
header::request_response::ResponseHeader,
ResponseHeader,
ResponsePayload,
>(TypeVariant::Dynamic);
self.prepare_message_type();
}
pub fn open_or_create(
self,
) -> Result<
request_response::PortFactory<
ServiceType,
RequestPayload,
RequestHeader,
[ResponsePayload],
ResponseHeader,
>,
RequestResponseOpenOrCreateError,
> {
self.open_or_create_with_attributes(&AttributeVerifier::new())
}
pub fn open_or_create_with_attributes(
mut self,
verifier: &AttributeVerifier,
) -> Result<
request_response::PortFactory<
ServiceType,
RequestPayload,
RequestHeader,
[ResponsePayload],
ResponseHeader,
>,
RequestResponseOpenOrCreateError,
> {
self.prepare_message_type_details();
self.open_or_create_impl(verifier)
}
pub fn open(
self,
) -> Result<
request_response::PortFactory<
ServiceType,
RequestPayload,
RequestHeader,
[ResponsePayload],
ResponseHeader,
>,
RequestResponseOpenError,
> {
self.open_with_attributes(&AttributeVerifier::new())
}
pub fn open_with_attributes(
mut self,
verifier: &AttributeVerifier,
) -> Result<
request_response::PortFactory<
ServiceType,
RequestPayload,
RequestHeader,
[ResponsePayload],
ResponseHeader,
>,
RequestResponseOpenError,
> {
self.prepare_message_type_details();
self.open_impl(verifier)
}
pub fn create(
self,
) -> Result<
request_response::PortFactory<
ServiceType,
RequestPayload,
RequestHeader,
[ResponsePayload],
ResponseHeader,
>,
RequestResponseCreateError,
> {
self.create_with_attributes(&AttributeSpecifier::new())
}
pub fn create_with_attributes(
mut self,
attributes: &AttributeSpecifier,
) -> Result<
request_response::PortFactory<
ServiceType,
RequestPayload,
RequestHeader,
[ResponsePayload],
ResponseHeader,
>,
RequestResponseCreateError,
> {
self.prepare_message_type_details();
self.create_impl(attributes)
}
}
impl<
ServiceType: Service,
RequestHeader: Debug + ZeroCopySend,
ResponseHeader: Debug + ZeroCopySend,
>
Builder<
[CustomPayloadMarker],
RequestHeader,
[CustomPayloadMarker],
ResponseHeader,
ServiceType,
>
{
#[doc(hidden)]
pub fn __internal_request_type_definition_name_hint(mut self, value: &TypeName) -> Self {
self.request_type_definition_name_hint = *value;
self
}
#[doc(hidden)]
pub unsafe fn __internal_request_flatbuffer_schema_path(mut self, path: &FilePath) -> Self {
self.request_flatbuffer_schema_path = Some(*path);
self
}
#[doc(hidden)]
pub fn __internal_response_type_definition_name_hint(mut self, value: &TypeName) -> Self {
self.response_type_definition_name_hint = *value;
self
}
#[doc(hidden)]
pub unsafe fn __internal_response_flatbuffer_schema_path(mut self, path: &FilePath) -> Self {
self.response_flatbuffer_schema_path = Some(*path);
self
}
#[doc(hidden)]
pub unsafe fn __internal_set_request_payload_type_details(
mut self,
value: &TypeDetail,
) -> Self {
self.override_request_payload_type = Some(*value);
self
}
#[doc(hidden)]
pub unsafe fn __internal_set_response_payload_type_details(
mut self,
value: &TypeDetail,
) -> Self {
self.override_response_payload_type = Some(*value);
self
}
#[doc(hidden)]
pub unsafe fn __internal_skip_type_definition_verification(mut self) -> Self {
self.skip_type_definition_verification = true;
self
}
}
impl<
RequestPayload: IceoryxSend + Debug + ?Sized,
ResponsePayload: Debug + IceoryxSend + ?Sized,
ServiceType: Service,
> Builder<RequestPayload, CustomHeaderMarker, ResponsePayload, CustomHeaderMarker, ServiceType>
{
#[doc(hidden)]
pub unsafe fn __internal_set_request_header_type_details(mut self, value: &TypeDetail) -> Self {
self.override_request_header_type = Some(*value);
self
}
#[doc(hidden)]
pub unsafe fn __internal_set_response_header_type_details(
mut self,
value: &TypeDetail,
) -> Self {
self.override_response_header_type = Some(*value);
self
}
}
impl<
RequestPayload: Debug,
RequestHeader: Debug + ZeroCopySend,
ResponsePayload: Debug + IceoryxSend + ?Sized,
ResponseHeader: Debug + ZeroCopySend,
ServiceType: Service,
> Builder<Flatbuffer<RequestPayload>, RequestHeader, ResponsePayload, ResponseHeader, ServiceType>
{
pub fn request_flatbuffer_schema_path(mut self, path: &FilePath) -> Self {
self.request_flatbuffer_schema_path = Some(*path);
self
}
}
impl<
RequestPayload: Debug + IceoryxSend + ?Sized,
RequestHeader: Debug + ZeroCopySend,
ResponsePayload: Debug,
ResponseHeader: Debug + ZeroCopySend,
ServiceType: Service,
> Builder<RequestPayload, RequestHeader, Flatbuffer<ResponsePayload>, ResponseHeader, ServiceType>
{
pub fn response_flatbuffer_schema_path(mut self, path: &FilePath) -> Self {
self.response_flatbuffer_schema_path = Some(*path);
self
}
}