diff --git a/doc/release-notes/iceoryx2-unreleased.md b/doc/release-notes/iceoryx2-unreleased.md index 877cac817d..47bbfca5e1 100644 --- a/doc/release-notes/iceoryx2-unreleased.md +++ b/doc/release-notes/iceoryx2-unreleased.md @@ -18,6 +18,9 @@ [#1289](https://github.com/eclipse-iceoryx/iceoryx2/issues/1289) * Add source `NodeId` to request and response header [#1308](https://github.com/eclipse-iceoryx/iceoryx2/issues/1308) +* Introduce `RelocatableOption` and `RelocatableDuration` which are + `ZeroCopySend` + [#1312](https://github.com/eclipse-iceoryx/iceoryx2/issues/1312) ### Bugfixes @@ -26,6 +29,8 @@ conflicts when merging. --> +* Remove default implementation of `ZeroCopySend` from `Option` and `Duration` + [#1312](https://github.com/eclipse-iceoryx/iceoryx2/issues/1312) * Bump wheel from 0.45.1 to 0.46.3 in /iceoryx2-ffi/python [#1316](https://github.com/eclipse-iceoryx/iceoryx2/issues/1316) diff --git a/examples/rust/discovery_service/discovery_service_client.rs b/examples/rust/discovery_service/discovery_service_client.rs index ef47004696..fba7144701 100644 --- a/examples/rust/discovery_service/discovery_service_client.rs +++ b/examples/rust/discovery_service/discovery_service_client.rs @@ -26,7 +26,7 @@ fn main() -> Result<(), Box> { let node = NodeBuilder::new().create::()?; let service = node - .service_builder(service_name().try_into()?) + .service_builder(service_name()) .request_response::<(), [StaticConfig]>() .open_or_create()?; diff --git a/iceoryx2-bb/container/src/lib.rs b/iceoryx2-bb/container/src/lib.rs index c3ac506fd8..83f1cf0498 100644 --- a/iceoryx2-bb/container/src/lib.rs +++ b/iceoryx2-bb/container/src/lib.rs @@ -110,6 +110,10 @@ pub mod flatmap; /// A trait that defines the interface of a string and several string variants. pub mod string; +/// Implementation of an [`Option`] that has a stable memory layout and is +/// shared memory compatible. +pub mod relocatable_option; + #[doc(hidden)] pub(crate) mod vec; /// A trait that defines the interface of a vector and several vector variants. diff --git a/iceoryx2-bb/container/src/relocatable_option.rs b/iceoryx2-bb/container/src/relocatable_option.rs new file mode 100644 index 0000000000..3391d952ec --- /dev/null +++ b/iceoryx2-bb/container/src/relocatable_option.rs @@ -0,0 +1,354 @@ +// Copyright (c) 2026 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use core::hash::Hash; +use core::{ + fmt::Debug, + marker::PhantomData, + ops::{Deref, DerefMut}, +}; + +use iceoryx2_bb_elementary_traits::{ + placement_default::PlacementDefault, zero_copy_send::ZeroCopySend, +}; +use iceoryx2_log::fatal_panic; +use serde::{de::Visitor, Deserialize, Serialize}; + +/// Implementation of an [`Option`] that is shared-memory compatible, +/// has a stable memory layout and can be used for zero-copy cross-language +/// communication. +/// +/// The usage is as close as possible to the original [`Option`], except for +/// the construction via [`Some`] and [`None`], which needs to be +/// [`RelocatableOption::Some`] and [`RelocatableOption::None`]. +/// +/// # Examples +/// +/// ## Construction Comparison +/// +/// ``` +/// use iceoryx2_bb_container::relocatable_option::RelocatableOption; +/// +/// // rust Option +/// fn do_stuff_1(value: i32) -> Option { +/// if value > 0 { +/// Some(value) +/// } else { +/// None +/// } +/// } +/// +/// // RelocatableOption +/// fn do_stuff_2(value: i32) -> RelocatableOption { +/// if value > 0 { +/// RelocatableOption::Some(value) +/// } else { +/// RelocatableOption::None +/// } +/// } +/// ``` +/// +/// ## Match Statements +/// +/// ``` +/// use iceoryx2_bb_container::relocatable_option::RelocatableOption; +/// +/// fn do_stuff() -> RelocatableOption { +/// RelocatableOption::None +/// } +/// +/// match do_stuff() { +/// RelocatableOption::Some(v) => println!("{v}"), +/// RelocatableOption::None => println!("none") +/// } +/// ``` +#[repr(C, u8)] +#[derive(Default, Clone, Copy, Hash, Debug, PartialEq, Eq)] +pub enum RelocatableOption { + /// Default value, defines an [`RelocatableOption`] that does contain nothing. + #[default] + None, + /// Defines an [`RelocatableOption`] that contains the provided type `T`. + Some(T), +} + +impl From> for RelocatableOption { + fn from(value: Option) -> Self { + match value { + Some(v) => RelocatableOption::Some(v), + None => RelocatableOption::None, + } + } +} + +impl From> for Option { + fn from(value: RelocatableOption) -> Self { + value.to_option() + } +} + +impl Serialize for RelocatableOption { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + Self::Some(v) => serializer.serialize_some(v), + Self::None => serializer.serialize_none(), + } + } +} + +struct RelocatableOptionVisitor { + _data: PhantomData, +} + +impl<'de, T: Deserialize<'de>> Visitor<'de> for RelocatableOptionVisitor { + type Value = RelocatableOption; + + fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { + write!( + formatter, + "an optional value of type {}", + core::any::type_name::() + ) + } + + fn visit_some(self, deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + Ok(RelocatableOption::Some(T::deserialize(deserializer)?)) + } + + fn visit_none(self) -> Result + where + E: serde::de::Error, + { + Ok(RelocatableOption::None) + } +} + +impl<'de, T: Deserialize<'de>> Deserialize<'de> for RelocatableOption { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_option(RelocatableOptionVisitor { _data: PhantomData }) + } +} + +unsafe impl ZeroCopySend for RelocatableOption {} + +impl PlacementDefault for RelocatableOption { + unsafe fn placement_default(ptr: *mut Self) { + ptr.write(RelocatableOption::None) + } +} + +impl RelocatableOption { + /// Creates a new [`Option`] containing `T`. + pub fn to_option(self) -> Option { + match self { + Self::Some(v) => Some(v), + Self::None => None, + } + } + + /// Returns an [`Option`] with a reference to `T` + pub fn as_option_ref(&self) -> Option<&T> { + match self { + Self::Some(v) => Some(v), + Self::None => None, + } + } + + /// Returns an [`Option`] with a mutable reference to `T` + pub fn as_option_mut(&mut self) -> Option<&mut T> { + match self { + Self::Some(v) => Some(v), + Self::None => None, + } + } + + /// Converts the `RelocatableOption` to `RelocatableOption<&T::Target>`. + pub fn as_deref(&self) -> RelocatableOption<&::Target> + where + T: Deref, + { + match self { + Self::Some(v) => RelocatableOption::Some(v.deref()), + Self::None => RelocatableOption::None, + } + } + + /// Converts the `RelocatableOption` to `RelocatableOption<&mut T::Target>`. + pub fn as_deref_mut(&mut self) -> RelocatableOption<&mut ::Target> + where + T: DerefMut, + { + match self { + Self::Some(v) => RelocatableOption::Some(v.deref_mut()), + Self::None => RelocatableOption::None, + } + } + + /// Returns a [`RelocatableOption`] that contains a mutable reference to `T` if + /// it holds a value, otherwise it contains nothing. + pub fn as_mut(&mut self) -> RelocatableOption<&mut T> { + match self { + Self::Some(ref mut v) => RelocatableOption::Some(v), + Self::None => RelocatableOption::None, + } + } + + /// Returns a [`RelocatableOption`] that contains a reference to `T` if it holds + /// a value, otherwise it contains nothing. + pub fn as_ref(&self) -> RelocatableOption<&T> { + match self { + Self::Some(ref v) => RelocatableOption::Some(v), + Self::None => RelocatableOption::None, + } + } + + /// Consumes the [`RelocatableOption`] and returns the contained value `T`. If + /// it does not contain a value a panic is raised with the provided + /// message. + pub fn expect(self, msg: &str) -> T { + match self { + Self::Some(v) => v, + Self::None => { + let origin = alloc::format!( + "RelocatableOption::<{}>::expect()", + core::any::type_name::() + ); + fatal_panic!(from origin, "Expect: {msg}"); + } + } + } + + /// If the [`RelocatableOption`] contains a value, the provided callback is + /// called. + pub fn inspect(self, f: F) -> Self { + if let Self::Some(data) = &self { + f(data) + } + + self + } + + /// Returns [`true`] if the [`RelocatableOption`] does not contain a value, other + /// it returns [`false`]. + pub fn is_none(&self) -> bool { + match self { + RelocatableOption::None => true, + RelocatableOption::Some(_v) => false, + } + } + + /// Returns [`true`] if the [`RelocatableOption`] does contain a value, other + /// it returns [`false`]. + pub fn is_some(&self) -> bool { + !self.is_none() + } + + /// Maps a `RelocatableOption` to a `RelocatableOption` + pub fn map U>(self, f: F) -> RelocatableOption { + match self { + RelocatableOption::None => RelocatableOption::None, + RelocatableOption::Some(v) => RelocatableOption::Some(f(v)), + } + } + + /// Replaces the existing value of the [`RelocatableOption`] with the new value. + /// The old value is returned. + pub fn replace(&mut self, value: T) -> RelocatableOption { + core::mem::replace(self, Self::Some(value)) + } + + /// Takes the value out of the [`RelocatableOption`] and returns it, leaving an + /// empty [`RelocatableOption`]. + pub fn take(&mut self) -> RelocatableOption { + core::mem::take(self) + } + + /// Takes the value out of the [`RelocatableOption`] if it has a value and the + /// predicate returns [`true`] leaving an empty [`RelocatableOption`]. + pub fn take_if bool>(&mut self, predicate: P) -> RelocatableOption { + match self { + RelocatableOption::None => RelocatableOption::None, + RelocatableOption::Some(v) => { + if predicate(v) { + core::mem::take(self) + } else { + RelocatableOption::None + } + } + } + } + + /// Consumes the [`RelocatableOption`] and returns the value of `T`. If the + /// [`RelocatableOption`] does not contain a value a panic is raised. + pub fn unwrap(self) -> T { + match self { + Self::Some(v) => v, + Self::None => { + let origin = alloc::format!( + "RelocatableOption::<{}>::unwrap()", + core::any::type_name::() + ); + fatal_panic!( + from origin, + "This should never happen! Accessing the value of an empty RelocatableOption." + ); + } + } + } + + /// Consumes the [`RelocatableOption`] and either returns the contained value, + /// if there is one, otherwise `default` is returned. + pub fn unwrap_or(self, alternative: T) -> T { + self.unwrap_or_else(|| alternative) + } + + /// Consumes the [`RelocatableOption`] and either returns the contained value, + /// if there is one, otherwise `T::default()` is returned. + pub fn unwrap_or_default(self) -> T + where + T: Default, + { + self.unwrap_or_else(|| T::default()) + } + + /// Consumes the [`RelocatableOption`] and either returns the contained value, + /// if there is one or returns the return value of the provided callback. + pub fn unwrap_or_else T>(self, f: F) -> T { + match self { + Self::Some(v) => v, + Self::None => f(), + } + } + + /// Consumes the [`RelocatableOption`] and returns the value of `T`. + /// + /// # Safety + /// + /// * [`RelocatableOption::is_some()`] == [`true`] + /// + pub unsafe fn unwrap_unchecked(self) -> T { + debug_assert!(self.is_some()); + match self { + RelocatableOption::Some(v) => v, + RelocatableOption::None => unsafe { core::hint::unreachable_unchecked() }, + } + } +} diff --git a/iceoryx2-bb/container/tests/relocatable_option_tests.rs b/iceoryx2-bb/container/tests/relocatable_option_tests.rs new file mode 100644 index 0000000000..f3cd4280a9 --- /dev/null +++ b/iceoryx2-bb/container/tests/relocatable_option_tests.rs @@ -0,0 +1,390 @@ +// Copyright (c) 2026 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +extern crate iceoryx2_bb_loggers; + +use std::mem::MaybeUninit; + +use iceoryx2_bb_container::relocatable_option::RelocatableOption; +use iceoryx2_bb_elementary_traits::placement_default::PlacementDefault; +use iceoryx2_bb_testing::{assert_that, lifetime_tracker::LifetimeTracker}; +use serde_test::{assert_tokens, Token}; + +#[test] +fn default_created_option_is_empty() { + let sut = RelocatableOption::::default(); + + assert_that!(sut.is_some(), eq false); + assert_that!(sut.is_none(), eq true); +} + +#[test] +fn when_empty_as_option_returns_empty_option() { + let sut = RelocatableOption::::default(); + + assert_that!(sut.as_option_ref(), eq Option::<&i32>::None); +} + +#[test] +fn when_with_value_as_option_returns_option_with_reference_to_that_value() { + let sut = RelocatableOption::::Some(1234); + + assert_that!(*sut.as_option_ref().unwrap(), eq 1234); +} + +#[test] +fn when_empty_as_option_mut_returns_empty_option() { + let mut sut = RelocatableOption::::default(); + + assert_that!(sut.as_option_mut(), eq Option::<&mut i32>::None); +} + +#[test] +fn when_with_value_as_option_returns_option_with_mut_reference_to_that_value() { + let mut sut = RelocatableOption::::Some(4313); + + assert_that!(*sut.as_option_mut().unwrap(), eq 4313); +} + +#[test] +fn when_empty_as_deref_returns_empty_option() { + let sut = RelocatableOption::>::default(); + + assert_that!(sut.as_deref(), eq RelocatableOption::<&[i32]>::None); +} + +#[test] +fn when_with_value_as_deref_returns_ref_to_target() { + let sut = RelocatableOption::>::Some(vec![1, 2, 3]); + + assert_that!(sut.as_deref().unwrap(), eq [1,2,3]); +} + +#[test] +fn when_empty_as_deref_mut_returns_empty_option() { + let mut sut = RelocatableOption::>::default(); + + assert_that!(sut.as_deref_mut(), eq RelocatableOption::<&mut [i32]>::None); +} + +#[test] +fn when_with_value_as_deref_mut_returns_ref_to_target() { + let mut sut = RelocatableOption::>::Some(vec![6, 6, 3]); + + assert_that!(sut.as_deref_mut().unwrap(), eq [6,6,3]); +} + +#[test] +fn when_empty_as_ref_returns_empty_option() { + let sut = RelocatableOption::::default(); + + assert_that!(sut.as_ref(), eq RelocatableOption::<&i32>::None); +} + +#[test] +fn when_with_value_as_ref_returns_ref_to_target() { + let sut = RelocatableOption::::Some(98123); + + assert_that!(*sut.as_ref().unwrap(), eq 98123); +} + +#[test] +fn when_empty_as_mut_returns_empty_option() { + let mut sut = RelocatableOption::::default(); + + assert_that!(sut.as_mut(), eq RelocatableOption::<&mut i32>::None); +} + +#[test] +fn when_with_value_as_mut_returns_ref_to_target() { + let mut sut = RelocatableOption::::Some(553); + + assert_that!(*sut.as_mut().unwrap(), eq 553); +} + +#[test] +fn expect_returns_value() { + let sut = RelocatableOption::::Some(1553); + + assert_that!(sut.expect(""), eq 1553); +} + +#[should_panic] +#[test] +fn expect_panics_when_empty() { + let sut = RelocatableOption::::None; + + sut.expect(""); +} + +#[test] +fn none_creates_empty_value() { + let sut = RelocatableOption::::None; + + assert_that!(sut.is_none(), eq true); + assert_that!(sut.is_some(), eq false); +} + +#[test] +fn some_creates_option_that_contains_the_value() { + let sut = RelocatableOption::::Some(89928); + + assert_that!(sut.is_none(), eq false); + assert_that!(sut.is_some(), eq true); + assert_that!(sut.unwrap(), eq 89928); +} + +#[test] +fn inspect_callback_is_not_called_when_empty() { + let sut = RelocatableOption::::None; + let mut callback_was_called = false; + sut.inspect(|_: &i32| callback_was_called = true); + + assert_that!(callback_was_called, eq false); +} + +#[test] +fn inspect_callback_is_called_when_it_contains_a_value() { + let sut = RelocatableOption::::Some(778); + let mut callback_was_called = false; + sut.inspect(|v: &i32| { + callback_was_called = true; + assert_that!(*v, eq 778); + }); + + assert_that!(callback_was_called, eq true); +} + +#[test] +fn map_of_empty_option_is_empty() { + let sut = RelocatableOption::::None; + + let mut callback_was_called = false; + assert_that!(sut.map(|v: i32| { + callback_was_called = true; + v + 1}).is_none(), eq true); + assert_that!(callback_was_called, eq false); +} + +#[test] +fn map_uses_value_and_creates_new_option() { + let sut = RelocatableOption::::Some(5); + + assert_that!(sut.map(|v: i32| v + 1), eq RelocatableOption::Some(6)); +} + +#[test] +fn replace_returns_none_when_option_is_empty() { + let mut sut = RelocatableOption::::None; + + assert_that!(sut.replace(89123).is_none(), eq true); + assert_that!(sut.unwrap(), eq 89123); +} + +#[test] +fn replace_returns_value_when_option_contains_value() { + let mut sut = RelocatableOption::::Some(9012); + + assert_that!(sut.replace(891231), eq RelocatableOption::Some(9012)); + assert_that!(sut.unwrap(), eq 891231); +} + +#[test] +fn take_empties_sut_and_returns_content() { + let mut sut_full = RelocatableOption::::Some(90125); + let mut sut_empty = RelocatableOption::::None; + + assert_that!(sut_full.take(), eq RelocatableOption::Some(90125)); + assert_that!(sut_empty.take(), eq RelocatableOption::None); + + assert_that!(sut_full.is_none(), eq true); + assert_that!(sut_empty.is_none(), eq true); +} + +#[test] +fn take_if_does_not_call_callback_when_empty() { + let mut sut = RelocatableOption::::None; + let mut callback_was_called = false; + let ret_val = sut.take_if(|_: &mut i32| { + callback_was_called = true; + false + }); + + assert_that!(callback_was_called, eq false); + assert_that!(ret_val, eq RelocatableOption::None); + assert_that!(sut, eq RelocatableOption::None); +} + +#[test] +fn take_if_returns_none_when_callback_returns_false() { + let mut sut = RelocatableOption::::Some(551); + let mut callback_was_called = false; + let ret_val = sut.take_if(|v: &mut i32| { + assert_that!(*v, eq 551); + callback_was_called = true; + false + }); + + assert_that!(callback_was_called, eq true); + assert_that!(ret_val, eq RelocatableOption::None); + assert_that!(sut, eq RelocatableOption::Some(551)); +} + +#[test] +fn take_if_returns_value_and_empties_option_when_callback_returns_true() { + let mut sut = RelocatableOption::::Some(1551); + let mut callback_was_called = false; + let ret_val = sut.take_if(|v| { + assert_that!(*v, eq 1551); + callback_was_called = true; + true + }); + + assert_that!(callback_was_called, eq true); + assert_that!(ret_val, eq RelocatableOption::Some(1551)); + assert_that!(sut, eq RelocatableOption::None); +} + +#[test] +fn unwrap_returns_value_when_it_has_one() { + let sut = RelocatableOption::::Some(15511); + + assert_that!(sut.unwrap(), eq 15511); +} + +#[should_panic] +#[test] +fn unwrap_panics_when_empty() { + let sut = RelocatableOption::::None; + + sut.unwrap(); +} + +#[test] +fn unwrap_or_returns_provided_value_when_empty() { + let sut = RelocatableOption::::None; + + assert_that!(sut.unwrap_or(8192), eq 8192); +} + +#[test] +fn unwrap_or_returns_value() { + let sut = RelocatableOption::::Some(661); + + assert_that!(sut.unwrap_or(8), eq 661); +} + +#[test] +fn unwrap_or_default_returns_default_when_empty() { + let sut = RelocatableOption::::None; + + assert_that!(sut.unwrap_or_default(), eq i32::default()); +} + +#[test] +fn unwrap_or_default_returns_value() { + let sut = RelocatableOption::::Some(981); + + assert_that!(sut.unwrap_or_default(), eq 981); +} + +#[test] +fn unwrap_or_else_returns_callable_value_when_empty() { + let sut = RelocatableOption::::None; + + assert_that!(sut.unwrap_or_else(|| 8127), eq 8127); +} + +#[test] +fn unwrap_or_else_returns_value() { + let sut = RelocatableOption::::Some(113); + + let mut callable_was_called = false; + assert_that!(sut.unwrap_or_else(|| {callable_was_called = true; 8127}), eq 113); + assert_that!(callable_was_called, eq false); +} + +#[test] +fn unwrap_unchecked_returns_value() { + let sut = RelocatableOption::::Some(1113); + + assert_that!(unsafe { sut.unwrap_unchecked() }, eq 1113); +} + +#[test] +fn element_is_dropped_on_option_drop() { + let tracker = LifetimeTracker::start_tracking(); + let sut = RelocatableOption::::Some(LifetimeTracker::new()); + assert_that!(tracker.number_of_living_instances(), eq 1); + + drop(sut); + assert_that!(tracker.number_of_living_instances(), eq 0); +} + +#[test] +fn clone_works() { + let sut_orig_some = RelocatableOption::::Some(8812); + let sut_orig_none = RelocatableOption::::None; + let sut_clone_some = sut_orig_some; + let sut_clone_none = sut_orig_none; + + assert_that!(sut_orig_some, eq sut_clone_some); + assert_that!(sut_orig_none, eq sut_clone_none); + assert_that!(sut_clone_none, ne sut_clone_some); +} + +#[test] +fn placement_default_works() { + let mut raw_sut = MaybeUninit::>::uninit(); + unsafe { RelocatableOption::placement_default(raw_sut.as_mut_ptr()) }; + + assert_that!(unsafe { raw_sut.assume_init().is_none() }, eq true); +} + +#[test] +fn serialization_works() { + let sut_none = RelocatableOption::::None; + let sut_some = RelocatableOption::::Some(551); + + assert_tokens(&sut_none, &[Token::None]); + assert_tokens(&sut_some, &[Token::Some, Token::I32(551)]); +} + +#[test] +fn empty_create_empty_native_option() { + let sut = RelocatableOption::::None; + + assert_that!(sut.to_option(), eq None); +} + +#[test] +fn value_creates_native_option_with_value() { + let sut = RelocatableOption::::Some(772); + + assert_that!(sut.to_option(), eq Some(772)); +} + +#[test] +fn native_to_relocatable_conversion_works() { + let native = Option::::Some(551); + let sut: RelocatableOption = native.into(); + + assert_that!(sut.to_option(), eq native); +} + +#[test] +fn relocatable_to_native_conversion_works() { + let sut = RelocatableOption::::Some(1823); + let native: Option = sut.into(); + + assert_that!(sut.to_option(), eq native); +} diff --git a/iceoryx2-bb/elementary-traits/src/zero_copy_send.rs b/iceoryx2-bb/elementary-traits/src/zero_copy_send.rs index 3aaaa2c0b6..78f362fa2f 100644 --- a/iceoryx2-bb/elementary-traits/src/zero_copy_send.rs +++ b/iceoryx2-bb/elementary-traits/src/zero_copy_send.rs @@ -69,12 +69,8 @@ unsafe impl ZeroCopySend for bool {} unsafe impl ZeroCopySend for () {} -unsafe impl ZeroCopySend for core::time::Duration {} - unsafe impl ZeroCopySend for [T] {} unsafe impl ZeroCopySend for [T; N] {} -unsafe impl ZeroCopySend for Option {} -unsafe impl ZeroCopySend for Result {} unsafe impl ZeroCopySend for core::mem::MaybeUninit {} unsafe impl ZeroCopySend for (T1, T2) {} diff --git a/iceoryx2-bb/posix/src/clock.rs b/iceoryx2-bb/posix/src/clock.rs index e36106541c..ffaec26588 100644 --- a/iceoryx2-bb/posix/src/clock.rs +++ b/iceoryx2-bb/posix/src/clock.rs @@ -185,6 +185,44 @@ impl TimeBuilder { } } +/// A intermediate [`Duration`] representation with a fixed memory layout which +/// is shared memory compatible. +#[repr(C)] +#[derive( + Default, Clone, Copy, Eq, PartialEq, Hash, Debug, ZeroCopySend, Serialize, Deserialize, +)] +pub struct RelocatableDuration { + seconds: u64, + nanoseconds: u32, +} + +impl RelocatableDuration { + /// Returns the [`RelocatableDuration`] in seconds + pub fn as_secs(&self) -> u64 { + self.seconds + } + + /// Returns the fractional part of the seconds in nanoseconds. + pub fn subsec_nanos(&self) -> u32 { + self.nanoseconds + } +} + +impl From for RelocatableDuration { + fn from(value: Duration) -> Self { + Self { + seconds: value.as_secs(), + nanoseconds: value.subsec_nanos(), + } + } +} + +impl From for Duration { + fn from(value: RelocatableDuration) -> Self { + Duration::from_secs(value.seconds) + Duration::from_nanos(value.nanoseconds as u64) + } +} + /// Represents time under a specified [`ClockType`] #[repr(C)] #[derive( diff --git a/iceoryx2-bb/posix/tests/clock_tests.rs b/iceoryx2-bb/posix/tests/clock_tests.rs index 61a4a50e6e..8033435363 100644 --- a/iceoryx2-bb/posix/tests/clock_tests.rs +++ b/iceoryx2-bb/posix/tests/clock_tests.rs @@ -85,3 +85,25 @@ fn clock_time_as_timespec_works() { assert_that!(timespec.tv_sec, eq now.as_duration().as_secs() as _); assert_that!(timespec.tv_nsec, eq now.as_duration().subsec_nanos() as _); } + +#[test] +fn clock_relocatable_duration_roundtrip_conversion() { + let secs = 123; + let nsecs = 456; + let duration = Duration::from_secs(secs) + Duration::from_nanos(nsecs); + let sut: RelocatableDuration = duration.into(); + let duration_2: Duration = sut.into(); + + assert_that!(duration, eq duration_2); + assert_that!(sut.as_secs(), eq duration.as_secs()); + assert_that!(sut.subsec_nanos(), eq duration.subsec_nanos()); +} + +#[test] +fn clock_relocatable_duration_max_value() { + let duration = Duration::MAX; + let sut: RelocatableDuration = duration.into(); + + assert_that!(sut.as_secs(), eq sut.as_secs()); + assert_that!(sut.subsec_nanos(), eq sut.subsec_nanos()); +} diff --git a/iceoryx2-cli/iox2-service/src/command/mod.rs b/iceoryx2-cli/iox2-service/src/command/mod.rs index 7b0abfcbb6..f1a05f07bb 100644 --- a/iceoryx2-cli/iox2-service/src/command/mod.rs +++ b/iceoryx2-cli/iox2-service/src/command/mod.rs @@ -84,7 +84,6 @@ pub(crate) fn get_pubsub_service_types( .publish_subscribe() .message_type_details() .user_header - .clone() }; let payload = unsafe { @@ -94,7 +93,6 @@ pub(crate) fn get_pubsub_service_types( .publish_subscribe() .message_type_details() .payload - .clone() }; let system_header = TypeDetail::new::
(TypeVariant::FixedSize); diff --git a/iceoryx2-cli/iox2-service/src/command/replay.rs b/iceoryx2-cli/iox2-service/src/command/replay.rs index c98c3bcd9d..f22ecd406e 100644 --- a/iceoryx2-cli/iox2-service/src/command/replay.rs +++ b/iceoryx2-cli/iox2-service/src/command/replay.rs @@ -38,7 +38,7 @@ pub(crate) fn replay(options: ReplayOptions, _format: Format) -> Result<()> { let service_name = match options.service { Some(v) => ServiceName::new(&v)?, - None => replay.header().service_name.clone(), + None => replay.header().service_name, }; let required_header = RecordHeaderDetails { diff --git a/iceoryx2-cli/lib/src/output.rs b/iceoryx2-cli/lib/src/output.rs index 05d4c9303d..9ac4732d32 100644 --- a/iceoryx2-cli/lib/src/output.rs +++ b/iceoryx2-cli/lib/src/output.rs @@ -71,7 +71,7 @@ where service_id: config.service_id().as_str().to_string(), service_name: config.name().as_str().to_string(), attributes: config.attributes().clone(), - pattern: config.messaging_pattern().clone(), + pattern: *config.messaging_pattern(), nodes: service.dynamic_details.as_ref().map(NodeList::from), } } diff --git a/iceoryx2-ffi/c/src/api/service_builder_blackboard.rs b/iceoryx2-ffi/c/src/api/service_builder_blackboard.rs index ec7147d522..2616eab05c 100644 --- a/iceoryx2-ffi/c/src/api/service_builder_blackboard.rs +++ b/iceoryx2-ffi/c/src/api/service_builder_blackboard.rs @@ -627,7 +627,7 @@ pub unsafe extern "C" fn iox2_service_builder_blackboard_creator_add( service_builder.__internal_add( key as *const u8, value_ptr as *mut u8, - type_details.clone(), + type_details, value_cleanup, ), )); @@ -641,7 +641,7 @@ pub unsafe extern "C" fn iox2_service_builder_blackboard_creator_add( service_builder.__internal_add( key as *const u8, value_ptr as *mut u8, - type_details.clone(), + type_details, value_cleanup, ), )); diff --git a/iceoryx2-ffi/python/src/message_type_details.rs b/iceoryx2-ffi/python/src/message_type_details.rs index ce16ce306e..f2f44af60a 100644 --- a/iceoryx2-ffi/python/src/message_type_details.rs +++ b/iceoryx2-ffi/python/src/message_type_details.rs @@ -25,19 +25,19 @@ impl MessageTypeDetails { #[getter] /// The `TypeDetail` of the header of a message, the first iceoryx2 internal part. pub fn header(&self) -> TypeDetail { - TypeDetail(self.0.header.clone()) + TypeDetail(self.0.header) } #[getter] /// The `TypeDetail` of the user_header or the custom header, is located directly after the /// header. pub fn user_header(&self) -> TypeDetail { - TypeDetail(self.0.user_header.clone()) + TypeDetail(self.0.user_header) } #[getter] /// The `TypeDetail` of the payload of the message, the last part. pub fn payload(&self) -> TypeDetail { - TypeDetail(self.0.payload.clone()) + TypeDetail(self.0.payload) } } diff --git a/iceoryx2-ffi/python/src/port_factory_blackboard.rs b/iceoryx2-ffi/python/src/port_factory_blackboard.rs index 11c9605810..314c7b193e 100644 --- a/iceoryx2-ffi/python/src/port_factory_blackboard.rs +++ b/iceoryx2-ffi/python/src/port_factory_blackboard.rs @@ -76,8 +76,8 @@ impl PortFactoryBlackboard { /// Returns the `ServiceName` of the service. pub fn name(&self) -> ServiceName { match &*self.value.lock() { - PortFactoryBlackboardType::Ipc(Some(v)) => ServiceName(v.name().clone()), - PortFactoryBlackboardType::Local(Some(v)) => ServiceName(v.name().clone()), + PortFactoryBlackboardType::Ipc(Some(v)) => ServiceName(*v.name()), + PortFactoryBlackboardType::Local(Some(v)) => ServiceName(*v.name()), _ => { fatal_panic!(from "PortFactoryBlackboard::name()", "Accessing a deleted PortFactoryBlackboard.") } @@ -113,12 +113,8 @@ impl PortFactoryBlackboard { /// the lifetime of the service. pub fn static_config(&self) -> StaticConfigBlackboard { match &*self.value.lock() { - PortFactoryBlackboardType::Ipc(Some(v)) => { - StaticConfigBlackboard(v.static_config().clone()) - } - PortFactoryBlackboardType::Local(Some(v)) => { - StaticConfigBlackboard(v.static_config().clone()) - } + PortFactoryBlackboardType::Ipc(Some(v)) => StaticConfigBlackboard(*v.static_config()), + PortFactoryBlackboardType::Local(Some(v)) => StaticConfigBlackboard(*v.static_config()), _ => { fatal_panic!(from "PortFactoryBlackboard::static_config()", "Accessing a deleted PortFactoryBlackboard.") } diff --git a/iceoryx2-ffi/python/src/port_factory_event.rs b/iceoryx2-ffi/python/src/port_factory_event.rs index a90b499efc..2e304a64e5 100644 --- a/iceoryx2-ffi/python/src/port_factory_event.rs +++ b/iceoryx2-ffi/python/src/port_factory_event.rs @@ -42,8 +42,8 @@ impl PortFactoryEvent { /// Returns the `ServiceName` of the service pub fn name(&self) -> ServiceName { match &*self.0.lock() { - PortFactoryEventType::Ipc(v) => ServiceName(v.name().clone()), - PortFactoryEventType::Local(v) => ServiceName(v.name().clone()), + PortFactoryEventType::Ipc(v) => ServiceName(*v.name()), + PortFactoryEventType::Local(v) => ServiceName(*v.name()), } } diff --git a/iceoryx2-ffi/python/src/port_factory_publish_subscribe.rs b/iceoryx2-ffi/python/src/port_factory_publish_subscribe.rs index 8561c59f71..e74911989f 100644 --- a/iceoryx2-ffi/python/src/port_factory_publish_subscribe.rs +++ b/iceoryx2-ffi/python/src/port_factory_publish_subscribe.rs @@ -74,8 +74,8 @@ impl PortFactoryPublishSubscribe { /// Returns the `ServiceName` of the service pub fn name(&self) -> ServiceName { match &*self.value.lock() { - PortFactoryPublishSubscribeType::Ipc(v) => ServiceName(v.name().clone()), - PortFactoryPublishSubscribeType::Local(v) => ServiceName(v.name().clone()), + PortFactoryPublishSubscribeType::Ipc(v) => ServiceName(*v.name()), + PortFactoryPublishSubscribeType::Local(v) => ServiceName(*v.name()), } } @@ -103,10 +103,10 @@ impl PortFactoryPublishSubscribe { pub fn static_config(&self) -> StaticConfigPublishSubscribe { match &*self.value.lock() { PortFactoryPublishSubscribeType::Ipc(v) => { - StaticConfigPublishSubscribe(v.static_config().clone()) + StaticConfigPublishSubscribe(*v.static_config()) } PortFactoryPublishSubscribeType::Local(v) => { - StaticConfigPublishSubscribe(v.static_config().clone()) + StaticConfigPublishSubscribe(*v.static_config()) } } } diff --git a/iceoryx2-ffi/python/src/port_factory_request_response.rs b/iceoryx2-ffi/python/src/port_factory_request_response.rs index 5d12c620a8..948f060ec8 100644 --- a/iceoryx2-ffi/python/src/port_factory_request_response.rs +++ b/iceoryx2-ffi/python/src/port_factory_request_response.rs @@ -67,8 +67,8 @@ impl PortFactoryRequestResponse { /// Returns the `ServiceName` of the service pub fn name(&self) -> ServiceName { match &*self.value.lock() { - PortFactoryRequestResponseType::Ipc(v) => ServiceName(v.name().clone()), - PortFactoryRequestResponseType::Local(v) => ServiceName(v.name().clone()), + PortFactoryRequestResponseType::Ipc(v) => ServiceName(*v.name()), + PortFactoryRequestResponseType::Local(v) => ServiceName(*v.name()), } } @@ -96,10 +96,10 @@ impl PortFactoryRequestResponse { pub fn static_config(&self) -> StaticConfigRequestResponse { match &*self.value.lock() { PortFactoryRequestResponseType::Ipc(v) => { - StaticConfigRequestResponse(v.static_config().clone()) + StaticConfigRequestResponse(*v.static_config()) } PortFactoryRequestResponseType::Local(v) => { - StaticConfigRequestResponse(v.static_config().clone()) + StaticConfigRequestResponse(*v.static_config()) } } } diff --git a/iceoryx2-ffi/python/src/service_builder_blackboard.rs b/iceoryx2-ffi/python/src/service_builder_blackboard.rs index d3aeec0351..67e36fa3e4 100644 --- a/iceoryx2-ffi/python/src/service_builder_blackboard.rs +++ b/iceoryx2-ffi/python/src/service_builder_blackboard.rs @@ -197,7 +197,7 @@ impl ServiceBuilderBlackboardCreator { this.__internal_add( key as *const u8, value_buffer, - value_details.0.clone(), + value_details.0, Box::new(move || { std::alloc::dealloc(value_buffer, value_layout); }), @@ -211,7 +211,7 @@ impl ServiceBuilderBlackboardCreator { this.__internal_add( key as *const u8, value_buffer, - value_details.0.clone(), + value_details.0, Box::new(move || { std::alloc::dealloc(value_buffer, value_layout); }), diff --git a/iceoryx2-ffi/python/src/service_details.rs b/iceoryx2-ffi/python/src/service_details.rs index e802105e93..3b19d3bf6b 100644 --- a/iceoryx2-ffi/python/src/service_details.rs +++ b/iceoryx2-ffi/python/src/service_details.rs @@ -102,8 +102,8 @@ impl ServiceDetails { /// Returns the `ServiceName` pub fn name(&self) -> ServiceName { match &self.0 { - ServiceDetailsType::Ipc(v) => ServiceName(v.static_details.name().clone()), - ServiceDetailsType::Local(v) => ServiceName(v.static_details.name().clone()), + ServiceDetailsType::Ipc(v) => ServiceName(*v.static_details.name()), + ServiceDetailsType::Local(v) => ServiceName(*v.static_details.name()), } } diff --git a/iceoryx2-ffi/python/src/static_config_blackboard.rs b/iceoryx2-ffi/python/src/static_config_blackboard.rs index ef9fcc2921..bed8e67649 100644 --- a/iceoryx2-ffi/python/src/static_config_blackboard.rs +++ b/iceoryx2-ffi/python/src/static_config_blackboard.rs @@ -38,6 +38,6 @@ impl StaticConfigBlackboard { #[getter] /// Returns the type details of the `Service`. pub fn type_details(&self) -> TypeDetail { - TypeDetail(self.0.type_details().clone()) + TypeDetail(*self.0.type_details()) } } diff --git a/iceoryx2-ffi/python/src/static_config_publish_subscribe.rs b/iceoryx2-ffi/python/src/static_config_publish_subscribe.rs index 3deb8ed678..caef0d8d1f 100644 --- a/iceoryx2-ffi/python/src/static_config_publish_subscribe.rs +++ b/iceoryx2-ffi/python/src/static_config_publish_subscribe.rs @@ -71,6 +71,6 @@ impl StaticConfigPublishSubscribe { #[getter] /// Returns the type details of the `Service`. pub fn message_type_details(&self) -> MessageTypeDetails { - MessageTypeDetails(self.0.message_type_details().clone()) + MessageTypeDetails(*self.0.message_type_details()) } } diff --git a/iceoryx2-ffi/python/src/static_config_request_response.rs b/iceoryx2-ffi/python/src/static_config_request_response.rs index 9b2bef040f..25ad2404da 100644 --- a/iceoryx2-ffi/python/src/static_config_request_response.rs +++ b/iceoryx2-ffi/python/src/static_config_request_response.rs @@ -26,13 +26,13 @@ impl StaticConfigRequestResponse { #[getter] /// Returns the request type details of the `Service`. pub fn request_message_type_details(&self) -> MessageTypeDetails { - MessageTypeDetails(self.0.request_message_type_details().clone()) + MessageTypeDetails(*self.0.request_message_type_details()) } #[getter] /// Returns the response type details of the `Service`. pub fn response_message_type_details(&self) -> MessageTypeDetails { - MessageTypeDetails(self.0.response_message_type_details().clone()) + MessageTypeDetails(*self.0.response_message_type_details()) } #[getter] diff --git a/iceoryx2-ffi/python/src/type_detail.rs b/iceoryx2-ffi/python/src/type_detail.rs index e15fba330b..35da6ad8f8 100644 --- a/iceoryx2-ffi/python/src/type_detail.rs +++ b/iceoryx2-ffi/python/src/type_detail.rs @@ -44,7 +44,7 @@ impl TypeDetail { /// always the same size like an `uint64_t` or `TypeVariant::Dynamic` when it is a dynamic /// array or vector pub fn type_variant(&self, value: &TypeVariant) -> Self { - let mut this = self.0.clone(); + let mut this = self.0; testing::type_detail_set_variant(&mut this, (value.clone()).into()); Self(this) @@ -52,21 +52,21 @@ impl TypeDetail { /// Sets the unique `TypeName` of the type pub fn type_name(&self, name: &TypeName) -> Self { - let mut this = self.0.clone(); + let mut this = self.0; testing::type_detail_set_name(&mut this, name.0); Self(this) } /// Sets the size of the type pub fn size(&self, size: usize) -> Self { - let mut this = self.0.clone(); + let mut this = self.0; testing::type_detail_set_size(&mut this, size); Self(this) } /// Sets the alignment of the type pub fn alignment(&self, alignment: usize) -> Self { - let mut this = self.0.clone(); + let mut this = self.0; testing::type_detail_set_alignment(&mut this, alignment); Self(this) } diff --git a/iceoryx2-userland/record-and-replay/src/recorder.rs b/iceoryx2-userland/record-and-replay/src/recorder.rs index b7483e9d44..268d0ec9bb 100644 --- a/iceoryx2-userland/record-and-replay/src/recorder.rs +++ b/iceoryx2-userland/record-and-replay/src/recorder.rs @@ -183,7 +183,7 @@ impl RecorderBuilder { }; let header = RecordHeader { - service_name: service_name.clone(), + service_name: *service_name, iceoryx2_version: PackageVersion::get().into(), details: RecordHeaderDetails { file_format_version: match self.data_representation { diff --git a/iceoryx2/conformance-tests/src/sample.rs b/iceoryx2/conformance-tests/src/sample.rs index 624ac87896..d0ef6faa3b 100644 --- a/iceoryx2/conformance-tests/src/sample.rs +++ b/iceoryx2/conformance-tests/src/sample.rs @@ -91,7 +91,7 @@ pub mod sample { let config = generate_isolated_config(); let test_context = TestContext::::new(&config); - let service_name = test_context.service_name.clone(); + let service_name = test_context.service_name; assert_that!(test_context.publisher_1.send_copy(5), eq Ok(1)); let sample = test_context.subscriber.receive().unwrap(); diff --git a/iceoryx2/conformance-tests/src/sample_mut.rs b/iceoryx2/conformance-tests/src/sample_mut.rs index 0524cbed4b..a9bda20df5 100644 --- a/iceoryx2/conformance-tests/src/sample_mut.rs +++ b/iceoryx2/conformance-tests/src/sample_mut.rs @@ -155,7 +155,7 @@ pub mod sample_mut { pub fn sample_of_dropped_service_does_block_new_service_creation() { let config = generate_isolated_config(); let test_context = TestContext::::new(&config); - let service_name = test_context.service_name.clone(); + let service_name = test_context.service_name; let _sample = test_context.publisher.loan_uninit().unwrap(); drop(test_context); diff --git a/iceoryx2/src/port/client.rs b/iceoryx2/src/port/client.rs index db56388129..44d6af02e5 100644 --- a/iceoryx2/src/port/client.rs +++ b/iceoryx2/src/port/client.rs @@ -429,7 +429,7 @@ impl< loan_counter: AtomicUsize::new(0), sender_max_borrowed_samples: static_config.max_loaned_requests, unable_to_deliver_strategy: client_factory.config.unable_to_deliver_strategy, - message_type_details: static_config.request_message_type_details.clone(), + message_type_details: static_config.request_message_type_details, // all requests are sent via one channel, only the responses require different // channels to guarantee that one response does not fill the buffer of another // response. @@ -464,7 +464,7 @@ impl< .expect("Heap allocator provides memory."), )), degradation_callback: client_factory.response_degradation_callback, - message_type_details: static_config.response_message_type_details.clone(), + message_type_details: static_config.response_message_type_details, receiver_max_borrowed_samples: static_config .max_borrowed_responses_per_pending_response, enable_safe_overflow: static_config.enable_safe_overflow_for_responses, diff --git a/iceoryx2/src/port/listener.rs b/iceoryx2/src/port/listener.rs index f3a1c1b86b..0ef4812445 100644 --- a/iceoryx2/src/port/listener.rs +++ b/iceoryx2/src/port/listener.rs @@ -219,7 +219,8 @@ impl Listener { .static_config .event() .deadline - .map(|v| v.value) + .map(|v| v.value.into()) + .into() } /// Non-blocking wait for new [`EventId`]s. Collects all [`EventId`]s that were received and diff --git a/iceoryx2/src/port/notifier.rs b/iceoryx2/src/port/notifier.rs index 44ca663733..dd51b16d4e 100644 --- a/iceoryx2/src/port/notifier.rs +++ b/iceoryx2/src/port/notifier.rs @@ -308,7 +308,10 @@ impl Notifier { Self::new_without_auto_event_emission(service.clone(), default_event_id)?; let static_config = service.static_config.event(); - new_self.on_drop_notification = static_config.notifier_dropped_event.map(EventId::new); + new_self.on_drop_notification = static_config + .notifier_dropped_event + .map(EventId::new) + .into(); if let Some(event_id) = static_config.notifier_created_event() { match new_self.notify_with_custom_event_id(event_id) { @@ -418,7 +421,8 @@ impl Notifier { .static_config .event() .deadline - .map(|v| v.value) + .map(|v| v.value.into()) + .into() } /// Notifies all [`crate::port::listener::Listener`] connected to the service with a custom @@ -485,6 +489,7 @@ impl Notifier { .static_config .event() .deadline + .as_option_ref() { let msg = "The notification was sent"; let duration_since_creation = fail!(from self, when deadline.creation_time.elapsed(), @@ -504,7 +509,7 @@ impl Notifier { duration_since_creation.as_nanos() as u64 - previous_duration_since_creation, ); - if deadline.value < duration_since_last_notification { + if duration_since_last_notification > deadline.value.into() { fail!(from self, with NotifierNotifyError::MissedDeadline, "{} but the deadline was hit. The service requires a notification after {:?} but {:?} passed without a notification.", msg, deadline.value, duration_since_last_notification); diff --git a/iceoryx2/src/port/publisher.rs b/iceoryx2/src/port/publisher.rs index 057a784d7b..220f4f5783 100644 --- a/iceoryx2/src/port/publisher.rs +++ b/iceoryx2/src/port/publisher.rs @@ -451,7 +451,7 @@ impl< loan_counter: AtomicUsize::new(0), sender_max_borrowed_samples: config.max_loaned_samples, unable_to_deliver_strategy: config.unable_to_deliver_strategy, - message_type_details: static_config.message_type_details.clone(), + message_type_details: static_config.message_type_details, number_of_channels: 1, }, config, diff --git a/iceoryx2/src/port/server.rs b/iceoryx2/src/port/server.rs index 0e2a4966e9..3565364b84 100644 --- a/iceoryx2/src/port/server.rs +++ b/iceoryx2/src/port/server.rs @@ -325,7 +325,7 @@ impl< .expect("Heap allocator provides memory."), receiver_port_id: server_id.value(), service_state: service.clone(), - message_type_details: static_config.request_message_type_details.clone(), + message_type_details: static_config.request_message_type_details, receiver_max_borrowed_samples: static_config.max_active_requests_per_client, enable_safe_overflow: static_config.enable_safe_overflow_for_requests, buffer_size: static_config.max_active_requests_per_client, @@ -406,7 +406,7 @@ impl< tagger: CyclicTagger::new(), loan_counter: AtomicUsize::new(0), unable_to_deliver_strategy: server_factory.config.unable_to_deliver_strategy, - message_type_details: static_config.response_message_type_details.clone(), + message_type_details: static_config.response_message_type_details, number_of_channels: number_of_requests_per_client, }; diff --git a/iceoryx2/src/port/subscriber.rs b/iceoryx2/src/port/subscriber.rs index edb17a4e6a..4fe71a86cd 100644 --- a/iceoryx2/src/port/subscriber.rs +++ b/iceoryx2/src/port/subscriber.rs @@ -203,7 +203,7 @@ impl< .expect("Heap allocator provides memory."), receiver_port_id: subscriber_id.value(), service_state: service.clone(), - message_type_details: static_config.message_type_details.clone(), + message_type_details: static_config.message_type_details, receiver_max_borrowed_samples: static_config.subscriber_max_borrowed_samples, enable_safe_overflow: static_config.enable_safe_overflow, buffer_size, diff --git a/iceoryx2/src/service/builder/blackboard.rs b/iceoryx2/src/service/builder/blackboard.rs index 1a46740926..9003476780 100644 --- a/iceoryx2/src/service/builder/blackboard.rs +++ b/iceoryx2/src/service/builder/blackboard.rs @@ -450,7 +450,7 @@ impl< TypeDetail::new::(message_type_details::TypeVariant::FixedSize); } Some(details) => { - self.config_details_mut().type_details = details.clone(); + self.config_details_mut().type_details = *details; } } } @@ -725,7 +725,7 @@ impl< }; (*self.builder.internals[i].value_writer)(mem.data_ptr); // write offset to value in payload_shm to entries vector - let res = entry.entries.push(Entry{type_details: self.builder.internals[i].value_type_details.clone(), offset: AtomicU64::new(mem.offset.offset() as u64)}); + let res = entry.entries.push(Entry{type_details: self.builder.internals[i].value_type_details, offset: AtomicU64::new(mem.offset.offset() as u64)}); if res.is_err() { error!(from self, "Writing the value offset to the blackboard management segment failed."); return false @@ -773,7 +773,7 @@ impl< impl Creator { #[doc(hidden)] pub unsafe fn __internal_set_key_type_details(mut self, value: &TypeDetail) -> Self { - self.builder.override_key_type = Some(value.clone()); + self.builder.override_key_type = Some(*value); self } @@ -794,7 +794,7 @@ impl Creator { value_details: TypeDetail, value_cleanup: Box, ) -> Self { - let key_type_details = match self.builder.override_key_type.clone() { + let key_type_details = match self.builder.override_key_type { None => { fatal_panic!(from self, "The key type details were not set when __internal_add was called!") } @@ -918,7 +918,7 @@ impl< msg, existing_settings.max_nodes, required_settings.max_nodes); } - Ok(existing_settings.clone()) + Ok(*existing_settings) } /// Opens an existing [`Service`]. @@ -993,7 +993,7 @@ impl< }; self.builder.base.service_config.messaging_pattern = - MessagingPattern::Blackboard(blackboard_static_config.clone()); + MessagingPattern::Blackboard(blackboard_static_config); let name = blackboard_name(self.builder.base.service_config.service_id().as_str()); @@ -1070,7 +1070,7 @@ impl< impl Opener { #[doc(hidden)] pub unsafe fn __internal_set_key_type_details(mut self, value: &TypeDetail) -> Self { - self.builder.override_key_type = Some(value.clone()); + self.builder.override_key_type = Some(*value); self } } diff --git a/iceoryx2/src/service/builder/event.rs b/iceoryx2/src/service/builder/event.rs index 4b5b46c034..cc1ee8057f 100644 --- a/iceoryx2/src/service/builder/event.rs +++ b/iceoryx2/src/service/builder/event.rs @@ -18,6 +18,7 @@ pub use crate::port::event_id::EventId; use alloc::format; +use iceoryx2_bb_container::relocatable_option::RelocatableOption; use iceoryx2_bb_posix::clock::Time; use iceoryx2_cal::dynamic_storage::DynamicStorageCreateError; use iceoryx2_log::{fail, fatal_panic}; @@ -229,8 +230,8 @@ impl Builder { /// Enables the deadline property of the service. There must be a notification emitted by any /// [`Notifier`](crate::port::notifier::Notifier) after at least the provided `deadline`. pub fn deadline(mut self, deadline: Duration) -> Self { - self.config_details().deadline = Some(Deadline { - value: deadline, + self.config_details().deadline = RelocatableOption::Some(Deadline { + value: deadline.into(), creation_time: Time::default(), }); self.verify_deadline = true; @@ -240,7 +241,7 @@ impl Builder { /// Disables the deadline property of the service. [`Notifier`](crate::port::notifier::Notifier) /// can signal notifications at any rate. pub fn disable_deadline(mut self) -> Self { - self.config_details().deadline = None; + self.config_details().deadline = RelocatableOption::None; self.verify_deadline = true; self } @@ -284,7 +285,7 @@ impl Builder { /// If the [`Service`] is created it defines the event that shall be emitted by every newly /// created [`Notifier`](crate::port::notifier::Notifier). pub fn notifier_created_event(mut self, value: EventId) -> Self { - self.config_details().notifier_created_event = Some(value.as_value()); + self.config_details().notifier_created_event = RelocatableOption::Some(value.as_value()); self.verify_notifier_created_event = true; self } @@ -292,7 +293,7 @@ impl Builder { /// If the [`Service`] is created it disables the event that shall be emitted by every newly /// created [`Notifier`](crate::port::notifier::Notifier). pub fn disable_notifier_created_event(mut self) -> Self { - self.config_details().notifier_created_event = None; + self.config_details().notifier_created_event = RelocatableOption::None; self.verify_notifier_created_event = true; self } @@ -300,7 +301,7 @@ impl Builder { /// If the [`Service`] is created it defines the event that shall be emitted by every /// [`Notifier`](crate::port::notifier::Notifier) before it is dropped. pub fn notifier_dropped_event(mut self, value: EventId) -> Self { - self.config_details().notifier_dropped_event = Some(value.as_value()); + self.config_details().notifier_dropped_event = RelocatableOption::Some(value.as_value()); self.verify_notifier_dropped_event = true; self } @@ -308,7 +309,7 @@ impl Builder { /// If the [`Service`] is created it disables the event that shall be emitted by every /// [`Notifier`](crate::port::notifier::Notifier) before it is dropped. pub fn disable_notifier_dropped_event(mut self) -> Self { - self.config_details().notifier_dropped_event = None; + self.config_details().notifier_dropped_event = RelocatableOption::None; self.verify_notifier_dropped_event = true; self } @@ -316,7 +317,7 @@ impl Builder { /// If the [`Service`] is created it defines the event that shall be emitted when a /// [`Notifier`](crate::port::notifier::Notifier) is identified as dead. pub fn notifier_dead_event(mut self, value: EventId) -> Self { - self.config_details().notifier_dead_event = Some(value.as_value()); + self.config_details().notifier_dead_event = RelocatableOption::Some(value.as_value()); self.verify_notifier_dead_event = true; self } @@ -324,7 +325,7 @@ impl Builder { /// If the [`Service`] is created it disables the event that shall be emitted when a /// [`Notifier`](crate::port::notifier::Notifier) is identified as dead. pub fn disable_notifier_dead_event(mut self) -> Self { - self.config_details().notifier_dead_event = None; + self.config_details().notifier_dead_event = RelocatableOption::None; self.verify_notifier_dead_event = true; self } @@ -481,7 +482,9 @@ impl Builder { .base .create_node_service_tag(msg, EventCreateError::InternalFailure)?; - if let Some(ref mut deadline) = self.base.service_config.event_mut().deadline { + if let RelocatableOption::Some(ref mut deadline) = + self.base.service_config.event_mut().deadline + { let now = fail!(from self, when Time::now(), with EventCreateError::InternalFailure, "{} since the current system time could not be acquired.", msg); diff --git a/iceoryx2/src/service/builder/mod.rs b/iceoryx2/src/service/builder/mod.rs index 75440fdea3..cea951d389 100644 --- a/iceoryx2/src/service/builder/mod.rs +++ b/iceoryx2/src/service/builder/mod.rs @@ -137,7 +137,7 @@ pub struct Builder { impl Builder { pub(crate) fn new(name: &ServiceName, shared_node: Arc>) -> Self { Self { - name: name.clone(), + name: *name, shared_node, _phantom_s: PhantomData, } diff --git a/iceoryx2/src/service/builder/publish_subscribe.rs b/iceoryx2/src/service/builder/publish_subscribe.rs index ecd401f383..869e5f67ed 100644 --- a/iceoryx2/src/service/builder/publish_subscribe.rs +++ b/iceoryx2/src/service/builder/publish_subscribe.rs @@ -243,8 +243,8 @@ impl< Self { base: self.base.clone(), override_alignment: self.override_alignment, - override_payload_type: self.override_payload_type.clone(), - override_user_header_type: self.override_user_header_type.clone(), + override_payload_type: self.override_payload_type, + override_user_header_type: self.override_user_header_type, verify_number_of_subscribers: self.verify_number_of_subscribers, verify_number_of_publishers: self.verify_number_of_publishers, verify_subscriber_max_buffer_size: self.verify_subscriber_max_buffer_size, @@ -521,7 +521,7 @@ impl< msg, existing_settings.max_nodes, required_settings.max_nodes); } - Ok(existing_settings.clone()) + Ok(*existing_settings) } fn create_impl( @@ -688,7 +688,7 @@ impl< }; self.base.service_config.messaging_pattern = - MessagingPattern::PublishSubscribe(pub_sub_static_config.clone()); + MessagingPattern::PublishSubscribe(pub_sub_static_config); if let Some(service_tag) = service_tag { service_tag.release_ownership(); @@ -769,7 +769,7 @@ impl { #[doc(hidden)] pub unsafe fn __internal_set_payload_type_details(mut self, value: &TypeDetail) -> Self { - self.override_payload_type = Some(value.clone()); + self.override_payload_type = Some(*value); self } } @@ -779,7 +779,7 @@ impl { #[doc(hidden)] pub unsafe fn __internal_set_user_header_type_details(mut self, value: &TypeDetail) -> Self { - self.override_user_header_type = Some(value.clone()); + self.override_user_header_type = Some(*value); self } } @@ -795,11 +795,11 @@ impl< MessageTypeDetails::from::(TypeVariant::FixedSize); if let Some(details) = &self.override_payload_type { - self.config_details_mut().message_type_details.payload = details.clone(); + self.config_details_mut().message_type_details.payload = *details; } if let Some(details) = &self.override_user_header_type { - self.config_details_mut().message_type_details.user_header = details.clone(); + self.config_details_mut().message_type_details.user_header = *details; } self.adjust_payload_alignment(); @@ -890,11 +890,11 @@ impl< MessageTypeDetails::from::(TypeVariant::Dynamic); if let Some(details) = &self.override_payload_type { - self.config_details_mut().message_type_details.payload = details.clone(); + self.config_details_mut().message_type_details.payload = *details; } if let Some(details) = &self.override_user_header_type { - self.config_details_mut().message_type_details.user_header = details.clone(); + self.config_details_mut().message_type_details.user_header = *details; } self.adjust_payload_alignment(); diff --git a/iceoryx2/src/service/builder/request_response.rs b/iceoryx2/src/service/builder/request_response.rs index 08035d1eec..86f1a8a835 100644 --- a/iceoryx2/src/service/builder/request_response.rs +++ b/iceoryx2/src/service/builder/request_response.rs @@ -264,10 +264,10 @@ impl< 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.clone(), - override_response_payload_type: self.override_response_payload_type.clone(), - override_request_header_type: self.override_request_header_type.clone(), - override_response_header_type: self.override_response_header_type.clone(), + 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, verify_enable_safe_overflow_for_requests: self.verify_enable_safe_overflow_for_requests, verify_enable_safe_overflow_for_responses: self .verify_enable_safe_overflow_for_responses, @@ -629,7 +629,7 @@ impl< msg, existing_configuration.max_nodes, required_configuration.max_nodes); } - Ok(existing_configuration.clone()) + Ok(*existing_configuration) } fn is_service_available( @@ -846,7 +846,7 @@ impl< }; self.base.service_config.messaging_pattern = - MessagingPattern::RequestResponse(request_response_static_config.clone()); + MessagingPattern::RequestResponse(request_response_static_config); if let Some(service_tag) = service_tag { service_tag.release_ownership(); @@ -915,25 +915,25 @@ impl< if let Some(details) = &self.override_request_payload_type { self.config_details_mut() .request_message_type_details - .payload = details.clone(); + .payload = *details; } if let Some(details) = &self.override_request_header_type { self.config_details_mut() .request_message_type_details - .user_header = details.clone(); + .user_header = *details; } if let Some(details) = &self.override_response_payload_type { self.config_details_mut() .response_message_type_details - .payload = details.clone(); + .payload = *details; } if let Some(details) = &self.override_response_header_type { self.config_details_mut() .response_message_type_details - .user_header = details.clone(); + .user_header = *details; } if let Some(alignment) = self.override_request_alignment { @@ -1518,7 +1518,7 @@ impl mut self, value: &TypeDetail, ) -> Self { - self.override_request_payload_type = Some(value.clone()); + self.override_request_payload_type = Some(*value); self } @@ -1527,13 +1527,13 @@ impl mut self, value: &TypeDetail, ) -> Self { - self.override_response_payload_type = Some(value.clone()); + self.override_response_payload_type = Some(*value); self } #[doc(hidden)] pub unsafe fn __internal_set_request_header_type_details(mut self, value: &TypeDetail) -> Self { - self.override_request_header_type = Some(value.clone()); + self.override_request_header_type = Some(*value); self } @@ -1542,7 +1542,7 @@ impl mut self, value: &TypeDetail, ) -> Self { - self.override_response_header_type = Some(value.clone()); + self.override_response_header_type = Some(*value); self } } diff --git a/iceoryx2/src/service/mod.rs b/iceoryx2/src/service/mod.rs index 47a809fda5..ab8c496b70 100644 --- a/iceoryx2/src/service/mod.rs +++ b/iceoryx2/src/service/mod.rs @@ -515,8 +515,8 @@ pub mod internal { return; } - let event_id = match service.static_config().notifier_dead_event { - Some(event_id) => event_id, + let event_id = match service.static_config().notifier_dead_event.as_option_ref() { + Some(event_id) => *event_id, None => return, }; diff --git a/iceoryx2/src/service/service_name.rs b/iceoryx2/src/service/service_name.rs index 3920440c4b..04dba1ba26 100644 --- a/iceoryx2/src/service/service_name.rs +++ b/iceoryx2/src/service/service_name.rs @@ -71,7 +71,7 @@ impl From for ServiceNameError { type ServiceNameString = StaticString; /// The name of a [`Service`](crate::service::Service). -#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, ZeroCopySend)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, ZeroCopySend)] #[repr(C)] pub struct ServiceName { value: ServiceNameString, diff --git a/iceoryx2/src/service/static_config/blackboard.rs b/iceoryx2/src/service/static_config/blackboard.rs index e0f83e9da7..4aee043357 100644 --- a/iceoryx2/src/service/static_config/blackboard.rs +++ b/iceoryx2/src/service/static_config/blackboard.rs @@ -40,7 +40,7 @@ use super::message_type_details::TypeDetail; /// The static configuration of an [`MessagingPattern::Blackboard`](crate::service::messaging_pattern::MessagingPattern::Blackboard) /// based service. Contains all parameters that do not change during the lifetime of a /// [`Service`](crate::service::Service). -#[derive(Debug, Clone, Eq, Hash, PartialEq, ZeroCopySend, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, ZeroCopySend, Serialize, Deserialize)] #[repr(C)] pub struct StaticConfig { pub(crate) max_readers: usize, diff --git a/iceoryx2/src/service/static_config/event.rs b/iceoryx2/src/service/static_config/event.rs index 1ff663299d..bbc674beba 100644 --- a/iceoryx2/src/service/static_config/event.rs +++ b/iceoryx2/src/service/static_config/event.rs @@ -35,16 +35,17 @@ use core::time::Duration; use crate::{config, prelude::EventId}; +use iceoryx2_bb_container::relocatable_option::RelocatableOption; use iceoryx2_bb_derive_macros::ZeroCopySend; use iceoryx2_bb_elementary_traits::zero_copy_send::ZeroCopySend; -use iceoryx2_bb_posix::clock::Time; +use iceoryx2_bb_posix::clock::{RelocatableDuration, Time}; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, ZeroCopySend, Serialize, Deserialize)] #[repr(C)] pub(crate) struct Deadline { pub(crate) creation_time: Time, - pub(crate) value: Duration, + pub(crate) value: RelocatableDuration, } /// The static configuration of an [`MessagingPattern::Event`](crate::service::messaging_pattern::MessagingPattern::Event) @@ -57,10 +58,10 @@ pub struct StaticConfig { pub(crate) max_listeners: usize, pub(crate) max_nodes: usize, pub(crate) event_id_max_value: usize, - pub(crate) deadline: Option, - pub(crate) notifier_created_event: Option, - pub(crate) notifier_dropped_event: Option, - pub(crate) notifier_dead_event: Option, + pub(crate) deadline: RelocatableOption, + pub(crate) notifier_created_event: RelocatableOption, + pub(crate) notifier_dropped_event: RelocatableOption, + pub(crate) notifier_dead_event: RelocatableOption, } impl StaticConfig { @@ -69,14 +70,19 @@ impl StaticConfig { max_notifiers: config.defaults.event.max_notifiers, max_listeners: config.defaults.event.max_listeners, max_nodes: config.defaults.event.max_nodes, - deadline: config.defaults.event.deadline.map(|v| Deadline { - creation_time: Time::default(), - value: v, - }), + deadline: config + .defaults + .event + .deadline + .map(|v| Deadline { + creation_time: Time::default(), + value: v.into(), + }) + .into(), event_id_max_value: config.defaults.event.event_id_max_value, - notifier_created_event: config.defaults.event.notifier_created_event, - notifier_dropped_event: config.defaults.event.notifier_dropped_event, - notifier_dead_event: config.defaults.event.notifier_dead_event, + notifier_created_event: config.defaults.event.notifier_created_event.into(), + notifier_dropped_event: config.defaults.event.notifier_dropped_event.into(), + notifier_dead_event: config.defaults.event.notifier_dead_event.into(), } } @@ -86,7 +92,7 @@ impl StaticConfig { /// to a [`WaitSet`](crate::waitset::WaitSet) are woken up and notified about the missed /// deadline. pub fn deadline(&self) -> Option { - self.deadline.map(|v| v.value) + self.deadline.as_option_ref().map(|v| v.value.into()) } /// Returns the maximum supported amount of [`Node`](crate::node::Node)s that can open the @@ -112,16 +118,22 @@ impl StaticConfig { /// Returns the emitted [`EventId`] when a new notifier is created. pub fn notifier_created_event(&self) -> Option { - self.notifier_created_event.map(EventId::new) + self.notifier_created_event + .as_option_ref() + .map(|v| EventId::new(*v)) } /// Returns the emitted [`EventId`] when a notifier is dropped. pub fn notifier_dropped_event(&self) -> Option { - self.notifier_dropped_event.map(EventId::new) + self.notifier_dropped_event + .as_option_ref() + .map(|v| EventId::new(*v)) } /// Returns the emitted [`EventId`] when a notifier is identified as dead. pub fn notifier_dead_event(&self) -> Option { - self.notifier_dead_event.map(EventId::new) + self.notifier_dead_event + .as_option_ref() + .map(|v| EventId::new(*v)) } } diff --git a/iceoryx2/src/service/static_config/message_type_details.rs b/iceoryx2/src/service/static_config/message_type_details.rs index 6be80679cd..4b73deabd7 100644 --- a/iceoryx2/src/service/static_config/message_type_details.rs +++ b/iceoryx2/src/service/static_config/message_type_details.rs @@ -54,7 +54,9 @@ pub enum TypeVariant { pub type TypeName = StaticString; /// Contains all type details required to connect to a [`crate::service::Service`] -#[derive(Default, Debug, Clone, Eq, Hash, PartialEq, ZeroCopySend, Serialize, Deserialize)] +#[derive( + Default, Debug, Clone, Copy, Eq, Hash, PartialEq, ZeroCopySend, Serialize, Deserialize, +)] #[repr(C)] pub struct TypeDetail { pub(crate) variant: TypeVariant, @@ -104,7 +106,9 @@ impl TypeDetail { } /// Contains all type information to the header and payload type. -#[derive(Default, Debug, Clone, Eq, Hash, PartialEq, ZeroCopySend, Serialize, Deserialize)] +#[derive( + Default, Debug, Clone, Copy, Eq, Hash, PartialEq, ZeroCopySend, Serialize, Deserialize, +)] #[repr(C)] pub struct MessageTypeDetails { /// The [`TypeDetail`] of the header of a message, the first iceoryx2 internal part. diff --git a/iceoryx2/src/service/static_config/messaging_pattern.rs b/iceoryx2/src/service/static_config/messaging_pattern.rs index cf100a809f..a991df0511 100644 --- a/iceoryx2/src/service/static_config/messaging_pattern.rs +++ b/iceoryx2/src/service/static_config/messaging_pattern.rs @@ -30,7 +30,7 @@ use super::request_response; /// /// This is a large struct (>1KB). Be cautious with where it is placed and how it is passed around. #[non_exhaustive] -#[derive(Debug, Clone, Eq, Hash, PartialEq, ZeroCopySend, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, ZeroCopySend, Serialize, Deserialize)] #[repr(C)] #[allow(clippy::large_enum_variant)] pub enum MessagingPattern { diff --git a/iceoryx2/src/service/static_config/mod.rs b/iceoryx2/src/service/static_config/mod.rs index 74a9d2bff7..9eae759260 100644 --- a/iceoryx2/src/service/static_config/mod.rs +++ b/iceoryx2/src/service/static_config/mod.rs @@ -67,7 +67,7 @@ impl StaticConfig { service_name, crate::service::messaging_pattern::MessagingPattern::RequestResponse, ), - service_name: service_name.clone(), + service_name: *service_name, messaging_pattern, attributes: AttributeSet::new(), } @@ -83,7 +83,7 @@ impl StaticConfig { service_name, crate::service::messaging_pattern::MessagingPattern::Event, ), - service_name: service_name.clone(), + service_name: *service_name, messaging_pattern, attributes: AttributeSet::new(), } @@ -100,7 +100,7 @@ impl StaticConfig { service_name, crate::service::messaging_pattern::MessagingPattern::PublishSubscribe, ), - service_name: service_name.clone(), + service_name: *service_name, messaging_pattern, attributes: AttributeSet::new(), } @@ -116,7 +116,7 @@ impl StaticConfig { service_name, crate::service::messaging_pattern::MessagingPattern::Blackboard, ), - service_name: service_name.clone(), + service_name: *service_name, messaging_pattern, attributes: AttributeSet::new(), } diff --git a/iceoryx2/src/service/static_config/publish_subscribe.rs b/iceoryx2/src/service/static_config/publish_subscribe.rs index e66dcd3f5f..08fa1e6b29 100644 --- a/iceoryx2/src/service/static_config/publish_subscribe.rs +++ b/iceoryx2/src/service/static_config/publish_subscribe.rs @@ -43,7 +43,7 @@ use serde::{Deserialize, Serialize}; /// [`MessagingPattern::PublishSubscribe`](crate::service::messaging_pattern::MessagingPattern::PublishSubscribe) /// based service. Contains all parameters that do not change during the lifetime of a /// [`Service`](crate::service::Service). -#[derive(Debug, Clone, Eq, Hash, PartialEq, ZeroCopySend, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, ZeroCopySend, Serialize, Deserialize)] #[repr(C)] pub struct StaticConfig { pub(crate) max_subscribers: usize, diff --git a/iceoryx2/src/service/static_config/request_response.rs b/iceoryx2/src/service/static_config/request_response.rs index 682fe81500..7d80a6ca3b 100644 --- a/iceoryx2/src/service/static_config/request_response.rs +++ b/iceoryx2/src/service/static_config/request_response.rs @@ -50,7 +50,7 @@ use super::message_type_details::MessageTypeDetails; /// [`MessagingPattern::RequestResponse`](crate::service::messaging_pattern::MessagingPattern::RequestResponse) /// based service. Contains all parameters that do not change during the lifetime of a /// [`Service`](crate::service::Service). -#[derive(Debug, Clone, Eq, Hash, PartialEq, ZeroCopySend, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, ZeroCopySend, Serialize, Deserialize)] #[repr(C)] pub struct StaticConfig { pub(crate) enable_safe_overflow_for_requests: bool,