use reqwest;
use wordnik_list as word_lib;
use serde_json::{self, Value};
pub fn get_word_defs(word: &str, num_of_defs: u32, client: &reqwest::blocking::Client) -> Vec<WordDef> {
let dictionary_check = format!("https://api.dictionaryapi.dev/api/v2/entries/en/{}", word);
let body = client.get(dictionary_check).send().unwrap() .text().unwrap();
let json_body: Value = serde_json::from_str(&body)
.expect("api.dictionaryapi.dev should always return valid json");
let mut output = Vec::new();
for def_num in 0..num_of_defs {
let word_map = &json_body[0]["meanings"][def_num as usize];
let word_def = &word_map["definitions"][0]["definition"];
let part_of_speech = &word_map["partOfSpeech"];
let word_def = word_def.as_str(); let part_of_speech = part_of_speech.as_str();
output.push(
WordDef::new(
word.to_string(),
if let Some(def) = word_def {
Some(def.to_string())
} else { None },
if let Some(pos) = part_of_speech {
Some(pos.to_string())
} else { None },
)
);
}
output
}
#[derive(Debug)]
pub struct WordDef{
#[allow(unused)]
pub word: String,
pub def: Option<String>,
pub part_of_speech: Option<String>,
}
impl WordDef {
fn new(word: String, def: Option<String>, part_of_speech: Option<String>) -> Self {
Self{
word,
def,
part_of_speech,
}
}
}
pub fn first_word(string: &str) -> String {
let string = string.trim();
let mut word = String::new();
for c in string.chars(){
if !c.is_whitespace() {
word.push(c);
} else {
return word;
}
}
word
}
#[derive(Clone, Debug)]
pub struct WordSim{
word_1: String,
word_2: String,
sim_amount: f32, }
use std::collections::HashMap;
impl WordSim{
pub fn get_word_2(&self) -> &str {
&self.word_2
}
pub fn get_word_1(&self) -> &str {
&self.word_1
}
pub fn new(word_1: &str, word_2: &str) -> Self{
let mut word_1_iter = word_1.chars().into_iter();
let mut word_2_iter = word_2.chars().into_iter();
let word_1_count = word_1.chars().count();
let word_2_count = word_2.chars().count();
let largest_word_count = word_1_count.max(word_2_count) as i32;
let mut word_map: HashMap<char, (Vec<u32>, Vec<u32>)> = HashMap::new();
let blank_2uvecs: (Vec<u32>, Vec<u32>) = (Vec::new(), Vec::new());
for word_place in 0..largest_word_count as u32{
if let Some(letter_1) = word_1_iter.next() {
(word_map.entry(letter_1).or_insert( blank_2uvecs.clone() )).0.push(word_place);
}
if let Some(letter_2) = word_2_iter.next() {
(word_map.entry(letter_2).or_insert( blank_2uvecs.clone() )).1.push(word_place);
}
}
let mut leftovers = 0_u32;
let mut movements = 0_u32;
for (_letter, (mut places1, mut places2)) in word_map.into_iter() {
while places1.len() > 0 && places2.len() > 0 {
movements += ( places1.pop().unwrap() as i32 - places2.pop().unwrap() as i32 ).abs() as u32;
}
leftovers += (places1.len() + places2.len()) as u32;
}
let max_diff = (word_1_count + word_2_count) * largest_word_count as usize;
let diff = movements + (leftovers * largest_word_count as u32);
let mut sim_amount = 1.0 - (diff as f32 / max_diff as f32);
if sim_amount == 1.0 && word_1 == word_2 {
sim_amount = 1.0/0.0;
}
Self{
word_1: word_1.to_string(),
word_2: word_2.to_string(),
sim_amount,
}
}
pub fn get_sim(&self) -> f32 {
self.sim_amount
}
}
struct WordSimStorage{
#[allow(unused)]
len: u32,
wordsims: Vec<WordSim>,
}
impl WordSimStorage{
fn new(size: u32) -> Self {
Self{
len: size,
wordsims: vec![WordSim::new("", "");size as usize],
}
}
fn add(&mut self, new_wordsim: WordSim) {
let mut place_val = 0;
for wordsim in self.wordsims.iter(){
if new_wordsim.get_sim() <= wordsim.get_sim() {
break;
} else {
place_val += 1;
}
}
if place_val == 0 { return; } self.wordsims[(place_val-1) as usize] = new_wordsim;
}
fn get_vec(&self) -> Vec<WordSim> {
self.wordsims.clone()
}
}
use std::sync::{mpsc::channel, Arc, Mutex};
use std::thread;
pub fn check_against(string: &str, top_number: u32, threads: u32) -> Vec<WordSim> {
let all_words: Arc<Vec<String>> =
Arc::new(word_lib::word_iterator().map(|ref_str| ref_str.to_string()).collect());
let all_words_count = all_words.len() as u32;
let mut jobs: Vec<(u32, u32)> = Vec::new();
let job_size = all_words_count/threads;
for job in 0..threads {
jobs.push( (job_size*job, job_size*(job+1)) );
if job+1 == threads {
jobs[job as usize].1 = all_words_count;
}
}
let output: Arc<Mutex<WordSimStorage>> =
Arc::new(Mutex::new(WordSimStorage::new(top_number))); let (tx, rx) = channel::<()>(); let string = Arc::new(string.to_string());
for job_set in jobs.into_iter() {
let (string, all_words, output, tx) = (
string.clone(),
all_words.clone(),
output.clone(),
tx.clone(),
);
thread::spawn(move || {
for i in job_set.0..job_set.1 {
let compare_word = &all_words[i as usize];
let word_sim = WordSim::new(&*string, &compare_word);
let mut output = output.lock().unwrap();
(*output).add(word_sim);
}
std::mem::drop(tx);
});
}
std::mem::drop(tx);
while let Ok(_) = rx.recv() { }
output.lock().unwrap().get_vec()
}