iceoryx2/lib.rs
1// Copyright (c) 2023 Contributors to the Eclipse Foundation
2//
3// See the NOTICE file(s) distributed with this work for additional
4// information regarding copyright ownership.
5//
6// This program and the accompanying materials are made available under the
7// terms of the Apache Software License 2.0 which is available at
8// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
9// which is available at https://opensource.org/licenses/MIT.
10//
11// SPDX-License-Identifier: Apache-2.0 OR MIT
12
13#![warn(clippy::alloc_instead_of_core)]
14#![warn(clippy::std_instead_of_alloc)]
15#![warn(clippy::std_instead_of_core)]
16#![warn(missing_docs)]
17
18//! # iceoryx2
19//!
20//! iceoryx2 is a cutting-edge service-oriented zero-copy lock-free inter-process communication
21//! middleware. Designed to support various
22//! [`MessagingPattern`](crate::service::messaging_pattern::MessagingPattern)s
23//! iceoryx2 empowers developers with
24//! the flexibility of:
25//!
26//! - Publish-Subscribe
27//! - Events
28//! - Request-Response
29//! - Blackboard (planned)
30//! - Pipeline (planned)
31//!
32//! For a comprehensive list of all planned features, please refer to the
33//! [GitHub Roadmap](https://github.com/eclipse-iceoryx/iceoryx2/blob/main/ROADMAP.md).
34//!
35//! Services are uniquely identified by name and
36//! [`MessagingPattern`](crate::service::messaging_pattern::MessagingPattern). They can be instantiated with
37//! diverse quality-of-service settings and are envisioned to be deployable in a `no_std` and
38//! safety-critical environment in the future.
39//!
40//! Moreover, iceoryx2 offers configuration options that enable multiple service setups to coexist
41//! on the same machine or even within the same process without interference. This versatility
42//! allows iceoryx2 to seamlessly integrate with other frameworks simultaneously.
43//!
44//! iceoryx2 traces its lineage back to the
45//! [eclipse iceoryx](https://github.com/eclipse-iceoryx/iceoryx) project, addressing a major
46//! drawback – the central daemon. iceoryx2 embraces a fully decentralized architecture,
47//! eliminating the need for a central daemon entirely.
48//!
49//! # Examples
50//!
51//! Each service is uniquely identified by a [`ServiceName`](crate::service::service_name::ServiceName).
52//! Initiating communication requires the creation of a service, which serves as a port factory.
53//! With this factory, endpoints for the service can be created, enabling seamless communication.
54//!
55//! For more detailed examples, explore the
56//! [GitHub example folder](https://github.com/eclipse-iceoryx/iceoryx2/tree/main/examples).
57//!
58//! ## Publish-Subscribe
59//!
60//! Explore a simple publish-subscribe setup where the subscriber continuously receives data from
61//! the publisher until the processes are gracefully terminated by the user with `CTRL+C`.
62//!
63//! **Subscriber (Process 1)**
64//!
65//! ```no_run
66//! use core::time::Duration;
67//! use iceoryx2::prelude::*;
68//!
69//! # fn main() -> Result<(), Box<dyn core::error::Error>> {
70//! const CYCLE_TIME: Duration = Duration::from_secs(1);
71//!
72//! let node = NodeBuilder::new().create::<ipc::Service>()?;
73//!
74//! // create our port factory by creating or opening the service
75//! let service = node.service_builder(&"My/Funk/ServiceName".try_into()?)
76//! .publish_subscribe::<u64>()
77//! .open_or_create()?;
78//!
79//! let subscriber = service.subscriber_builder().create()?;
80//!
81//! while node.wait(CYCLE_TIME).is_ok() {
82//! while let Some(sample) = subscriber.receive()? {
83//! println!("received: {:?}", *sample);
84//! }
85//! }
86//! # Ok(())
87//! # }
88//! ```
89//!
90//! **Publisher (Process 2)**
91//!
92//! ```no_run
93//! use core::time::Duration;
94//! use iceoryx2::prelude::*;
95//!
96//! # fn main() -> Result<(), Box<dyn core::error::Error>> {
97//! const CYCLE_TIME: Duration = Duration::from_secs(1);
98//!
99//! let node = NodeBuilder::new().create::<ipc::Service>()?;
100//!
101//! // create our port factory by creating or opening the service
102//! let service = node.service_builder(&"My/Funk/ServiceName".try_into()?)
103//! .publish_subscribe::<u64>()
104//! .open_or_create()?;
105//!
106//! let publisher = service.publisher_builder().create()?;
107//!
108//! while node.wait(CYCLE_TIME).is_ok() {
109//! let sample = publisher.loan_uninit()?;
110//! let sample = sample.write_payload(1234);
111//! sample.send()?;
112//! }
113//!
114//! # Ok(())
115//! # }
116//! ```
117//!
118//! ## Request-Response
119//!
120//! This is a simple request-response example where a client sends a request, and the server
121//! responds with multiple replies until the processes are gracefully terminated by the user
122//! with `CTRL+C`
123//!
124//! **Client (Process 1)**
125//!
126//! ```no_run
127//! use core::time::Duration;
128//! use iceoryx2::prelude::*;
129//!
130//! const CYCLE_TIME: Duration = Duration::from_secs(1);
131//!
132//! # fn main() -> Result<(), Box<dyn core::error::Error>> {
133//! let node = NodeBuilder::new().create::<ipc::Service>()?;
134//!
135//! let service = node
136//! .service_builder(&"My/Funk/ServiceName".try_into()?)
137//! .request_response::<u64, u64>()
138//! .open_or_create()?;
139//!
140//! let client = service.client_builder().create()?;
141//!
142//! // sending first request by using slower, inefficient copy API
143//! let mut pending_response = client.send_copy(1234)?;
144//!
145//! while node.wait(CYCLE_TIME).is_ok() {
146//! // acquire all responses to our request from our buffer that were sent by the servers
147//! while let Some(response) = pending_response.receive()? {
148//! println!(" received response: {:?}", *response);
149//! }
150//!
151//! // send all other requests by using zero copy API
152//! let request = client.loan_uninit()?;
153//! let request = request.write_payload(5678);
154//!
155//! pending_response = request.send()?;
156//! }
157//! # Ok(())
158//! # }
159//! ```
160//!
161//! **Server (Process 2)**
162//!
163//! ```no_run
164//! use core::time::Duration;
165//! use iceoryx2::prelude::*;
166//!
167//! const CYCLE_TIME: Duration = Duration::from_millis(100);
168//!
169//! # fn main() -> Result<(), Box<dyn core::error::Error>> {
170//! let node = NodeBuilder::new().create::<ipc::Service>()?;
171//!
172//! let service = node
173//! .service_builder(&"My/Funk/ServiceName".try_into()?)
174//! .request_response::<u64, u64>()
175//! .open_or_create()?;
176//!
177//! let server = service.server_builder().create()?;
178//!
179//! while node.wait(CYCLE_TIME).is_ok() {
180//! while let Some(active_request) = server.receive()? {
181//! println!("received request: {:?}", *active_request);
182//!
183//! // use zero copy API, send out some responses to demonstrate the streaming API
184//! for n in 0..4 {
185//! let response = active_request.loan_uninit()?;
186//! let response = response.write_payload(n as _);
187//! println!(" send response: {:?}", *response);
188//! response.send()?;
189//! }
190//! }
191//! }
192//! # Ok(())
193//! # }
194//! ```
195//!
196//! ## Events
197//!
198//! Explore a straightforward event setup, where the listener patiently awaits events from the
199//! notifier. This continuous event listening continues until the user gracefully terminates
200//! the processes by pressing `CTRL+C`.
201//!
202//! **Listener (Process 1)**
203//!
204//! ```no_run
205//! use core::time::Duration;
206//! use iceoryx2::prelude::*;
207//!
208//! # fn main() -> Result<(), Box<dyn core::error::Error>> {
209//! const CYCLE_TIME: Duration = Duration::from_secs(1);
210//!
211//! let node = NodeBuilder::new().create::<ipc::Service>()?;
212//!
213//! let event = node.service_builder(&"MyEventName".try_into()?)
214//! .event()
215//! .open_or_create()?;
216//!
217//! let mut listener = event.listener_builder().create()?;
218//!
219//! while node.wait(Duration::ZERO).is_ok() {
220//! if let Ok(Some(event_id)) = listener.timed_wait_one(CYCLE_TIME) {
221//! println!("event was triggered with id: {:?}", event_id);
222//! }
223//! }
224//!
225//! # Ok(())
226//! # }
227//! ```
228//!
229//! **Notifier (Process 2)**
230//!
231//! ```no_run
232//! use core::time::Duration;
233//! use iceoryx2::prelude::*;
234//!
235//! # fn main() -> Result<(), Box<dyn core::error::Error>> {
236//! const CYCLE_TIME: Duration = Duration::from_secs(1);
237//!
238//! let node = NodeBuilder::new().create::<ipc::Service>()?;
239//!
240//! let event = node.service_builder(&"MyEventName".try_into()?)
241//! .event()
242//! .open_or_create()?;
243//!
244//! let notifier = event.notifier_builder().create()?;
245//!
246//! let mut counter: usize = 0;
247//! while node.wait(CYCLE_TIME).is_ok() {
248//! counter += 1;
249//! notifier.notify_with_custom_event_id(EventId::new(counter))?;
250//!
251//! println!("Trigger event with id {} ...", counter);
252//! }
253//!
254//! # Ok(())
255//! # }
256//! ```
257//!
258//! # Quality Of Services
259//!
260//! Quality of service settings, or service settings, play a crucial role in determining memory
261//! allocation in a worst-case scenario. These settings can be configured during the creation of
262//! a service, immediately after defining the
263//! [`MessagingPattern`](crate::service::messaging_pattern::MessagingPattern). In cases where the service
264//! already exists, these settings are interpreted as minimum requirements, ensuring a flexible
265//! and dynamic approach to memory management.
266//!
267//! ## Publish-Subscribe
268//!
269//! For a detailed documentation see the
270//! [`publish_subscribe::Builder`](crate::service::builder::publish_subscribe::Builder)
271//!
272//! ```
273//! use iceoryx2::prelude::*;
274//!
275//! # fn main() -> Result<(), Box<dyn core::error::Error>> {
276//! let node = NodeBuilder::new().create::<ipc::Service>()?;
277//!
278//! let service = node.service_builder(&"PubSubQos".try_into()?)
279//! .publish_subscribe::<u64>()
280//! // when the subscriber buffer is full the oldest data is overridden with the newest
281//! .enable_safe_overflow(true)
282//! // how many samples a subscriber can borrow in parallel
283//! .subscriber_max_borrowed_samples(2)
284//! // the maximum history size a subscriber can request
285//! .history_size(3)
286//! // the maximum buffer size of a subscriber
287//! .subscriber_max_buffer_size(4)
288//! // the maximum amount of subscribers of this service
289//! .max_subscribers(5)
290//! // the maximum amount of publishers of this service
291//! .max_publishers(2)
292//! .create()?;
293//!
294//! # Ok(())
295//! # }
296//! ```
297//!
298//! ## Request-Response
299//!
300//! For a detailed documentation see the
301//! [`request_response::Builder`](crate::service::builder::request_response::Builder)
302//!
303//! ```
304//! use iceoryx2::prelude::*;
305//!
306//! # fn main() -> Result<(), Box<dyn core::error::Error>> {
307//! let node = NodeBuilder::new().create::<ipc::Service>()?;
308//!
309//! let service = node.service_builder(&"ReqResQos".try_into()?)
310//! .request_response::<u64, u64>()
311//! // overrides the alignment of the request payload
312//! .request_payload_alignment(Alignment::new(128).unwrap())
313//! // overrides the alignment of the response payload
314//! .response_payload_alignment(Alignment::new(128).unwrap())
315//! // when the server buffer is full the oldest data is overridden with the newest
316//! .enable_safe_overflow_for_requests(true)
317//! // when the client buffer is full the oldest data is overridden with the newest
318//! .enable_safe_overflow_for_responses(true)
319//! // allows to send requests without expecting an answer
320//! .enable_fire_and_forget_requests(true)
321//! // how many requests can a client send in parallel
322//! .max_active_requests_per_client(2)
323//! // how many request payload objects can be loaned in parallel
324//! .max_loaned_requests(1)
325//! // the max buffer size for incoming responses per request
326//! .max_response_buffer_size(4)
327//! // the max number of servers
328//! .max_servers(2)
329//! // the max number of clients
330//! .max_clients(10)
331//! .create()?;
332//!
333//! # Ok(())
334//! # }
335//! ```
336//!
337//! ## Event
338//!
339//! For a detailed documentation see the
340//! [`event::Builder`](crate::service::builder::event::Builder)
341//!
342//! ```
343//! use core::time::Duration;
344//! use iceoryx2::prelude::*;
345//!
346//! # fn main() -> Result<(), Box<dyn core::error::Error>> {
347//! let node = NodeBuilder::new().create::<ipc::Service>()?;
348//!
349//! let event = node.service_builder(&"EventQos".try_into()?)
350//! .event()
351//! // the maximum amount of notifiers of this service
352//! .max_notifiers(2)
353//! // the maximum amount of listeners of this service
354//! .max_listeners(2)
355//! // defines the maximum supported event id value
356//! // WARNING: an increased value can have a significant performance impact on some
357//! // configurations that use a bitset as event tracking mechanism
358//! .event_id_max_value(256)
359//! // optional event id that is emitted when a new notifier was created
360//! .notifier_created_event(EventId::new(999))
361//! // optional event id that is emitted when a notifier is dropped
362//! .notifier_dropped_event(EventId::new(0))
363//! // optional event id that is emitted when a notifier is identified as dead
364//! .notifier_dead_event(EventId::new(2000))
365//! // the deadline of the service defines how long a listener has to wait at most until
366//! // a signal will be received
367//! .deadline(Duration::from_secs(1))
368//! .create()?;
369//! # Ok(())
370//! # }
371//! ```
372//!
373//! # Port Behavior
374//!
375//! Certain ports in iceoryx2 provide users with the flexibility to define custom behaviors in
376//! specific situations.
377//! Custom port behaviors can be specified during the creation of a port,
378//! utilizing the port factory or service, immediately following the specification of the port
379//! type. This feature enhances the adaptability of iceoryx2 to diverse use cases and scenarios.
380//!
381//! ```
382//! use iceoryx2::prelude::*;
383//!
384//! # fn main() -> Result<(), Box<dyn core::error::Error>> {
385//! let node = NodeBuilder::new().create::<ipc::Service>()?;
386//!
387//! let service = node.service_builder(&"My/Funk/ServiceName".try_into()?)
388//! .publish_subscribe::<u64>()
389//! .enable_safe_overflow(false)
390//! .open_or_create()?;
391//!
392//! let publisher = service.publisher_builder()
393//! // the maximum amount of samples this publisher can loan in parallel
394//! .max_loaned_samples(2)
395//! // defines the behavior when a sample could not be delivered when the subscriber buffer is
396//! // full, only useful in an non-overflow scenario
397//! .unable_to_deliver_strategy(UnableToDeliverStrategy::DiscardSample)
398//! .create()?;
399//!
400//! # Ok(())
401//! # }
402//! ```
403//!
404//! # Feature Flags
405//!
406//! * `dev_permissions` - The permissions of all resources will be set to read, write, execute
407//! for everyone. This shall not be used in production and is meant to be enabled in a docker
408//! environment with inconsistent user configuration.
409//! * `logger_log` - Uses the [log crate](https://crates.io/crates/log) as default log backend
410//! * `logger_tracing` - Uses the [tracing crate](https://crates.io/crates/tracing) as default log
411//! backend
412//!
413//! # Custom Configuration
414//!
415//! iceoryx2 offers the flexibility to configure default quality of service settings, paths, and
416//! file suffixes through a custom configuration file.
417//!
418//! For in-depth details and examples, please visit the
419//! [GitHub config folder](https://github.com/eclipse-iceoryx/iceoryx2/tree/main/config).
420
421#[cfg(doctest)]
422mod compiletests;
423
424pub(crate) mod constants;
425
426/// Handles iceoryx2s global configuration
427pub mod config;
428
429/// Central instance that owns all service entities and can handle incoming event in an event loop
430pub mod node;
431
432/// The ports or communication endpoints of iceoryx2
433pub mod port;
434
435pub(crate) mod raw_sample;
436
437/// Represents a "connection" to a [`Client`](crate::port::client::Client) that corresponds to a
438/// previously received [`RequestMut`](crate::request_mut::RequestMut).
439pub mod active_request;
440
441/// Represents a "connection" to a [`Server`](crate::port::server::Server) that corresponds to a
442/// previously sent [`RequestMut`](crate::request_mut::RequestMut).
443pub mod pending_response;
444
445/// The payload that is sent by a [`Client`](crate::port::client::Client) to a
446/// [`Server`](crate::port::server::Server).
447pub mod request_mut;
448
449/// The uninitialized payload that is sent by a [`Client`](crate::port::client::Client) to a
450/// [`Server`](crate::port::server::Server).
451pub mod request_mut_uninit;
452
453/// The answer a [`Client`](crate::port::client::Client) receives from a
454/// [`Server`](crate::port::server::Server) on a [`RequestMut`](crate::request_mut::RequestMut).
455pub mod response;
456
457/// The answer a [`Server`](crate::port::server::Server) allocates to respond to
458/// a received [`RequestMut`](crate::request_mut::RequestMut) from a
459/// [`Client`](crate::port::client::Client)
460pub mod response_mut;
461
462pub mod response_mut_uninit;
463
464/// The payload that is received by a [`Subscriber`](crate::port::subscriber::Subscriber).
465pub mod sample;
466
467/// The payload that is sent by a [`Publisher`](crate::port::publisher::Publisher).
468pub mod sample_mut;
469
470/// The uninitialized payload that is sent by a [`Publisher`](crate::port::publisher::Publisher).
471pub mod sample_mut_uninit;
472
473/// The foundation of communication the service with its
474/// [`MessagingPattern`](crate::service::messaging_pattern::MessagingPattern)
475pub mod service;
476
477/// Defines how constructs like the [`Node`](crate::node::Node) or the
478/// [`WaitSet`](crate::waitset::WaitSet) shall handle system signals.
479pub mod signal_handling_mode;
480
481/// Loads a meaninful subset to cover 90% of the iceoryx2 communication use cases.
482pub mod prelude;
483
484#[doc(hidden)]
485pub mod testing;
486
487/// Event handling mechanism to wait on multiple [`Listener`](crate::port::listener::Listener)s
488/// in one call, realizing the reactor pattern. (Event multiplexer)
489pub mod waitset;