shape_runtime/
content_dispatch.rs1use crate::content_renderer::RendererCapabilities;
17use shape_value::DataTable;
18use shape_value::content::{BorderStyle, ContentNode, ContentTable};
19
20pub mod adapters {
22 pub const TERMINAL: &str = "Terminal";
23 pub const HTML: &str = "Html";
24 pub const MARKDOWN: &str = "Markdown";
25 pub const JSON: &str = "Json";
26 pub const PLAIN: &str = "Plain";
27}
28
29pub fn capabilities_for_adapter(adapter: &str) -> RendererCapabilities {
30 match adapter {
31 adapters::TERMINAL => RendererCapabilities::terminal(),
32 adapters::HTML => RendererCapabilities::html(),
33 adapters::MARKDOWN => RendererCapabilities::markdown(),
34 adapters::JSON => RendererCapabilities::json(),
35 _ => RendererCapabilities::plain(),
36 }
37}
38
39pub fn datatable_to_content_node(dt: &DataTable, max_rows: Option<usize>) -> ContentNode {
42 use arrow_array::Array;
43
44 let headers = dt.column_names();
45 let total = dt.row_count();
46 let limit = max_rows.unwrap_or(total).min(total);
47
48 let schema = dt.inner().schema();
49 let column_types: Vec<String> = schema
50 .fields()
51 .iter()
52 .map(|f| arrow_type_label(f.data_type()))
53 .collect();
54
55 let batch = dt.inner();
56 let mut rows = Vec::with_capacity(limit);
57 for row_idx in 0..limit {
58 let mut cells = Vec::with_capacity(headers.len());
59 for col_idx in 0..headers.len() {
60 let col = batch.column(col_idx);
61 let text = if col.is_null(row_idx) {
62 "null".to_string()
63 } else {
64 arrow_cell_display(col.as_ref(), row_idx)
65 };
66 cells.push(ContentNode::plain(text));
67 }
68 rows.push(cells);
69 }
70
71 ContentNode::Table(ContentTable {
72 headers,
73 rows,
74 border: BorderStyle::default(),
75 max_rows: None,
76 column_types: Some(column_types),
77 total_rows: if total > limit { Some(total) } else { None },
78 sortable: true,
79 })
80}
81
82fn arrow_type_label(dt: &arrow_schema::DataType) -> String {
83 use arrow_schema::DataType;
84 match dt {
85 DataType::Int8 => "i8".to_string(),
86 DataType::Int16 => "i16".to_string(),
87 DataType::Int32 => "i32".to_string(),
88 DataType::Int64 => "int".to_string(),
89 DataType::UInt8 => "u8".to_string(),
90 DataType::UInt16 => "u16".to_string(),
91 DataType::UInt32 => "u32".to_string(),
92 DataType::UInt64 => "u64".to_string(),
93 DataType::Float32 => "f32".to_string(),
94 DataType::Float64 => "number".to_string(),
95 DataType::Boolean => "bool".to_string(),
96 DataType::Utf8 | DataType::LargeUtf8 => "string".to_string(),
97 DataType::Date32 | DataType::Date64 => "date".to_string(),
98 DataType::Timestamp(_, _) => "timestamp".to_string(),
99 other => format!("{:?}", other),
100 }
101}
102
103fn arrow_cell_display(array: &dyn arrow_array::Array, index: usize) -> String {
104 use arrow_array::cast::AsArray;
105 use arrow_schema::DataType;
106
107 match array.data_type() {
108 DataType::Int8 => array.as_primitive::<arrow_array::types::Int8Type>().value(index).to_string(),
109 DataType::Int16 => array.as_primitive::<arrow_array::types::Int16Type>().value(index).to_string(),
110 DataType::Int32 => array.as_primitive::<arrow_array::types::Int32Type>().value(index).to_string(),
111 DataType::Int64 => array.as_primitive::<arrow_array::types::Int64Type>().value(index).to_string(),
112 DataType::UInt8 => array.as_primitive::<arrow_array::types::UInt8Type>().value(index).to_string(),
113 DataType::UInt16 => array.as_primitive::<arrow_array::types::UInt16Type>().value(index).to_string(),
114 DataType::UInt32 => array.as_primitive::<arrow_array::types::UInt32Type>().value(index).to_string(),
115 DataType::UInt64 => array.as_primitive::<arrow_array::types::UInt64Type>().value(index).to_string(),
116 DataType::Float32 => array.as_primitive::<arrow_array::types::Float32Type>().value(index).to_string(),
117 DataType::Float64 => array.as_primitive::<arrow_array::types::Float64Type>().value(index).to_string(),
118 DataType::Boolean => array.as_boolean().value(index).to_string(),
119 DataType::Utf8 => array.as_string::<i32>().value(index).to_string(),
120 DataType::LargeUtf8 => array.as_string::<i64>().value(index).to_string(),
121 _ => format!("{:?}", array.slice(index, 1)),
122 }
123}