Skip to content

Commit 9bfaec4

Browse files
committed
Avoid O(n^2) lookup for schema
1 parent e3c8732 commit 9bfaec4

File tree

1 file changed

+58
-43
lines changed

1 file changed

+58
-43
lines changed

crates/utils/re_mcap/src/layers/ros2_reflection.rs

Lines changed: 58 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,42 @@ pub enum Ros2ReflectionError {
7171
Downcast(&'static str),
7272
}
7373

74+
/// Minimal wrapper around [`StructBuilder`] that also holds the [`MessageSpecification`]
75+
struct MessageStructBuilder {
76+
builder: StructBuilder,
77+
spec: Arc<MessageSpecification>,
78+
}
79+
80+
impl ArrayBuilder for MessageStructBuilder {
81+
fn as_any(&self) -> &dyn std::any::Any {
82+
self
83+
}
84+
85+
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
86+
self
87+
}
88+
89+
fn into_box_any(self: Box<Self>) -> Box<dyn std::any::Any> {
90+
self
91+
}
92+
93+
fn len(&self) -> usize {
94+
self.builder.len()
95+
}
96+
97+
fn is_empty(&self) -> bool {
98+
self.builder.is_empty()
99+
}
100+
101+
fn finish(&mut self) -> arrow::array::ArrayRef {
102+
Arc::new(self.builder.finish())
103+
}
104+
105+
fn finish_cloned(&self) -> arrow::array::ArrayRef {
106+
Arc::new(self.builder.finish_cloned())
107+
}
108+
}
109+
74110
impl Ros2ReflectionMessageParser {
75111
fn new(num_rows: usize, message_schema: MessageSchema) -> anyhow::Result<Self> {
76112
let mut fields = Vec::new();
@@ -110,7 +146,7 @@ impl MessageParser for Ros2ReflectionMessageParser {
110146
// a field is missing from the message that we received.
111147
for (field_name, builder) in &mut self.fields {
112148
if let Some(field_value) = message_fields.get(field_name) {
113-
append_value(builder.values(), field_value, &self.message_schema)?;
149+
append_value(builder.values(), field_value)?;
114150
builder.append(true);
115151
} else {
116152
builder.append(false);
@@ -253,7 +289,6 @@ fn append_primitive_array(
253289
fn append_value(
254290
builder: &mut dyn ArrayBuilder,
255291
val: &Value,
256-
schema: &MessageSchema,
257292
) -> Result<(), Ros2ReflectionError> {
258293
match val {
259294
Value::Bool(x) => downcast_builder::<BooleanBuilder>(builder)?.append_value(*x),
@@ -271,41 +306,31 @@ fn append_value(
271306
downcast_builder::<StringBuilder>(builder)?.append_value(x.clone());
272307
}
273308
Value::Message(message_fields) => {
274-
let struct_builder = downcast_builder::<StructBuilder>(builder)?;
275-
276-
// For nested messages, we need to find the matching specification from dependencies
277-
// Since we don't have type information here, we'll try to match by field names
278-
let matching_spec = find_matching_message_spec(schema, message_fields);
279-
280-
if let Some(spec) = matching_spec {
281-
// Use the specification field order to iterate through struct builder fields
282-
for (i, spec_field) in spec.fields.iter().enumerate() {
283-
if let Some(field_builder) = struct_builder.field_builders_mut().get_mut(i) {
284-
if let Some(field_value) = message_fields.get(&spec_field.name) {
285-
append_value(field_builder, field_value, schema)?;
286-
} else {
287-
//TODO(gijsd): Field is missing in the message, append null
288-
re_log::warn_once!(
289-
"Field {} is missing in the message, appending null",
290-
spec_field.name
291-
);
292-
}
309+
let message_struct_builder = downcast_builder::<MessageStructBuilder>(builder)?;
310+
let spec = &message_struct_builder.spec;
311+
312+
// Use the specification field order to iterate through struct builder fields
313+
for (i, spec_field) in spec.fields.iter().enumerate() {
314+
if let Some(field_builder) = message_struct_builder.builder.field_builders_mut().get_mut(i) {
315+
if let Some(field_value) = message_fields.get(&spec_field.name) {
316+
append_value(field_builder, field_value)?;
317+
} else {
318+
//TODO(gijsd): Field is missing in the message, append null
319+
re_log::warn_once!(
320+
"Field {} is missing in the message, appending null",
321+
spec_field.name
322+
);
293323
}
294324
}
295-
} else {
296-
re_log::warn_once!(
297-
"Could not find matching message specification for nested message with fields: {:?}",
298-
message_fields.keys().collect::<Vec<_>>()
299-
);
300325
}
301326

302-
struct_builder.append(true);
327+
message_struct_builder.builder.append(true);
303328
}
304329
Value::Array(vec) | Value::Sequence(vec) => {
305330
let list_builder = downcast_builder::<ListBuilder<Box<dyn ArrayBuilder>>>(builder)?;
306331

307332
for val in vec {
308-
append_value(list_builder.values(), val, schema)?;
333+
append_value(list_builder.values(), val)?;
309334
}
310335
list_builder.append(true);
311336
}
@@ -317,23 +342,10 @@ fn append_value(
317342
Ok(())
318343
}
319344

320-
fn find_matching_message_spec<'a>(
321-
schema: &'a MessageSchema,
322-
message_fields: &'a std::collections::BTreeMap<String, Value>,
323-
) -> Option<&'a MessageSpecification> {
324-
schema.dependencies.iter().find(|spec| {
325-
spec.fields.len() == message_fields.len()
326-
&& spec
327-
.fields
328-
.iter()
329-
.all(|f| message_fields.contains_key(&f.name))
330-
})
331-
}
332-
333345
fn struct_builder_from_message_spec(
334346
spec: &MessageSpecification,
335347
dependencies: &[MessageSpecification],
336-
) -> anyhow::Result<StructBuilder> {
348+
) -> anyhow::Result<MessageStructBuilder> {
337349
let fields = spec
338350
.fields
339351
.iter()
@@ -348,7 +360,10 @@ fn struct_builder_from_message_spec(
348360
let (fields, field_builders): (Vec<Field>, Vec<Box<dyn ArrayBuilder>>) =
349361
fields.into_iter().unzip();
350362

351-
Ok(StructBuilder::new(fields, field_builders))
363+
Ok(MessageStructBuilder {
364+
builder: StructBuilder::new(fields, field_builders),
365+
spec: Arc::new(spec.clone()),
366+
})
352367
}
353368

354369
fn arrow_builder_from_type(

0 commit comments

Comments
 (0)