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;