Skip to content

Commit 5e02ca5

Browse files
iox-eclipse-iceoryx#743 Add autolink plugin for MkDocs and move images into one folder
Signed-off-by: Simon Hoinkis <simon.hoinkis@apex.ai>
1 parent ce2272a commit 5e02ca5

27 files changed

+1549
-16
lines changed

doc/design/request_response_communication.md

+9-9
Original file line numberDiff line numberDiff line change
@@ -40,34 +40,34 @@ In order to support asynchronous requests, a sequence ID should be part of each
4040

4141
This is an overview of the untyped `Client` and `Server` classes.
4242

43-
![simple class diagram](diagrams/request_response/overview_class.svg)
43+
![simple class diagram](overview_class.svg)
4444

4545
The `Client` and `Server` are reusing the `ChunkSender` and `ChunkReceiver` building blocks. The `Client` uses a `ChunkSender` to send requests and a `ChunkReceiver` to get the responses while the `Server` uses a `ChunkReceiver` to get the requests and a `ChunkSender` to send the responses.
4646

4747
#### Typed API
4848

49-
![typed API](diagrams/request_response/typed_api.svg)
49+
![typed API](typed_api.svg)
5050

5151
Since the `Response` is tied to a specific `Request`, the `loan` method takes a `Request` to populate the `Response` with the correct settings.
5252
Alternatively, a `Request` could have a `createResponse` method which returns a `Response` with the correct settings.
5353

5454
#### Untyped API
5555

56-
![untyped API](diagrams/request_response/untyped_api.svg)
56+
![untyped API](untyped_api.svg)
5757

5858
Similar to the the typed API, `loan` takes a pointer to a `RequestHeader` to populate the `ResponseHeader` with the correct settings.
5959

6060
#### Client Port
6161

62-
![client port](diagrams/request_response/client_port.svg)
62+
![client port](client_port.svg)
6363

6464
The `ClientPortData` is located in the shared memory and contain only the data but no methods to access them.
6565
`ClientPortUser` is the class providing the methods for the user access and `ClientPortRouDi` provides the
6666
interface RouDi needs to connect the client to the server and to cleanup the port resources.
6767

6868
#### Server Port
6969

70-
![server port](diagrams/request_response/server_port.svg)
70+
![server port](server_port.svg)
7171

7272
Similar to the Client Port, the Server Port has `ServerPortData` which is located in the shared memory and contain only the data but no methods to access them.
7373
`ServerPortUser` is the class providing the methods for the user access and `ServerPortRouDi` provides the
@@ -77,7 +77,7 @@ It must be ensured that only one server with a given `ServiceDescription` can ru
7777

7878
#### Request/Response Header
7979

80-
![rpc header](diagrams/request_response/request_response_header.svg)
80+
![rpc header](request_response_header.svg)
8181

8282
Since request and response need to encode different meta-information, we also need different header for the messages.
8383
The common data is aggregated in `RpcBaseHeader` which contains a `cxx::UniqueId` to the `ClientChunkQueueData_t` and a sequence ID.
@@ -101,7 +101,7 @@ The `RequestHeader` has also the option to specify a message as fire and forget,
101101
102102
#### Client/Server Options
103103
104-
![client and server options](diagrams/request_response/client_and_server_options.svg)
104+
![client and server options](client_and_server_options.svg)
105105
106106
The client and server options can be used to control certain aspects of the clients and servers.
107107
Beside setting the capacity of the queues and defining whether a client should be connected and a server offering on creation,
@@ -114,14 +114,14 @@ If the options don't match, the client will not be connected to the server, simi
114114
115115
The client is guided by the following state machine.
116116
117-
![client state machine](diagrams/request_response/client_state_machine.svg)
117+
![client state machine](client_state_machine.svg)
118118
119119
Similar to the subscriber state machine, the client passes it's response queue with the `CONNECT` CaPro message to the server.
120120
The server will pass its request queue with the `ACK` CaPro message to the client.
121121
122122
Following is a sequence diagram which shows all this cases
123123
124-
![client and server service discovery](diagrams/request_response/client_and_server_service_discovery.svg)
124+
![client and server service discovery](client_and_server_service_discovery.svg)
125125
126126
### Code example
127127

doc/design/service-discovery.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,9 @@ Contra:
128128
* Built-in topic approach based on `InterfacePort`'s
129129
* Sniff and intercept `CaproMessage`
130130

131-
![overview diagram](diagrams/service-discovery/overview-alternative-b.svg)
131+
![overview diagram](overview-alternative-b.svg)
132132

133-
![sequence diagram](diagrams/service-discovery/sequence-diagram-alternative-b.svg)
133+
![sequence diagram](sequence-diagram-alternative-b.svg)
134134

135135
Pro:
136136

@@ -172,9 +172,9 @@ Create a new publisher in RouDi which sends a `ServiceRegistryTopic`. This publi
172172
change in the service registry and to transmit the service discovery registry. The complete old service registry
173173
(saved locally) would be compared to the new service registry in a new class, extending the public user API.
174174

175-
![overview diagram](diagrams/service-discovery/overview-alternative-d.svg)
175+
![overview diagram](overview-alternative-d.svg)
176176

177-
![sequence diagram](diagrams/service-discovery/sequence-diagram-alternative-d.svg)
177+
![sequence diagram](sequence-diagram-alternative-d.svg)
178178

179179
Pro:
180180

