mirror of
https://github.com/lov3b/ecb-rates.git
synced 2025-12-19 19:00:39 +01:00
Compare commits
1 Commits
v1.0.1
...
feature/sm
| Author | SHA1 | Date | |
|---|---|---|---|
| 0f930271c7 |
30
Cargo.lock
generated
30
Cargo.lock
generated
@@ -91,6 +91,15 @@ version = "2.10.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "borsh"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f"
|
||||||
|
dependencies = [
|
||||||
|
"cfg_aliases",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.19.1"
|
version = "3.19.1"
|
||||||
@@ -119,6 +128,12 @@ version = "1.0.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg_aliases"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.42"
|
version = "0.4.42"
|
||||||
@@ -227,6 +242,7 @@ dependencies = [
|
|||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"smol_str",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -961,9 +977,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-pki-types"
|
name = "rustls-pki-types"
|
||||||
version = "1.13.1"
|
version = "1.13.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "708c0f9d5f54ba0272468c1d306a52c495b31fa155e91bc25371e6df7996908c"
|
checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
@@ -1096,6 +1112,16 @@ version = "1.15.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smol_str"
|
||||||
|
version = "0.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3498b0a27f93ef1402f20eefacfaa1691272ac4eca1cdc8c596cb0a245d6cbf5"
|
||||||
|
dependencies = [
|
||||||
|
"borsh",
|
||||||
|
"serde_core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.6.1"
|
version = "0.6.1"
|
||||||
|
|||||||
@@ -34,4 +34,5 @@ quick-xml = { version = "0.38", features = ["async-tokio", "tokio"] }
|
|||||||
reqwest = "0.12"
|
reqwest = "0.12"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
smol_str = { version = "0.3", features = ["serde"] }
|
||||||
tokio = { version = "1.48", features = ["macros"] }
|
tokio = { version = "1.48", features = ["macros"] }
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use clap::{arg, Parser, ValueEnum};
|
use clap::{arg, Parser, ValueEnum};
|
||||||
|
use smol_str::SmolStr;
|
||||||
|
|
||||||
use super::{ShowDays, SortBy};
|
use super::{ShowDays, SortBy};
|
||||||
|
|
||||||
@@ -8,7 +9,7 @@ use super::{ShowDays, SortBy};
|
|||||||
pub struct Cli {
|
pub struct Cli {
|
||||||
/// Which currencies do you want to fetch rates for?
|
/// Which currencies do you want to fetch rates for?
|
||||||
#[arg(long = "currencies", short = 'c')]
|
#[arg(long = "currencies", short = 'c')]
|
||||||
pub currencies: Vec<String>,
|
pub currencies: Vec<SmolStr>,
|
||||||
|
|
||||||
#[arg(value_enum, default_value_t = FormatOption::Plain)]
|
#[arg(value_enum, default_value_t = FormatOption::Plain)]
|
||||||
pub command: FormatOption,
|
pub command: FormatOption,
|
||||||
@@ -35,7 +36,7 @@ pub struct Cli {
|
|||||||
|
|
||||||
/// Recalculate to the perspective from an included currency
|
/// Recalculate to the perspective from an included currency
|
||||||
#[arg(long = "perspective", short = 'p')]
|
#[arg(long = "perspective", short = 'p')]
|
||||||
pub perspective: Option<String>,
|
pub perspective: Option<SmolStr>,
|
||||||
|
|
||||||
/// Invert the rate
|
/// Invert the rate
|
||||||
#[arg(long = "invert", short = 'i')]
|
#[arg(long = "invert", short = 'i')]
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use clap::Parser as _;
|
|||||||
use ecb_rates::cache::{Cache, CacheLine};
|
use ecb_rates::cache::{Cache, CacheLine};
|
||||||
use ecb_rates::HeaderDescription;
|
use ecb_rates::HeaderDescription;
|
||||||
use reqwest::{Client, IntoUrl};
|
use reqwest::{Client, IntoUrl};
|
||||||
|
use smol_str::StrExt;
|
||||||
use std::process::ExitCode;
|
use std::process::ExitCode;
|
||||||
|
|
||||||
use ecb_rates::cli::{Cli, FormatOption};
|
use ecb_rates::cli::{Cli, FormatOption};
|
||||||
@@ -78,7 +79,7 @@ async fn main() -> ExitCode {
|
|||||||
parsed
|
parsed
|
||||||
};
|
};
|
||||||
|
|
||||||
cli.perspective = cli.perspective.map(|s| s.to_uppercase());
|
cli.perspective = cli.perspective.map(|s| s.to_uppercase_smolstr());
|
||||||
if let Some(currency) = cli.perspective.as_ref() {
|
if let Some(currency) = cli.perspective.as_ref() {
|
||||||
header_description.replace_eur(¤cy);
|
header_description.replace_eur(¤cy);
|
||||||
let error_occured = change_perspective(&mut parsed, ¤cy).is_none();
|
let error_occured = change_perspective(&mut parsed, ¤cy).is_none();
|
||||||
@@ -99,7 +100,7 @@ async fn main() -> ExitCode {
|
|||||||
let currencies = cli
|
let currencies = cli
|
||||||
.currencies
|
.currencies
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| x.to_uppercase())
|
.map(|x| x.to_uppercase_smolstr())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
filter_currencies(&mut parsed, ¤cies);
|
filter_currencies(&mut parsed, ¤cies);
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use smol_str::SmolStr;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||||
pub struct ExchangeRateResult {
|
pub struct ExchangeRateResult {
|
||||||
pub time: String,
|
pub time: SmolStr,
|
||||||
pub rates: HashMap<String, f64>,
|
pub rates: HashMap<SmolStr, f64>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,37 +2,44 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use quick_xml::events::Event;
|
use quick_xml::events::Event;
|
||||||
use quick_xml::Reader;
|
use quick_xml::Reader;
|
||||||
|
use smol_str::SmolStr;
|
||||||
|
|
||||||
use crate::models::ExchangeRateResult;
|
use crate::models::ExchangeRateResult;
|
||||||
|
|
||||||
|
fn smol_from_utf8(bytes: &[u8]) -> SmolStr {
|
||||||
|
str::from_utf8(bytes)
|
||||||
|
.map(SmolStr::new)
|
||||||
|
.unwrap_or_else(|_| SmolStr::new(String::from_utf8_lossy(bytes)))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse(xml: &str) -> anyhow::Result<Vec<ExchangeRateResult>> {
|
pub fn parse(xml: &str) -> anyhow::Result<Vec<ExchangeRateResult>> {
|
||||||
let mut reader = Reader::from_str(xml);
|
let mut reader = Reader::from_str(xml);
|
||||||
reader.config_mut().trim_text(true);
|
reader.config_mut().trim_text(true);
|
||||||
|
|
||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
let mut current_time: Option<String> = None;
|
let mut current_time: Option<SmolStr> = None;
|
||||||
let mut inside_cube_time = false;
|
let mut inside_cube_time = false;
|
||||||
let mut current_rates = HashMap::new();
|
let mut current_rates = HashMap::new();
|
||||||
|
|
||||||
fn handle_cube_element(
|
fn handle_cube_element(
|
||||||
e: &quick_xml::events::BytesStart,
|
e: &quick_xml::events::BytesStart,
|
||||||
current_time: &mut Option<String>,
|
current_time: &mut Option<SmolStr>,
|
||||||
inside_cube_time: &mut bool,
|
inside_cube_time: &mut bool,
|
||||||
current_rates: &mut HashMap<String, f64>,
|
current_rates: &mut HashMap<SmolStr, f64>,
|
||||||
results: &mut Vec<ExchangeRateResult>,
|
results: &mut Vec<ExchangeRateResult>,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
if e.name().local_name().as_ref() != b"Cube" {
|
if e.name().local_name().as_ref() != b"Cube" {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut time_attr: Option<String> = None;
|
let mut time_attr: Option<SmolStr> = None;
|
||||||
let mut currency_attr: Option<String> = None;
|
let mut currency_attr: Option<SmolStr> = None;
|
||||||
let mut rate_attr: Option<String> = None;
|
let mut rate_attr: Option<SmolStr> = None;
|
||||||
|
|
||||||
for attr_result in e.attributes() {
|
for attr_result in e.attributes() {
|
||||||
let attr = attr_result?;
|
let attr = attr_result?;
|
||||||
let key = attr.key.as_ref();
|
let key = attr.key.as_ref();
|
||||||
let val = String::from_utf8_lossy(attr.value.as_ref()).to_string();
|
let val = smol_from_utf8(attr.value.as_ref());
|
||||||
|
|
||||||
match key {
|
match key {
|
||||||
b"time" => {
|
b"time" => {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use smol_str::SmolStr;
|
||||||
|
|
||||||
use crate::cli::SortBy;
|
use crate::cli::SortBy;
|
||||||
use crate::models::ExchangeRateResult;
|
use crate::models::ExchangeRateResult;
|
||||||
use crate::DEFAULT_WIDTH;
|
use crate::DEFAULT_WIDTH;
|
||||||
@@ -8,20 +10,20 @@ use super::table_display::helper_table_print;
|
|||||||
use super::{TableGet, TableTrait};
|
use super::{TableGet, TableTrait};
|
||||||
|
|
||||||
pub struct Table {
|
pub struct Table {
|
||||||
pub(super) header: Option<String>,
|
pub(super) header: Option<SmolStr>,
|
||||||
pub(super) column_left: String,
|
pub(super) column_left: SmolStr,
|
||||||
pub(super) column_right: String,
|
pub(super) column_right: SmolStr,
|
||||||
pub(super) rows: Vec<(String, f64)>,
|
pub(super) rows: Vec<(SmolStr, f64)>,
|
||||||
pub color: bool,
|
pub color: bool,
|
||||||
pub width: usize,
|
pub width: usize,
|
||||||
pub left_offset: usize,
|
pub left_offset: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TableTrait<'a> for Table {
|
impl<'a> TableTrait<'a> for Table {
|
||||||
type Header = String;
|
type Header = SmolStr;
|
||||||
type ColumnLeft = String;
|
type ColumnLeft = SmolStr;
|
||||||
type ColumnRight = String;
|
type ColumnRight = SmolStr;
|
||||||
type RowLeft = String;
|
type RowLeft = SmolStr;
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
header: Option<Self::Header>,
|
header: Option<Self::Header>,
|
||||||
@@ -59,8 +61,8 @@ impl<'a> TableTrait<'a> for Table {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TableGet for Table {
|
impl TableGet for Table {
|
||||||
type RowLeftRef = String;
|
type RowLeftRef = SmolStr;
|
||||||
type RowRightRef = String;
|
type RowRightRef = SmolStr;
|
||||||
|
|
||||||
fn get_header(&self) -> Option<&str> {
|
fn get_header(&self) -> Option<&str> {
|
||||||
self.header.as_deref()
|
self.header.as_deref()
|
||||||
@@ -77,7 +79,7 @@ impl TableGet for Table {
|
|||||||
fn get_width(&self) -> usize {
|
fn get_width(&self) -> usize {
|
||||||
self.width
|
self.width
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_left_offset(&self) -> usize {
|
fn get_left_offset(&self) -> usize {
|
||||||
self.left_offset
|
self.left_offset
|
||||||
}
|
}
|
||||||
@@ -85,7 +87,7 @@ impl TableGet for Table {
|
|||||||
|
|
||||||
impl From<ExchangeRateResult> for Table {
|
impl From<ExchangeRateResult> for Table {
|
||||||
fn from(value: ExchangeRateResult) -> Self {
|
fn from(value: ExchangeRateResult) -> Self {
|
||||||
let mut table = Table::new(Some(value.time), "Currency".to_string(), "Rate".to_string());
|
let mut table = Table::new(Some(value.time), "Currency".into(), "Rate".into());
|
||||||
for (key, val) in value.rates.into_iter() {
|
for (key, val) in value.rates.into_iter() {
|
||||||
table.add_row(key, val);
|
table.add_row(key, val);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
use std::{borrow::BorrowMut, collections::HashMap, ops::Deref};
|
use std::{borrow::BorrowMut, collections::HashMap, ops::Deref};
|
||||||
|
|
||||||
|
use smol_str::SmolStr;
|
||||||
|
|
||||||
use crate::models::ExchangeRateResult;
|
use crate::models::ExchangeRateResult;
|
||||||
|
|
||||||
pub fn filter_currencies(exchange_rate_results: &mut [ExchangeRateResult], currencies: &[String]) {
|
pub fn filter_currencies(exchange_rate_results: &mut [ExchangeRateResult], currencies: &[SmolStr]) {
|
||||||
for exchange_rate in exchange_rate_results {
|
for exchange_rate in exchange_rate_results {
|
||||||
let rates_ptr: *mut HashMap<String, f64> = &mut exchange_rate.rates;
|
let rates_ptr: *mut HashMap<_, _> = &mut exchange_rate.rates;
|
||||||
exchange_rate
|
exchange_rate
|
||||||
.rates
|
.rates
|
||||||
.keys()
|
.keys()
|
||||||
@@ -32,7 +34,7 @@ pub fn change_perspective(
|
|||||||
*iter_rate = eur_rate * iter_rate.deref();
|
*iter_rate = eur_rate * iter_rate.deref();
|
||||||
}
|
}
|
||||||
|
|
||||||
rate_res.rates.insert("EUR".to_string(), eur_rate);
|
rate_res.rates.insert("EUR".into(), eur_rate);
|
||||||
}
|
}
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user