1use std::hash::Hasher as _;
2
3use arrow::datatypes::Schema as ArrowSchema;
4use arrow::error::ArrowError;
5
6use re_log_types::external::re_types_core::ComponentDescriptor;
7use re_log_types::{RecordingId, StoreKind, TableId};
8
9use crate::{TypeConversionError, invalid_field, missing_field};
10
11#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13#[repr(u8)]
14pub enum Compression {
15 Off = 0,
16
17 LZ4 = 1,
19}
20
21impl From<crate::common::v1alpha1::Compression> for Compression {
22 fn from(value: crate::common::v1alpha1::Compression) -> Self {
23 match value {
24 crate::common::v1alpha1::Compression::Unspecified
25 | crate::common::v1alpha1::Compression::None => Self::Off,
26 crate::common::v1alpha1::Compression::Lz4 => Self::LZ4,
27 }
28 }
29}
30
31impl From<Compression> for crate::common::v1alpha1::Compression {
32 fn from(value: Compression) -> Self {
33 match value {
34 Compression::Off => Self::None,
35 Compression::LZ4 => Self::Lz4,
36 }
37 }
38}
39
40impl TryFrom<&crate::common::v1alpha1::Schema> for ArrowSchema {
43 type Error = ArrowError;
44
45 fn try_from(value: &crate::common::v1alpha1::Schema) -> Result<Self, Self::Error> {
46 let schema_bytes = value
47 .arrow_schema
48 .as_ref()
49 .ok_or(ArrowError::InvalidArgumentError(
50 "missing schema bytes".to_owned(),
51 ))?;
52 Ok(Self::clone(
53 re_sorbet::migrated_schema_from_ipc(schema_bytes)?.as_ref(),
54 ))
55 }
56}
57
58impl TryFrom<&ArrowSchema> for crate::common::v1alpha1::Schema {
59 type Error = ArrowError;
60
61 fn try_from(value: &ArrowSchema) -> Result<Self, Self::Error> {
62 Ok(Self {
63 arrow_schema: Some(re_sorbet::ipc_from_schema(value)?.into()),
64 })
65 }
66}
67
68impl TryFrom<crate::common::v1alpha1::Schema> for ArrowSchema {
69 type Error = ArrowError;
70
71 fn try_from(value: crate::common::v1alpha1::Schema) -> Result<Self, Self::Error> {
72 (&value).try_into()
73 }
74}
75
76impl From<re_log_types::EntryId> for crate::common::v1alpha1::EntryId {
79 #[inline]
80 fn from(value: re_log_types::EntryId) -> Self {
81 Self {
82 id: Some(value.id.into()),
83 }
84 }
85}
86
87impl TryFrom<crate::common::v1alpha1::EntryId> for re_log_types::EntryId {
88 type Error = TypeConversionError;
89
90 fn try_from(value: crate::common::v1alpha1::EntryId) -> Result<Self, Self::Error> {
91 let id = value
92 .id
93 .ok_or(missing_field!(crate::common::v1alpha1::EntryId, "id"))?;
94 Ok(Self { id: id.try_into()? })
95 }
96}
97
98impl From<re_tuid::Tuid> for crate::common::v1alpha1::EntryId {
101 fn from(id: re_tuid::Tuid) -> Self {
102 let id: re_log_types::EntryId = id.into();
103 Self {
104 id: Some(id.id.into()),
105 }
106 }
107}
108
109impl TryFrom<crate::common::v1alpha1::Tuid> for crate::common::v1alpha1::EntryId {
110 type Error = TypeConversionError;
111
112 fn try_from(id: crate::common::v1alpha1::Tuid) -> Result<Self, Self::Error> {
113 let id: re_tuid::Tuid = id.try_into()?;
114 Ok(Self {
115 id: Some(id.into()),
116 })
117 }
118}
119
120#[derive(
123 Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
124)]
125pub struct SegmentId {
126 pub id: String,
127}
128
129impl SegmentId {
130 #[inline]
131 pub fn new(id: String) -> Self {
132 Self { id }
133 }
134}
135
136impl From<String> for SegmentId {
137 fn from(id: String) -> Self {
138 Self { id }
139 }
140}
141
142impl From<&str> for SegmentId {
143 fn from(id: &str) -> Self {
144 Self { id: id.to_owned() }
145 }
146}
147
148impl std::fmt::Display for SegmentId {
149 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
150 self.id.fmt(f)
151 }
152}
153
154impl TryFrom<crate::common::v1alpha1::SegmentId> for SegmentId {
155 type Error = TypeConversionError;
156
157 fn try_from(value: crate::common::v1alpha1::SegmentId) -> Result<Self, Self::Error> {
158 Ok(Self {
159 id: value
160 .id
161 .ok_or(missing_field!(crate::common::v1alpha1::SegmentId, "id"))?,
162 })
163 }
164}
165
166impl From<SegmentId> for crate::common::v1alpha1::SegmentId {
167 fn from(value: SegmentId) -> Self {
168 Self { id: Some(value.id) }
169 }
170}
171
172impl AsRef<str> for SegmentId {
173 fn as_ref(&self) -> &str {
174 self.id.as_str()
175 }
176}
177
178impl From<String> for crate::common::v1alpha1::SegmentId {
181 fn from(id: String) -> Self {
182 Self { id: Some(id) }
183 }
184}
185
186impl From<&str> for crate::common::v1alpha1::SegmentId {
187 fn from(id: &str) -> Self {
188 Self {
189 id: Some(id.to_owned()),
190 }
191 }
192}
193
194#[derive(Debug, Clone)]
197pub struct DatasetHandle {
198 pub id: Option<re_log_types::EntryId>,
199 pub store_kind: StoreKind,
200 pub url: url::Url,
201}
202
203impl DatasetHandle {
204 pub fn new(url: url::Url, store_kind: StoreKind) -> Self {
206 Self {
207 id: None,
208 store_kind,
209 url,
210 }
211 }
212}
213
214impl TryFrom<crate::common::v1alpha1::DatasetHandle> for DatasetHandle {
215 type Error = TypeConversionError;
216
217 fn try_from(value: crate::common::v1alpha1::DatasetHandle) -> Result<Self, Self::Error> {
218 Ok(Self {
219 id: value.entry_id.map(|id| id.try_into()).transpose()?,
220 store_kind: crate::common::v1alpha1::StoreKind::try_from(value.store_kind)?.into(),
221 url: value
222 .dataset_url
223 .ok_or(missing_field!(
224 crate::common::v1alpha1::DatasetHandle,
225 "dataset_url"
226 ))?
227 .parse()
228 .map_err(|err| {
229 invalid_field!(crate::common::v1alpha1::DatasetHandle, "dataset_url", err)
230 })?,
231 })
232 }
233}
234
235impl From<DatasetHandle> for crate::common::v1alpha1::DatasetHandle {
236 fn from(value: DatasetHandle) -> Self {
237 Self {
238 entry_id: value.id.map(Into::into),
239 store_kind: crate::common::v1alpha1::StoreKind::from(value.store_kind) as i32,
240 dataset_url: Some(value.url.to_string()),
241 }
242 }
243}
244
245impl crate::common::v1alpha1::TaskId {
249 pub fn new() -> Self {
250 Self::from_hashable(re_tuid::Tuid::new())
251 }
252
253 pub fn from_hashable<H: std::hash::Hash>(hashable: H) -> Self {
254 let mut hasher = std::hash::DefaultHasher::new();
255 hashable.hash(&mut hasher);
256 let id = hasher.finish();
257
258 Self {
259 id: format!("task_{id:016x}"),
260 }
261 }
262}
263
264impl TryFrom<crate::common::v1alpha1::Tuid> for re_tuid::Tuid {
267 type Error = TypeConversionError;
268
269 fn try_from(value: crate::common::v1alpha1::Tuid) -> Result<Self, Self::Error> {
270 let time_ns = value
271 .time_ns
272 .ok_or(missing_field!(crate::common::v1alpha1::Tuid, "time_ns"))?;
273 let inc = value
274 .inc
275 .ok_or(missing_field!(crate::common::v1alpha1::Tuid, "inc"))?;
276
277 Ok(Self::from_nanos_and_inc(time_ns, inc))
278 }
279}
280
281impl From<re_tuid::Tuid> for crate::common::v1alpha1::Tuid {
282 fn from(value: re_tuid::Tuid) -> Self {
283 Self {
284 time_ns: Some(value.nanos_since_epoch()),
285 inc: Some(value.inc()),
286 }
287 }
288}
289
290impl From<re_log_types::EntityPath> for crate::common::v1alpha1::EntityPath {
291 fn from(value: re_log_types::EntityPath) -> Self {
292 Self {
293 path: value.to_string(),
294 }
295 }
296}
297
298impl TryFrom<crate::common::v1alpha1::EntityPath> for re_log_types::EntityPath {
299 type Error = TypeConversionError;
300
301 fn try_from(value: crate::common::v1alpha1::EntityPath) -> Result<Self, Self::Error> {
302 Self::parse_strict(&value.path)
303 .map_err(|err| invalid_field!(crate::common::v1alpha1::EntityPath, "path", err))
304 }
305}
306
307impl From<re_log_types::AbsoluteTimeRange> for crate::common::v1alpha1::TimeRange {
308 fn from(value: re_log_types::AbsoluteTimeRange) -> Self {
309 Self {
310 start: value.min().as_i64(),
311 end: value.max().as_i64(),
312 }
313 }
314}
315
316impl From<crate::common::v1alpha1::TimeRange> for re_log_types::AbsoluteTimeRange {
317 fn from(value: crate::common::v1alpha1::TimeRange) -> Self {
318 Self::new(
319 re_log_types::TimeInt::new_temporal(value.start),
320 re_log_types::TimeInt::new_temporal(value.end),
321 )
322 }
323}
324
325impl From<re_log_types::AbsoluteTimeRange> for crate::common::v1alpha1::IndexRange {
326 fn from(value: re_log_types::AbsoluteTimeRange) -> Self {
327 Self {
328 time_range: Some(value.into()),
329 }
330 }
331}
332
333impl TryFrom<crate::common::v1alpha1::IndexRange> for re_log_types::AbsoluteTimeRange {
334 type Error = TypeConversionError;
335
336 fn try_from(value: crate::common::v1alpha1::IndexRange) -> Result<Self, Self::Error> {
337 value
338 .time_range
339 .ok_or(missing_field!(
340 crate::common::v1alpha1::IndexRange,
341 "time_range"
342 ))
343 .map(|time_range| Self::new(time_range.start, time_range.end))
344 }
345}
346
347impl From<crate::common::v1alpha1::Timeline> for re_log_types::TimelineName {
348 fn from(value: crate::common::v1alpha1::Timeline) -> Self {
349 Self::new(&value.name)
350 }
351}
352
353impl From<re_log_types::TimelineName> for crate::common::v1alpha1::Timeline {
354 fn from(value: re_log_types::TimelineName) -> Self {
355 Self {
356 name: value.to_string(),
357 }
358 }
359}
360
361impl From<re_log_types::Timeline> for crate::common::v1alpha1::Timeline {
362 fn from(value: re_log_types::Timeline) -> Self {
363 Self {
364 name: value.name().to_string(),
365 }
366 }
367}
368
369impl TryFrom<crate::common::v1alpha1::IndexColumnSelector> for re_log_types::TimelineName {
370 type Error = TypeConversionError;
371
372 fn try_from(value: crate::common::v1alpha1::IndexColumnSelector) -> Result<Self, Self::Error> {
373 let timeline = value.timeline.ok_or(missing_field!(
374 crate::common::v1alpha1::IndexColumnSelector,
375 "timeline"
376 ))?;
377 Ok(timeline.into())
378 }
379}
380
381impl From<re_log_types::TimelineName> for crate::common::v1alpha1::IndexColumnSelector {
382 fn from(value: re_log_types::TimelineName) -> Self {
383 Self {
384 timeline: Some(value.into()),
385 }
386 }
387}
388
389impl From<crate::common::v1alpha1::ApplicationId> for re_log_types::ApplicationId {
390 #[inline]
391 fn from(value: crate::common::v1alpha1::ApplicationId) -> Self {
392 Self::from(value.id)
393 }
394}
395
396impl From<re_log_types::ApplicationId> for crate::common::v1alpha1::ApplicationId {
397 #[inline]
398 fn from(value: re_log_types::ApplicationId) -> Self {
399 Self {
400 id: value.to_string(),
401 }
402 }
403}
404
405impl From<crate::common::v1alpha1::StoreKind> for re_log_types::StoreKind {
406 #[inline]
407 fn from(value: crate::common::v1alpha1::StoreKind) -> Self {
408 match value {
409 crate::common::v1alpha1::StoreKind::Unspecified
410 | crate::common::v1alpha1::StoreKind::Recording => Self::Recording,
411 crate::common::v1alpha1::StoreKind::Blueprint => Self::Blueprint,
412 }
413 }
414}
415
416impl From<re_log_types::StoreKind> for crate::common::v1alpha1::StoreKind {
417 #[inline]
418 fn from(value: re_log_types::StoreKind) -> Self {
419 match value {
420 re_log_types::StoreKind::Recording => Self::Recording,
421 re_log_types::StoreKind::Blueprint => Self::Blueprint,
422 }
423 }
424}
425
426#[derive(Debug, Clone)]
432pub struct StoreIdMissingApplicationIdError {
433 pub store_kind: re_log_types::StoreKind,
434 pub recording_id: RecordingId,
435}
436
437impl StoreIdMissingApplicationIdError {
438 pub fn recover(self, application_id: re_log_types::ApplicationId) -> re_log_types::StoreId {
440 re_log_types::StoreId::new(self.store_kind, application_id, self.recording_id)
441 }
442
443 #[inline]
444 pub fn into_type_conversion_error(self, msg: impl Into<String>) -> TypeConversionError {
445 TypeConversionError::LegacyStoreIdError(format!(
446 "{} (kind: {}, recording_id: {})",
447 msg.into(),
448 self.store_kind,
449 self.recording_id
450 ))
451 }
452}
453
454impl TryFrom<crate::common::v1alpha1::StoreId> for re_log_types::StoreId {
456 type Error = StoreIdMissingApplicationIdError;
457
458 #[inline]
459 fn try_from(value: crate::common::v1alpha1::StoreId) -> Result<Self, Self::Error> {
460 let store_kind = value.kind().into();
461 let recording_id = RecordingId::from(value.recording_id);
462
463 match value.application_id {
465 None => Err(StoreIdMissingApplicationIdError {
466 store_kind,
467 recording_id,
468 }),
469 Some(application_id) => Ok(re_log_types::StoreId::new(
470 store_kind,
471 application_id,
472 recording_id,
473 )),
474 }
475 }
476}
477
478impl From<re_log_types::StoreId> for crate::common::v1alpha1::StoreId {
479 #[inline]
480 fn from(value: re_log_types::StoreId) -> Self {
481 let kind: crate::common::v1alpha1::StoreKind = value.kind().into();
482 Self {
483 kind: kind as i32,
484 recording_id: value.recording_id().as_str().to_owned(),
485 application_id: Some(value.application_id().clone().into()),
486 }
487 }
488}
489
490impl From<re_log_types::TableId> for crate::common::v1alpha1::TableId {
491 #[inline]
492 fn from(value: re_log_types::TableId) -> Self {
493 Self {
494 id: value.as_str().to_owned(),
495 }
496 }
497}
498
499impl From<crate::common::v1alpha1::TableId> for re_log_types::TableId {
500 #[inline]
501 fn from(value: crate::common::v1alpha1::TableId) -> Self {
502 TableId::from(value.id)
503 }
504}
505
506#[derive(Debug, Default, Clone)]
509pub struct ScanParameters {
510 pub columns: Vec<String>,
511 pub on_missing_columns: IfMissingBehavior,
512 pub filter: Option<String>,
513 pub limit_offset: Option<i64>,
514 pub limit_len: Option<i64>,
515 pub order_by: Vec<ScanParametersOrderClause>,
516 pub explain_plan: bool,
517 pub explain_filter: bool,
518}
519
520impl TryFrom<crate::common::v1alpha1::ScanParameters> for ScanParameters {
521 type Error = TypeConversionError;
522
523 fn try_from(value: crate::common::v1alpha1::ScanParameters) -> Result<Self, Self::Error> {
524 Ok(Self {
525 columns: value.columns,
526 on_missing_columns: crate::common::v1alpha1::IfMissingBehavior::try_from(
527 value.on_missing_columns,
528 )?
529 .into(),
530 filter: value.filter,
531 limit_offset: value.limit_offset,
532 limit_len: value.limit_len,
533 order_by: value
534 .order_by
535 .into_iter()
536 .map(|ob| ob.try_into())
537 .collect::<Result<Vec<_>, _>>()?,
538 explain_plan: value.explain_plan,
539 explain_filter: value.explain_filter,
540 })
541 }
542}
543
544impl From<ScanParameters> for crate::common::v1alpha1::ScanParameters {
545 fn from(value: ScanParameters) -> Self {
546 Self {
547 columns: value.columns,
548 on_missing_columns: crate::common::v1alpha1::IfMissingBehavior::from(
549 value.on_missing_columns,
550 ) as _,
551 filter: value.filter,
552 limit_offset: value.limit_offset,
553 limit_len: value.limit_len,
554 order_by: value.order_by.into_iter().map(|ob| ob.into()).collect(),
555 explain_plan: value.explain_plan,
556 explain_filter: value.explain_filter,
557 }
558 }
559}
560
561#[derive(Debug, Default, Clone)]
562pub struct ScanParametersOrderClause {
563 pub descending: bool,
564 pub nulls_last: bool,
565 pub column_name: String,
566}
567
568impl TryFrom<crate::common::v1alpha1::ScanParametersOrderClause> for ScanParametersOrderClause {
569 type Error = TypeConversionError;
570
571 fn try_from(
572 value: crate::common::v1alpha1::ScanParametersOrderClause,
573 ) -> Result<Self, Self::Error> {
574 Ok(Self {
575 descending: value.descending,
576 nulls_last: value.nulls_last,
577 column_name: value.column_name.ok_or(missing_field!(
578 crate::common::v1alpha1::ScanParametersOrderClause,
579 "column_name"
580 ))?,
581 })
582 }
583}
584
585impl From<ScanParametersOrderClause> for crate::common::v1alpha1::ScanParametersOrderClause {
586 fn from(value: ScanParametersOrderClause) -> Self {
587 Self {
588 descending: value.descending,
589 nulls_last: value.nulls_last,
590 column_name: Some(value.column_name),
591 }
592 }
593}
594
595#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
596pub enum IfMissingBehavior {
597 Skip,
598 Error,
599}
600
601impl Default for IfMissingBehavior {
602 fn default() -> Self {
603 Self::Skip
604 }
605}
606
607impl From<crate::common::v1alpha1::IfMissingBehavior> for IfMissingBehavior {
608 fn from(value: crate::common::v1alpha1::IfMissingBehavior) -> Self {
609 use crate::common::v1alpha1 as common;
610 match value {
611 common::IfMissingBehavior::Unspecified | common::IfMissingBehavior::Skip => Self::Skip,
612 common::IfMissingBehavior::Error => Self::Error,
613 }
614 }
615}
616
617impl From<IfMissingBehavior> for crate::common::v1alpha1::IfMissingBehavior {
618 fn from(value: IfMissingBehavior) -> Self {
619 match value {
620 IfMissingBehavior::Skip => Self::Skip,
621 IfMissingBehavior::Error => Self::Error,
622 }
623 }
624}
625
626#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
627pub enum IfDuplicateBehavior {
628 Overwrite,
629 Skip,
630 Error,
631}
632
633impl Default for IfDuplicateBehavior {
634 fn default() -> Self {
635 Self::Skip
636 }
637}
638
639impl TryFrom<i32> for IfDuplicateBehavior {
640 type Error = TypeConversionError;
641
642 fn try_from(value: i32) -> Result<Self, TypeConversionError> {
643 let proto_value = crate::common::v1alpha1::IfDuplicateBehavior::try_from(value)?;
644 Ok(Self::from(proto_value))
645 }
646}
647
648impl From<crate::common::v1alpha1::IfDuplicateBehavior> for IfDuplicateBehavior {
649 fn from(value: crate::common::v1alpha1::IfDuplicateBehavior) -> Self {
650 use crate::common::v1alpha1 as common;
651 match value {
652 common::IfDuplicateBehavior::Unspecified | common::IfDuplicateBehavior::Skip => {
653 Self::Skip
654 }
655 common::IfDuplicateBehavior::Overwrite => Self::Overwrite,
656 common::IfDuplicateBehavior::Error => Self::Error,
657 }
658 }
659}
660
661impl From<IfDuplicateBehavior> for crate::common::v1alpha1::IfDuplicateBehavior {
662 fn from(value: IfDuplicateBehavior) -> Self {
663 match value {
664 IfDuplicateBehavior::Overwrite => Self::Overwrite,
665 IfDuplicateBehavior::Skip => Self::Skip,
666 IfDuplicateBehavior::Error => Self::Error,
667 }
668 }
669}
670
671impl From<ComponentDescriptor> for crate::common::v1alpha1::ComponentDescriptor {
674 fn from(value: ComponentDescriptor) -> Self {
675 Self {
676 archetype: value.archetype.map(|n| n.full_name().to_owned()),
677 component: Some(value.component.to_string()),
678 component_type: value.component_type.map(|c| c.full_name().to_owned()),
679 }
680 }
681}
682
683impl TryFrom<crate::common::v1alpha1::ComponentDescriptor> for ComponentDescriptor {
684 type Error = TypeConversionError;
685
686 fn try_from(value: crate::common::v1alpha1::ComponentDescriptor) -> Result<Self, Self::Error> {
687 let crate::common::v1alpha1::ComponentDescriptor {
688 archetype,
689 component,
690 component_type,
691 } = value;
692
693 let component = component.ok_or(missing_field!(
694 crate::common::v1alpha1::ComponentDescriptor,
695 "component"
696 ))?;
697
698 Ok(ComponentDescriptor {
699 archetype: archetype.map(Into::into),
700 component: component.into(),
701 component_type: component_type.map(Into::into),
702 })
703 }
704}
705
706impl From<re_build_info::BuildInfo> for crate::common::v1alpha1::BuildInfo {
709 fn from(build_info: re_build_info::BuildInfo) -> Self {
710 Self {
711 crate_name: Some(build_info.crate_name.to_string()),
712 features: Some(build_info.features.to_string()),
713 version: Some(build_info.version.into()),
714 rustc_version: Some(build_info.rustc_version.to_string()),
715 llvm_version: Some(build_info.llvm_version.to_string()),
716 git_hash: Some(build_info.git_hash.to_string()),
717 git_branch: Some(build_info.git_branch.to_string()),
718 target_triple: Some(build_info.target_triple.to_string()),
719 build_time: Some(build_info.datetime.to_string()),
720 is_debug_build: Some(build_info.is_debug_build),
721 }
722 }
723}
724
725impl From<crate::common::v1alpha1::BuildInfo> for re_build_info::BuildInfo {
726 fn from(build_info: crate::common::v1alpha1::BuildInfo) -> Self {
727 Self {
728 crate_name: build_info.crate_name().to_owned().into(),
729 features: build_info.features().to_owned().into(),
730 version: build_info.version.clone().unwrap_or_default().into(),
731 rustc_version: build_info.rustc_version().to_owned().into(),
732 llvm_version: build_info.llvm_version().to_owned().into(),
733 git_hash: build_info.git_hash().to_owned().into(),
734 git_branch: build_info.git_branch().to_owned().into(),
735 is_in_rerun_workspace: false,
736 target_triple: build_info.target_triple().to_owned().into(),
737 datetime: build_info.build_time().to_owned().into(),
738 is_debug_build: build_info.is_debug_build(),
739 }
740 }
741}
742
743impl From<re_build_info::CrateVersion> for crate::common::v1alpha1::SemanticVersion {
744 fn from(version: re_build_info::CrateVersion) -> Self {
745 crate::common::v1alpha1::SemanticVersion {
746 major: Some(version.major.into()),
747 minor: Some(version.minor.into()),
748 patch: Some(version.patch.into()),
749 meta: version.meta.map(Into::into),
750 }
751 }
752}
753
754impl From<crate::common::v1alpha1::SemanticVersion> for re_build_info::CrateVersion {
755 fn from(version: crate::common::v1alpha1::SemanticVersion) -> Self {
756 Self {
757 major: version.major() as u8,
758 minor: version.minor() as u8,
759 patch: version.patch() as u8,
760 meta: version.meta.map(Into::into),
761 }
762 }
763}
764
765impl From<re_build_info::Meta> for crate::common::v1alpha1::semantic_version::Meta {
766 fn from(version_meta: re_build_info::Meta) -> Self {
767 match version_meta {
768 re_build_info::Meta::Rc(v) => Self::Rc(v.into()),
769
770 re_build_info::Meta::Alpha(v) => Self::Alpha(v.into()),
771
772 re_build_info::Meta::DevAlpha { alpha, commit } => {
773 Self::DevAlpha(crate::common::v1alpha1::DevAlpha {
774 alpha: Some(alpha.into()),
775 commit: commit.map(|s| String::from_utf8_lossy(s).to_string()),
776 })
777 }
778 }
779 }
780}
781
782impl From<crate::common::v1alpha1::semantic_version::Meta> for re_build_info::Meta {
783 fn from(version_meta: crate::common::v1alpha1::semantic_version::Meta) -> Self {
784 match version_meta {
785 crate::common::v1alpha1::semantic_version::Meta::Rc(v) => Self::Rc(v as _),
786
787 crate::common::v1alpha1::semantic_version::Meta::Alpha(v) => Self::Alpha(v as _),
788
789 crate::common::v1alpha1::semantic_version::Meta::DevAlpha(dev_alpha) => {
790 Self::DevAlpha {
791 alpha: dev_alpha.alpha() as u8,
792 commit: None,
796 }
797 }
798 }
799 }
800}
801
802impl TryFrom<crate::common::v1alpha1::RerunChunk> for arrow::array::RecordBatch {
805 type Error = TypeConversionError;
806
807 fn try_from(value: crate::common::v1alpha1::RerunChunk) -> Result<Self, Self::Error> {
808 Self::try_from(&value)
809 }
810}
811
812impl TryFrom<&crate::common::v1alpha1::RerunChunk> for arrow::array::RecordBatch {
813 type Error = TypeConversionError;
814
815 fn try_from(value: &crate::common::v1alpha1::RerunChunk) -> Result<Self, Self::Error> {
816 match value.encoder_version() {
817 crate::common::v1alpha1::EncoderVersion::Unspecified => {
818 return Err(missing_field!(
819 crate::common::v1alpha1::RerunChunk,
820 "encoder_version"
821 ));
822 }
823
824 crate::common::v1alpha1::EncoderVersion::V0 => {
825 let Some(bytes) = value.payload.as_ref() else {
826 return Err(missing_field!(
827 crate::common::v1alpha1::DataframePart,
828 "payload"
829 ));
830 };
831 let Some(batch) =
832 record_batch_from_ipc_bytes(bytes, Compression::Off, bytes.len() as u64)?
833 else {
834 return Err(invalid_field!(
835 crate::common::v1alpha1::RerunChunk,
836 "payload",
837 "empty"
838 ));
839 };
840 Ok(batch)
841 }
842 }
843 }
844}
845
846impl From<arrow::array::RecordBatch> for crate::common::v1alpha1::RerunChunk {
847 fn from(value: arrow::array::RecordBatch) -> Self {
848 Self::from(&value)
849 }
850}
851
852impl From<&arrow::array::RecordBatch> for crate::common::v1alpha1::RerunChunk {
853 fn from(value: &arrow::array::RecordBatch) -> Self {
854 let version = crate::common::v1alpha1::EncoderVersion::V0;
855 Self {
856 encoder_version: version as i32,
857 payload: Some(record_batch_to_ipc_bytes(value, Compression::Off).0.into()),
858 }
859 }
860}
861
862impl TryFrom<crate::common::v1alpha1::DataframePart> for arrow::array::RecordBatch {
863 type Error = TypeConversionError;
864
865 fn try_from(value: crate::common::v1alpha1::DataframePart) -> Result<Self, Self::Error> {
866 Self::try_from(&value)
867 }
868}
869
870impl TryFrom<&crate::common::v1alpha1::DataframePart> for arrow::array::RecordBatch {
871 type Error = TypeConversionError;
872
873 fn try_from(value: &crate::common::v1alpha1::DataframePart) -> Result<Self, Self::Error> {
874 match value.encoder_version() {
875 crate::common::v1alpha1::EncoderVersion::Unspecified => {
876 return Err(missing_field!(
877 crate::common::v1alpha1::RerunChunk,
878 "encoder_version"
879 ));
880 }
881
882 crate::common::v1alpha1::EncoderVersion::V0 => {
883 let Some(bytes) = value.payload.as_ref() else {
884 return Err(missing_field!(
885 crate::common::v1alpha1::DataframePart,
886 "payload"
887 ));
888 };
889
890 let compression =
891 crate::common::v1alpha1::Compression::try_from(value.compression)?;
892 let compression = Compression::from(compression);
893
894 let Some(batch) =
895 record_batch_from_ipc_bytes(bytes, compression, value.uncompressed_size)?
896 else {
897 return Err(invalid_field!(
898 crate::common::v1alpha1::RerunChunk,
899 "payload",
900 "empty"
901 ));
902 };
903 Ok(batch)
904 }
905 }
906 }
907}
908
909impl From<arrow::array::RecordBatch> for crate::common::v1alpha1::DataframePart {
910 fn from(value: arrow::array::RecordBatch) -> Self {
911 Self::from(&value)
912 }
913}
914
915impl From<&arrow::array::RecordBatch> for crate::common::v1alpha1::DataframePart {
916 fn from(value: &arrow::array::RecordBatch) -> Self {
917 let version = crate::common::v1alpha1::EncoderVersion::V0;
918 let compression = crate::common::v1alpha1::Compression::Lz4;
919 let (payload, uncompressed_size) = record_batch_to_ipc_bytes(value, compression.into());
920 Self {
921 encoder_version: version as i32, payload: Some(payload.into()),
923 compression: compression as i32, uncompressed_size,
925 }
926 }
927}
928
929#[tracing::instrument(level = "debug", skip_all)]
931fn record_batch_to_ipc_bytes(
932 batch: &arrow::array::RecordBatch,
933 compression: Compression,
934) -> (Vec<u8>, u64) {
935 let schema = batch.schema_ref().as_ref();
936
937 let mut uncompressed = Vec::new();
938
939 {
940 let mut sw = {
941 let _span = tracing::trace_span!("schema").entered();
942 arrow::ipc::writer::StreamWriter::try_new(&mut uncompressed, schema)
943 .expect("encoding the schema of a valid RecordBatch as IPC bytes into a growable in-memory buffer cannot possibly fail")
944 };
945
946 {
947 let _span = tracing::trace_span!("data").entered();
948 sw.write(batch)
949 .expect("encoding the data of a valid RecordBatch as IPC bytes into a growable in-memory buffer cannot possibly fail");
950 }
951
952 sw.finish()
953 .expect("encoding a valid RecordBatch as IPC bytes into a growable in-memory buffer cannot possibly fail");
954 }
955
956 let uncompressed_size = uncompressed.len() as u64;
957
958 let data = match compression {
959 Compression::Off => uncompressed,
960 Compression::LZ4 => {
961 re_tracing::profile_scope!("lz4::compress");
962 let _span = tracing::trace_span!("lz4::compress").entered();
963 lz4_flex::block::compress(&uncompressed)
964 }
965 };
966
967 (data, uncompressed_size)
968}
969
970#[tracing::instrument(level = "debug", skip_all)]
972fn record_batch_from_ipc_bytes(
973 bytes: &[u8],
974 compression: Compression,
975 uncompressed_size: u64,
976) -> Result<Option<arrow::array::RecordBatch>, ArrowError> {
977 let mut uncompressed = Vec::new();
978 let bytes = match compression {
979 Compression::Off => bytes,
980 Compression::LZ4 => {
981 re_tracing::profile_scope!("LZ4-decompress");
982 let _span = tracing::trace_span!("lz4::decompress").entered();
983 uncompressed.resize(uncompressed_size as usize, 0);
984 lz4_flex::block::decompress_into(bytes, &mut uncompressed).map_err(|err| {
985 ArrowError::ParseError(format!("LZ4 decompression failure: {err:#}"))
986 })?;
987 uncompressed.as_slice()
988 }
989 };
990
991 let mut stream = {
992 let _span = tracing::trace_span!("schema").entered();
993 arrow::ipc::reader::StreamReader::try_new(bytes, None)?
994 };
995
996 let _span = tracing::trace_span!("data").entered();
997 stream.next().transpose()
998}
999
1000#[cfg(test)]
1003mod tests {
1004
1005 #[test]
1006 fn entity_path_conversion() {
1007 let entity_path = re_log_types::EntityPath::parse_strict("a/b/c").unwrap();
1008 let proto_entity_path: crate::common::v1alpha1::EntityPath = entity_path.clone().into();
1009 let entity_path2: re_log_types::EntityPath = proto_entity_path.try_into().unwrap();
1010 assert_eq!(entity_path, entity_path2);
1011 }
1012
1013 #[test]
1014 fn time_range_conversion() {
1015 let time_range = re_log_types::AbsoluteTimeRange::new(
1016 re_log_types::TimeInt::new_temporal(123456789),
1017 re_log_types::TimeInt::new_temporal(987654321),
1018 );
1019 let proto_time_range: crate::common::v1alpha1::TimeRange = time_range.into();
1020 let time_range2: re_log_types::AbsoluteTimeRange = proto_time_range.into();
1021 assert_eq!(time_range, time_range2);
1022 }
1023
1024 #[test]
1025 fn index_range_conversion() {
1026 let time_range = re_log_types::AbsoluteTimeRange::new(
1027 re_log_types::TimeInt::new_temporal(123456789),
1028 re_log_types::TimeInt::new_temporal(987654321),
1029 );
1030 let proto_index_range: crate::common::v1alpha1::IndexRange = time_range.into();
1031 let time_range2: re_log_types::AbsoluteTimeRange = proto_index_range.try_into().unwrap();
1032 assert_eq!(time_range, time_range2);
1033 }
1034
1035 #[test]
1036 fn index_column_selector_conversion() {
1037 let timeline = re_log_types::TimelineName::log_time();
1038 let proto_index_column_selector: crate::common::v1alpha1::IndexColumnSelector =
1039 crate::common::v1alpha1::IndexColumnSelector {
1040 timeline: Some(timeline.into()),
1041 };
1042 let timeline2: re_log_types::TimelineName = proto_index_column_selector.try_into().unwrap();
1043 assert_eq!(timeline, timeline2);
1044 }
1045
1046 #[test]
1047 fn application_id_conversion() {
1048 let application_id = re_log_types::ApplicationId::from("test");
1049 let proto_application_id: crate::common::v1alpha1::ApplicationId =
1050 application_id.clone().into();
1051 let application_id2: re_log_types::ApplicationId = proto_application_id.into();
1052 assert_eq!(application_id, application_id2);
1053 }
1054
1055 #[test]
1056 fn store_kind_conversion() {
1057 let store_kind = re_log_types::StoreKind::Recording;
1058 let proto_store_kind: crate::common::v1alpha1::StoreKind = store_kind.into();
1059 let store_kind2: re_log_types::StoreKind = proto_store_kind.into();
1060 assert_eq!(store_kind, store_kind2);
1061 }
1062
1063 #[test]
1064 fn store_id_conversion() {
1065 let store_id = re_log_types::StoreId::new(
1066 re_log_types::StoreKind::Recording,
1067 "test_app_id",
1068 "test_recording",
1069 );
1070 let proto_store_id: crate::common::v1alpha1::StoreId = store_id.clone().into();
1071 let store_id2: re_log_types::StoreId = proto_store_id.try_into().unwrap();
1072 assert_eq!(store_id, store_id2);
1073 }
1074
1075 #[test]
1076 fn test_tuid_conversion() {
1077 let tuid = re_tuid::Tuid::new();
1078 let proto_tuid: crate::common::v1alpha1::Tuid = tuid.into();
1079 let tuid2: re_tuid::Tuid = proto_tuid.try_into().unwrap();
1080 assert_eq!(tuid, tuid2);
1081 }
1082}