Skip to content

Commit 515d05c

Browse files
emilkWumpf
andauthored
New C++ API for timestamp/duration indices (#9200)
### Related * Part of #8635 ### What Updated the C++ API to distinguish between absolute timestamps and and relative durations. We've deprecated the following functions in `RecordingStream`, with the following replacements: * `set_time_sequence` -> `set_index_sequence` * `set_time` -> `set_index_duration` or `set_index_timestamp` * `set_time_seconds` -> `set_index_duration_secs` or `set_index_timestamp_seconds_since_epoch` * `set_time_nanos` -> `set_index_duration_nanos` or `set_index_timestamp_nanos_since_epoch` `TimeColumn` also has deprecated functions. ### Questions to reviewer The names for the functions in `TimeColumn` are somewhat inconsistent with those of `RecordingStream`. ### Other notes I also changed/broke the C API. ### TODO * [ ] Full check --------- Co-authored-by: Andreas Reich <[email protected]>
1 parent 6140319 commit 515d05c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+460
-234
lines changed

crates/top/rerun_c/src/lib.rs

+20-57
Original file line numberDiff line numberDiff line change
@@ -226,11 +226,14 @@ impl CSortingStatus {
226226
#[repr(u32)]
227227
#[derive(Debug, Clone, Copy)]
228228
pub enum CTimeType {
229-
/// Normal wall time.
230-
Time = 0,
231-
232229
/// Used e.g. for frames in a film.
233230
Sequence = 1,
231+
232+
/// Nanoseconds.
233+
Duration = 2,
234+
235+
/// Nanoseconds since Unix epoch (1970-01-01 00:00:00 UTC).
236+
Timestamp = 3,
234237
}
235238

236239
/// See `rr_timeline` in the C header.
@@ -251,8 +254,9 @@ impl TryFrom<CTimeline> for Timeline {
251254
fn try_from(timeline: CTimeline) -> Result<Self, CError> {
252255
let name = timeline.name.as_str("timeline.name")?;
253256
let typ = match timeline.typ {
254-
CTimeType::Time => TimeType::Time,
255257
CTimeType::Sequence => TimeType::Sequence,
258+
// TODO(#8635): differentiate between duration and timestamp
259+
CTimeType::Duration | CTimeType::Timestamp => TimeType::Time,
256260
};
257261
Ok(Self::new(name, typ))
258262
}
@@ -720,73 +724,32 @@ pub extern "C" fn rr_recording_stream_stdout(id: CRecordingStream, error: *mut C
720724
}
721725

722726
#[allow(clippy::result_large_err)]
723-
fn rr_recording_stream_set_time_sequence_impl(
727+
fn rr_recording_stream_set_index_impl(
724728
stream: CRecordingStream,
725729
timeline_name: CStringView,
726-
sequence: i64,
730+
time_type: CTimeType,
731+
value: i64,
727732
) -> Result<(), CError> {
728733
let timeline = timeline_name.as_str("timeline_name")?;
729-
recording_stream(stream)?.set_time_sequence(timeline, sequence);
730-
Ok(())
731-
}
732-
733-
#[allow(unsafe_code)]
734-
#[no_mangle]
735-
pub extern "C" fn rr_recording_stream_set_time_sequence(
736-
stream: CRecordingStream,
737-
timeline_name: CStringView,
738-
sequence: i64,
739-
error: *mut CError,
740-
) {
741-
if let Err(err) = rr_recording_stream_set_time_sequence_impl(stream, timeline_name, sequence) {
742-
err.write_error(error);
743-
}
744-
}
745-
746-
#[allow(clippy::result_large_err)]
747-
fn rr_recording_stream_set_time_seconds_impl(
748-
stream: CRecordingStream,
749-
timeline_name: CStringView,
750-
seconds: f64,
751-
) -> Result<(), CError> {
752-
let timeline = timeline_name.as_str("timeline_name")?;
753-
recording_stream(stream)?.set_time_seconds(timeline, seconds);
754-
Ok(())
755-
}
756-
757-
#[allow(unsafe_code)]
758-
#[no_mangle]
759-
pub extern "C" fn rr_recording_stream_set_time_seconds(
760-
stream: CRecordingStream,
761-
timeline_name: CStringView,
762-
seconds: f64,
763-
error: *mut CError,
764-
) {
765-
if let Err(err) = rr_recording_stream_set_time_seconds_impl(stream, timeline_name, seconds) {
766-
err.write_error(error);
734+
let stream = recording_stream(stream)?;
735+
match time_type {
736+
CTimeType::Sequence => stream.set_time_sequence(timeline, value),
737+
// TODO(#8635): do different things for Duration and Timestamp
738+
CTimeType::Duration | CTimeType::Timestamp => stream.set_time_nanos(timeline, value),
767739
}
768-
}
769-
770-
#[allow(clippy::result_large_err)]
771-
fn rr_recording_stream_set_time_nanos_impl(
772-
stream: CRecordingStream,
773-
timeline_name: CStringView,
774-
nanos: i64,
775-
) -> Result<(), CError> {
776-
let timeline = timeline_name.as_str("timeline_name")?;
777-
recording_stream(stream)?.set_time_nanos(timeline, nanos);
778740
Ok(())
779741
}
780742

781743
#[allow(unsafe_code)]
782744
#[no_mangle]
783-
pub extern "C" fn rr_recording_stream_set_time_nanos(
745+
pub extern "C" fn rr_recording_stream_set_index(
784746
stream: CRecordingStream,
785747
timeline_name: CStringView,
786-
nanos: i64,
748+
time_type: CTimeType,
749+
value: i64,
787750
error: *mut CError,
788751
) {
789-
if let Err(err) = rr_recording_stream_set_time_nanos_impl(stream, timeline_name, nanos) {
752+
if let Err(err) = rr_recording_stream_set_index_impl(stream, timeline_name, time_type, value) {
790753
err.write_error(error);
791754
}
792755
}

docs/content/reference/migration/migration-0-23.md

+22-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,16 @@ Previously, you could (confusingly) have two timelines with the same name, as lo
88
This is no longer possible.
99
Timelines are now uniquely identified by name, and if you use different types on the same timeline, you will get a logged warning, and the _latest_ type will be used to interpret the full set of time data.
1010

11-
## 🐍 Python: replaced `rr.set_time_*` with `rr.set_index`
11+
## Rename some timeline-related things as "index"
12+
We're planning on adding support for different types of indices in the future, so to that point we're slowly migrating our API to refer to these things as _indices_ rather than _timelines_.
13+
14+
## Differentiate between timestamps and durations
15+
We've added a explicit API for setting time, where you need to explicitly specify if a time is either a timestamp (e.g. `2025-03-03T14:34:56.123456789`) or a duration (e.g. `123s`).
16+
17+
Before, Rerun would try to guess what you meant (small values were assumed to be durations, and large values were assumes to be durations since the Unix epoch, i.e. timestamps).
18+
Now you need to be explicit.
19+
20+
### 🐍 Python: replaced `rr.set_time_*` with `rr.set_index`
1221
We're moving towards a more explicit API for setting time, where you need to explicitly specify if a time is either a datetime (e.g. `2025-03-03T14:34:56.123456789`) or a timedelta (e.g. `123s`).
1322

1423
Previously we would infer the user intent at runtime based on the value: if it was large enough, it was interpreted as time since the Unix epoch, otherwise it was interpreted as a timedelta.
@@ -26,7 +35,7 @@ To this end, we're deprecated `rr.set_time_seconds`, `rr.set_time_nanos`, as wel
2635
* [`datetime.datetime`](https://docs.python.org/3/library/datetime.html#datetime.datetime)
2736
* [`numpy.datetime64`](https://numpy.org/doc/stable/reference/arrays.scalars.html#numpy.datetime64)
2837

29-
### Migrating
38+
#### Migrating
3039
##### `rr.set_sequence("foo", 42)`
3140
New: `rr.set_index("foo", sequence=42)`
3241

@@ -53,11 +62,11 @@ Either:
5362
The former is subject to (double-precision) floating point precision loss (still microsecond precision for the next century), while the latter is lossless.
5463

5564

56-
## 🐍 Python: replaced `rr.Time*Column` with `rr.IndexColumn`
65+
### 🐍 Python: replaced `rr.Time*Column` with `rr.IndexColumn`
5766
Similarly to the above new `set_index` API, there is also a new `IndexColumn` class that replaces `TimeSequenceColumn`, `TimeSecondsColumn`, and `TimeNanosColumn`.
5867
The migration is very similar to the above.
5968

60-
### Migration
69+
#### Migration
6170
##### `rr.TimeSequenceColumn("foo", values)`
6271
New: `rr.IndexColumn("foo", sequence=values)`
6372

@@ -81,6 +90,15 @@ Either:
8190

8291
The former is subject to (double-precision) floating point precision loss (still microsecond precision for the next century), while the latter is lossless.
8392

93+
### 🌊 C++: replaced `RecordingStream::set_time_*` with `set_index_*`
94+
We've deprecated the following functions, with the following replacements:
95+
* `set_time_sequence` -> `set_index_sequence`
96+
* `set_time` -> `set_index_duration` or `set_index_timestamp`
97+
* `set_time_seconds` -> `set_index_duration_secs` or `set_index_timestamp_seconds_since_epoch`
98+
* `set_time_nanos` -> `set_index_duration_nanos` or `set_index_timestamp_nanos_since_epoch`
99+
100+
`TimeColumn` also has deprecated functions.
101+
84102
## 🐍 Python: removed `rr.log_components()`, `rr.connect()`, `rr.connect_tcp()`, and `rr.serve()`
85103

86104
These functions were [deprecated](migration-0-22.md#python-api-changes) in 0.22 and are no longer available.

docs/snippets/all/archetypes/image_row_updates.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ int main() {
1212
const size_t WIDTH = 300;
1313

1414
for (size_t t = 0; t < 20; ++t) {
15-
rec.set_time_sequence("time", static_cast<int64_t>(t));
15+
rec.set_index_sequence("time", static_cast<int64_t>(t));
1616

1717
std::vector<uint8_t> data(WIDTH * HEIGHT * 3, 0);
1818
for (size_t i = 0; i < data.size(); i += 3) {

docs/snippets/all/archetypes/instance_poses3d_combined.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
int main() {
77
const auto rec = rerun::RecordingStream("rerun_example_instance_pose3d_combined");
8-
rec.set_time_sequence("frame", 0);
8+
rec.set_index_sequence("frame", 0);
99

1010
// Log a box and points further down in the hierarchy.
1111
rec.log("world/box", rerun::Boxes3D::from_half_sizes({{1.0, 1.0, 1.0}}));
@@ -15,7 +15,7 @@ int main() {
1515
);
1616

1717
for (int i = 0; i < 180; ++i) {
18-
rec.set_time_sequence("frame", i);
18+
rec.set_index_sequence("frame", i);
1919

2020
// Log a regular transform which affects both the box and the points.
2121
rec.log(

docs/snippets/all/archetypes/mesh3d_instancing.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ int main() {
66
const auto rec = rerun::RecordingStream("rerun_example_mesh3d_instancing");
77
rec.spawn().exit_on_failure();
88

9-
rec.set_time_sequence("frame", 0);
9+
rec.set_index_sequence("frame", 0);
1010
rec.log(
1111
"shape",
1212
rerun::Mesh3D(
@@ -19,7 +19,7 @@ int main() {
1919
rec.log("shape/box", rerun::Boxes3D::from_half_sizes({{5.0f, 5.0f, 5.0f}}));
2020

2121
for (int i = 0; i < 100; ++i) {
22-
rec.set_time_sequence("frame", i);
22+
rec.set_index_sequence("frame", i);
2323
rec.log(
2424
"shape",
2525
rerun::InstancePoses3D()

docs/snippets/all/archetypes/mesh3d_partial_updates.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ int main() {
2525
};
2626

2727
// Log the initial state of our triangle:
28-
rec.set_time_sequence("frame", 0);
28+
rec.set_index_sequence("frame", 0);
2929
rec.log(
3030
"triangle",
3131
rerun::Mesh3D(vertex_positions)
@@ -35,7 +35,7 @@ int main() {
3535

3636
// Only update its vertices' positions each frame
3737
for (int i = 1; i < 300; ++i) {
38-
rec.set_time_sequence("frame", i);
38+
rec.set_index_sequence("frame", i);
3939

4040
const auto factor = fabsf(sinf(static_cast<float>(i) * 0.04f));
4141
const auto modified_vertex_positions = {

docs/snippets/all/archetypes/points3d_column_updates.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ int main() {
2929

3030
// Log at seconds 10-14
3131
auto times = rerun::Collection{10s, 11s, 12s, 13s, 14s};
32-
auto time_column = rerun::TimeColumn::from_times("time", std::move(times));
32+
auto time_column = rerun::TimeColumn::from_durations("time", std::move(times));
3333

3434
// Partition our data as expected across the 5 timesteps.
3535
auto position = rerun::Points3D().with_positions(positions).columns({2, 4, 4, 3, 4});

docs/snippets/all/archetypes/points3d_partial_updates.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ int main() {
1414
positions.emplace_back(static_cast<float>(i), 0.0f, 0.0f);
1515
}
1616

17-
rec.set_time_sequence("frame", 0);
17+
rec.set_index_sequence("frame", 0);
1818
rec.log("points", rerun::Points3D(positions));
1919

2020
for (int i = 0; i < 10; ++i) {
@@ -37,14 +37,14 @@ int main() {
3737
}
3838

3939
// Update only the colors and radii, leaving everything else as-is.
40-
rec.set_time_sequence("frame", i);
40+
rec.set_index_sequence("frame", i);
4141
rec.log("points", rerun::Points3D::update_fields().with_radii(radii).with_colors(colors));
4242
}
4343

4444
std::vector<rerun::Radius> radii;
4545
radii.emplace_back(0.3f);
4646

4747
// Update the positions and radii, and clear everything else in the process.
48-
rec.set_time_sequence("frame", 20);
48+
rec.set_index_sequence("frame", 20);
4949
rec.log("points", rerun::Points3D::clear_fields().with_positions(positions).with_radii(radii));
5050
}

docs/snippets/all/archetypes/points3d_row_updates.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ int main() {
2727
std::vector<float> radii = {0.05f, 0.01f, 0.2f, 0.1f, 0.3f};
2828

2929
for (size_t i = 0; i < 5; i++) {
30-
rec.set_time_seconds("time", 10.0 + static_cast<double>(i));
30+
rec.set_index_duration_secs("time", 10.0 + static_cast<double>(i));
3131
rec.log(
3232
"points",
3333
rerun::Points3D(positions[i]).with_colors(colors[i]).with_radii(radii[i])

docs/snippets/all/archetypes/scalar_multiple_plots.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ int main() {
2222

2323
// Log the data on a timeline called "step".
2424
for (int t = 0; t < static_cast<int>(TAU * 2.0 * 100.0); ++t) {
25-
rec.set_time_sequence("step", t);
25+
rec.set_index_sequence("step", t);
2626

2727
rec.log("trig/sin", rerun::Scalar(sin(t / 100.0)));
2828
rec.log("trig/cos", rerun::Scalar(cos(static_cast<float>(t) / 100.0f)));

docs/snippets/all/archetypes/scalar_row_updates.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ int main() {
1111
rec.spawn().exit_on_failure();
1212

1313
for (int step = 0; step < 64; ++step) {
14-
rec.set_time_sequence("step", step);
14+
rec.set_index_sequence("step", step);
1515
rec.log("scalars", rerun::Scalar(sin(static_cast<double>(step) / 10.0)));
1616
}
1717
}

docs/snippets/all/archetypes/scalar_simple.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ int main() {
1010

1111
// Log the data on a timeline called "step".
1212
for (int step = 0; step < 64; ++step) {
13-
rec.set_time_sequence("step", step);
13+
rec.set_index_sequence("step", step);
1414
rec.log("scalar", rerun::Scalar(std::sin(static_cast<double>(step) / 10.0)));
1515
}
1616
}

docs/snippets/all/archetypes/series_line_style.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ int main() {
2424

2525
// Log the data on a timeline called "step".
2626
for (int t = 0; t < static_cast<int>(TAU * 2.0 * 100.0); ++t) {
27-
rec.set_time_sequence("step", t);
27+
rec.set_index_sequence("step", t);
2828

2929
rec.log("trig/sin", rerun::Scalar(sin(static_cast<double>(t) / 100.0)));
3030
rec.log("trig/cos", rerun::Scalar(cos(static_cast<double>(t) / 100.0)));

docs/snippets/all/archetypes/series_point_style.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ int main() {
3232

3333
// Log the data on a timeline called "step".
3434
for (int t = 0; t < static_cast<int>(TAU * 2.0 * 10.0); ++t) {
35-
rec.set_time_sequence("step", t);
35+
rec.set_index_sequence("step", t);
3636

3737
rec.log("trig/sin", rerun::Scalar(sin(static_cast<double>(t) / 10.0)));
3838
rec.log("trig/cos", rerun::Scalar(cos(static_cast<double>(t) / 10.0)));

docs/snippets/all/archetypes/transform3d_axes.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ int main() {
88

99
auto base_axes = rerun::Transform3D().with_axis_length(1.0);
1010

11-
rec.set_time_sequence("step", 0);
11+
rec.set_index_sequence("step", 0);
1212

1313
rec.log("base", base_axes);
1414

1515
for (int deg = 0; deg < 360; deg++) {
16-
rec.set_time_sequence("step", deg);
16+
rec.set_index_sequence("step", deg);
1717

1818
rec.log(
1919
"base/rotated",

docs/snippets/all/archetypes/transform3d_column_updates.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ int main() {
1818
const auto rec = rerun::RecordingStream("rerun_example_transform3d_column_updates");
1919
rec.spawn().exit_on_failure();
2020

21-
rec.set_time_sequence("tick", 0);
21+
rec.set_index_sequence("tick", 0);
2222
rec.log(
2323
"box",
2424
rerun::Boxes3D::from_half_sizes({{4.f, 2.f, 1.0f}}).with_fill_mode(rerun::FillMode::Solid),

docs/snippets/all/archetypes/transform3d_hierarchy.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ int main() {
1010

1111
// TODO(#5521): log two views as in the python example
1212

13-
rec.set_time_seconds("sim_time", 0.0);
13+
rec.set_index_duration_secs("sim_time", 0.0);
1414

1515
// Planetary motion is typically in the XY plane.
1616
rec.log_static("/", rerun::ViewCoordinates::RIGHT_HAND_Z_UP);
@@ -52,7 +52,7 @@ int main() {
5252
// Movement via transforms.
5353
for (int i = 0; i < 6 * 120; i++) {
5454
float time = static_cast<float>(i) / 120.0f;
55-
rec.set_time_seconds("sim_time", time);
55+
rec.set_index_duration_secs("sim_time", time);
5656
float r_moon = time * 5.0f;
5757
float r_planet = time * 2.0f;
5858

docs/snippets/all/archetypes/transform3d_row_updates.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ int main() {
1414
const auto rec = rerun::RecordingStream("rerun_example_transform3d_row_updates");
1515
rec.spawn().exit_on_failure();
1616

17-
rec.set_time_sequence("tick", 0);
17+
rec.set_index_sequence("tick", 0);
1818
rec.log(
1919
"box",
2020
rerun::Boxes3D::from_half_sizes({{4.f, 2.f, 1.0f}}).with_fill_mode(rerun::FillMode::Solid),
2121
rerun::Transform3D().with_axis_length(10.0)
2222
);
2323

2424
for (int t = 0; t < 100; t++) {
25-
rec.set_time_sequence("tick", t + 1);
25+
rec.set_index_sequence("tick", t + 1);
2626
rec.log(
2727
"box",
2828
rerun::Transform3D()

docs/snippets/all/archetypes/video_auto_frames.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ int main(int argc, char* argv[]) {
2828
video_asset.read_frame_timestamps_ns().value_or_throw();
2929
// Note timeline values don't have to be the same as the video timestamps.
3030
auto time_column =
31-
rerun::TimeColumn::from_times("video_time", rerun::borrow(frame_timestamps_ns));
31+
rerun::TimeColumn::from_durations("video_time", rerun::borrow(frame_timestamps_ns));
3232

3333
std::vector<rerun::components::VideoTimestamp> video_timestamps(frame_timestamps_ns.size());
3434
for (size_t i = 0; i < frame_timestamps_ns.size(); i++) {

0 commit comments

Comments
 (0)