Skip to content

Conversation

grtlr
Copy link
Member

@grtlr grtlr commented Oct 1, 2025

Related

What

This PR introduces the concept of Lenses as a way to express re-interpretation and manipulation of component columns. This can, for example, be useful to attach Rerun semantics to arbitrary Arrow components that are created when loading MCAP files.

For now, the only way to access the feature is via the LensesSink, which transforms component columns and then forwards aggregated chunks to the backing sink.

Important

Lenses are still a very experimental feature and we expect the API to change a lot in upcoming releases.

@grtlr grtlr marked this pull request as draft October 1, 2025 11:50
@grtlr grtlr added the 🪵 Log & send APIs Affects the user-facing API for all languages label Oct 1, 2025
Copy link

github-actions bot commented Oct 7, 2025

Latest documentation preview deployed successfully.

Result Commit Link
9e5a849 https://landing-lpn6u6r71-rerun.vercel.app/docs

Note: This comment is updated whenever you push a commit.

Copy link

github-actions bot commented Oct 7, 2025

Web viewer built successfully.

Result Commit Link Manifest
9e5a849 https://rerun.io/viewer/pr/11394 +nightly +main

Note: This comment is updated whenever you push a commit.

@grtlr grtlr requested a review from Copilot October 7, 2025 15:05
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces the concept of "Lenses" as an experimental feature for semantic mapping and transformation of arbitrary data in Rerun. Lenses provide a way to re-interpret and manipulate component columns, which is particularly useful for attaching Rerun semantics to arbitrary Arrow components when loading external data formats like MCAP files.

Key changes:

  • New Lens struct that defines input-to-output transformations for component data
  • LensesSink that wraps existing sinks and applies lens transformations before forwarding data
  • Various transformation operations (Op) including field access, type casting, and custom functions

Reviewed Changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
examples/rust/lenses/src/main.rs Complete example demonstrating lens usage with flag transformations, text mapping, and struct destructuring
examples/rust/lenses/README.md Documentation for the lenses example
examples/rust/lenses/Cargo.toml Cargo configuration for the lenses example package
crates/top/re_sdk/src/lib.rs Adds public module declaration for the experimental lenses feature
crates/top/re_sdk/src/lenses.rs Core implementation of the lenses system including sink, operations, and builder patterns
Multiple snapshot files Test snapshots for various lens transformation scenarios

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@grtlr grtlr marked this pull request as ready for review October 7, 2025 15:24
Base automatically changed from grtlr/improve-error-message to main October 7, 2025 15:24
Comment on lines +376 to +379
// This means we drop chunks that belong to the same entity but don't have the component.
let Some((_component_descr, list_array)) = found else {
return Default::default();
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's not necessarily anything better we can do here, but flagging this as possibly worrisome.

I think the real question is whether a user (esp if using a Func op) can change the validity of a row from null -> some value. If they can, then input-side concatentation of chunks (which auto-fills missing components with nulls) would lead to different outputs.

If we say any null input row must also correspond to a null output row, then this makes sense as a performance optimization.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If they can, then input-side concatentation of chunks (which auto-fills missing components with nulls) would lead to different outputs.

Hmm, I don't think I follow. What do you mean be "input-side concatenation of chunks" here? The batcher?

@Wumpf Wumpf self-requested a review October 8, 2025 11:20
Copy link
Member

@Wumpf Wumpf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!
Left mostly ~style nits. Only more serious concern I have is how operations are modeled right now, but we've already discussed this and we can take of that later. Modelling of inputs & outputs, ast separation as well as the general premise make a lot of sense to me, great start

use super::*;

/// Creates a chunk that contains all sorts of validity, nullability, and empty lists.
// ┌──────────────┬───────────┐
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very helpful, thanks for including these

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fun fact, Claude does a good job going from these schematics to ArrayBuilders.

grtlr added a commit that referenced this pull request Oct 8, 2025
)

### Related

* Closes RR-2552.
* Related to RR-2553.
* Related to #11394.
* [x] Requires #11458.

 
### What

This changes our `protobuf` reflection code to put the entire message
behind a single component to make it easier to extract it from lenses.
This also guarantees that each protobuf message is always
self-contained.
Wumpf pushed a commit that referenced this pull request Oct 8, 2025
)

### Related

* Closes RR-2552.
* Related to RR-2553.
* Related to #11394.
* [x] Requires #11458.

 
### What

This changes our `protobuf` reflection code to put the entire message
behind a single component to make it easier to extract it from lenses.
This also guarantees that each protobuf message is always
self-contained.
Comment on lines +1 to +18
//! Lenses allow you to extract, transform, and restructure component data. They
//! are applied to chunks that match the specified entity path filter and contain
//! the target component.
//!
//! See [`lenses::Lens`] for more details and assumptions. One way to make use of lenses is
//! by using the [`lenses::LensesSink`].
pub(crate) mod ast;
mod error;
mod op;
mod sink;

pub use self::{
// We should be careful not to expose to much implementation details here.
ast::{Lens, LensBuilder, Op},
error::Error,
sink::LensesSink,
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!

@grtlr grtlr merged commit caba960 into main Oct 9, 2025
40 checks passed
@grtlr grtlr deleted the grtlr/lenses branch October 9, 2025 06:50
grtlr added a commit that referenced this pull request Oct 9, 2025
…#11481)

### Related

* Follow up of #11394.
* Part of RR-2554.

### What

This derives the entity path for the output column from the input
column's chunk, unless specified otherwise. This saves a lot of
duplicated code, because now multiple input entities can be treated at
once using the `EntityPathFilter` of the input column.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
include in changelog 🪵 Log & send APIs Affects the user-facing API for all languages
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants