#include // A very simple custom container type. template struct MyContainer { T* data; size_t size; MyContainer(size_t size_) : data(new T[size_]), size(size_) {} // For demonstration purposes: This container can't be copied. MyContainer(const MyContainer&) = delete; ~MyContainer() { delete[] data; } }; // A custom vector type. struct MyVec3 { float x, y, z; }; /// Adapts `MyContainer` to a `Collection`. /// /// With this in place, `Collection` can be constructed from a `MyContainer`! template <> struct rerun::CollectionAdapter> { // Creating a Collection from a non-temporary is done by casting & borrowing binary compatible data. Collection operator()(const MyContainer& container) { return Collection::borrow(container.data, container.size); } // For temporaries we have to do a copy since the pointer doesn't live long enough. // If you don't implement this, the other overload may be used for temporaries and cause // undefined behavior. Collection operator()(MyContainer&& container) { std::vector components(container.size); for (size_t i = 0; i < container.size; ++i) { components[i] = rerun::Position3D(container.data[i].x, container.data[i].y, container.data[i].z); } return Collection::take_ownership(std::move(components)); } }; int main() { // Create a new `RecordingStream` which sends data over gRPC to the viewer process. const auto rec = rerun::RecordingStream("rerun_example_custom_component_adapter"); rec.spawn().exit_on_failure(); // Construct some data in a custom format. MyContainer points(3); points.data[0] = MyVec3{0.0f, 0.0f, 0.0f}; points.data[1] = MyVec3{1.0f, 0.0f, 0.0f}; points.data[2] = MyVec3{0.0f, 1.0f, 0.0f}; // Log the "my_points" entity with our data, using the `Points3D` archetype. // Of course you can mix and match built-in types and custom types on the same archetype. rec.log("my_points", rerun::Points3D(points).with_labels({"a", "b", "c"})); }