reactive_graph_server/shared/output_format/
render_table.rs

1use crate::shared::output_format::OutputFormatArgs;
2use crate::shared::output_format::OutputFormatArgsOptional;
3use reactive_graph_serde::error::SerializationError;
4use serde::Serialize;
5use std::process::exit;
6use table_to_html::HtmlTable;
7use tabled::Table;
8use tabled::Tabled;
9use tabled::settings::Style;
10use tabled::settings::Width;
11use tabled::settings::object::Rows;
12use thiserror::Error;
13use toml::map::Map;
14
15#[derive(Debug, Error)]
16pub enum RenderTableError {
17    #[error("Failed to serialize: {0}")]
18    SerializationError(#[from] SerializationError),
19    #[error("Not yet implemented")]
20    NotImplemented,
21}
22
23pub trait RenderTable {
24    fn render(&self, output_format: &OutputFormatArgs) -> Result<String, RenderTableError>;
25
26    fn do_print_table_and_exit(&self, output_format: &OutputFormatArgs) -> !;
27    fn print_table_and_exit(&self, output_format: &OutputFormatArgsOptional) -> !;
28}
29
30impl<T: Tabled + Serialize> RenderTable for Vec<T> {
31    fn render(&self, output_format: &OutputFormatArgs) -> Result<String, RenderTableError> {
32        match output_format {
33            OutputFormatArgs::Table => {
34                let table = Table::new(self).modify(Rows::new(1..), Width::wrap(40)).to_owned();
35                Ok(format!("{table}"))
36            }
37            OutputFormatArgs::HtmlTable => Ok(HtmlTable::with_header(Vec::<Vec<String>>::from(Table::builder(self)))
38                .to_string()
39                .trim()
40                .to_string()),
41            OutputFormatArgs::MarkdownTable => {
42                let table = Table::new(self).with(Style::markdown()).to_owned();
43                Ok(format!("{table}"))
44            }
45            OutputFormatArgs::Count => Ok(format!("{}", self.len())),
46            OutputFormatArgs::Json | OutputFormatArgs::Json5 => Ok(serde_json::to_string_pretty(self).map_err(SerializationError::Json)?),
47            OutputFormatArgs::Toml => {
48                let inner = toml::Value::try_from(self).map_err(SerializationError::Toml)?;
49                let mut map: Map<String, toml::Value> = Map::new();
50                let type_name = std::any::type_name::<T>().rsplit_once("::").unwrap_or_default().1.to_string();
51                map.insert(type_name, inner);
52                let table = toml::Value::Table(map);
53                Ok(toml::to_string_pretty(&table).map_err(SerializationError::Toml)?)
54            }
55        }
56    }
57
58    fn do_print_table_and_exit(&self, output_format: &OutputFormatArgs) -> ! {
59        match self.render(output_format) {
60            Ok(rendered_table) => {
61                println!("{rendered_table}");
62                exit(0);
63            }
64            Err(e) => {
65                eprintln!("{e}");
66                exit(1);
67            }
68        }
69    }
70    fn print_table_and_exit(&self, output_format: &OutputFormatArgsOptional) -> ! {
71        self.do_print_table_and_exit(&output_format.output_format.clone().unwrap_or_default())
72    }
73}