mirror of
				https://github.com/lov3b/ecb-rates.git
				synced 2025-10-31 13:20:24 +01:00 
			
		
		
		
	Create non-owned variant of the table.
It yields ~12% faster time for cached results in historical day resolution
This commit is contained in:
		| @@ -6,7 +6,7 @@ use std::{borrow::BorrowMut, collections::HashMap, process::ExitCode}; | ||||
| use ecb_rates::cli::{Cli, FormatOption}; | ||||
| use ecb_rates::models::ExchangeRateResult; | ||||
| use ecb_rates::parsing::parse; | ||||
| use ecb_rates::table::Table; | ||||
| use ecb_rates::table::{TableRef, TableTrait}; | ||||
|  | ||||
| async fn get_and_parse(url: impl IntoUrl) -> anyhow::Result<Vec<ExchangeRateResult>> { | ||||
|     let client = Client::new(); | ||||
| @@ -96,7 +96,7 @@ async fn main() -> ExitCode { | ||||
|         FormatOption::Plain => parsed | ||||
|             .iter() | ||||
|             .map(|x| { | ||||
|                 let mut t: Table = x.clone().into(); | ||||
|                 let mut t: TableRef = x.into(); | ||||
|                 t.sort(); | ||||
|                 format!("{}", t) | ||||
|             }) | ||||
|   | ||||
							
								
								
									
										91
									
								
								src/table.rs
									
									
									
									
									
								
							
							
						
						
									
										91
									
								
								src/table.rs
									
									
									
									
									
								
							| @@ -1,91 +0,0 @@ | ||||
| use colored::*; | ||||
| use std::fmt::Display; | ||||
|  | ||||
| use crate::models::ExchangeRateResult; | ||||
|  | ||||
| pub struct Table { | ||||
|     header: Option<String>, | ||||
|     column_left: String, | ||||
|     column_right: String, | ||||
|     rows: Vec<(String, String)>, | ||||
|     pub color: bool, | ||||
|     pub width: usize, | ||||
| } | ||||
|  | ||||
| impl Table { | ||||
|     fn new(header: Option<String>, column_left: String, column_right: String) -> Self { | ||||
|         Self { | ||||
|             header, | ||||
|             column_left, | ||||
|             column_right, | ||||
|             rows: Vec::new(), | ||||
|             color: false, | ||||
|             width: 21, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[allow(dead_code)] | ||||
|     fn disable_header(&mut self) { | ||||
|         self.header = None | ||||
|     } | ||||
|  | ||||
|     #[allow(dead_code)] | ||||
|     fn set_header(&mut self, header: String) { | ||||
|         self.header = Some(header); | ||||
|     } | ||||
|  | ||||
|     fn add_row(&mut self, row_left: String, row_right: String) { | ||||
|         self.rows.push((row_left, row_right)); | ||||
|     } | ||||
|  | ||||
|     pub fn sort(&mut self) { | ||||
|         self.rows.sort_by(|a, b| a.1.cmp(&b.1)) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Display for Table { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         if let Some(header) = self.header.as_ref() { | ||||
|             let middle_padding_amount = (self.width - header.len()) / 2; | ||||
|             assert!(middle_padding_amount > 0); | ||||
|             let middle_padding = " ".repeat(middle_padding_amount); | ||||
|             writeln!( | ||||
|                 f, | ||||
|                 "{}{}{}", | ||||
|                 middle_padding, | ||||
|                 header.bold().cyan(), | ||||
|                 middle_padding | ||||
|             )?; | ||||
|         } | ||||
|  | ||||
|         let right_padding_amount = self.width - self.column_left.len() - self.column_right.len(); | ||||
|         let right_padding = " ".repeat(right_padding_amount); | ||||
|         writeln!( | ||||
|             f, | ||||
|             "{}{}{}", | ||||
|             self.column_left.bold().yellow(), | ||||
|             right_padding, | ||||
|             self.column_right.bold().yellow() | ||||
|         )?; | ||||
|         writeln!(f, "{}", "-".repeat(self.width))?; | ||||
|  | ||||
|         for (left, right) in self.rows.iter() { | ||||
|             let padding_amount = self.width - left.len() - right.len(); | ||||
|             let padding = " ".repeat(padding_amount); | ||||
|             writeln!(f, "{}{}{}", left.bold().green(), padding, right)?; | ||||
|         } | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<ExchangeRateResult> for Table { | ||||
|     fn from(value: ExchangeRateResult) -> Self { | ||||
|         let mut table = Table::new(Some(value.time), "Currency".to_string(), "Rate".to_string()); | ||||
|         for (key, val) in value.rates.into_iter() { | ||||
|             table.add_row(key, val.to_string()); | ||||
|         } | ||||
|  | ||||
|         table | ||||
|     } | ||||
| } | ||||
							
								
								
									
										11
									
								
								src/table/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/table/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| mod table_getter; | ||||
| mod table_owned; | ||||
| mod table_ref; | ||||
| mod table_trait; | ||||
| mod table_display; | ||||
|  | ||||
| pub use table_getter::TableGet; | ||||
| pub use table_owned::Table; | ||||
| pub use table_ref::TableRef; | ||||
| pub use table_trait::TableTrait; | ||||
|  | ||||
							
								
								
									
										46
									
								
								src/table/table_display.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/table/table_display.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| use colored::Colorize; | ||||
|  | ||||
| use super::TableGet; | ||||
|  | ||||
| pub fn helper_table_print<T: TableGet>( | ||||
|     f: &mut std::fmt::Formatter<'_>, | ||||
|     table: &T, | ||||
| ) -> std::fmt::Result { | ||||
|     let width = table.get_width(); | ||||
|  | ||||
|     if let Some(header) = table.get_header() { | ||||
|         let middle_padding_amount = (width - header.len()) / 2; | ||||
|         assert!(middle_padding_amount > 0); | ||||
|         let middle_padding = " ".repeat(middle_padding_amount); | ||||
|         writeln!( | ||||
|             f, | ||||
|             "{}{}{}", | ||||
|             middle_padding, | ||||
|             header.bold().cyan(), | ||||
|             middle_padding | ||||
|         )?; | ||||
|     } | ||||
|  | ||||
|     let column_left = table.get_column_left(); | ||||
|     let column_right = table.get_column_right(); | ||||
|     let right_padding_amount = width - column_left.len() - column_right.len(); | ||||
|     let right_padding = " ".repeat(right_padding_amount); | ||||
|     writeln!( | ||||
|         f, | ||||
|         "{}{}{}", | ||||
|         column_left.bold().yellow(), | ||||
|         right_padding, | ||||
|         column_right.bold().yellow() | ||||
|     )?; | ||||
|     writeln!(f, "{}", "-".repeat(width))?; | ||||
|  | ||||
|     for (left, right) in table.get_rows().iter() { | ||||
|         let left_str = left.as_ref(); | ||||
|         let right_str = right.to_string(); | ||||
|         let padding_amount = width.saturating_sub(left_str.len() + right_str.len()); | ||||
|         let padding = " ".repeat(padding_amount); | ||||
|         writeln!(f, "{}{}{}", left_str.bold().green(), padding, right_str)?; | ||||
|     } | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
							
								
								
									
										10
									
								
								src/table/table_getter.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/table/table_getter.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| pub trait TableGet { | ||||
|     type RowLeftRef: AsRef<str>; | ||||
|     type RowRightRef: AsRef<str>; | ||||
|  | ||||
|     fn get_header(&self) -> Option<&str>; | ||||
|     fn get_column_left(&self) -> &str; | ||||
|     fn get_column_right(&self) -> &str; | ||||
|     fn get_rows(&self) -> &Vec<(Self::RowLeftRef, f64)>; | ||||
|     fn get_width(&self) -> usize; | ||||
| } | ||||
							
								
								
									
										91
									
								
								src/table/table_owned.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								src/table/table_owned.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | ||||
| use std::fmt::Display; | ||||
|  | ||||
| use crate::models::ExchangeRateResult; | ||||
|  | ||||
| use super::table_display::helper_table_print; | ||||
| use super::{TableGet, TableTrait}; | ||||
|  | ||||
| pub struct Table { | ||||
|     header: Option<String>, | ||||
|     column_left: String, | ||||
|     column_right: String, | ||||
|     rows: Vec<(String, f64)>, | ||||
|     pub color: bool, | ||||
|     pub width: usize, | ||||
| } | ||||
|  | ||||
| impl<'a> TableTrait<'a> for Table { | ||||
|     type Header = String; | ||||
|     type ColumnLeft = String; | ||||
|     type ColumnRight = String; | ||||
|     type RowLeft = String; | ||||
|  | ||||
|     fn new( | ||||
|         header: Option<Self::Header>, | ||||
|         column_left: Self::ColumnLeft, | ||||
|         column_right: Self::ColumnRight, | ||||
|     ) -> Self { | ||||
|         Self { | ||||
|             header, | ||||
|             column_left, | ||||
|             column_right, | ||||
|             rows: Vec::new(), | ||||
|             color: false, | ||||
|             width: 21, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn disable_header(&mut self) { | ||||
|         self.header = None; | ||||
|     } | ||||
|  | ||||
|     fn set_header(&mut self, header: Self::Header) { | ||||
|         self.header = Some(header); | ||||
|     } | ||||
|  | ||||
|     fn add_row(&mut self, row_left: Self::RowLeft, row_right: f64) { | ||||
|         self.rows.push((row_left, row_right)); | ||||
|     } | ||||
|  | ||||
|     fn sort(&mut self) { | ||||
|         self.rows.sort_by(|a, b| a.1.total_cmp(&b.1)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl TableGet for Table { | ||||
|     type RowLeftRef = String; | ||||
|     type RowRightRef = String; | ||||
|  | ||||
|     fn get_header(&self) -> Option<&str> { | ||||
|         self.header.as_deref() | ||||
|     } | ||||
|     fn get_column_left(&self) -> &str { | ||||
|         &self.column_left | ||||
|     } | ||||
|     fn get_column_right(&self) -> &str { | ||||
|         &self.column_right | ||||
|     } | ||||
|     fn get_rows(&self) -> &Vec<(Self::RowLeftRef, f64)> { | ||||
|         &self.rows | ||||
|     } | ||||
|     fn get_width(&self) -> usize { | ||||
|         self.width | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<ExchangeRateResult> for Table { | ||||
|     fn from(value: ExchangeRateResult) -> Self { | ||||
|         let mut table = Table::new(Some(value.time), "Currency".to_string(), "Rate".to_string()); | ||||
|         for (key, val) in value.rates.into_iter() { | ||||
|             table.add_row(key, val); | ||||
|         } | ||||
|  | ||||
|         table | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Display for Table { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         helper_table_print(f, self) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										92
									
								
								src/table/table_ref.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								src/table/table_ref.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,92 @@ | ||||
| use std::fmt::Display; | ||||
|  | ||||
| use crate::models::ExchangeRateResult; | ||||
|  | ||||
| use super::table_display::helper_table_print; | ||||
| use super::table_getter::TableGet; | ||||
| use super::table_trait::TableTrait; | ||||
|  | ||||
| pub struct TableRef<'a> { | ||||
|     header: Option<&'a str>, | ||||
|     column_left: &'a str, | ||||
|     column_right: &'a str, | ||||
|     rows: Vec<(&'a str, f64)>, | ||||
|     pub color: bool, | ||||
|     pub width: usize, | ||||
| } | ||||
|  | ||||
| impl<'a> TableTrait<'a> for TableRef<'a> { | ||||
|     type Header = &'a str; | ||||
|     type ColumnLeft = &'a str; | ||||
|     type ColumnRight = &'a str; | ||||
|     type RowLeft = &'a str; | ||||
|  | ||||
|     fn new( | ||||
|         header: Option<Self::Header>, | ||||
|         column_left: Self::ColumnLeft, | ||||
|         column_right: Self::ColumnRight, | ||||
|     ) -> Self { | ||||
|         Self { | ||||
|             header, | ||||
|             column_left, | ||||
|             column_right, | ||||
|             rows: Vec::new(), | ||||
|             color: false, | ||||
|             width: 21, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn disable_header(&mut self) { | ||||
|         self.header = None; | ||||
|     } | ||||
|  | ||||
|     fn set_header(&mut self, header: Self::Header) { | ||||
|         self.header = Some(header); | ||||
|     } | ||||
|  | ||||
|     fn add_row(&mut self, row_left: Self::RowLeft, row_right: f64) { | ||||
|         self.rows.push((row_left, row_right)); | ||||
|     } | ||||
|  | ||||
|     fn sort(&mut self) { | ||||
|         self.rows.sort_by(|a, b| a.1.total_cmp(&b.1)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a> TableGet for TableRef<'a> { | ||||
|     type RowLeftRef = &'a str; | ||||
|     type RowRightRef = &'a str; | ||||
|  | ||||
|     fn get_header(&self) -> Option<&str> { | ||||
|         self.header | ||||
|     } | ||||
|     fn get_column_left(&self) -> &str { | ||||
|         self.column_left | ||||
|     } | ||||
|     fn get_column_right(&self) -> &str { | ||||
|         self.column_right | ||||
|     } | ||||
|     fn get_rows(&self) -> &Vec<(Self::RowLeftRef, f64)> { | ||||
|         &self.rows | ||||
|     } | ||||
|     fn get_width(&self) -> usize { | ||||
|         self.width | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a> From<&'a ExchangeRateResult> for TableRef<'a> { | ||||
|     fn from(value: &'a ExchangeRateResult) -> Self { | ||||
|         let mut table = TableRef::new(Some(&value.time), "Currency", "Rate"); | ||||
|         for (key, val) in value.rates.iter() { | ||||
|             table.add_row(key, *val); | ||||
|         } | ||||
|  | ||||
|         table | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a> Display for TableRef<'a> { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         helper_table_print(f, self) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										12
									
								
								src/table/table_trait.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/table/table_trait.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| pub trait TableTrait<'a> { | ||||
|     type Header; | ||||
|     type ColumnLeft; | ||||
|     type ColumnRight; | ||||
|     type RowLeft; | ||||
|  | ||||
|     fn new(header: Option<Self::Header>, column_left: Self::ColumnLeft, column_right: Self::ColumnRight) -> Self; | ||||
|     fn disable_header(&mut self); | ||||
|     fn set_header(&mut self, header: Self::Header); | ||||
|     fn add_row(&mut self, row_left: Self::RowLeft, row_right: f64); | ||||
|     fn sort(&mut self); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user