use Link; use searchers::Searcher; use reqwest; use reqwest::Client; use serde_json; use serde_json::Value; use std; use std::io::Read; use std::any::Any; #[derive(Debug)] pub struct MtgCard { name: String, cost: String, typeline: String, rules: String, flavor: Option, power: Option, toughness: Option, url: String, image_url: String } impl Link for MtgCard { fn label (&self) -> &str { &self.name } fn url (&self) -> &str { &self.url } fn as_any (&self) -> &Any { self } } pub struct MtgSearcher { client: Client } impl MtgSearcher { pub fn new () -> MtgSearcher { MtgSearcher { client: Client::new().unwrap() } } fn do_search (&self, name: &str) -> Result { let mut contents = String::new(); let api_url = &format!("https://api.magicthegathering.io/v1/cards?name={}", name); self.client.get(api_url).send()?.read_to_string(&mut contents)?; Result::Ok(contents) } } fn parse_entry (page: String) -> Result { let parsed: Value = serde_json::from_str(&page)?; let ref parsed_entry = parsed["cards"][0]; if let Some(_) = parsed_entry.as_object() { Result::Ok(MtgCard { name: parsed_entry["name"].as_str().map(String::from).expect("expected name in json data"), cost: parsed_entry["manaCost"].as_str().map(String::from).expect("expected cost in json data"), typeline: parsed_entry["type"].as_str().map(String::from).expect("expected type in json data"), rules: parsed_entry["text"].as_str().map(String::from).expect("expected text in json data"), flavor: parsed_entry["flavor"].as_str().map(String::from), power: parsed_entry["power"].as_str().map(String::from), toughness: parsed_entry["toughness"].as_str().map(String::from), url: parsed_entry["imageUrl"].as_str().map(String::from).expect("expected image url in json data"), image_url: parsed_entry["imageUrl"].as_str().map(String::from).expect("expected image url in json data") }) } else { Result::Err(Error::Other(String::from("No card info found"))) } } impl Searcher for MtgSearcher { fn exact_search (&self, name: &str) -> Option { let search = format!(r#""{}""#, name); self.do_search(&search).and_then(parse_entry).ok() } } #[derive(Debug)] enum Error { Http(reqwest::Error), Io(std::io::Error), Json(serde_json::Error), Other(String) } impl From for Error { fn from (error: reqwest::Error) -> Error { Error::Http(error) } } impl From for Error { fn from (error: std::io::Error) -> Error { Error::Io(error) } } impl From for Error { fn from (error: serde_json::Error) -> Error { Error::Json(error) } }