From 06df4087752e3319c16ac4821f97e449b562dd29 Mon Sep 17 00:00:00 2001 From: Clement Rey Date: Wed, 13 Dec 2023 16:10:36 +0100 Subject: [PATCH 1/8] add C support for RecordingStream::stdout --- crates/rerun_c/src/lib.rs | 19 +++++++++++++++++++ crates/rerun_c/src/rerun.h | 11 +++++++++++ 2 files changed, 30 insertions(+) diff --git a/crates/rerun_c/src/lib.rs b/crates/rerun_c/src/lib.rs index ebac91fcf505..fcbc4b9e9734 100644 --- a/crates/rerun_c/src/lib.rs +++ b/crates/rerun_c/src/lib.rs @@ -161,6 +161,7 @@ pub enum CErrorCode { _CategoryRecordingStream = 0x0000_00100, RecordingStreamCreationFailure, RecordingStreamSaveFailure, + RecordingStreamStdoutFailure, // TODO(cmc): Really this should be its own category… RecordingStreamSpawnFailure, @@ -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, diff --git a/crates/rerun_c/src/rerun.h b/crates/rerun_c/src/rerun.h index ca0a02c599af..34f72b1d3840 100644 --- a/crates/rerun_c/src/rerun.h +++ b/crates/rerun_c/src/rerun.h @@ -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. @@ -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. From a3e12ae4ba230f40d113566590963a490a9e5e6a Mon Sep 17 00:00:00 2001 From: Clement Rey Date: Wed, 13 Dec 2023 16:10:45 +0100 Subject: [PATCH 2/8] add C++ support for RecordingStream::stdout --- rerun_cpp/src/rerun/c/rerun.h | 11 +++++++++++ rerun_cpp/src/rerun/recording_stream.cpp | 6 ++++++ rerun_cpp/src/rerun/recording_stream.hpp | 10 ++++++++++ 3 files changed, 27 insertions(+) diff --git a/rerun_cpp/src/rerun/c/rerun.h b/rerun_cpp/src/rerun/c/rerun.h index 83a06d6331fb..93a072b9c3df 100644 --- a/rerun_cpp/src/rerun/c/rerun.h +++ b/rerun_cpp/src/rerun/c/rerun.h @@ -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. @@ -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. diff --git a/rerun_cpp/src/rerun/recording_stream.cpp b/rerun_cpp/src/rerun/recording_stream.cpp index a4dd57e72b58..8d9284542295 100644 --- a/rerun_cpp/src/rerun/recording_stream.cpp +++ b/rerun_cpp/src/rerun/recording_stream.cpp @@ -128,6 +128,12 @@ namespace rerun { return status; } + Error RecordingStream::stdout() const { + rr_error status = {}; + rr_recording_stream_stdout(_id, &status); + return status; + } + void RecordingStream::flush_blocking() const { rr_recording_stream_flush_blocking(_id); } diff --git a/rerun_cpp/src/rerun/recording_stream.hpp b/rerun_cpp/src/rerun/recording_stream.hpp index b62b3350f14e..5229fc85d243 100644 --- a/rerun_cpp/src/rerun/recording_stream.hpp +++ b/rerun_cpp/src/rerun/recording_stream.hpp @@ -174,6 +174,16 @@ namespace rerun { /// This function returns immediately. Error save(std::string_view path) const; + /// 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. + Error stdout() const; + /// Initiates a flush the batching pipeline and waits for it to propagate. /// /// See `RecordingStream` docs for ordering semantics and multithreading guarantees. From e9214ad97898b2bb05d0f8de9396adacb9b44c97 Mon Sep 17 00:00:00 2001 From: Clement Rey Date: Wed, 13 Dec 2023 16:11:50 +0100 Subject: [PATCH 3/8] add cpp example --- examples/cpp/stdio/CMakeLists.txt | 32 +++++++++++++++++++++++++++++++ examples/cpp/stdio/README.md | 23 ++++++++++++++++++++++ examples/cpp/stdio/main.cpp | 20 +++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 examples/cpp/stdio/CMakeLists.txt create mode 100644 examples/cpp/stdio/README.md create mode 100644 examples/cpp/stdio/main.cpp diff --git a/examples/cpp/stdio/CMakeLists.txt b/examples/cpp/stdio/CMakeLists.txt new file mode 100644 index 000000000000..bf72c54d6cae --- /dev/null +++ b/examples/cpp/stdio/CMakeLists.txt @@ -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=` 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) diff --git a/examples/cpp/stdio/README.md b/examples/cpp/stdio/README.md new file mode 100644 index 000000000000..3d46c6ec6a48 --- /dev/null +++ b/examples/cpp/stdio/README.md @@ -0,0 +1,23 @@ +--- +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 +--- + + + + + + + + + +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 +just cpp-build-examples +echo 'hello from stdin!' | ./build/debug/examples/cpp/stdio/example_stdio | rerun +``` diff --git a/examples/cpp/stdio/main.cpp b/examples/cpp/stdio/main.cpp new file mode 100644 index 000000000000..c9aa4390f22c --- /dev/null +++ b/examples/cpp/stdio/main.cpp @@ -0,0 +1,20 @@ +#include +#include + +#include +#include + +using rerun::demo::grid3d; + +int main() { + const auto rec = rerun::RecordingStream("rerun_example_stdio"); + rec.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)); +} From 087c7e984e192d2fb50fde331fef745b2b2e4e43 Mon Sep 17 00:00:00 2001 From: Clement Rey Date: Wed, 13 Dec 2023 16:12:47 +0100 Subject: [PATCH 4/8] update op docs --- docs/content/reference/sdk-operating-modes.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/content/reference/sdk-operating-modes.md b/docs/content/reference/sdk-operating-modes.md index 9c8bcfa3d1c5..e59312d03f71 100644 --- a/docs/content/reference/sdk-operating-modes.md +++ b/docs/content/reference/sdk-operating-modes.md @@ -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). From 4e1eda6ce0eb91c75b947f6f46a5dc7ad1861cc5 Mon Sep 17 00:00:00 2001 From: Clement Rey Date: Thu, 14 Dec 2023 07:51:01 +0100 Subject: [PATCH 5/8] update example docs --- examples/cpp/stdio/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cpp/stdio/README.md b/examples/cpp/stdio/README.md index 3d46c6ec6a48..47f03cb3b8a3 100644 --- a/examples/cpp/stdio/README.md +++ b/examples/cpp/stdio/README.md @@ -19,5 +19,5 @@ Demonstrates how to log data to standard output with the Rerun SDK, and then vis To build it from a checkout of the repository (requires a Rust toolchain): ```bash just cpp-build-examples -echo 'hello from stdin!' | ./build/debug/examples/cpp/stdio/example_stdio | rerun +echo 'hello from stdin!' | ./build/debug/examples/cpp/stdio/example_stdio | rerun - ``` From f302f50f623aa70fb01d08be1063dc4f995706ef Mon Sep 17 00:00:00 2001 From: Clement Rey Date: Thu, 14 Dec 2023 07:53:50 +0100 Subject: [PATCH 6/8] remove example bloat --- examples/cpp/stdio/main.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/cpp/stdio/main.cpp b/examples/cpp/stdio/main.cpp index c9aa4390f22c..66a24c9b01d4 100644 --- a/examples/cpp/stdio/main.cpp +++ b/examples/cpp/stdio/main.cpp @@ -2,9 +2,6 @@ #include #include -#include - -using rerun::demo::grid3d; int main() { const auto rec = rerun::RecordingStream("rerun_example_stdio"); From d2ea0f7ecf88addaaeb3ca8e4dee7886b0504790 Mon Sep 17 00:00:00 2001 From: Clement Rey Date: Thu, 14 Dec 2023 09:20:00 +0100 Subject: [PATCH 7/8] c++26 does not yet support the word 'stdout', but we'll get there i promise --- examples/cpp/stdio/main.cpp | 2 +- rerun_cpp/src/rerun/recording_stream.cpp | 2 +- rerun_cpp/src/rerun/recording_stream.hpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/cpp/stdio/main.cpp b/examples/cpp/stdio/main.cpp index 66a24c9b01d4..ce84081aad67 100644 --- a/examples/cpp/stdio/main.cpp +++ b/examples/cpp/stdio/main.cpp @@ -5,7 +5,7 @@ int main() { const auto rec = rerun::RecordingStream("rerun_example_stdio"); - rec.stdout().exit_on_failure(); + rec.to_stdout().exit_on_failure(); std::string input; std::string line; diff --git a/rerun_cpp/src/rerun/recording_stream.cpp b/rerun_cpp/src/rerun/recording_stream.cpp index 8d9284542295..bd77c196cab6 100644 --- a/rerun_cpp/src/rerun/recording_stream.cpp +++ b/rerun_cpp/src/rerun/recording_stream.cpp @@ -128,7 +128,7 @@ namespace rerun { return status; } - Error RecordingStream::stdout() const { + Error RecordingStream::to_stdout() const { rr_error status = {}; rr_recording_stream_stdout(_id, &status); return status; diff --git a/rerun_cpp/src/rerun/recording_stream.hpp b/rerun_cpp/src/rerun/recording_stream.hpp index 5229fc85d243..346309bb09da 100644 --- a/rerun_cpp/src/rerun/recording_stream.hpp +++ b/rerun_cpp/src/rerun/recording_stream.hpp @@ -174,7 +174,7 @@ namespace rerun { /// This function returns immediately. Error save(std::string_view path) const; - /// Stream all log-data to stdout. + /// Stream all log-data to standard output. /// /// Pipe the result into the Rerun Viewer to visualize it. /// @@ -182,7 +182,7 @@ namespace rerun { /// default back to `buffered` mode, in order not to break the user's terminal. /// /// This function returns immediately. - Error stdout() const; + Error to_stdout() const; /// Initiates a flush the batching pipeline and waits for it to propagate. /// From bdc1f08805bdc14b6e15f97decd0c86fa7b6913f Mon Sep 17 00:00:00 2001 From: Clement Rey Date: Thu, 14 Dec 2023 11:45:18 +0100 Subject: [PATCH 8/8] address PR comments --- examples/cpp/CMakeLists.txt | 6 ++++-- examples/cpp/stdio/README.md | 5 +++-- rerun_cpp/src/rerun/error.hpp | 1 + rerun_cpp/src/rerun/recording_stream.hpp | 4 ++++ 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt index 1102cba5ebc5..c603e3c35dff 100644 --- a/examples/cpp/CMakeLists.txt +++ b/examples/cpp/CMakeLists.txt @@ -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) diff --git a/examples/cpp/stdio/README.md b/examples/cpp/stdio/README.md index 47f03cb3b8a3..823c505c7740 100644 --- a/examples/cpp/stdio/README.md +++ b/examples/cpp/stdio/README.md @@ -18,6 +18,7 @@ Demonstrates how to log data to standard output with the Rerun SDK, and then vis To build it from a checkout of the repository (requires a Rust toolchain): ```bash -just cpp-build-examples -echo 'hello from stdin!' | ./build/debug/examples/cpp/stdio/example_stdio | rerun - +cmake . +cmake --build . --target example_stdio +echo 'hello from stdin!' | ./examples/cpp/stdio/example_stdio | rerun - ``` diff --git a/rerun_cpp/src/rerun/error.hpp b/rerun_cpp/src/rerun/error.hpp index 3623bf691553..a1b71c01ef42 100644 --- a/rerun_cpp/src/rerun/error.hpp +++ b/rerun_cpp/src/rerun/error.hpp @@ -45,6 +45,7 @@ namespace rerun { _CategoryRecordingStream = 0x0000'0100, RecordingStreamCreationFailure, RecordingStreamSaveFailure, + RecordingStreamStdoutFailure, RecordingStreamSpawnFailure, // Arrow data processing errors. diff --git a/rerun_cpp/src/rerun/recording_stream.hpp b/rerun_cpp/src/rerun/recording_stream.hpp index 346309bb09da..e3e063ade4d3 100644 --- a/rerun_cpp/src/rerun/recording_stream.hpp +++ b/rerun_cpp/src/rerun/recording_stream.hpp @@ -182,6 +182,10 @@ namespace rerun { /// 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.