# user-header

## Introduction

This example demonstrates how to leverage the user-header to send custom meta-information with each sample.
Specifically, we want to send a timestamp alongside the sample.
The example contains code for the typed and untyped C++ API as well as for the C language binding.

## Expected Output

[![asciicast](https://asciinema.org/a/410691.svg)](https://asciinema.org/a/410691)

## Code walkthrough

The examples uses the user-header and user-payload which is defined in `user_header_and_payload_types.hpp`
for the C++ API and in `user_header_and_payload_types.h` for the C API. The user-header consists of a simple `uint64_t`
which is used to transmit a timestamp and the user-payload is a Fibonacci number.

This are the definitions for the C++ API:

```cpp
struct Header
{
    uint64_t publisherTimestamp{0};
};
```


```cpp
struct Data
{
    uint64_t fibonacci{0};
};
```

This are the definitions for the C API:

```c
typedef struct
{
    uint64_t publisherTimestamp;
} Header;
```


```c
typedef struct
{
    uint64_t fibonacci;
} Data;
```

### Publisher Typed C++ API

At first, there are includes for the user-header and user-payload types
and the iceoryx includes for publisher and runtime.

```cpp
#include "user_header_and_payload_types.hpp"

#include "iceoryx_hoofs/posix_wrapper/signal_watcher.hpp"
#include "iceoryx_posh/popo/publisher.hpp"
#include "iceoryx_posh/runtime/posh_runtime.hpp"
```

Next, the iceoryx runtime is initialized. With this call, the application will be registered at `RouDi`,
the routing and discovery daemon.

```cpp
constexpr char APP_NAME[] = "iox-cpp-user-header-publisher";
iox::runtime::PoshRuntime::initRuntime(APP_NAME);
```

Now, we create the publisher. Unlike the other examples, this uses the second template parameter to define the user-header.
This is the only change compared to the other examples with the typed C++ API.

```cpp
iox::popo::Publisher<Data, Header> publisher({"Example", "User-Header", "Timestamp"});
```

In the main loop, a Fibonacci sequence is created and every second a number is published.
The Fibonacci number is passed to the `loan` method which construct the `Data` object if the loaning was successful.
This example uses the functional approach with `and_then` and `or_else`. Please have a look at the `icehello` example
if you prefer a more traditional approach.

```cpp
uint64_t timestamp = 42;
uint64_t fibonacciLast = 0;
uint64_t fibonacciCurrent = 1;
while (!iox::posix::hasTerminationRequested())
{
    auto fibonacciNext = fibonacciCurrent + fibonacciLast;
    fibonacciLast = fibonacciCurrent;
    fibonacciCurrent = fibonacciNext;

    publisher.loan(Data{fibonacciCurrent})
        .and_then([&](auto& sample) {
            // ...
        })
        .or_else([&](auto& error) {
            // ...
        });

    constexpr uint64_t MILLISECONDS_SLEEP{1000U};
    std::this_thread::sleep_for(std::chrono::milliseconds(MILLISECONDS_SLEEP));
    timestamp += MILLISECONDS_SLEEP;
}
```

When the loaning was successful, we get a sample and can access it in the `and_then` branch.
The sample has a `getUserHeader` method which returns a reference to the user-header we specified with the template parameter.
In this case it's the `Header` struct and we set the `publisherTimestamp`.

```cpp
sample.getUserHeader().publisherTimestamp = timestamp;
sample.publish();

std::cout << APP_NAME << " sent data: " << fibonacciCurrent << " with timestamp " << timestamp << "ms"
          << std::endl;
```

If the loaning fails, the `or_else` branch is executed, which prints an error message

```cpp
std::cout << APP_NAME << " could not loan sample! Error code: " << error << std::endl;
```

### Publisher Untyped C++ API

The example with the untyped C++ publisher is quite similar to the one with the typed publisher.
The few differences will be discussed in this section.

At first there is a different include

```cpp
#include "iceoryx_posh/popo/untyped_publisher.hpp"
```

When the publisher is created, there is also no notion of a user-header and it looks exactly the same like already shown in other examples.

```cpp
iox::popo::UntypedPublisher publisher({"Example", "User-Header", "Timestamp"});
```

Variations come again into play when the chunk is loaned. Since the API is untyped,
the parameter for the user-header have to be provided with the `loan` call. These are optional parameter and
are set to values indicating no user-header by default.

```cpp
publisher.loan(sizeof(Data), alignof(Data), sizeof(Header), alignof(Header))
    .and_then([&](auto& userPayload) {
        // ...
    })
    .or_else([&](auto& error) {
        // ...
    });
```

Lastly, since the untyped C++ API returns a `void` pointer to the user-payload, there is an intermediate step
to access the user-header by obtaining a `ChunkHeader` first, which provides a method to get the user-header.
This also return a `void` pointer, which makes a cast to the actual type necessary.

```cpp
auto header = static_cast<Header*>(iox::mepoo::ChunkHeader::fromUserPayload(userPayload)->userHeader());
header->publisherTimestamp = timestamp;

auto data = static_cast<Data*>(userPayload);
data->fibonacci = fibonacciCurrent;

publisher.publish(userPayload);

std::cout << APP_NAME << " sent data: " << fibonacciCurrent << " with timestamp " << timestamp << "ms"
          << std::endl;
```

### Publisher C API

The example for the C API is similar to the one in `icedelivery_in_c` and therefore only the user-header related parts are looked into.
The overall structure is the same like in the typed and untyped C++ API counterparts.

The functions to access the user-header are located in the following include

```cpp
#include "iceoryx_binding_c/chunk.h"
```

Similar to the untyped C++ API, the user-header parameter are specified with the loan function.
Since C does not have overloading, this is done by a different function

```cpp
void* userPayload;
const uint32_t ALIGNMENT = 8;
enum iox_AllocationResult res = iox_pub_loan_aligned_chunk_with_user_header(
    publisher, &userPayload, sizeof(Data), ALIGNMENT, sizeof(Header), ALIGNMENT);
```

Like with the untyped C++ API, the path to the user-header needs an intermediate step with the `iox_chunk_header_t` and
explicit casting to since the functions return `void` pointer.

```cpp
iox_chunk_header_t* chunkHeader = iox_chunk_header_from_user_payload(userPayload);
Header* header = (Header*)iox_chunk_header_to_user_header(chunkHeader);
header->publisherTimestamp = timestamp;

Data* data = (Data*)userPayload;
data->fibonacci = fibonacciCurrent;

iox_pub_publish_chunk(publisher, userPayload);

// explicit cast to unsigned long since on macOS an uint64_t is a different built-in type than on Linux
printf("%s sent data: %lu with timestamp %ldms\n",
       APP_NAME,
       (unsigned long)fibonacciCurrent,
       (unsigned long)timestamp);
fflush(stdout);
```

### Subscriber Typed C++ API

The boilerplate code for the subscriber is the same like for the publisher, therefore only the specific subscriber code is discussed in this section.

To use the subscriber, `subscriber.hpp` needs to be included.
Similar to the publisher, the subscriber requires the same additional template parameter when
it is used with a user header.

```cpp
iox::popo::Subscriber<Data, Header> subscriber({"Example", "User-Header", "Timestamp"});
```

The main loop is quite simple. The publisher is periodically polled and the data of the received sample is printed.
Again, the user-header is accessed by the `getUserHeader` method of the sample.

```cpp
while (!iox::posix::hasTerminationRequested())
{
    subscriber.take().and_then([&](auto& sample) {
        std::cout << APP_NAME << " got value: " << sample->fibonacci << " with timestamp "
                  << sample.getUserHeader().publisherTimestamp << "ms" << std::endl;
    });

    constexpr std::chrono::milliseconds SLEEP_TIME{100U};
    std::this_thread::sleep_for(SLEEP_TIME);
}
```

### Subscriber Untyped C++ API

On the subscriber side, the typed and untyped examples are even closer in similarity than the publisher example.
The notable difference is the `take` method, which returns a `void` pointer to the user-payload.
Like with the untyped publisher, in order to get the user-header the `ChunkHeader` must be obtained.
Contrary to the untyped publisher, we must cast to a `const T*` type, like `const Header*`
since we are not allowed to mutate the header from a subscriber.
At the end, the chunk must be released to prevent chunk leaks. This is done by calling the `release` method with user-payload pointer.

```cpp
subscriber.take().and_then([&](auto& userPayload) {
    auto header =
        static_cast<const Header*>(iox::mepoo::ChunkHeader::fromUserPayload(userPayload)->userHeader());

    auto data = static_cast<const Data*>(userPayload);

    std::cout << APP_NAME << " got value: " << data->fibonacci << " with timestamp "
              << header->publisherTimestamp << "ms" << std::endl;

    subscriber.release(userPayload);
});
```

### Subscriber C API

Finally there is the C API example. Like with the publisher example for the C API we just take a look at the user-header specific parts.
The overall structure is the same like in the typed and untyped C++ API counterparts.

As we already have seen with the untyped C++ example, the call to take the sample is independent of the usage of a user-header.
Likewise, the access to the user-header is done by the intermediate step of getting an `iox_chunk_header_t` first.
Since we are not allowed to mutate the user-header from a subscriber, the respective functions with a `_const` suffix must be used.
At last, the chunk is released in order to prevent chunk leaks.

```cpp
const void* userPayload;
if (iox_sub_take_chunk(subscriber, &userPayload) == ChunkReceiveResult_SUCCESS)
{
    const iox_chunk_header_t* chunkHeader = iox_chunk_header_from_user_payload_const(userPayload);
    const Header* header = (const Header*)(iox_chunk_header_to_user_header_const(chunkHeader));

    const Data* data = (const Data*)userPayload;

    // explicit cast to unsigned long since on macOS an uint64_t is a different built-in type than on Linux
    printf("%s got value: %lu with timestamp %ldms\n",
           APP_NAME,
           (unsigned long)data->fibonacci,
           (unsigned long)header->publisherTimestamp);
    fflush(stdout);

    iox_sub_release_chunk(subscriber, userPayload);
}
```

[Check out User-Header on GitHub :fontawesome-brands-github:](https://github.com/eclipse-iceoryx/iceoryx/tree/v2.0.0/iceoryx_examples/user_header){ .md-button }

