diff --git a/src/data.rs b/src/data.rs
index ac52e94..7bbc210 100644
--- a/src/data.rs
+++ b/src/data.rs
@@ -30,7 +30,7 @@ pub struct Card {
impl Display for Card {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{} (", &self.name)?;
+ write!(f, r#"
"#, &self.id, &self.name)?;
if let Some(level) = self.level {
if self.card_type.contains("XYZ") {
f.write_str("Rank ")?;
@@ -44,9 +44,7 @@ impl Display for Card {
if let Some(attr) = &self.attribute {
write!(f, "{attr}/")?;
}
- write!(f, "{} {})", self.r#type, self.card_type)?;
- f.write_str("
")?;
- f.write_str(&self.text)?;
+ write!(f, "{} {}", self.r#type, self.card_type)?;
if self.card_type.contains(&String::from("Monster")) {
f.write_str("
")?;
match (self.atk, self.def) {
@@ -57,6 +55,8 @@ impl Display for Card {
(None, None) => write!(f, "? ATK / ? DEF")?,
}
}
+ f.write_str("
")?;
+ f.write_str(&self.text)?;
Ok(())
}
}
diff --git a/src/main.rs b/src/main.rs
index 693f494..c2819d2 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -28,7 +28,7 @@ async fn main() -> std::io::Result<()> {
// tap these so they’re initialized
let num_cards = (CARDS_BY_ID.len() + SEARCH_CARDS.len()) / 2;
println!("Read {num_cards} cards in {:?}", now.elapsed());
- HttpServer::new(|| App::new().service(search)).bind((Ipv4Addr::from([127, 0, 0, 1]), 8080))?.run().await
+ HttpServer::new(|| App::new().service(search).service(card_info)).bind((Ipv4Addr::from([127, 0, 0, 1]), 8080))?.run().await
}
#[derive(Debug, Deserialize)]
@@ -44,43 +44,92 @@ async fn search(q: Option, web::Form>>) -> Resul
Some(Either::Left(web::Query(Query { q }))) => Some(q),
Some(Either::Right(web::Form(Query { q }))) => Some(q),
None => None,
- };
+ }
+ .filter(|s| !s.is_empty());
let mut res = String::with_capacity(10_000);
- res.write_str(HEADER)?;
+ res.push_str(HEADER);
+ render_searchbox(&mut res, &q)?;
+ match q {
+ Some(q) => render_results(&mut res, &q)?,
+ None => res.push_str("Enter a query above to search"),
+ }
+ finish_document(&mut res);
+ Ok(HttpResponse::Ok().insert_header(header::ContentType::html()).body(res))
+}
+
+#[get("/{id}")]
+async fn card_info(card_id: web::Path) -> Result> {
+ let mut res = String::with_capacity(2_000);
+ res.push_str(HEADER);
+ render_searchbox(&mut res, &None)?;
+ match CARDS_BY_ID.get(&card_id) {
+ Some(card) => {
+ res.push_str(r#""#);
+ write!(
+ res,
+ r#"
+"#,
+ card.id,
+ )?;
+ }
+ None => res.push_str("Card not found"),
+ }
+ Ok(HttpResponse::Ok().insert_header(header::ContentType::html()).body(res))
+}
+
+fn render_searchbox(res: &mut String, query: &Option) -> std::fmt::Result {
write!(
res,
r#"
"#,
- match &q {
+ match &query {
Some(q) => q,
None => "",
}
+ )
+}
+
+fn render_results(res: &mut String, query: &str) -> Result<(), Box> {
+ let query = match parser::parse_filters(query) {
+ Ok(q) => q,
+ Err(e) => {
+ write!(res, "Could not parse query: {e:?}")?;
+ return Ok(());
+ }
+ };
+ let now = Instant::now();
+ let matches: Vec<&Card> = SEARCH_CARDS
+ .iter()
+ .filter(|card| query.iter().all(|(_, q)| q(card)))
+ .map(|c| CARDS_BY_ID.get(&c.id).unwrap())
+ .take(RESULT_LIMIT)
+ .collect();
+ write!(
+ res,
+ "Showing {} results where {} (took {:?})",
+ matches.len(),
+ query.iter().map(|(f, _)| f.to_string()).join(" and "),
+ now.elapsed()
)?;
- if let Some(q) = q {
- let query = parser::parse_filters(&q)?;
- let now = Instant::now();
- let matches: Vec<&Card> = SEARCH_CARDS
- .iter()
- .filter(|card| query.iter().all(|(_, q)| q(card)))
- .map(|c| CARDS_BY_ID.get(&c.id).unwrap())
- .take(RESULT_LIMIT)
- .collect();
+ if matches.is_empty() {
+ return Ok(());
+ }
+ res.push_str("");
+ for card in matches {
write!(
res,
- "Showing {} results where {} (took {:?})
",
- matches.len(),
- query.iter().map(|(f, _)| f.to_string()).join(" and "),
- now.elapsed()
+ r#"{card} | |
"#,
+ card.id, card.id
)?;
- for card in matches {
- res.push_str(&card.to_string());
- res.push_str("
");
- }
- write!(res, "