mirror of
https://github.com/lov3b/ecb-rates.git
synced 2025-04-18 12:20: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::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);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user