-
Notifications
You must be signed in to change notification settings - Fork 129
Expand file tree
/
Copy pathcommon.rs
More file actions
148 lines (139 loc) · 4.59 KB
/
Copy pathcommon.rs
File metadata and controls
148 lines (139 loc) · 4.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
use defichain_rpc::json::token::TokenInfo;
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
use super::query::PaginationQuery;
pub fn parse_display_symbol(token_info: &TokenInfo) -> String {
if token_info.is_lps {
let tokens: Vec<&str> = token_info.symbol.split('-').collect();
if tokens.len() == 2 {
return format!(
"{}-{}",
parse_dat_symbol(tokens[0]),
parse_dat_symbol(tokens[1])
);
}
} else if token_info.is_dat {
return parse_dat_symbol(&token_info.symbol);
}
token_info.symbol.clone()
}
fn parse_dat_symbol(symbol: &str) -> String {
let special_symbols = ["DUSD", "DFI", "csETH"];
if special_symbols.contains(&symbol) {
symbol.to_string()
} else {
format!("d{}", symbol)
}
}
/// Finds the balance of a specified token symbol within a list of token strings.
///
/// This function iterates through a vector of token strings, where each string
/// represents an amount followed by a token symbol in the format "amount@symbol".
/// It searches for the specified token symbol and returns the corresponding balance.
/// If the token symbol is not found or if there are any parsing errors, it returns 0.
///
/// # Arguments
///
/// * `tokens` - A vector of strings representing token amounts with their symbols.
/// * `symbol` - A reference to a string representing the token symbol to find the balance for.
///
/// # Examples
///
/// ```
/// let tokens = vec![
/// "557.35080849@DFI".to_string(),
/// "9.98000000@BTC".to_string(),
/// "421.46947098@DUSD".to_string()
/// ];
/// let balance = find_token_balance(tokens, "DFI");
/// assert_eq!(balance, 557.35080849);
/// ```
///
/// # Returns
///
/// The balance of the specified token symbol if found; otherwise, returns 0.
pub fn find_token_balance(tokens: Vec<String>, symbol: &str) -> Decimal {
tokens
.iter()
.find_map(|t| {
t.ends_with(symbol)
.then(|| t.split("@").next().and_then(|v| v.parse::<Decimal>().ok()))
.flatten()
})
.unwrap_or_default()
}
/// Provides a simulated pagination mechanism for iterators where native pagination is not available.
///
/// This trait extends any Rust iterator to include a `paginate` method, allowing for pseudo-pagination
/// based on custom logic. It's should only be used to query defid list* RPC that don't implement native pagination
///
/// # Warning
///
/// This method should be used cautiously, as it involves retrieving all data from the data source
/// before applying pagination. This can lead to significant performance and resource usage issues,
/// especially with large datasets. It is recommended to use this approach only defid does not accept
/// any pagination parameter.
///
/// # Parameters
///
/// - `query`: A reference to `PaginationQuery`
/// - `skip_while`: A closure that determines the starting point of data to consider, mimicking the
/// 'start' parameter in traditional pagination. Once an item fails this condition, pagination starts.
///
/// # Example
///
/// ```rust
/// use crate::Paginate;
///
/// let query = {
/// next: Some(1)
/// limit: 3
/// };
///
/// let skip_while = |el: &LoanSchemeResult| match &query.next {
/// None => false,
/// Some(v) => v != &el.id,
/// };
/// let res: Vec<_> = ctx
/// .client
/// .list_loan_schemes()
/// .await?
/// .into_iter()
/// .fake_paginate(&query, skip_while)
/// .collect();
///
/// assert!(res.len() <= query.size, "The result should not contain more items than the specified limit");
/// assert!(res[0].id > query.next.unwrap(), "The result should start after the requested start id");
/// ```
pub trait Paginate<'a, T>: Iterator<Item = T> + Sized {
fn fake_paginate<F>(
self,
query: &PaginationQuery,
skip_while: F,
) -> Box<dyn Iterator<Item = T> + 'a>
where
F: FnMut(&T) -> bool + 'a;
fn paginate(self, query: &PaginationQuery) -> Box<dyn Iterator<Item = T> + 'a>;
}
impl<'a, T, I> Paginate<'a, T> for I
where
I: Iterator<Item = T> + 'a,
{
fn fake_paginate<F>(
self,
query: &PaginationQuery,
skip_while: F,
) -> Box<dyn Iterator<Item = T> + 'a>
where
F: FnMut(&T) -> bool + 'a,
{
Box::new(
self.skip_while(skip_while)
.skip(query.next.is_some() as usize)
.take(query.size),
)
}
fn paginate(self, query: &PaginationQuery) -> Box<dyn Iterator<Item = T> + 'a> {
Box::new(self.skip(query.next.is_some() as usize).take(query.size))
}
}