pub use crate::port::event_id::EventId;
use crate::service::resource::NoResource;
use alloc::format;
use iceoryx2_bb_container::relocatable_option::RelocatableOption;
use iceoryx2_bb_posix::clock::Time;
use iceoryx2_log::{fail, fatal_panic};
use crate::service::builder::{DynamicConfigCreationArgs, ServiceCreateError, ServiceOpenError};
use crate::service::dynamic_config::MessagingPatternSettings;
use crate::service::port_factory::event;
use crate::service::static_config::messaging_pattern::MessagingPattern;
use crate::service::*;
use crate::service::{self, dynamic_config::event::DynamicConfigSettings};
use self::attribute::{AttributeSpecifier, AttributeVerifier};
use static_config::event::Deadline;
use super::ServiceState;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum EventOpenError {
Interrupt,
DoesNotExist,
InsufficientPermissions,
ServiceInCorruptedState,
IncompatibleMessagingPattern,
IncompatibleAttributes,
InternalFailure,
IncompatibleDeadline,
IncompatibleNotifierCreatedEvent,
IncompatibleNotifierDroppedEvent,
IncompatibleNotifierDeadEvent,
HangsInCreation,
DoesNotSupportRequestedAmountOfNotifiers,
DoesNotSupportRequestedAmountOfListeners,
DoesNotSupportRequestedMaxEventId,
DoesNotSupportRequestedAmountOfNodes,
ExceedsMaxNumberOfNodes,
IsMarkedForDestruction,
UnableToCreateServiceTag,
VersionMismatch,
}
impl core::fmt::Display for EventOpenError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "EventOpenError::{self:?}")
}
}
impl core::error::Error for EventOpenError {}
impl From<ServiceState> for EventOpenError {
fn from(value: ServiceState) -> Self {
match value {
ServiceState::Interrupt => EventOpenError::Interrupt,
ServiceState::IncompatibleMessagingPattern | ServiceState::IncompatiblePayload => {
EventOpenError::IncompatibleMessagingPattern
}
ServiceState::InsufficientPermissions => EventOpenError::InsufficientPermissions,
ServiceState::HangsInCreation => EventOpenError::HangsInCreation,
ServiceState::Corrupted => EventOpenError::ServiceInCorruptedState,
ServiceState::InternalFailure => EventOpenError::InternalFailure,
ServiceState::VersionMismatch => EventOpenError::VersionMismatch,
}
}
}
impl From<ServiceOpenError> for EventOpenError {
fn from(value: ServiceOpenError) -> Self {
match value {
ServiceOpenError::Interrupt => EventOpenError::Interrupt,
ServiceOpenError::DoesNotExist => EventOpenError::DoesNotExist,
ServiceOpenError::ExceedsMaxNumberOfNodes => EventOpenError::ExceedsMaxNumberOfNodes,
ServiceOpenError::HangsInCreation => EventOpenError::HangsInCreation,
ServiceOpenError::IncompatibleMessagingPattern => {
EventOpenError::IncompatibleMessagingPattern
}
ServiceOpenError::IncompatiblePayload => EventOpenError::IncompatibleMessagingPattern,
ServiceOpenError::InsufficientPermissions => EventOpenError::InsufficientPermissions,
ServiceOpenError::InternalFailure
| ServiceOpenError::UnableToAcquireTypeDefinition
| ServiceOpenError::InvalidTypeDefinition => EventOpenError::InternalFailure,
ServiceOpenError::IsMarkedForDestruction => EventOpenError::IsMarkedForDestruction,
ServiceOpenError::ServiceInCorruptedState => EventOpenError::ServiceInCorruptedState,
ServiceOpenError::UnableToCreateServiceTag => EventOpenError::UnableToCreateServiceTag,
ServiceOpenError::VersionMismatch => EventOpenError::VersionMismatch,
}
}
}
impl From<EventOpenError> for ServiceOpenError {
fn from(value: EventOpenError) -> Self {
match value {
EventOpenError::DoesNotExist => ServiceOpenError::DoesNotExist,
EventOpenError::ExceedsMaxNumberOfNodes => ServiceOpenError::ExceedsMaxNumberOfNodes,
EventOpenError::HangsInCreation => ServiceOpenError::HangsInCreation,
EventOpenError::IncompatibleMessagingPattern => {
ServiceOpenError::IncompatibleMessagingPattern
}
EventOpenError::InsufficientPermissions => ServiceOpenError::InsufficientPermissions,
EventOpenError::IsMarkedForDestruction => ServiceOpenError::IsMarkedForDestruction,
EventOpenError::ServiceInCorruptedState => ServiceOpenError::ServiceInCorruptedState,
EventOpenError::UnableToCreateServiceTag => ServiceOpenError::UnableToCreateServiceTag,
EventOpenError::VersionMismatch => ServiceOpenError::VersionMismatch,
EventOpenError::Interrupt => ServiceOpenError::Interrupt,
EventOpenError::DoesNotSupportRequestedAmountOfListeners
| EventOpenError::InternalFailure
| EventOpenError::DoesNotSupportRequestedAmountOfNodes
| EventOpenError::DoesNotSupportRequestedAmountOfNotifiers
| EventOpenError::DoesNotSupportRequestedMaxEventId
| EventOpenError::IncompatibleAttributes
| EventOpenError::IncompatibleDeadline
| EventOpenError::IncompatibleNotifierCreatedEvent
| EventOpenError::IncompatibleNotifierDeadEvent
| EventOpenError::IncompatibleNotifierDroppedEvent => ServiceOpenError::InternalFailure,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum EventCreateError {
Interrupt,
ServiceInCorruptedState,
InternalFailure,
IsBeingCreatedByAnotherInstance,
AlreadyExists,
InsufficientPermissions,
UnableToCreateServiceTag,
ServiceConfigCouldNotBeCreated,
EventIdExceedsMaxSupportedValue,
UnableToGenerateUniqueServiceId,
}
impl From<ServiceCreateError> for EventCreateError {
fn from(value: ServiceCreateError) -> Self {
match value {
ServiceCreateError::Interrupt => EventCreateError::Interrupt,
ServiceCreateError::AlreadyExists => EventCreateError::AlreadyExists,
ServiceCreateError::InsufficientPermissions => {
EventCreateError::InsufficientPermissions
}
ServiceCreateError::InternalFailure
| ServiceCreateError::UnableToAcquireTypeDefinition
| ServiceCreateError::InvalidTypeDefinition => EventCreateError::InternalFailure,
ServiceCreateError::IsBeingCreatedByAnotherInstance => {
EventCreateError::IsBeingCreatedByAnotherInstance
}
ServiceCreateError::ServiceInCorruptedState => {
EventCreateError::ServiceInCorruptedState
}
ServiceCreateError::UnableToCreateServiceTag => {
EventCreateError::UnableToCreateServiceTag
}
ServiceCreateError::ServiceConfigCouldNotBeCreated => {
EventCreateError::ServiceConfigCouldNotBeCreated
}
ServiceCreateError::UnableToGenerateUniqueServiceId => {
EventCreateError::UnableToGenerateUniqueServiceId
}
}
}
}
impl From<EventCreateError> for ServiceCreateError {
fn from(value: EventCreateError) -> Self {
match value {
EventCreateError::AlreadyExists => ServiceCreateError::AlreadyExists,
EventCreateError::InsufficientPermissions => {
ServiceCreateError::InsufficientPermissions
}
EventCreateError::IsBeingCreatedByAnotherInstance => {
ServiceCreateError::IsBeingCreatedByAnotherInstance
}
EventCreateError::ServiceInCorruptedState => {
ServiceCreateError::ServiceInCorruptedState
}
EventCreateError::UnableToCreateServiceTag => {
ServiceCreateError::UnableToCreateServiceTag
}
EventCreateError::ServiceConfigCouldNotBeCreated => {
ServiceCreateError::ServiceConfigCouldNotBeCreated
}
EventCreateError::Interrupt => ServiceCreateError::Interrupt,
EventCreateError::InternalFailure => ServiceCreateError::InternalFailure,
EventCreateError::EventIdExceedsMaxSupportedValue => {
ServiceCreateError::InternalFailure
}
EventCreateError::UnableToGenerateUniqueServiceId => {
ServiceCreateError::UnableToGenerateUniqueServiceId
}
}
}
}
impl core::fmt::Display for EventCreateError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "EventCreateError::{self:?}")
}
}
impl core::error::Error for EventCreateError {}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum EventOpenOrCreateError {
EventOpenError(EventOpenError),
EventCreateError(EventCreateError),
SystemInFlux,
}
impl From<EventOpenError> for EventOpenOrCreateError {
fn from(value: EventOpenError) -> Self {
EventOpenOrCreateError::EventOpenError(value)
}
}
impl From<EventCreateError> for EventOpenOrCreateError {
fn from(value: EventCreateError) -> Self {
EventOpenOrCreateError::EventCreateError(value)
}
}
impl core::fmt::Display for EventOpenOrCreateError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "EventOpenOrCreateError::{self:?}")
}
}
impl core::error::Error for EventOpenOrCreateError {}
impl From<ServiceState> for EventOpenOrCreateError {
fn from(value: ServiceState) -> Self {
EventOpenOrCreateError::EventOpenError(value.into())
}
}
#[derive(Debug, Clone, Copy, Default)]
struct Verify {
max_notifiers: bool,
max_listeners: bool,
max_nodes: bool,
event_id_max_value: bool,
deadline: bool,
notifier_created_event: bool,
notifier_dropped_event: bool,
notifier_dead_event: bool,
}
#[derive(Debug, Clone)]
pub struct Builder<ServiceType: service::Service> {
base: builder::BuilderWithServiceType<ServiceType>,
verify: Verify,
}
impl<ServiceType: service::Service> Builder<ServiceType> {
pub(crate) fn new(base: builder::BuilderWithServiceType<ServiceType>) -> Self {
let mut new_self = Self {
base,
verify: Verify::default(),
};
new_self.base.service_config.messaging_pattern = MessagingPattern::Event(
static_config::event::StaticConfig::new(new_self.base.shared_node.config()),
);
new_self
}
fn config_details(&mut self) -> &mut static_config::event::StaticConfig {
match self.base.service_config.messaging_pattern {
MessagingPattern::Event(ref mut v) => v,
_ => {
fatal_panic!(from self, "This should never happen! Accessing wrong messaging pattern in Event builder!");
}
}
}
pub fn deadline(mut self, deadline: Duration) -> Self {
self.config_details().deadline = RelocatableOption::Some(Deadline {
value: deadline.into(),
creation_time: Time::default(),
});
self.verify.deadline = true;
self
}
pub fn disable_deadline(mut self) -> Self {
self.config_details().deadline = RelocatableOption::None;
self.verify.deadline = true;
self
}
pub fn max_nodes(mut self, value: usize) -> Self {
self.config_details().max_nodes = value;
self.verify.max_nodes = true;
self
}
pub fn event_id_max_value(mut self, value: usize) -> Self {
self.config_details().event_id_max_value = value;
self.verify.event_id_max_value = true;
self
}
pub fn max_notifiers(mut self, value: usize) -> Self {
self.config_details().max_notifiers = value;
self.verify.max_notifiers = true;
self
}
pub fn max_listeners(mut self, value: usize) -> Self {
self.config_details().max_listeners = value;
self.verify.max_listeners = true;
self
}
pub fn notifier_created_event(mut self, value: EventId) -> Self {
self.config_details().notifier_created_event = RelocatableOption::Some(value.as_value());
self.verify.notifier_created_event = true;
self
}
pub fn disable_notifier_created_event(mut self) -> Self {
self.config_details().notifier_created_event = RelocatableOption::None;
self.verify.notifier_created_event = true;
self
}
pub fn notifier_dropped_event(mut self, value: EventId) -> Self {
self.config_details().notifier_dropped_event = RelocatableOption::Some(value.as_value());
self.verify.notifier_dropped_event = true;
self
}
pub fn disable_notifier_dropped_event(mut self) -> Self {
self.config_details().notifier_dropped_event = RelocatableOption::None;
self.verify.notifier_dropped_event = true;
self
}
pub fn notifier_dead_event(mut self, value: EventId) -> Self {
self.config_details().notifier_dead_event = RelocatableOption::Some(value.as_value());
self.verify.notifier_dead_event = true;
self
}
pub fn disable_notifier_dead_event(mut self) -> Self {
self.config_details().notifier_dead_event = RelocatableOption::None;
self.verify.notifier_dead_event = true;
self
}
pub fn open_or_create(self) -> Result<event::PortFactory<ServiceType>, EventOpenOrCreateError> {
self.open_or_create_with_attributes(&AttributeVerifier::new())
}
pub fn open_or_create_with_attributes(
mut self,
attributes: &AttributeVerifier,
) -> Result<event::PortFactory<ServiceType>, EventOpenOrCreateError> {
let msg = "Unable to open or create event service";
self.adjust_attributes_to_meaningful_values();
self.base.open_or_create(
msg,
attributes,
EventOpenOrCreateError::EventOpenError(EventOpenError::InternalFailure),
EventOpenOrCreateError::SystemInFlux,
|attributes| self.open_impl(attributes),
|attributes| self.create_impl(attributes),
)
}
pub fn open(self) -> Result<event::PortFactory<ServiceType>, EventOpenError> {
self.open_with_attributes(&AttributeVerifier::new())
}
pub fn open_with_attributes(
self,
required_attributes: &AttributeVerifier,
) -> Result<event::PortFactory<ServiceType>, EventOpenError> {
self.open_impl(required_attributes)
}
fn open_impl(
&self,
required_attributes: &AttributeVerifier,
) -> Result<event::PortFactory<ServiceType>, EventOpenError> {
let msg = "Unable to open event service";
let service_state = self.base.open(
msg,
|| self.base.is_service_available(msg),
|existing_service_config| -> Result<(), EventOpenError> {
self.verify_service_configuration(msg, existing_service_config, required_attributes)
},
|_| Ok(NoResource),
)?;
Ok(event::PortFactory::new(service_state))
}
pub fn create(self) -> Result<event::PortFactory<ServiceType>, EventCreateError> {
self.create_with_attributes(&AttributeSpecifier::new())
}
pub fn create_with_attributes(
mut self,
attributes: &AttributeSpecifier,
) -> Result<event::PortFactory<ServiceType>, EventCreateError> {
self.adjust_attributes_to_meaningful_values();
self.create_impl(attributes)
}
fn create_impl(
&self,
attributes: &AttributeSpecifier,
) -> Result<event::PortFactory<ServiceType>, EventCreateError> {
let origin = format!("{self:?}");
let msg = "Unable to create event service";
{
let settings = self.base.service_config.event();
let max = settings.event_id_max_value;
for (label, opt_id) in [
(
"notifier_created_event",
settings.notifier_created_event.as_option_ref().copied(),
),
(
"notifier_dropped_event",
settings.notifier_dropped_event.as_option_ref().copied(),
),
(
"notifier_dead_event",
settings.notifier_dead_event.as_option_ref().copied(),
),
] {
if let Some(id) = opt_id
&& id > max
{
fail!(from self,
with EventCreateError::EventIdExceedsMaxSupportedValue,
"{} since the {} value {} exceeds event_id_max_value {}.",
msg, label, id, max);
}
}
}
let prepare_static_config = |service_config: &mut StaticConfig| {
if let RelocatableOption::Some(ref mut deadline) = service_config.event_mut().deadline {
let now = fail!(from origin, when Time::now(),
with ServiceCreateError::InternalFailure,
"{} since the current system time could not be acquired.", msg);
deadline.creation_time = now;
}
Ok(())
};
let generate_dynamic_config = |service_config: &StaticConfig| {
let event_config = service_config.event();
let dynamic_config_setting = DynamicConfigSettings {
number_of_listeners: event_config.max_listeners,
number_of_notifiers: event_config.max_notifiers,
};
DynamicConfigCreationArgs {
messaging_pattern_settings: MessagingPatternSettings::Event(dynamic_config_setting),
additional_size:
dynamic_config::event::DynamicConfig::<ServiceType::Bag>::memory_size(
&dynamic_config_setting,
),
max_number_of_nodes: event_config.max_nodes,
}
};
let service_state = self.base.create(
msg,
attributes,
|| self.base.is_service_available(msg),
prepare_static_config,
generate_dynamic_config,
|_| Ok(NoResource),
|_| {},
|service_config| {
UniqueServiceId::from_event_service::<ServiceType>(
service_config.name(),
self.base.shared_node.config(),
)
},
)?;
Ok(event::PortFactory::new(service_state))
}
fn adjust_attributes_to_meaningful_values(&mut self) {
let origin = format!("{self:?}");
let settings = self.base.service_config.event_mut();
if settings.max_notifiers == 0 {
warn!(from origin, "Setting the maximum amount of notifiers to 0 is not supported. Adjust it to 1, the smallest supported value.");
settings.max_notifiers = 1;
}
if settings.max_listeners == 0 {
warn!(from origin, "Setting the maximum amount of listeners to 0 is not supported. Adjust it to 1, the smallest supported value.");
settings.max_listeners = 1;
}
if settings.max_nodes == 0 {
warn!(from origin, "Setting the maximum amount of nodes to 0 is not supported. Adjust it to 1, the smallest supported value.");
settings.max_nodes = 1;
}
}
fn verify_service_configuration(
&self,
msg: &str,
existing_service_config: &StaticConfig,
required_attributes: &AttributeVerifier,
) -> Result<(), EventOpenError> {
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 EventOpenError::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_settings = required_service_config.event();
let existing_settings = match &existing_service_config.messaging_pattern {
MessagingPattern::Event(v) => v,
p => {
fail!(from self, with EventOpenError::IncompatibleMessagingPattern,
"{} since a service with the messaging pattern {:?} exists but MessagingPattern::Event is required.", msg, p);
}
};
if self.verify.max_notifiers
&& existing_settings.max_notifiers < required_settings.max_notifiers
{
fail!(from self, with EventOpenError::DoesNotSupportRequestedAmountOfNotifiers,
"{} since the event supports only {} notifiers but a support of {} notifiers was requested.",
msg, existing_settings.max_notifiers, required_settings.max_notifiers);
}
if self.verify.max_listeners
&& existing_settings.max_listeners < required_settings.max_listeners
{
fail!(from self, with EventOpenError::DoesNotSupportRequestedAmountOfListeners,
"{} since the event supports only {} listeners but a support of {} listeners was requested.",
msg, existing_settings.max_notifiers, required_settings.max_listeners);
}
if self.verify.event_id_max_value
&& existing_settings.event_id_max_value < required_settings.event_id_max_value
{
fail!(from self, with EventOpenError::DoesNotSupportRequestedMaxEventId,
"{} since the event supports only EventIds with a value of at most {} a support of {} was requested.",
msg, existing_settings.event_id_max_value, required_settings.event_id_max_value);
}
if self.verify.max_nodes && existing_settings.max_nodes < required_settings.max_nodes {
fail!(from self, with EventOpenError::DoesNotSupportRequestedAmountOfNodes,
"{} since the event supports only {} nodes but {} are required.",
msg, existing_settings.max_nodes, required_settings.max_nodes);
}
if self.verify.notifier_created_event
&& existing_settings.notifier_created_event != required_settings.notifier_created_event
{
fail!(from self, with EventOpenError::IncompatibleNotifierCreatedEvent,
"{} since the notifier_created_event id is {:?} but the value {:?} is required.",
msg, existing_settings.notifier_created_event, required_settings.notifier_created_event);
}
if self.verify.notifier_dropped_event
&& existing_settings.notifier_dropped_event != required_settings.notifier_dropped_event
{
fail!(from self, with EventOpenError::IncompatibleNotifierDroppedEvent,
"{} since the notifier_dropped_event id is {:?} but the value {:?} is required.",
msg, existing_settings.notifier_dropped_event, required_settings.notifier_dropped_event);
}
if self.verify.notifier_dead_event
&& existing_settings.notifier_dead_event != required_settings.notifier_dead_event
{
fail!(from self, with EventOpenError::IncompatibleNotifierDeadEvent,
"{} since the notifier_dead_event id is {:?} but the value {:?} is required.",
msg, existing_settings.notifier_dead_event, required_settings.notifier_dead_event);
}
if self.verify.deadline
&& existing_settings.deadline.map(|v| v.value)
!= required_settings.deadline.map(|v| v.value)
{
fail!(from self, with EventOpenError::IncompatibleDeadline,
"{} since the deadline is {:?} but a deadline of {:?} is required.",
msg, existing_settings.deadline, required_settings.deadline);
}
Ok(())
}
}