use crate::{
width, BinaryFormat, BoolFormat, CellFormat, CellFormatShorthand, ColumnData, ColumnType,
FontStyle, FormatError, NumberFormat, StringFormat, UnknownFormat,
};
#[derive(Debug, Clone)]
pub struct ColumnFormatShorthand {
pub name: String,
pub display_name: String,
pub format: CellFormatShorthand,
pub horizontal_align: HorizontalAlign,
pub vertical_align: VerticalAlign,
pub font_style: Option<FontStyle>,
}
impl ColumnFormatShorthand {
pub fn finalize(self, column_type: &ColumnType) -> Result<ColumnFormat, FormatError> {
Ok(ColumnFormat {
name: self.name,
display_name: self.display_name,
format: self.format.finalize(column_type)?,
horizontal_align: self.horizontal_align,
vertical_align: self.vertical_align,
font_style: self.font_style,
})
}
}
impl Default for ColumnFormatShorthand {
fn default() -> ColumnFormatShorthand {
let format = UnknownFormat {
min_width: None,
max_width: None,
};
ColumnFormatShorthand {
name: "".to_string(),
display_name: "".to_string(),
format: CellFormatShorthand::Unknown(format),
horizontal_align: HorizontalAlign::Right,
vertical_align: VerticalAlign::Top,
font_style: None,
}
}
}
#[derive(Debug, Clone)]
pub struct ColumnFormat {
pub name: String,
pub display_name: String,
pub format: CellFormat,
pub horizontal_align: HorizontalAlign,
pub vertical_align: VerticalAlign,
pub font_style: Option<FontStyle>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum HorizontalAlign {
Left,
Right,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum VerticalAlign {
Top,
Bottom,
}
impl ColumnFormat {
pub fn header_width(&self) -> usize {
width(&self.display_name)
}
pub fn get_min_width(&self) -> usize {
self.format.get_min_width().unwrap_or(0)
}
pub fn get_max_width(&self) -> usize {
self.format.get_max_width().unwrap_or(usize::MAX)
}
pub fn format(&self, series: &ColumnData) -> Result<Vec<String>, FormatError> {
let formatted: Result<Vec<String>, FormatError> = match series {
ColumnData::BinaryColumn(value) => {
let fmt: BinaryFormat = self.format.clone().try_into()?;
value.iter().map(|v| fmt.format(v)).collect()
}
ColumnData::BinaryOptionColumn(value) => {
let fmt: BinaryFormat = self.format.clone().try_into()?;
value
.iter()
.map(|v| fmt.format_option(v, fmt.fill_char.to_string().repeat(fmt.min_width)))
.collect()
}
ColumnData::FloatColumn(value) => {
let fmt: NumberFormat = self.format.clone().try_into()?;
value.iter().map(|v| fmt.format(*v)).collect()
}
ColumnData::FloatOptionColumn(value) => {
let fmt: NumberFormat = self.format.clone().try_into()?;
value
.iter()
.map(|v| fmt.format_option(*v, fmt.fill.to_string().repeat(fmt.min_width)))
.collect()
}
ColumnData::IntegerColumn(value) => {
let fmt: NumberFormat = self.format.clone().try_into()?;
value.iter().map(|v| fmt.format(*v)).collect()
}
ColumnData::IntegerOptionColumn(value) => {
let fmt: NumberFormat = self.format.clone().try_into()?;
value
.iter()
.map(|v| fmt.format_option(*v, fmt.fill.to_string().repeat(fmt.min_width)))
.collect()
}
ColumnData::StringColumn(value) => {
let fmt: StringFormat = self.format.clone().try_into()?;
value.iter().map(|v| fmt.format(v)).collect()
}
ColumnData::StringOptionColumn(value) => {
let fmt: StringFormat = self.format.clone().try_into()?;
value
.iter()
.map(|v| {
fmt.format_option(
v.clone(),
fmt.fill_char.to_string().repeat(fmt.min_width),
)
})
.collect()
}
ColumnData::BoolColumn(value) => {
let fmt: BoolFormat = self.format.clone().try_into()?;
value.iter().map(|v| fmt.format(*v)).collect()
}
ColumnData::BoolOptionColumn(value) => {
let fmt: BoolFormat = self.format.clone().try_into()?;
value
.iter()
.map(|v| fmt.format_option(*v, fmt.fill_char.to_string().repeat(fmt.min_width)))
.collect()
}
};
let formatted = formatted?;
Ok(formatted)
}
}
impl ColumnFormat {
pub fn name<T: AsRef<str>>(mut self, name: T) -> ColumnFormat {
let name = name.as_ref().to_string();
self.name = name.clone();
if self.display_name.is_empty() {
self.display_name = name
};
self
}
pub fn display_name<T: AsRef<str>>(mut self, display_name: T) -> ColumnFormat {
self.display_name = display_name.as_ref().to_string();
self
}
pub fn newline_underscores(mut self) -> ColumnFormat {
self.display_name = self.display_name.replace('_', "\n");
self
}
pub fn width(self, width: usize) -> ColumnFormat {
self.min_width(width).max_width(width)
}
pub fn min_width(mut self, width: usize) -> ColumnFormat {
self.format = self.format.min_width(width);
self
}
pub fn max_width(mut self, width: usize) -> ColumnFormat {
self.format = self.format.max_width(width);
self
}
}
impl ColumnFormatShorthand {
pub fn new() -> ColumnFormatShorthand {
ColumnFormatShorthand::default()
}
pub fn name<T: AsRef<str>>(mut self, name: T) -> ColumnFormatShorthand {
let name = name.as_ref().to_string();
self.name = name.clone();
if self.display_name.is_empty() {
self.display_name = name
};
self
}
pub fn display_name<T: AsRef<str>>(mut self, display_name: T) -> ColumnFormatShorthand {
self.display_name = display_name.as_ref().to_string();
self
}
pub fn newline_underscores(mut self) -> ColumnFormatShorthand {
self.display_name = self.display_name.replace('_', "\n");
self
}
pub fn width(self, width: usize) -> ColumnFormatShorthand {
self.min_width(width).max_width(width)
}
pub fn min_width(mut self, width: usize) -> ColumnFormatShorthand {
self.format = self.format.min_width(width);
self
}
pub fn max_width(mut self, width: usize) -> ColumnFormatShorthand {
self.format = self.format.max_width(width);
self
}
pub fn set_format<T: Into<CellFormatShorthand>>(mut self, format: T) -> ColumnFormatShorthand {
self.format = format.into();
self
}
pub fn font_style<T: Into<FontStyle>>(mut self, font_style: T) -> ColumnFormatShorthand {
self.font_style = Some(font_style.into());
self
}
pub fn left_justify(mut self) -> ColumnFormatShorthand {
self.horizontal_align = HorizontalAlign::Left;
self
}
}