Skip to content

Commit

Permalink
Standard input/output support 4: C++ SDK stdout impl/examples/docs (#…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
teh-cmc authored Dec 14, 2023
1 parent da466ee commit 55beca2
Show file tree
Hide file tree
Showing 11 changed files with 145 additions and 2 deletions.
19 changes: 19 additions & 0 deletions crates/rerun_c/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ pub enum CErrorCode {
_CategoryRecordingStream = 0x0000_00100,
RecordingStreamCreationFailure,
RecordingStreamSaveFailure,
RecordingStreamStdoutFailure,
// TODO(cmc): Really this should be its own category…
RecordingStreamSpawnFailure,

Expand Down Expand Up @@ -468,6 +469,24 @@ pub extern "C" fn rr_recording_stream_save(
}
}

#[allow(clippy::result_large_err)]
fn rr_recording_stream_stdout_impl(stream: CRecordingStream) -> Result<(), CError> {
recording_stream(stream)?.stdout().map_err(|err| {
CError::new(
CErrorCode::RecordingStreamStdoutFailure,
&format!("Failed to forward recording stream to stdout: {err}"),
)
})
}

#[allow(unsafe_code)]
#[no_mangle]
pub extern "C" fn rr_recording_stream_stdout(id: CRecordingStream, error: *mut CError) {
if let Err(err) = rr_recording_stream_stdout_impl(id) {
err.write_error(error);
}
}

#[allow(clippy::result_large_err)]
fn rr_recording_stream_set_time_sequence_impl(
stream: CRecordingStream,
Expand Down
11 changes: 11 additions & 0 deletions crates/rerun_c/src/rerun.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ enum {
_RR_ERROR_CODE_CATEGORY_RECORDING_STREAM = 0x000000100,
RR_ERROR_CODE_RECORDING_STREAM_CREATION_FAILURE,
RR_ERROR_CODE_RECORDING_STREAM_SAVE_FAILURE,
RR_ERROR_CODE_RECORDING_STREAM_STDOUT_FAILURE,
RR_ERROR_CODE_RECORDING_STREAM_SPAWN_FAILURE,

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

/// Stream all log-data to stdout.
///
/// Pipe the result into the Rerun Viewer to visualize it.
///
/// If there isn't any listener at the other end of the pipe, the `RecordingStream` will
/// default back to `buffered` mode, in order not to break the user's terminal.
///
/// This function returns immediately.
extern void rr_recording_stream_stdout(rr_recording_stream stream, rr_error* error);

/// Initiates a flush the batching pipeline and waits for it to propagate.
///
/// See `rr_recording_stream` docs for ordering semantics and multithreading guarantees.
Expand Down
6 changes: 6 additions & 0 deletions docs/content/reference/sdk-operating-modes.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ Use [`RecordingStream::save`](https://docs.rs/rerun/latest/rerun/struct.Recordin

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

#### C++

Use [`RecordingStream::stdout`](https://ref.rerun.io/docs/cpp/stable/classrerun_1_1RecordingStream.html#SOMEHASH?speculative-link).

Check out our [dedicated example](https://github.com/rerun-io/rerun/tree/latest/examples/cpp/stdio/main.cpp?speculative-link).

#### Python

Use [`rr.stdout`](https://ref.rerun.io/docs/python/stable/common/initialization_functions/#rerun.stdout?speculative-link).
Expand Down
6 changes: 4 additions & 2 deletions examples/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
add_subdirectory(clock)
add_subdirectory(custom_collection_adapter)
add_subdirectory(dna)
add_subdirectory(shared_recording)
add_subdirectory(minimal)
add_subdirectory(shared_recording)
add_subdirectory(spawn_viewer)
add_subdirectory(stdio)

add_custom_target(examples)

add_dependencies(examples example_clock)
add_dependencies(examples example_custom_collection_adapter)
add_dependencies(examples example_dna)
add_dependencies(examples example_shared_recording)
add_dependencies(examples example_minimal)
add_dependencies(examples example_shared_recording)
add_dependencies(examples example_spawn_viewer)
add_dependencies(examples example_stdio)
32 changes: 32 additions & 0 deletions examples/cpp/stdio/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
cmake_minimum_required(VERSION 3.16...3.27)

# If you use the example outside of the Rerun SDK you need to specify
# where the rerun_c build is to be found by setting the `RERUN_CPP_URL` variable.
# This can be done by passing `-DRERUN_CPP_URL=<path to rerun_sdk_cpp zip>` to cmake.
if(DEFINED RERUN_REPOSITORY)
add_executable(example_stdio main.cpp)
rerun_strict_warning_settings(example_stdio)
else()
project(example_stdio LANGUAGES CXX)

add_executable(example_stdio main.cpp)

# Set the path to the rerun_c build.
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.")
option(RERUN_FIND_PACKAGE "Whether to use find_package to find a preinstalled rerun package (instead of using FetchContent)." OFF)

if(RERUN_FIND_PACKAGE)
find_package(rerun_sdk REQUIRED)
else()
# Download the rerun_sdk
include(FetchContent)
FetchContent_Declare(rerun_sdk URL ${RERUN_CPP_URL})
FetchContent_MakeAvailable(rerun_sdk)
endif()

# Rerun requires at least C++17, but it should be compatible with newer versions.
set_property(TARGET example_stdio PROPERTY CXX_STANDARD 17)
endif()

# Link against rerun_sdk.
target_link_libraries(example_stdio PRIVATE rerun_sdk)
24 changes: 24 additions & 0 deletions examples/cpp/stdio/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
title: Standard Input/Output example
python: https://github.com/rerun-io/rerun/tree/latest/examples/python/stdio/main.py?speculative-link
rust: https://github.com/rerun-io/rerun/tree/latest/examples/rust/stdio/src/main.rs?speculative-link
cpp: https://github.com/rerun-io/rerun/tree/latest/examples/cpp/stdio/main.cpp?speculative-link
thumbnail: https://static.rerun.io/stdio/25c5aba992d4c8b3861386d8d9539a4823dca117/480w.png
---

<picture>
<img src="https://static.rerun.io/stdio/25c5aba992d4c8b3861386d8d9539a4823dca117/full.png" alt="">
<source media="(max-width: 480px)" srcset="https://static.rerun.io/stdio/25c5aba992d4c8b3861386d8d9539a4823dca117/480w.png">
<source media="(max-width: 768px)" srcset="https://static.rerun.io/stdio/25c5aba992d4c8b3861386d8d9539a4823dca117/768w.png">
<source media="(max-width: 1024px)" srcset="https://static.rerun.io/stdio/25c5aba992d4c8b3861386d8d9539a4823dca117/1024w.png">
<source media="(max-width: 1200px)" srcset="https://static.rerun.io/stdio/25c5aba992d4c8b3861386d8d9539a4823dca117/1200w.png">
</picture>

Demonstrates how to log data to standard output with the Rerun SDK, and then visualize it from standard input with the Rerun Viewer.

To build it from a checkout of the repository (requires a Rust toolchain):
```bash
cmake .
cmake --build . --target example_stdio
echo 'hello from stdin!' | ./examples/cpp/stdio/example_stdio | rerun -
```
17 changes: 17 additions & 0 deletions examples/cpp/stdio/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include <iostream>
#include <string>

#include <rerun.hpp>

int main() {
const auto rec = rerun::RecordingStream("rerun_example_stdio");
rec.to_stdout().exit_on_failure();

std::string input;
std::string line;
while (std::getline(std::cin, line)) {
input += line + '\n';
}

rec.log("stdin", rerun::TextDocument(input));
}
11 changes: 11 additions & 0 deletions rerun_cpp/src/rerun/c/rerun.h

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

1 change: 1 addition & 0 deletions rerun_cpp/src/rerun/error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ namespace rerun {
_CategoryRecordingStream = 0x0000'0100,
RecordingStreamCreationFailure,
RecordingStreamSaveFailure,
RecordingStreamStdoutFailure,
RecordingStreamSpawnFailure,

// Arrow data processing errors.
Expand Down
6 changes: 6 additions & 0 deletions rerun_cpp/src/rerun/recording_stream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,12 @@ namespace rerun {
return status;
}

Error RecordingStream::to_stdout() const {
rr_error status = {};
rr_recording_stream_stdout(_id, &status);
return status;
}

void RecordingStream::flush_blocking() const {
rr_recording_stream_flush_blocking(_id);
}
Expand Down
14 changes: 14 additions & 0 deletions rerun_cpp/src/rerun/recording_stream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,20 @@ namespace rerun {
/// This function returns immediately.
Error save(std::string_view path) const;

/// Stream all log-data to standard output.
///
/// Pipe the result into the Rerun Viewer to visualize it.
///
/// If there isn't any listener at the other end of the pipe, the `RecordingStream` will
/// default back to `buffered` mode, in order not to break the user's terminal.
///
/// This function returns immediately.
//
// NOTE: This should be called `stdout` like in other SDK, but turns out that `stdout` is a
// macro when compiling with msvc [1].
// [1]: https://learn.microsoft.com/en-us/cpp/c-runtime-library/stdin-stdout-stderr?view=msvc-170
Error to_stdout() const;

/// Initiates a flush the batching pipeline and waits for it to propagate.
///
/// See `RecordingStream` docs for ordering semantics and multithreading guarantees.
Expand Down

0 comments on commit 55beca2

Please sign in to comment.