mirror of
				https://github.com/lov3b/ecb-rates.git
				synced 2025-10-31 05:10:25 +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::cli::{Cli, FormatOption}; | ||||||
| use ecb_rates::models::ExchangeRateResult; | use ecb_rates::models::ExchangeRateResult; | ||||||
| use ecb_rates::parsing::parse; | 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>> { | async fn get_and_parse(url: impl IntoUrl) -> anyhow::Result<Vec<ExchangeRateResult>> { | ||||||
|     let client = Client::new(); |     let client = Client::new(); | ||||||
| @@ -96,7 +96,7 @@ async fn main() -> ExitCode { | |||||||
|         FormatOption::Plain => parsed |         FormatOption::Plain => parsed | ||||||
|             .iter() |             .iter() | ||||||
|             .map(|x| { |             .map(|x| { | ||||||
|                 let mut t: Table = x.clone().into(); |                 let mut t: TableRef = x.into(); | ||||||
|                 t.sort(); |                 t.sort(); | ||||||
|                 format!("{}", t) |                 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