use crate::wordlist::BIP39_LIST;
use strsim::levenshtein;
pub use crate::token_kind::{Score, Amount, TokenKind, TokenKindCorrect};
pub struct BIP39;
impl TokenKind for BIP39 {
const MAX: usize = 2048;
fn from_idx(&self, value: usize) -> Option<String> {
if value < BIP39_LIST.len() {
Some(BIP39_LIST[value].to_string())
} else {
None
}
}
fn from_name(&self, name: &str) -> Option<usize> {
BIP39_LIST.iter().position(|&w| w == name)
}
}
impl TokenKindCorrect for BIP39 {
fn suggest(&self, query: &str, amount: impl Amount) -> Vec<Score> {
let mut suggestions: Vec<Score> = BIP39_LIST.iter()
.map(|&w| Score { item: w.to_string(), score: levenshtein(query, w) })
.collect();
suggestions.sort_by_key(|s| s.score);
match amount.amount() {
Some(n) => suggestions.into_iter().take(n).collect(),
None => suggestions
}
}
}
pub struct Digits;
impl TokenKind for Digits {
const MAX: usize = 1000000;
fn from_idx(&self, value: usize) -> Option<String> {
if value < 1000000 {
Some(value.to_string().clone())
} else {
None
}
}
fn from_name(&self, name: &str) -> Option<usize> {
match name.parse::<usize>() {
Ok(num) if num < 1_000_000 => Some(num),
_ => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_bip39() {
let bip39_instance: BIP39 = BIP39 {};
assert_eq!(bip39_instance.from_idx(0), Some("abandon".to_string()));
assert_eq!(bip39_instance.from_idx(2047), Some("zoo".to_string()));
assert!(bip39_instance.from_idx(2048).is_none());
}
#[test]
fn both_way() {
let bip39_instance: BIP39 = BIP39 {};
for i in 0..BIP39_LIST.len() {
let word = bip39_instance.from_idx(i).unwrap();
let index = bip39_instance.from_name(&word).unwrap();
assert_eq!(i, index);
}
}
}