@@ -416,5 +416,5 @@ PoshRuntime::findService(const capro::ServiceDescription& serviceDescription) no
416416
* [x] How does the SOME/IP-SD service discovery API look like?
417417
* [x] What does a `ros topic list` do in rmw_iceoryx?
418418
* [ ] Filter for `ServiceDescription::EventString` needed by AUTOSAR? Not supported by `ServiceRegistry::find()` as of today
419-
* [ ] Decision on mapping table between iceory and DDS (see [overview.md](../website/getting-started/overview.md))
419+
* [ ] Decision on mapping table between iceory and DDS (see [Overview](overview.md))
420420
* [ ] Current mapping table between iceoryx and DDS does not work with service discovery
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# How optional and error values are returned in iceoryx
2+
3+
Many parts of the iceoryx C++ API follow a functional programming approach and allow the user to specify functions
4+
which handle the possible cases, e.g. what should happen when data is received.
5+
6+
This is very flexible but requires using the monadic types `cxx::expected` and `cxx::optional`, which we
7+
introduce in the following sections.
8+
9+
## Optional
10+
11+
The type `iox::cxx::optional<T>` is used to indicate that there may or may not be a value of a specific type `T`
12+
available. This is essentially the 'maybe [monad](https://en.wikipedia.org/wiki/Monad_(functional_programming))' in
13+
functional programming. Assuming we have some optional (usually the result of some computation)
14+
15+
```cpp
16+
optional<int> result = someComputation();
17+
```
18+
19+
we can check for its value using
20+
21+
```cpp
22+
if(result.has_value())
23+
{
24+
auto value = result.value();
25+
// do something with the value
26+
}
27+
else
28+
{
29+
// handle the case that there is no value
30+
}
31+
```
32+
33+
A shorthand to get the value is
34+
35+
```cpp
36+
auto value = *result;
37+
```
38+
39+
!!! attention
40+
Accessing the value if there is no value terminates the application, so it must be checked beforehand.
41+
42+
We can achieve the same with the functional approach by providing a function for both cases.
43+
44+
```cpp
45+
result.and_then([](int& value) { /*do something with the value*/ })
46+
.or_else([]() { /*handle the case that there is no value*/ });
47+
```
48+
49+
Notice that we get the value by reference, so if a copy is desired it has to be created explicitly in the
50+
[lambda](https://en.wikipedia.org/wiki/Anonymous_function#C++_(since_C++11)) or function we pass.
51+
52+
The optional can be initialized from a value directly
53+
54+
```cpp
55+
optional<int> result = 73;
56+
result = 37;
57+
```
58+
59+
If the optional is default initialized, it is automatically set to its null value of type `iox::cxx::nullopt_t`.
60+
This can be also done directly by using the constant `iox::cxx::nullopt`
61+
62+
```cpp
63+
result = iox::cxx::nullopt;
64+
```
65+
66+
For a complete list of available functions see
67+
[`optional.hpp`](https://github.com/eclipse-iceoryx/iceoryx/blob/master/iceoryx_hoofs/include/iceoryx_hoofs/cxx/optional.hpp).
68+
The `iox::cxx::optional` behaves like the [`std::optional`](https://en.cppreference.com/w/cpp/utility/optional)
69+
except that it does not throw exceptions and has no undefined behavior.
70+
71+
## Expected
72+
73+
`iox::cxx::expected<T, E>` generalizes `iox::cxx::optional` by admitting a value of another type `E` instead of
74+
no value at all, i.e. it contains either a value of type `T` or `E`. In this way, `expected` is a special case of
75+
the 'either monad'. It is usually used to pass a value of type `T` or an error that may have occurred, i.e. `E` is the
76+
error type.
77+
78+
For more information on how it is used for error handling see
79+
[error-handling.md](https://github.com/eclipse-iceoryx/iceoryx/blob/master/doc/design/error-handling.md).
80+
81+
Assume we have `E` as an error type, then we can create a value
82+
83+
```cpp
84+
iox::cxx::expected<int, E> result(iox::cxx::success<int>(73));
85+
```
86+
87+
and use the value or handle a potential error
88+
89+
```cpp
90+
if (!result.has_error())
91+
{
92+
auto value = result.value();
93+
// do something with the value
94+
}
95+
else
96+
{
97+
auto error = result.get_error();
98+
// handle the error
99+
}
100+
```
101+
102+
If we need an error value, we set
103+
104+
```cpp
105+
result = iox::cxx::error<E>(errorCode);
106+
```
107+
108+
which assumes that `E` can be constructed from an `errorCode`.
109+
110+
We again can employ a functional approach like this:
111+
112+
```cpp
113+
auto handleValue = [](int& value) { /*do something with the value*/ };
114+
auto handleError = [](E& value) { /*handle the error*/ };
115+
result.and_then(handleValue).or_else(handleError);
116+
```
117+
118+
There are more convenience functions such as `value_or` which provides the value or an alternative specified by the
119+
user. These can be found in
120+
[`expected.hpp`](https://github.com/eclipse-iceoryx/iceoryx/blob/master/iceoryx_hoofs/include/iceoryx_hoofs/cxx/expected.hpp).
121+
122+
Note that when we move an `expected`, the origin contains a moved `T` or `E`, depending on the content before the move.
123+
This mirrors the behavior of moving the content out of the `iox::cxx::expected` like with
124+
`auto foo = std::move(bar.value());` with `bar` being an `iox::cxx::expected`.
125+
Like all objects, `T` and `E` must therefore be in a well defined state after the move.

0 commit comments

Comments
 (0)