mod border_color;
mod card_faces;
mod color;
mod finishes;
mod frame;
mod frame_effect;
mod game;
mod image_status;
mod languages;
mod layout;
mod legality;
mod preview;
mod price;
mod produced_mana;
mod promo_types;
mod purchase_uris;
mod rarity;
mod related_card;
mod related_uris;
mod security_stamp;
use std::ops::{Index, IndexMut};
use chrono::NaiveDate;
use purchase_uris::PurchaseUris;
use related_uris::RelatedUris;
use serde::{Deserialize, Serialize};
use url::Url;
use uuid::Uuid;
pub use self::border_color::BorderColor;
pub use self::card_faces::CardFace;
pub use self::color::{Color, Colors, Multicolored};
pub use self::finishes::Finishes;
pub use self::frame::Frame;
pub use self::frame_effect::FrameEffect;
pub use self::game::Game;
pub use self::image_status::ImageStatus;
pub use self::layout::Layout;
pub use self::legality::Legality;
pub use self::preview::Preview;
pub use self::price::Price;
pub use self::produced_mana::{ProducedMana, UnfinityMana};
pub use self::promo_types::PromoType;
pub use self::rarity::Rarity;
pub use self::related_card::Component;
pub use self::related_card::RelatedCard;
pub use self::security_stamp::SecurityStamp;
use crate::format::Format;
use crate::list::{List, ListIter};
use crate::ruling::Ruling;
use crate::search::Search;
use crate::set::{Set, SetCode, SetType};
use crate::uri::Uri;
use crate::util::CARDS_URL;
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
#[cfg_attr(not(feature = "unknown_variants"), derive(Copy))]
#[cfg_attr(
all(
not(feature = "unknown_variants"),
not(feature = "unknown_variants_slim")
),
non_exhaustive
)]
#[serde(deny_unknown_fields)]
#[allow(missing_docs)]
pub struct CardLegality {
#[serde(default)]
pub standard: Legality,
#[serde(default)]
pub modern: Legality,
#[serde(default)]
pub legacy: Legality,
#[serde(default)]
pub vintage: Legality,
#[serde(default)]
pub commander: Legality,
#[serde(default)]
pub future: Legality,
#[serde(default)]
pub pauper: Legality,
#[serde(default)]
pub pioneer: Legality,
#[serde(default)]
pub penny: Legality,
#[serde(default)]
pub duel: Legality,
#[serde(default, rename = "oldschool")]
pub old_school: Legality,
#[serde(default)]
pub historic: Legality,
#[serde(default)]
pub gladiator: Legality,
#[serde(default)]
pub brawl: Legality,
#[serde(default)]
pub premodern: Legality,
#[serde(default, rename = "paupercommander")]
pub pauper_commander: Legality,
#[serde(default)]
pub alchemy: Legality,
#[serde(default)]
pub explorer: Legality,
#[serde(default)]
pub predh: Legality,
#[serde(default)]
pub oathbreaker: Legality,
#[serde(default)]
pub timeless: Legality,
#[serde(default, rename = "standardbrawl")]
pub standard_brawl: Legality,
#[serde(default, rename = "historicbrawl")]
pub historic_brawl: Legality,
}
impl Index<Format> for CardLegality {
type Output = Legality;
fn index(&self, index: Format) -> &Self::Output {
match index {
Format::Standard => &self.standard,
Format::Modern => &self.modern,
Format::Legacy => &self.legacy,
Format::Vintage => &self.vintage,
Format::Commander => &self.commander,
Format::Future => &self.future,
Format::Pauper => &self.pauper,
Format::Pioneer => &self.pioneer,
Format::Penny => &self.penny,
Format::Duel => &self.duel,
Format::OldSchool => &self.old_school,
Format::Historic => &self.historic,
Format::Gladiator => &self.gladiator,
Format::Brawl => &self.brawl,
Format::Premodern => &self.premodern,
Format::PauperCommander => &self.pauper_commander,
Format::Alchemy => &self.alchemy,
Format::Explorer => &self.explorer,
Format::Predh => &self.predh,
Format::Oathbreaker => &self.oathbreaker,
Format::Timeless => &self.timeless,
Format::StandardBrawl => &self.standard_brawl,
Format::HistoricBrawl => &self.historic_brawl,
}
}
}
impl IndexMut<Format> for CardLegality {
fn index_mut(&mut self, index: Format) -> &mut Self::Output {
match index {
Format::Standard => &mut self.standard,
Format::Modern => &mut self.modern,
Format::Legacy => &mut self.legacy,
Format::Vintage => &mut self.vintage,
Format::Commander => &mut self.commander,
Format::Future => &mut self.future,
Format::Pauper => &mut self.pauper,
Format::Pioneer => &mut self.pioneer,
Format::Penny => &mut self.penny,
Format::Duel => &mut self.duel,
Format::OldSchool => &mut self.old_school,
Format::Historic => &mut self.historic,
Format::Gladiator => &mut self.gladiator,
Format::Brawl => &mut self.brawl,
Format::Premodern => &mut self.premodern,
Format::PauperCommander => &mut self.pauper_commander,
Format::Alchemy => &mut self.alchemy,
Format::Explorer => &mut self.explorer,
Format::Predh => &mut self.predh,
Format::Oathbreaker => &mut self.oathbreaker,
Format::Timeless => &mut self.timeless,
Format::StandardBrawl => &mut self.standard_brawl,
Format::HistoricBrawl => &mut self.historic_brawl,
}
}
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
#[cfg_attr(test, serde(deny_unknown_fields))]
pub struct ImageUris {
#[serde(default)]
pub png: Option<Url>,
#[serde(default)]
pub border_crop: Option<Url>,
#[serde(default)]
pub art_crop: Option<Url>,
#[serde(default)]
pub large: Option<Url>,
#[serde(default)]
pub normal: Option<Url>,
#[serde(default)]
pub small: Option<Url>,
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
#[cfg_attr(test, serde(deny_unknown_fields))]
#[non_exhaustive]
pub struct Card {
pub arena_id: Option<usize>,
pub id: Uuid,
pub lang: String,
pub mtgo_id: Option<usize>,
pub mtgo_foil_id: Option<usize>,
pub multiverse_ids: Option<Vec<usize>>,
pub tcgplayer_id: Option<usize>,
pub tcgplayer_etched_id: Option<usize>,
pub cardmarket_id: Option<usize>,
pub oracle_id: Option<Uuid>,
pub prints_search_uri: Uri<List<Card>>,
pub rulings_uri: Uri<Vec<Ruling>>,
pub scryfall_uri: Url,
pub uri: Uri<Card>,
pub all_parts: Option<Vec<RelatedCard>>,
pub card_faces: Option<Vec<CardFace>>,
pub cmc: Option<f32>,
pub color_identity: Vec<Color>,
pub color_indicator: Option<Vec<Color>>,
pub colors: Option<Vec<Color>>,
pub edhrec_rank: Option<usize>,
pub game_changer: Option<bool>,
pub foil: bool,
pub hand_modifier: Option<String>,
pub keywords: Vec<String>,
pub layout: Layout,
pub legalities: CardLegality,
pub life_modifier: Option<String>,
pub loyalty: Option<String>,
pub mana_cost: Option<String>,
pub name: String,
pub nonfoil: bool,
pub oracle_text: Option<String>,
pub oversized: bool,
pub power: Option<String>,
pub produced_mana: Option<Vec<ProducedMana>>,
pub reserved: bool,
pub toughness: Option<String>,
pub type_line: Option<String>,
pub penny_rank: Option<u64>,
pub defense: Option<String>,
pub artist: Option<String>,
pub artist_ids: Option<Vec<Uuid>>,
pub booster: bool,
pub border_color: BorderColor,
pub card_back_id: Option<Uuid>,
pub collector_number: String,
#[serde(default)]
pub content_warning: bool,
pub digital: bool,
pub flavor_name: Option<String>,
pub flavor_text: Option<String>,
#[serde(default)]
pub frame_effects: Vec<FrameEffect>,
pub frame: Frame,
pub full_art: bool,
pub games: Vec<Game>,
pub highres_image: bool,
pub illustration_id: Option<Uuid>,
pub image_status: ImageStatus,
#[serde(default)]
pub image_uris: Option<ImageUris>,
#[serde(default)]
pub prices: Price,
pub printed_name: Option<String>,
pub printed_text: Option<String>,
pub printed_type_line: Option<String>,
pub promo: bool,
pub purchase_uris: Option<PurchaseUris>,
pub rarity: Rarity,
pub related_uris: Option<RelatedUris>,
pub released_at: NaiveDate,
pub reprint: bool,
pub scryfall_set_uri: String,
pub set_name: String,
pub set_search_uri: Uri<List<Card>>,
pub set_type: SetType,
pub set_uri: Uri<Set>,
pub set: SetCode,
pub set_id: Uuid,
pub story_spotlight: bool,
pub textless: bool,
pub variation: bool,
pub variation_of: Option<Uuid>,
pub watermark: Option<String>,
#[serde(default)]
pub preview: Preview,
pub finishes: Vec<Finishes>,
#[serde(default)]
pub security_stamp: Option<SecurityStamp>,
#[serde(default)]
pub promo_types: Vec<PromoType>,
pub attraction_lights: Option<Vec<u8>>,
#[cfg(test)]
#[serde(rename = "object")]
_object: String,
}
impl Card {
pub async fn random() -> crate::Result<Card> {
Uri::from(CARDS_URL.join("random/")?).fetch().await
}
pub async fn search(query: impl Search) -> crate::Result<ListIter<Card>> {
let mut url = CARDS_URL.join("search/")?;
query.write_query(&mut url)?;
Uri::from(url).fetch_iter().await
}
pub async fn search_all(query: impl Search) -> crate::Result<Vec<Card>> {
let mut url = CARDS_URL.join("search/")?;
query.write_query(&mut url)?;
Uri::from(url).fetch_all().await
}
pub async fn search_random(query: impl Search) -> crate::Result<Card> {
let mut url = CARDS_URL.join("random/")?;
query.write_query(&mut url)?;
Uri::from(url).fetch().await
}
pub async fn named(name: &str) -> crate::Result<Card> {
let mut url = CARDS_URL.join("named")?;
url.query_pairs_mut().append_pair("exact", name);
Uri::from(url).fetch().await
}
pub async fn named_fuzzy(query: &str) -> crate::Result<Card> {
let mut url = CARDS_URL.join("named")?;
url.query_pairs_mut().append_pair("fuzzy", query);
Uri::from(url).fetch().await
}
pub async fn set_and_number(set_code: &str, number: usize) -> crate::Result<Card> {
Uri::from(CARDS_URL.join(&format!("{set_code}/{number}"))?)
.fetch()
.await
}
pub async fn multiverse(multiverse_id: usize) -> crate::Result<Card> {
Uri::from(
CARDS_URL
.join("multiverse/")?
.join(&multiverse_id.to_string())?,
)
.fetch()
.await
}
pub async fn mtgo(mtgo_id: usize) -> crate::Result<Card> {
Uri::from(CARDS_URL.join("mtgo/")?.join(&mtgo_id.to_string())?)
.fetch()
.await
}
pub async fn arena(arena_id: usize) -> crate::Result<Card> {
Uri::from(CARDS_URL.join("arena/")?.join(&arena_id.to_string())?)
.fetch()
.await
}
pub async fn tcgplayer(tcgplayer_id: usize) -> crate::Result<Card> {
Uri::from(
CARDS_URL
.join("tcgplayer/")?
.join(&tcgplayer_id.to_string())?,
)
.fetch()
.await
}
pub async fn scryfall_id(scryfall_id: Uuid) -> crate::Result<Card> {
Uri::from(CARDS_URL.join(&scryfall_id.to_string())?)
.fetch()
.await
}
}