mirror of
https://github.com/lov3b/ecb-rates.git
synced 2025-04-11 12:40:11 +02: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:
parent
27fb228e87
commit
81ec482918
@ -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);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user