Skip to content

Commit 55beca2

Browse files
authored
Standard input/output support 4: C++ SDK stdout impl/examples/docs (#4514)
Allow the C++ SDK to stream RRD data to stdout. Checks: - [x] `just py-build && just cpp-build-examples && echo 'hello from stdin!' | ./build/debug/examples/cpp/stdio/example_stdio | rerun -` --- Part of a small PR series to add stdio streaming support to our Viewer and SDKs: - #4511 - #4512 - #4513 - #4514
1 parent da466ee commit 55beca2

File tree

11 files changed

+145
-2
lines changed

11 files changed

+145
-2
lines changed

crates/rerun_c/src/lib.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ pub enum CErrorCode {
161161
_CategoryRecordingStream = 0x0000_00100,
162162
RecordingStreamCreationFailure,
163163
RecordingStreamSaveFailure,
164+
RecordingStreamStdoutFailure,
164165
// TODO(cmc): Really this should be its own category…
165166
RecordingStreamSpawnFailure,
166167

@@ -468,6 +469,24 @@ pub extern "C" fn rr_recording_stream_save(
468469
}
469470
}
470471

472+
#[allow(clippy::result_large_err)]
473+
fn rr_recording_stream_stdout_impl(stream: CRecordingStream) -> Result<(), CError> {
474+
recording_stream(stream)?.stdout().map_err(|err| {
475+
CError::new(
476+
CErrorCode::RecordingStreamStdoutFailure,
477+
&format!("Failed to forward recording stream to stdout: {err}"),
478+
)
479+
})
480+
}
481+
482+
#[allow(unsafe_code)]
483+
#[no_mangle]
484+
pub extern "C" fn rr_recording_stream_stdout(id: CRecordingStream, error: *mut CError) {
485+
if let Err(err) = rr_recording_stream_stdout_impl(id) {
486+
err.write_error(error);
487+
}
488+
}
489+
471490
#[allow(clippy::result_large_err)]
472491
fn rr_recording_stream_set_time_sequence_impl(
473492
stream: CRecordingStream,

crates/rerun_c/src/rerun.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ enum {
198198
_RR_ERROR_CODE_CATEGORY_RECORDING_STREAM = 0x000000100,
199199
RR_ERROR_CODE_RECORDING_STREAM_CREATION_FAILURE,
200200
RR_ERROR_CODE_RECORDING_STREAM_SAVE_FAILURE,
201+
RR_ERROR_CODE_RECORDING_STREAM_STDOUT_FAILURE,
201202
RR_ERROR_CODE_RECORDING_STREAM_SPAWN_FAILURE,
202203

203204
// Arrow data processing errors.
@@ -333,6 +334,16 @@ extern void rr_recording_stream_spawn(
333334
/// This function returns immediately.
334335
extern void rr_recording_stream_save(rr_recording_stream stream, rr_string path, rr_error* error);
335336

337+
/// Stream all log-data to stdout.
338+
///
339+
/// Pipe the result into the Rerun Viewer to visualize it.
340+
///
341+
/// If there isn't any listener at the other end of the pipe, the `RecordingStream` will
342+
/// default back to `buffered` mode, in order not to break the user's terminal.
343+
///
344+
/// This function returns immediately.
345+
extern void rr_recording_stream_stdout(rr_recording_stream stream, rr_error* error);
346+
336347
/// Initiates a flush the batching pipeline and waits for it to propagate.
337348
///
338349
/// See `rr_recording_stream` docs for ordering semantics and multithreading guarantees.

docs/content/reference/sdk-operating-modes.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,12 @@ Use [`RecordingStream::save`](https://docs.rs/rerun/latest/rerun/struct.Recordin
8080

8181
Streams all logging data to standard output, which can then be loaded by the Rerun Viewer by streaming it from standard input.
8282

83+
#### C++
84+
85+
Use [`RecordingStream::stdout`](https://ref.rerun.io/docs/cpp/stable/classrerun_1_1RecordingStream.html#SOMEHASH?speculative-link).
86+
87+
Check out our [dedicated example](https://github.com/rerun-io/rerun/tree/latest/examples/cpp/stdio/main.cpp?speculative-link).
88+
8389
#### Python
8490

8591
Use [`rr.stdout`](https://ref.rerun.io/docs/python/stable/common/initialization_functions/#rerun.stdout?speculative-link).

examples/cpp/CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
add_subdirectory(clock)
22
add_subdirectory(custom_collection_adapter)
33
add_subdirectory(dna)
4-
add_subdirectory(shared_recording)
54
add_subdirectory(minimal)
5+
add_subdirectory(shared_recording)
66
add_subdirectory(spawn_viewer)
7+
add_subdirectory(stdio)
78

89
add_custom_target(examples)
910

1011
add_dependencies(examples example_clock)
1112
add_dependencies(examples example_custom_collection_adapter)
1213
add_dependencies(examples example_dna)
13-
add_dependencies(examples example_shared_recording)
1414
add_dependencies(examples example_minimal)
15+
add_dependencies(examples example_shared_recording)
1516
add_dependencies(examples example_spawn_viewer)
17+
add_dependencies(examples example_stdio)

examples/cpp/stdio/CMakeLists.txt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
cmake_minimum_required(VERSION 3.16...3.27)
2+
3+
# If you use the example outside of the Rerun SDK you need to specify
4+
# where the rerun_c build is to be found by setting the `RERUN_CPP_URL` variable.
5+
# This can be done by passing `-DRERUN_CPP_URL=<path to rerun_sdk_cpp zip>` to cmake.
6+
if(DEFINED RERUN_REPOSITORY)
7+
add_executable(example_stdio main.cpp)
8+
rerun_strict_warning_settings(example_stdio)
9+
else()
10+
project(example_stdio LANGUAGES CXX)
11+
12+
add_executable(example_stdio main.cpp)
13+
14+
# Set the path to the rerun_c build.
15+
set(RERUN_CPP_URL "https://github.com/rerun-io/rerun/releases/latest/download/rerun_cpp_sdk.zip" CACHE STRING "URL to the rerun_cpp zip.")
16+
option(RERUN_FIND_PACKAGE "Whether to use find_package to find a preinstalled rerun package (instead of using FetchContent)." OFF)
17+
18+
if(RERUN_FIND_PACKAGE)
19+
find_package(rerun_sdk REQUIRED)
20+
else()
21+
# Download the rerun_sdk
22+
include(FetchContent)
23+
FetchContent_Declare(rerun_sdk URL ${RERUN_CPP_URL})
24+
FetchContent_MakeAvailable(rerun_sdk)
25+
endif()
26+
27+
# Rerun requires at least C++17, but it should be compatible with newer versions.
28+
set_property(TARGET example_stdio PROPERTY CXX_STANDARD 17)
29+
endif()
30+
31+
# Link against rerun_sdk.
32+
target_link_libraries(example_stdio PRIVATE rerun_sdk)

examples/cpp/stdio/README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
title: Standard Input/Output example
3+
python: https://github.com/rerun-io/rerun/tree/latest/examples/python/stdio/main.py?speculative-link
4+
rust: https://github.com/rerun-io/rerun/tree/latest/examples/rust/stdio/src/main.rs?speculative-link
5+
cpp: https://github.com/rerun-io/rerun/tree/latest/examples/cpp/stdio/main.cpp?speculative-link
6+
thumbnail: https://static.rerun.io/stdio/25c5aba992d4c8b3861386d8d9539a4823dca117/480w.png
7+
---
8+
9+
<picture>
10+
<img src="https://static.rerun.io/stdio/25c5aba992d4c8b3861386d8d9539a4823dca117/full.png" alt="">
11+
<source media="(max-width: 480px)" srcset="https://static.rerun.io/stdio/25c5aba992d4c8b3861386d8d9539a4823dca117/480w.png">
12+
<source media="(max-width: 768px)" srcset="https://static.rerun.io/stdio/25c5aba992d4c8b3861386d8d9539a4823dca117/768w.png">
13+
<source media="(max-width: 1024px)" srcset="https://static.rerun.io/stdio/25c5aba992d4c8b3861386d8d9539a4823dca117/1024w.png">
14+
<source media="(max-width: 1200px)" srcset="https://static.rerun.io/stdio/25c5aba992d4c8b3861386d8d9539a4823dca117/1200w.png">
15+
</picture>
16+
17+
Demonstrates how to log data to standard output with the Rerun SDK, and then visualize it from standard input with the Rerun Viewer.
18+
19+
To build it from a checkout of the repository (requires a Rust toolchain):
20+
```bash
21+
cmake .
22+
cmake --build . --target example_stdio
23+
echo 'hello from stdin!' | ./examples/cpp/stdio/example_stdio | rerun -
24+
```

examples/cpp/stdio/main.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <iostream>
2+
#include <string>
3+
4+
#include <rerun.hpp>
5+
6+
int main() {
7+
const auto rec = rerun::RecordingStream("rerun_example_stdio");
8+
rec.to_stdout().exit_on_failure();
9+
10+
std::string input;
11+
std::string line;
12+
while (std::getline(std::cin, line)) {
13+
input += line + '\n';
14+
}
15+
16+
rec.log("stdin", rerun::TextDocument(input));
17+
}

rerun_cpp/src/rerun/c/rerun.h

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rerun_cpp/src/rerun/error.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ namespace rerun {
4545
_CategoryRecordingStream = 0x0000'0100,
4646
RecordingStreamCreationFailure,
4747
RecordingStreamSaveFailure,
48+
RecordingStreamStdoutFailure,
4849
RecordingStreamSpawnFailure,
4950

5051
// Arrow data processing errors.

rerun_cpp/src/rerun/recording_stream.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@ namespace rerun {
128128
return status;
129129
}
130130

131+
Error RecordingStream::to_stdout() const {
132+
rr_error status = {};
133+
rr_recording_stream_stdout(_id, &status);
134+
return status;
135+
}
136+
131137
void RecordingStream::flush_blocking() const {
132138
rr_recording_stream_flush_blocking(_id);
133139
}

0 commit comments

Comments
 (0)