1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
use itertools::Itertools;

use re_chunk_store::external::arrow2;
use re_chunk_store::external::arrow2::array::Utf8Array;
use re_types::SizeBytes as _;
use re_ui::UiExt;

// Note: this is copied and heavily modified from `re_data_ui`. We don't want to unify them because
// that would likely introduce an undesired dependency (`re_chunk_store_ui` should remain as
// independent as possible from the viewer, so it may be split off one day).
pub(crate) fn arrow_ui(ui: &mut egui::Ui, array: &dyn arrow2::array::Array) {
    ui.scope(|ui| {
        ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Truncate);

        // Special-treat text.
        // Note: we match on the raw data here, so this works for any component containing text.
        if let Some(utf8) = array.as_any().downcast_ref::<Utf8Array<i32>>() {
            if utf8.len() == 1 {
                let string = utf8.value(0);
                ui.monospace(string);
                return;
            }
        }
        if let Some(utf8) = array.as_any().downcast_ref::<Utf8Array<i64>>() {
            if utf8.len() == 1 {
                let string = utf8.value(0);
                ui.monospace(string);
                return;
            }
        }

        let num_bytes = array.total_size_bytes();
        if num_bytes < 3000 {
            if array.is_empty() {
                ui.monospace("[]");
                return;
            }

            let instance_count = array.len();
            let display = arrow2::array::get_display(array, "null");

            if instance_count == 1 {
                let mut string = String::new();
                match display(&mut string, 0) {
                    Ok(_) => ui.monospace(&string),
                    Err(err) => ui.error_with_details_on_hover(&err.to_string()),
                };
                return;
            } else {
                ui.label(format!("{instance_count} items"))
                    .on_hover_ui(|ui| {
                        ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Wrap);
                        ui.monospace(format!(
                            "[{}]",
                            (0..instance_count)
                                .filter_map(|index| {
                                    let mut s = String::new();
                                    //TODO(ab): should we care about errors here?
                                    display(&mut s, index).ok().map(|_| s)
                                })
                                .join(", ")
                        ));
                    });
            }

            return;
        }

        // Fallback:
        let bytes = re_format::format_bytes(num_bytes as _);

        let data_type_formatted = format!("{:?}", array.data_type());

        if data_type_formatted.len() < 20 {
            // e.g. "4.2 KiB of Float32"
            ui.label(&format!("{bytes} of {data_type_formatted}"));
        } else {
            // Huge datatype, probably a union horror show
            ui.label(format!("{bytes} of data"));
        }
    });
}