Skip to content

[#602] enforce that payload and header types implement ZeroCopySend #684

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.Bazel.lock
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"checksum": "c0294216ae977097aad891704f8414d46ad64dde120eab3a6437fdfa59210ece",
"checksum": "a276856e54d5cde5c7e147e1fc65f356f023f86997fd07a9f9f90024f9181e58",
"crates": {
"addr2line 0.24.2": {
"name": "addr2line",
Expand Down
6 changes: 6 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

52 changes: 47 additions & 5 deletions doc/release-notes/iceoryx2-unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,49 @@

### API Breaking Changes

1. Renamed `PublisherLoanError` into `LoanError`
1. Add requirement that every payload and user header type must implement
`ZeroCopySend` for type safe shared memory usage
[#602](https://github.com/eclipse-iceoryx/iceoryx2/issues/602)

```rust
// old
#[repr(C)]
pub struct TransmissionData {
// ...
}

#[repr(C)]
pub struct CustomHeader {
// ...
}

let service = node
.service_builder(&"ServiceName".try_into()?)
.publish_subscribe::<TransmissionData>()
.user_header::<CustomHeader>()
.open_or_create()?;

// new
#[derive(ZeroCopySend)]
#[repr(C)]
pub struct TransmissionData {
// ...
}

#[derive(ZeroCopySend)]
#[repr(C)]
pub struct CustomHeader {
// ...
}

let service = node
.service_builder(&"ServiceName".try_into()?)
.publish_subscribe::<TransmissionData>()
.user_header::<CustomHeader>()
.open_or_create()?;
```

2. Renamed `PublisherLoanError` into `LoanError`

```rust
// old
Expand All @@ -124,7 +166,7 @@
};
```

2. Renamed `PublisherSendError` into `SendError`
3. Renamed `PublisherSendError` into `SendError`

```rust
// old
Expand All @@ -142,7 +184,7 @@
};
```

3. Renamed `SubscriberReceiveError` into `ReceiveError`
4. Renamed `SubscriberReceiveError` into `ReceiveError`

```rust
// old
Expand All @@ -160,8 +202,8 @@
}
```

4. Renamed `PublisherSendError::ConnectionBrokenSincePublisherNoLongerExists`
5. Renamed `PublisherSendError::ConnectionBrokenSincePublisherNoLongerExists`
into `SendError::ConnectionBrokenSinceSenderNoLongerExists`

5. Renamed `ConnectionFailure::UnableToMapPublishersDataSegment`
6. Renamed `ConnectionFailure::UnableToMapPublishersDataSegment`
into `ConnectionFailure::UnableToMapSendersDataSegment`
2 changes: 2 additions & 0 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ version = { workspace = true }
[dependencies]
iceoryx2 = { workspace = true }
iceoryx2-bb-container = { workspace = true }
iceoryx2-bb-derive-macros = { workspace = true }
iceoryx2-bb-elementary = { workspace = true }
iceoryx2-bb-log = { workspace = true }
iceoryx2-bb-system-types = { workspace = true }

Expand Down
6 changes: 0 additions & 6 deletions examples/c/publish_subscribe_cross_language/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,6 @@ For C applications, these type names must be set with
`iox2_service_builder_pub_sub_set_user_header_type_details` before creating the
service.

> [!NOTE]
> The type name can't currently be set for Rust applications. If you want to
> communicate with Rust applications, you can determine the type names on the
> Rust side with `core::any::type_name()` and use these as the type names in C
> applications.

When the type names are set to the same value, and the structure has the same
memory layout, the C applications and applications written in other supported
languages can communicate.
10 changes: 4 additions & 6 deletions examples/c/publish_subscribe_cross_language/src/message_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,18 @@

#include <stdint.h>

// payload_type_name is equivalent to the payload type name used on the Rust side and was determined with
// `core::any::type_name::<TransmissionData>()`
// payload_type_name is equivalent to the payload type name used on the Rust side
// NOLINTNEXTLINE, C idiomatic way for compile time const variables
#define PAYLOAD_TYPE_NAME "examples_common::transmission_data::TransmissionData"
#define IOX2_PAYLOAD_TYPE_NAME "TransmissionData"
struct TransmissionData {
int32_t x;
int32_t y;
double funky;
};

// user_header_type_name is equivalent to the user header type name used on the Rust side and was determined with
// `core::any::type_name::<CustomHeader>()`
// user_header_type_name is equivalent to the user header type name used on the Rust side
// NOLINTNEXTLINE, C idiomatic way for compile time const variables
#define USER_HEADER_TYPE_NAME "examples_common::custom_header::CustomHeader"
#define IOX2_USER_HEADER_TYPE_NAME "CustomHeader"
struct CustomHeader {
int32_t version;
uint64_t timestamp;
Expand Down
8 changes: 4 additions & 4 deletions examples/c/publish_subscribe_cross_language/src/publisher.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ int main(void) {
// set pub sub payload type
if (iox2_service_builder_pub_sub_set_payload_type_details(&service_builder_pub_sub,
iox2_type_variant_e_FIXED_SIZE,
PAYLOAD_TYPE_NAME,
strlen(PAYLOAD_TYPE_NAME),
IOX2_PAYLOAD_TYPE_NAME,
strlen(IOX2_PAYLOAD_TYPE_NAME),
sizeof(struct TransmissionData),
alignof(struct TransmissionData))
!= IOX2_OK) {
Expand All @@ -59,8 +59,8 @@ int main(void) {
// set pub sub user header type
if (iox2_service_builder_pub_sub_set_user_header_type_details(&service_builder_pub_sub,
iox2_type_variant_e_FIXED_SIZE,
USER_HEADER_TYPE_NAME,
strlen(USER_HEADER_TYPE_NAME),
IOX2_USER_HEADER_TYPE_NAME,
strlen(IOX2_USER_HEADER_TYPE_NAME),
sizeof(struct CustomHeader),
alignof(struct CustomHeader))
!= IOX2_OK) {
Expand Down
14 changes: 4 additions & 10 deletions examples/c/publish_subscribe_cross_language/src/subscriber.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,10 @@ int main(void) {
iox2_service_builder_pub_sub_h service_builder_pub_sub = iox2_service_builder_pub_sub(service_builder);

// set pub sub payload type
// payload_type_name is equivalent to the payload type name used on the Rust side and was determined with
// `core::any::type_name::<TransmissionData>()`
const char* payload_type_name = "examples_common::transmission_data::TransmissionData";
if (iox2_service_builder_pub_sub_set_payload_type_details(&service_builder_pub_sub,
iox2_type_variant_e_FIXED_SIZE,
payload_type_name,
strlen(payload_type_name),
IOX2_PAYLOAD_TYPE_NAME,
strlen(IOX2_PAYLOAD_TYPE_NAME),
sizeof(struct TransmissionData),
alignof(struct TransmissionData))
!= IOX2_OK) {
Expand All @@ -60,13 +57,10 @@ int main(void) {
}

// set pub sub user header type
// user_header_type_name is equivalent to the user header type name used on the Rust side and was determined with
// `core::any::type_name::<CustomHeader>()`
const char* user_header_type_name = "examples_common::custom_header::CustomHeader";
if (iox2_service_builder_pub_sub_set_user_header_type_details(&service_builder_pub_sub,
iox2_type_variant_e_FIXED_SIZE,
user_header_type_name,
strlen(user_header_type_name),
IOX2_USER_HEADER_TYPE_NAME,
strlen(IOX2_USER_HEADER_TYPE_NAME),
sizeof(struct CustomHeader),
alignof(struct CustomHeader))
!= IOX2_OK) {
Expand Down
27 changes: 10 additions & 17 deletions examples/cxx/publish_subscribe_cross_language/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,41 +74,34 @@ To communicate with each other, publisher and subscriber applications must share
the same service configuration, including the payload and the user header type
name.

The internally derived type names usually depend on the used programming
language. To allow cross-language communication involving C++ applications,
iceoryx2 provides the possibility to customize the payload and the user header
type name by setting `IOX2_TYPE_NAME` in the sent C++ data struct and user
header, e.g.
To allow cross-language communication involving C++ applications, iceoryx2
provides the possibility to customize the payload and the user header type name
by setting `IOX2_TYPE_NAME` in the sent C++ data struct and user header, e.g.

```cxx
struct TransmissionData {
static constexpr const char* IOX2_TYPE_NAME = "examples_common::transmission_data::TransmissionData";
static constexpr const char* IOX2_TYPE_NAME = "TransmissionData";
std::int32_t x;
std::int32_t y;
double funky;
};

struct CustomHeader {
static constexpr const char* IOX2_TYPE_NAME = "examples_common::custom_header::CustomHeader";
static constexpr const char* IOX2_TYPE_NAME = "CustomHeader";
int32_t version;
uint64_t timestamp;
};
```

> [!NOTE]
> The type name can't currently be set for Rust applications. If you want to
> communicate with Rust applications, you can determine the type names on the
> Rust side with `core::any::type_name()` and use these as the type names in C++
> applications.
>
> For the C++ types (u)int{8|16|32|64}_t, float, double and bool, you don't need
> to provide `IOX2_TYPE_NAME` for the payload as these types are automatically
> translated into the Rust equivalents.

When the type names are set to the same value, and the structure has the same
memory layout, the C++ applications and applications written in other supported
languages can communicate.

> [!NOTE]
> For the communication with Rust applications, you don't need to provide
> `IOX2_TYPE_NAME` for (u)int{8|16|32|64}_t, float, double and bool payloads.
> These types are automatically translated into the Rust equivalents.

You can also send dynamic data between C++ and Rust applications (see
[Publish-Subscribe With Dynamic Data](../publish_subscribe_dynamic_data)). If
you send `iox::Slice`s of (u)int{8|16|32|64}_t, float, double or bool, the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@
#include <iostream>

struct TransmissionData {
// IOX2_TYPE_NAME is equivalent to the payload type name used on the Rust side and was determined with
// `core::any::type_name::<TransmissionData>()`
static constexpr const char* IOX2_TYPE_NAME = "examples_common::transmission_data::TransmissionData";
// IOX2_TYPE_NAME is equivalent to the payload type name used on the Rust side
static constexpr const char* IOX2_TYPE_NAME = "TransmissionData";
std::int32_t x;
std::int32_t y;
double funky;
Expand All @@ -31,9 +30,8 @@ inline auto operator<<(std::ostream& stream, const TransmissionData& value) -> s
}

struct CustomHeader {
// IOX2_TYPE_NAME is equivalent to the user header type name used on the Rust side and was determined with
// `core::any::type_name::<CustomHeader>()`
static constexpr const char* IOX2_TYPE_NAME = "examples_common::custom_header::CustomHeader";
// IOX2_TYPE_NAME is equivalent to the user header type name used on the Rust side
static constexpr const char* IOX2_TYPE_NAME = "CustomHeader";
int32_t version;
uint64_t timestamp;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT

#include "iox/duration.hpp"
#include "iox2/log.hpp"
#include "iox2/node.hpp"
#include "iox2/sample_mut.hpp"
#include "iox2/service_name.hpp"
Expand All @@ -24,6 +25,7 @@ constexpr iox::units::Duration CYCLE_TIME = iox::units::Duration::fromSeconds(1)

auto main() -> int {
using namespace iox2;
set_log_level_from_env_or(LogLevel::Info);
auto node = NodeBuilder().create<ServiceType::Ipc>().expect("successful node creation");

auto service = node.service_builder(ServiceName::create("My/Funk/ServiceName").expect("valid service name"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <iostream>

#include "iox/duration.hpp"
#include "iox2/log.hpp"
#include "iox2/node.hpp"
#include "iox2/service_name.hpp"
#include "iox2/service_type.hpp"
Expand All @@ -22,6 +23,7 @@ constexpr iox::units::Duration CYCLE_TIME = iox::units::Duration::fromSeconds(1)

auto main() -> int {
using namespace iox2;
set_log_level_from_env_or(LogLevel::Info);
auto node = NodeBuilder().create<ServiceType::Ipc>().expect("successful node creation");

auto service = node.service_builder(ServiceName::create("My/Funk/ServiceName").expect("valid service name"))
Expand Down
8 changes: 7 additions & 1 deletion examples/rust/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,11 @@ load("@rules_rust//rust:defs.bzl", "rust_library")
rust_library(
name = "examples-common",
srcs = glob(["_examples_common/**/*.rs"]),
deps = ["//iceoryx2:iceoryx2"],
deps = [
"//iceoryx2:iceoryx2",
"//iceoryx2-bb/elementary:iceoryx2-bb-elementary",
],
proc_macro_deps = [
"//iceoryx2-bb/derive-macros:iceoryx2-bb-derive-macros",
],
)
6 changes: 5 additions & 1 deletion examples/rust/_examples_common/custom_header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
//
// SPDX-License-Identifier: Apache-2.0 OR MIT

#[derive(Default, Debug)]
use iceoryx2::prelude::*;

#[derive(Default, Debug, ZeroCopySend)]
// optional type name; if not set, `core::any::type_name::<CustomHeader>()` is used
#[type_name("CustomHeader")]
#[repr(C)]
pub struct CustomHeader {
pub version: i32,
Expand Down
6 changes: 5 additions & 1 deletion examples/rust/_examples_common/transmission_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
//
// SPDX-License-Identifier: Apache-2.0 OR MIT

#[derive(Debug)]
use iceoryx2::prelude::*;

#[derive(Debug, ZeroCopySend)]
// optional type name; if not set, `core::any::type_name::<TransmissionData>()` is used
#[type_name("TransmissionData")]
#[repr(C)]
pub struct TransmissionData {
pub x: i32,
Expand Down
4 changes: 4 additions & 0 deletions examples/rust/complex_data_types/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,9 @@ rust_binary(
deps = [
"//iceoryx2:iceoryx2",
"//iceoryx2-bb/container:iceoryx2-bb-container",
"//iceoryx2-bb/elementary:iceoryx2-bb-elementary",
],
proc_macro_deps = [
"//iceoryx2-bb/derive-macros:iceoryx2-bb-derive-macros",
],
)
4 changes: 2 additions & 2 deletions examples/rust/complex_data_types/complex_data_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use iceoryx2_bb_container::{

// For both data types we derive from PlacementDefault to allow in memory initialization
// without any copy. Avoids stack overflows when data type is larger than the available stack.
#[derive(Debug, Default, PlacementDefault)]
#[derive(Debug, Default, PlacementDefault, ZeroCopySend)]
#[repr(C)]
pub struct ComplexData {
name: FixedSizeByteString<4>,
Expand All @@ -28,7 +28,7 @@ pub struct ComplexData {

// For both data types we derive from PlacementDefault to allow in memory initialization
// without any copy. Avoids stack overflows when data type is larger than the available stack.
#[derive(Debug, Default, PlacementDefault)]
#[derive(Debug, Default, PlacementDefault, ZeroCopySend)]
#[repr(C)]
pub struct ComplexDataType {
plain_old_data: u64,
Expand Down
Loading