runtime/globals/console/
table.rs1use std::borrow::Cow;
8use std::fmt;
9use std::fmt::{Display, Formatter};
10use std::iter::{empty, once, repeat_with};
11
12use either::Either;
13use indexmap::IndexSet;
14use ion::conversions::FromValue as _;
15use ion::format::key::{KeyDisplay, format_key};
16use ion::format::{Config, format_value};
17use ion::{Context, Object, OwnedKey, Result};
18
19fn combine_keys(_: &Context, indexes: IndexSet<i32>, headers: IndexSet<String>) -> IndexSet<OwnedKey<'_>> {
20 let mut indexes: Vec<i32> = indexes.into_iter().collect();
21 indexes.sort_unstable();
22
23 let mut keys: IndexSet<OwnedKey> = indexes.into_iter().map(OwnedKey::Int).collect();
24 keys.extend(headers.into_iter().map(OwnedKey::String));
25 keys
26}
27
28pub(crate) fn sort_keys<'cx, I: IntoIterator<Item = Result<OwnedKey<'cx>>>>(
29 cx: &'cx Context, unsorted: I,
30) -> ion::Result<IndexSet<OwnedKey<'cx>>> {
31 let mut indexes = IndexSet::<i32>::new();
32 let mut headers = IndexSet::<String>::new();
33
34 for key in unsorted {
35 match key {
36 Ok(OwnedKey::Int(index)) => indexes.insert(index),
37 Ok(OwnedKey::String(header)) => headers.insert(header),
38 Err(e) => return Err(e),
39 _ => false,
40 };
41 }
42
43 Ok(combine_keys(cx, indexes, headers))
44}
45
46pub(crate) enum Cell<'cx> {
47 Key(KeyDisplay<'cx>),
48 String(Cow<'static, str>),
49}
50
51impl Display for Cell<'_> {
52 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
53 match self {
54 Cell::Key(key) => key.fmt(f),
55 Cell::String(string) => Display::fmt(string, f),
56 }
57 }
58}
59
60pub(crate) fn get_cells<'cx>(
61 cx: &'cx Context, object: &Object, rows: &'cx IndexSet<OwnedKey>, columns: &'cx IndexSet<OwnedKey>,
62 has_values: bool,
63) -> impl IntoIterator<Item = impl IntoIterator<Item = Cell<'cx>>> {
64 rows.iter().map(move |row| {
65 let Ok(Some(value)) = object.get(cx, row) else {
66 return Either::Left(empty());
67 };
68 let key = Cell::Key(format_key(cx, Config::default(), row));
69
70 if let Ok(object) = Object::from_value(cx, &value, true, ()) {
71 let cells = columns.iter().map(move |column| match object.get(cx, column) {
72 Ok(Some(val)) => Cell::String(Cow::Owned(
73 format_value(cx, Config::default().multiline(false).quoted(true), &val).to_string(),
74 )),
75 _ => Cell::String(Cow::Borrowed("")),
76 });
77
78 let cells = once(key).chain(cells);
79 let cells = if has_values {
80 Either::Left(cells.chain(once(Cell::String(Cow::Borrowed("")))))
81 } else {
82 Either::Right(cells)
83 };
84
85 Either::Right(Either::Right(cells))
86 } else {
87 let cells = once(key).chain(repeat_with(|| Cell::String(Cow::Borrowed(""))).take(columns.len()));
88 let cells = if has_values {
89 Either::Left(cells.chain(once(Cell::String(Cow::Owned(
90 format_value(cx, Config::default().multiline(false).quoted(true), &value).to_string(),
91 )))))
92 } else {
93 Either::Right(cells)
94 };
95 Either::Right(Either::Left(cells))
96 }
97 })
98}