scryfall/search/param/
value.rs

1//! This module defines the types for searching with parameters that can take
2//! a value argument. The type [`ValueKind`] defines the parameter that is
3//! being searched for, and cannot be constructed directly. Instead, use helper
4//! functions such as [`oracle_text()`], [`artist()`], or [`toughness()`].
5//!
6//! The helper functions are generic and are constrained by [`ParamValue`] and
7//! its sub-traits, in order to allow more flexibility in their use.
8//! See [`TextValue`], [`NumericValue`], and [`ColorValue`] for examples of how
9//! this works.
10
11use std::fmt;
12
13pub use self::functions::*;
14use crate::search::param::compare::{compare_op_str, Compare, CompareOp};
15use crate::search::param::Param;
16
17/// The type of parameter that this is. Corresponds to the name before the ':'
18/// or other operator.
19///
20/// Refer to [the syntax documentation](https://scryfall.com/docs/syntax) for details on the
21/// available parameter types.
22#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
23pub struct ValueKind(ValueKindImpl);
24
25impl ValueKind {
26    pub(super) fn fmt_value(&self, value: &str, f: &mut fmt::Formatter) -> fmt::Result {
27        write!(f, "{self}:{value}")
28    }
29
30    pub(super) fn fmt_comparison(
31        &self,
32        op: CompareOp,
33        value: &str,
34        f: &mut fmt::Formatter,
35    ) -> fmt::Result {
36        write!(f, "{}{}{}", self, compare_op_str(Some(op)), value)
37    }
38}
39
40#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
41enum ValueKindImpl {
42    Color,
43    ColorIdentity,
44    Type,
45    Oracle,
46    FullOracle,
47    Keyword,
48    Mana,
49    Devotion,
50    Produces,
51    Rarity,
52    InRarity,
53    Set,
54    InSet,
55    Number,
56    Block,
57    SetType,
58    InSetType,
59    Cube,
60    Format,
61    Banned,
62    Restricted,
63    Cheapest,
64    Artist,
65    Flavor,
66    Watermark,
67    BorderColor,
68    Frame,
69    Date,
70    Game,
71    InGame,
72    Language,
73    InLanguage,
74    Name,
75    NumericComparable(NumProperty),
76}
77
78/// These properties can be compared against one another.
79///
80/// For example `power(gt(NumericProperty::Toughness)`.
81#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
82pub enum NumProperty {
83    /// The card's power. Only creature cards have this.
84    Power,
85    /// The card's toughness. Only creature cards have this.
86    Toughness,
87    /// The card's power plus its toughness. Only creatures cards have this.
88    PowTou,
89    /// The card's starting loyalty. Only planeswalker cards have this.
90    ///
91    /// The value '0' will match non-numeric loyalties such as 'X'.
92    Loyalty,
93    /// The card's converted mana cost. Cards without a mana cost have a
94    /// converted mana cost of '0'.
95    Cmc,
96    /// The number of artists who contributed to this printing of the card.
97    ///
98    /// *Note*: This is not the same as the number of unique artists for a
99    /// particular card.
100    ArtistCount,
101    /// This card's current nonfoil market price in US Dollars.
102    Usd,
103    /// This card's current foil market price in US Dollars.
104    UsdFoil,
105    /// This card's current market price in Euros.
106    Eur,
107    /// This card's current market price in MTGO Tickets.
108    Tix,
109    /// The number of different illustrations among prints of this card.
110    IllustrationCount,
111    /// The number of different prints of this card, including both paper and
112    /// digital-exclusive sets.
113    PrintCount,
114    /// The number of different sets this card has appeared in, including both
115    /// paper and digital-exclusive sets.
116    SetCount,
117    /// The number of different prints of this card in paper.
118    PaperPrintCount,
119    /// The number of different sets this card has appeared in, paper only.
120    PaperSetCount,
121    /// The release year of this printing.
122    Year,
123}
124
125const fn numeric_property_str(prop: NumProperty) -> &'static str {
126    match prop {
127        NumProperty::Power => "power",
128        NumProperty::Toughness => "toughness",
129        NumProperty::PowTou => "powtou",
130        NumProperty::Loyalty => "loyalty",
131        NumProperty::Cmc => "cmc",
132        NumProperty::ArtistCount => "artists",
133        NumProperty::Usd => "usd",
134        NumProperty::UsdFoil => "usdfoil",
135        NumProperty::Eur => "eur",
136        NumProperty::Tix => "tix",
137        NumProperty::IllustrationCount => "illustrations",
138        NumProperty::PrintCount => "prints",
139        NumProperty::SetCount => "sets",
140        NumProperty::PaperPrintCount => "paperprints",
141        NumProperty::PaperSetCount => "papersets",
142        NumProperty::Year => "year",
143    }
144}
145
146impl fmt::Display for NumProperty {
147    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
148        f.write_str(numeric_property_str(*self))
149    }
150}
151
152impl fmt::Display for ValueKind {
153    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
154        write!(
155            f,
156            "{}",
157            match &self.0 {
158                ValueKindImpl::Color => "color",
159                ValueKindImpl::ColorIdentity => "identity",
160                ValueKindImpl::Type => "type",
161                ValueKindImpl::Oracle => "oracle",
162                ValueKindImpl::FullOracle => "fulloracle",
163                ValueKindImpl::Keyword => "keyword",
164                ValueKindImpl::Mana => "mana",
165                ValueKindImpl::Devotion => "devotion",
166                ValueKindImpl::Produces => "produces",
167                ValueKindImpl::Rarity => "rarity",
168                ValueKindImpl::Set => "set",
169                ValueKindImpl::Number => "number",
170                ValueKindImpl::Block => "block",
171                ValueKindImpl::SetType => "settype",
172                ValueKindImpl::Cube => "cube",
173                ValueKindImpl::Format => "format",
174                ValueKindImpl::Banned => "banned",
175                ValueKindImpl::Restricted => "restricted",
176                ValueKindImpl::Cheapest => "cheapest",
177                ValueKindImpl::Artist => "artist",
178                ValueKindImpl::Flavor => "flavor",
179                ValueKindImpl::Watermark => "watermark",
180                ValueKindImpl::BorderColor => "border",
181                ValueKindImpl::Frame => "frame",
182                ValueKindImpl::Date => "date",
183                ValueKindImpl::Game => "game",
184                ValueKindImpl::Language => "language",
185                ValueKindImpl::InRarity
186                | ValueKindImpl::InSet
187                | ValueKindImpl::InSetType
188                | ValueKindImpl::InGame
189                | ValueKindImpl::InLanguage => "in",
190                ValueKindImpl::Name => "name",
191                ValueKindImpl::NumericComparable(np) => numeric_property_str(*np),
192            }
193        )
194    }
195}
196
197/// The base trait for a parameter value. The `into_param` method handles
198/// converting the type into a [`Param`].
199pub trait ParamValue: fmt::Debug + fmt::Display {
200    /// Convert this value into a [`Param`] with the specified `kind`.
201    fn into_param(self, kind: ValueKind) -> Param
202    where
203        Self: Sized,
204    {
205        Param::value(kind, self)
206    }
207}
208
209/// A numeric value for a parameter.
210///
211/// Searchable parameters which directly use a `NumericValue` argument include
212/// [`color_count()`] and [`collector_number()`]. Other parameters, such as
213/// [`power()`] and [`toughness()`], can be directly compared against one
214/// another. See [`NumericComparableValue`] for more information.
215///
216/// This trait is implemented for all numeric primitive types.
217pub trait NumericValue: ParamValue {}
218
219macro_rules! impl_numeric_values {
220    ($($Ty:ty,)*) => {
221        $(
222            impl ParamValue for $Ty {}
223            impl NumericValue for $Ty {}
224            impl NumericComparableValue for $Ty {}
225        )*
226    };
227}
228
229#[rustfmt::skip]
230impl_numeric_values!(
231    usize, u8, u16, u32, u64, u128,
232    isize, i8, i16, i32, i64, i128,
233    f32, f64,
234);
235
236/// A numeric value for a parameter, supporting [comparison
237/// operators][super::compare].
238///
239/// Parameters with a `NumericComparableValue` include [`power()`],
240/// [`toughness()`], and [`cmc()`].
241///
242/// Parameters that use this trait can be compared to one another through
243/// the [`NumProperty`] enum. For example, to search for a card with power
244/// greater than its toughness:
245///
246/// ```rust,no_run
247/// use scryfall::search::prelude::*;
248/// let query = power(gt(NumProperty::Toughness));
249/// ```
250///
251/// This trait is implemented by all `NumericValue` types and the `NumProperty`
252/// enum.
253pub trait NumericComparableValue: ParamValue {}
254
255impl<T: NumericComparableValue> NumericComparableValue for Compare<T> {}
256
257impl ParamValue for NumProperty {
258    fn into_param(self, kind: ValueKind) -> Param {
259        numeric_property_str(self).into_param(kind)
260    }
261}
262impl NumericComparableValue for NumProperty {}
263
264/// A string value for a parameter. Does not support comparison
265/// operations.
266///
267/// Searchable parameters that directly use a `TextValue` argument include
268/// [`watermark()`] and [`keyword()`]. Additionally, many types can
269pub trait TextValue: ParamValue {}
270
271/// Helper struct for a quoted value. The `Display` impl for this struct
272/// surrounds the value in quotes. Representations that already contain
273/// quotes are not supported.
274#[derive(Clone, PartialEq, Eq, Hash, Debug)]
275struct Quoted<T>(T);
276
277impl<T: fmt::Display> fmt::Display for Quoted<T> {
278    // TODO(msmorgan): This breaks if the value has quotes in it.
279    //     Scryfall does not support quote escaping.
280    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
281        write!(f, "\"{}\"", self.0)
282    }
283}
284
285impl ParamValue for Quoted<String> {
286    fn into_param(self, kind: ValueKind) -> Param {
287        Param::value(kind, self)
288    }
289}
290impl TextValue for Quoted<String> {}
291
292impl ParamValue for String {
293    fn into_param(self, kind: ValueKind) -> Param {
294        Quoted(self).into_param(kind)
295    }
296}
297impl TextValue for String {}
298
299impl ParamValue for &str {
300    fn into_param(self, kind: ValueKind) -> Param {
301        self.to_string().into_param(kind)
302    }
303}
304impl TextValue for &str {}
305
306/// A string or regular expression value for a parameter. Does not support
307/// comparison operators.
308///
309/// Some searchable properties can be searched with regular expressions.
310/// These properties are [`name()`], [`type_line()`], [`oracle_text()`],
311/// and [`flavor_text()`]. To specify a regular expression, use the
312/// [`Regex`] type from this module.
313///
314/// This trait is implemented for all `TextValue` types and `Regex`.
315///
316/// For more information on supported regular expressions, see the
317/// [official help page](https://scryfall.com/docs/regular-expressions).
318pub trait TextOrRegexValue: ParamValue {}
319
320impl<T: TextValue> TextOrRegexValue for T {}
321
322/// `Regex` is a newtype for String, indicating that the string represents a
323/// regular expression and should be surrounded by slashes in the search
324/// query.
325///
326/// For more information on supported regular expressions, see the
327/// [official help page](https://scryfall.com/docs/regular-expressions).
328///
329/// # Example
330///
331/// ```rust
332/// # use scryfall::search::prelude::*;
333/// # fn main() -> scryfall::Result<()> {
334/// # tokio_test::block_on(async {
335/// let cards_named_fog = name(Regex::from(r"^fog$")).search_all().await?;
336/// assert_eq!(cards_named_fog.len(), 1);
337/// assert_eq!(cards_named_fog[0].name, "Fog");
338/// # Ok(())
339/// # })
340/// # }
341/// ```
342#[derive(Clone, PartialEq, Eq, Hash, Debug)]
343pub struct Regex(pub String);
344
345impl fmt::Display for Regex {
346    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
347        write!(f, "/{}/", self.0.replace('/', "\\/"))
348    }
349}
350
351impl<T: AsRef<str>> From<T> for Regex {
352    fn from(string: T) -> Self {
353        Regex(string.as_ref().to_string())
354    }
355}
356
357impl ParamValue for Regex {}
358impl TextOrRegexValue for Regex {}
359
360/// A color value represents one or more colors, or colorless/multicolored.
361/// Supports [comparison operators][super::compare].
362///
363/// `ColorValue` is the argument type for the functions [`color()`] and
364/// [`color_identity()`].
365///
366/// This type is implemented for [`Color`][crate::card::Color],
367/// [`Colors`][crate::card::Colors],
368/// [`Multicolored`][crate::card:: Multicolored],
369/// and all [`TextValue`] types.
370pub trait ColorValue: ParamValue {}
371
372impl<T: ColorValue> ColorValue for Compare<T> {}
373
374impl ParamValue for crate::card::Color {}
375impl ColorValue for crate::card::Color {}
376
377impl ParamValue for crate::card::Colors {}
378impl ColorValue for crate::card::Colors {}
379
380impl ParamValue for crate::card::Multicolored {}
381impl ColorValue for crate::card::Multicolored {}
382
383impl<T: TextValue> ColorValue for T {}
384
385/// A value representing an amount of devotion to one or two colors. Supports
386/// [comparison operations][super::compare].
387///
388/// The only parameter that takes a `DevotionValue` is [`devotion()`].
389///
390/// This trait is implemented by the [`Devotion`] type from this module.
391///
392/// # Example
393/// ```rust
394/// # use scryfall::search::prelude::*;
395/// # fn main() -> scryfall::Result<()> {
396/// # tokio_test::block_on(async {
397/// use scryfall::card::Color;
398/// let five_red_devotion = devotion(Devotion::monocolor(Color::Red, 5)).random().await?;
399/// assert!(five_red_devotion.cmc.unwrap() >= 5.0);
400/// # Ok(())
401/// # })
402/// # }
403/// ```
404pub trait DevotionValue: ParamValue {}
405
406/// A representation of a permanent's devotion to one or two colors. Use the
407/// constructors [`monocolor`][Devotion::monocolor()] and
408/// [`hybrid`][Devotion::hybrid()] to create values of this type.
409#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
410pub struct Devotion(crate::card::Color, Option<crate::card::Color>, usize);
411
412impl fmt::Display for Devotion {
413    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
414        let count = self.2;
415        if count == 0 {
416            // This is invalid syntax, but prevents false positives. The query "devotion:"
417            // returns cards with a name containing "devotion".
418            write!(f, "0")
419        } else {
420            let color_a = self.0;
421            for _ in 0..count {
422                match self.1 {
423                    Some(color_b) if color_b != color_a => {
424                        write!(f, "{{{color_a}/{color_b}}}")
425                    },
426                    _ => write!(f, "{{{color_a}}}"),
427                }?;
428            }
429            Ok(())
430        }
431    }
432}
433
434impl ParamValue for Devotion {}
435impl DevotionValue for Devotion {}
436
437impl DevotionValue for Compare<Devotion> {}
438
439impl Devotion {
440    /// Constructs a `Devotion` object with the given color and devotion count.
441    pub fn monocolor(color: crate::card::Color, count: usize) -> Self {
442        Devotion(color, None, count)
443    }
444
445    /// Constructs a `Devotion` object representing devotion to two colors with
446    /// the given count.
447    pub fn hybrid(color_a: crate::card::Color, color_b: crate::card::Color, count: usize) -> Self {
448        Devotion(color_a, Some(color_b), count)
449    }
450}
451
452/// A value representing the rarity of a printing. Supports [comparison
453/// operators][super::compare].
454///
455/// Parameter functions with a `RarityValue` argument include [`rarity()`]
456/// and [`in_rarity()`].
457///
458/// This trait is implemented for `String`, `&str`, and the
459/// [`Rarity`][crate::card::Rarity] enum.
460///
461/// # Example
462///
463/// ```rust
464/// # use scryfall::search::prelude::*;
465/// use scryfall::card::Rarity;
466/// # fn main() -> scryfall::Result<()> {
467/// # tokio_test::block_on(async {
468/// // Get the most expensive Common card, in USD.
469/// let card = SearchOptions::new()
470///     .query(rarity(Rarity::Common).and(cheapest("usd")))
471///     .sort(SortOrder::Usd, SortDirection::Descending)
472///     .unique(UniqueStrategy::Cards)
473///     .search()
474///     .await?
475///     .next()
476///     .await
477///     .unwrap()?;
478///
479/// assert!(card.prices.usd.is_some());
480/// # Ok(())
481/// # })
482/// # }
483/// ```
484pub trait RarityValue: ParamValue {}
485
486impl<T: TextValue> RarityValue for T {}
487
488impl ParamValue for crate::card::Rarity {}
489impl RarityValue for crate::card::Rarity {}
490
491impl RarityValue for Compare<crate::card::Rarity> {}
492impl<T: TextValue> RarityValue for Compare<T> {}
493
494/// A value representing the name or code of the set a printing appears in.
495///
496/// Parameters with a `SetValue` argument include [`set()`] and [`in_set()`].
497///
498/// This trait is implemented for `String`, `&str`, and
499/// [`SetCode`][crate::set::SetCode].
500///
501/// # Example
502///
503/// ```rust
504/// # use scryfall::search::prelude::*;
505/// # fn main() -> scryfall::Result<()> {
506/// # tokio_test::block_on(async {
507/// // Get a random Abzan card from Khans of Tarkir.
508/// let card = set("ktk").and(name("abzan")).random().await?;
509/// assert!(card.name.to_lowercase().contains("abzan"));
510/// # Ok(())
511/// # })
512/// # }
513/// ```
514pub trait SetValue: ParamValue {}
515
516impl<T: TextValue> SetValue for T {}
517
518impl ParamValue for crate::set::SetCode {}
519impl SetValue for crate::set::SetCode {}
520
521/// A value representing a draft cube from MTGO, such as the
522/// [Vintage Cube](https://scryfall.com/cubes/vintage).
523///
524/// `CubeValue` is used as the value type for [`cube()`].
525///
526/// This trait is implemented for `String` and `&str`.
527pub trait CubeValue: ParamValue {}
528
529impl<T: TextValue> CubeValue for T {}
530
531/// A value representing a constructed format, such as Standard or Commander.
532///
533/// Parameters with a `FormatValue` argument include [`format()`], [`banned()`],
534/// and [`restricted()`].
535///
536/// This trait is implemented for `String` and `&str`, as well as the
537/// [`Format`][crate::format::Format] enum.
538///
539/// ```rust
540/// # use scryfall::search::prelude::*;
541/// # fn main() -> scryfall::Result<()> {
542/// # tokio_test::block_on(async {
543/// use scryfall::format::Format;
544/// // Find a card that's restricted in Vintage whose name contains 'recall'.
545/// let card = restricted(Format::Vintage)
546///     .and(name("recall"))
547///     .search_all()
548///     .await?
549///     .into_iter()
550///     .next()
551///     .unwrap();
552/// assert_eq!(card.name, "Ancestral Recall");
553/// # Ok(())
554/// # })
555/// # }
556/// ```
557pub trait FormatValue: ParamValue {}
558
559impl<T: TextValue> FormatValue for T {}
560
561impl ParamValue for crate::format::Format {}
562impl FormatValue for crate::format::Format {}
563
564/// A value representing a currency which has prices available on Scryfall.
565///
566/// `CurrencyValue` is used as an argument for the [`cheapest`] parameter.
567///
568/// This trait is implemented for `String` and `&str`.
569pub trait CurrencyValue: ParamValue {}
570
571impl<T: TextValue> CurrencyValue for T {}
572
573/// A value representing a type of Magic set, such as a core set or a duel deck.
574///
575/// `SetTypeValue` is used as the argument type for [`set_type()`] and
576/// [`in_set_type()`].
577///
578/// This trait is implemented for the [`SetType`][crate::set::SetType] enum
579/// and all [`TextValue`] types.
580pub trait SetTypeValue: ParamValue {}
581
582impl ParamValue for crate::set::SetType {}
583impl SetTypeValue for crate::set::SetType {}
584
585impl<T: TextValue> SetTypeValue for T {}
586
587/// A value representing a border color, such as black, white, or silver.
588///
589/// `BorderColorValue` is used as the argument type for [`border_color()`].
590///
591/// This trait is implemented for the [`BorderColor`][crate::card::BorderColor]
592/// and all [`TextValue`] types.
593pub trait BorderColorValue: ParamValue {}
594
595impl<T: TextValue> BorderColorValue for T {}
596
597impl ParamValue for crate::card::BorderColor {}
598impl BorderColorValue for crate::card::BorderColor {}
599
600/// A value representing card frames and frame effects.
601///
602/// `FrameValue` is the argument type for [`frame()`].
603///
604/// This trait is implemented for the enums [`Frame`][crate::card::Frame]
605/// and [`FrameEffect`][crate::card::FrameEffect], as well as all [`TextValue`]
606/// types.
607pub trait FrameValue: ParamValue {}
608
609impl<T: TextValue> FrameValue for T {}
610
611impl ParamValue for crate::card::FrameEffect {}
612impl FrameValue for crate::card::FrameEffect {}
613
614impl ParamValue for crate::card::Frame {}
615impl FrameValue for crate::card::Frame {}
616
617/// A parameter that represents a date. A set code can also be used used to
618/// stand for the date that set was released. Supports
619/// [comparison operators][super::compare].
620///
621/// `DateValue` is the argument type for [`date()`].
622///
623/// This trait is implemented for [`chrono::NaiveDate`],
624/// [`SetCode`][crate::set::SetCode], and any [`TextValue`] such as `String` or
625/// `&str`. When searching with a string, it must either be a valid set code or
626/// a date in the format `yyyy[-mm[-dd]]`.
627pub trait DateValue: ParamValue {}
628
629impl<T: DateValue> DateValue for Compare<T> {}
630
631impl<T: SetValue> DateValue for T {}
632
633impl ParamValue for chrono::NaiveDate {
634    fn into_param(self, kind: ValueKind) -> Param
635    where
636        Self: Sized,
637    {
638        Param::value(kind, self.format("%Y-%m-%d").to_string())
639    }
640}
641impl DateValue for chrono::NaiveDate {}
642
643/// A parameter that specifies a game that the card appears in.
644///
645/// `GameValue` is the argument type for [`game()`] and [`in_game()`].
646///
647/// This trait is implemented for the [`Game`][crate::card::Game] enum, and for
648/// all [`TextValue`] types, such as `String` and `&str`.
649pub trait GameValue: ParamValue {}
650
651impl<T: TextValue> GameValue for T {}
652
653impl ParamValue for crate::card::Game {}
654impl GameValue for crate::card::Game {}
655
656/// A parameter that represents a written language that a card
657/// is printed in. For a full list of supported languages,
658/// refer to the [official docs](https://scryfall.com/docs/api/languages).
659///
660/// `LanguageValue` is used as an argument to [`language()`] and
661/// [`in_language()`].
662///
663/// This trait is implemented for all `TextValue` types.
664pub trait LanguageValue: ParamValue {}
665
666impl<T: TextValue> LanguageValue for T {}
667
668mod functions {
669    use super::*;
670    use crate::search::query::Query;
671
672    macro_rules! value_fns {
673        ($(
674            $(#[$($attr:meta)*])*
675            $func:ident => $Kind:ident : $Constraint:ident,
676        )*) => {
677            $(
678                $(#[$($attr)*])*
679                pub fn $func(value: impl $Constraint) -> Query {
680                    Query::Param(value.into_param(ValueKind(ValueKindImpl::$Kind)))
681                }
682            )*
683        };
684    }
685
686    value_fns! {
687        #[doc = "The color of this card, based on indicator or cost."]
688        color => Color: ColorValue,
689        #[doc = "The number of colors of this card, based on indicator or cost."]
690        color_count => Color: NumericValue,
691        #[doc = "The color identity of this card, for Commander-like formats."]
692        color_identity => ColorIdentity: ColorValue,
693        #[doc = "The number of colors in this card's identity, for Commander-like formats."]
694        color_identity_count => ColorIdentity: NumericValue,
695        #[doc = "The type line of this card."]
696        type_line => Type: TextOrRegexValue,
697        #[doc = "The updated oracle text of this card."]
698        oracle_text => Oracle: TextOrRegexValue,
699        #[doc = "The updated oracle text of this card, including reminder text."]
700        full_oracle_text => FullOracle: TextOrRegexValue,
701        #[doc = "Keyword ability that this card has."]
702        keyword => Keyword: TextValue,
703        #[doc = "The mana cost of this card."]
704        mana => Mana: ColorValue,
705        #[doc = "The devotion granted by this permanent. See [`Devotion`]."]
706        devotion => Devotion: DevotionValue,
707        #[doc = "The colors of mana produced by this card."]
708        produces => Produces: ColorValue,
709        #[doc = "The rarity of this printing."]
710        rarity => Rarity: RarityValue,
711        #[doc = "Has the card ever been printed in this rarity?"]
712        in_rarity => InRarity: RarityValue,
713        #[doc = "The set code of this printing."]
714        set => Set: SetValue,
715        #[doc = "Was the card printed in this set?"]
716        in_set => InSet: SetValue,
717        #[doc = "The card's collector number."]
718        collector_number => Number: NumericValue,
719        #[doc = "The block of this card. Works with any set grouped in the same block."]
720        block => Block: SetValue,
721        #[doc = "The type of set this printing is in."]
722        set_type => SetType: SetTypeValue,
723        #[doc = "Has the card appeared in a set of this type?"]
724        in_set_type => InSetType: SetTypeValue,
725        #[doc = "Does the card appear in this cube on MTGO?"]
726        cube => Cube: CubeValue,
727        #[doc(hidden)]
728        format => Format: FormatValue,
729        #[doc = "The card is banned in this format."]
730        banned => Banned: FormatValue,
731        #[doc = "The card is restricted in this format."]
732        restricted => Restricted: FormatValue,
733        #[doc = "Return the printing that is the cheapest in the specified currency."]
734        cheapest => Cheapest: CurrencyValue,
735        #[doc = "The artist who illustrated this card."]
736        artist => Artist: TextValue,
737        #[doc = "The flavor text of this printing."]
738        flavor_text => Flavor: TextOrRegexValue,
739        #[doc = "The type of watermark on this printing."]
740        watermark => Watermark: TextValue,
741        #[doc = "The border color of this printing."]
742        border_color => BorderColor: BorderColorValue,
743        #[doc = "The card frame of this printing, related to the year of the print."]
744        frame => Frame: FrameValue,
745        #[doc = "The date this printing was released."]
746        date => Date: DateValue,
747        #[doc = "This printing is available in the specified game."]
748        game => Game: GameValue,
749        #[doc = "This card is available in the specified game."]
750        in_game => InGame: GameValue,
751        #[doc = "This printing is in the specified language."]
752        language => Language: LanguageValue,
753        #[doc = "Has this card ever been printed in the specified language?"]
754        in_language => InLanguage: LanguageValue,
755        #[doc = "The card's name, using fuzzy search."]
756        name => Name: TextOrRegexValue,
757    }
758
759    macro_rules! numeric_value_fns {
760        ($(
761            $(#[$($attr:meta)*])*
762            $func:ident => $NumProp:ident,
763        )*) => {
764            $(
765                $(#[$($attr)*])*
766                pub fn $func(value: impl NumericComparableValue) -> Query {
767                    Query::Param(value.into_param(ValueKind(
768                        ValueKindImpl::NumericComparable(NumProperty::$NumProp),
769                    )))
770                }
771            )*
772        };
773    }
774
775    numeric_value_fns! {
776        #[doc = "The card's power, if it is a creature or vehicle. '*' and 'X' count as 0."]
777        power => Power,
778        #[doc = "The card's toughness, if it is a creature or vehicle. '*' and 'X' count as 0."]
779        toughness => Toughness,
780        #[doc = "The card's power plus its toughness."]
781        pow_tou => PowTou,
782        #[doc = "The card's loyalty, if it is a planeswalker. 'X' counts as 0."]
783        loyalty => Loyalty,
784        #[doc = "The converted mana cost of this card."]
785        cmc => Cmc,
786        #[doc = "The number of artists credited for this printing."]
787        artist_count => ArtistCount,
788        #[doc = "The current market price of this card in US Dollars."]
789        usd => Usd,
790        #[doc = "The current foil market price of this card in US Dollars."]
791        usd_foil => UsdFoil,
792        #[doc = "The current market price of this card in Euros."]
793        eur => Eur,
794        #[doc = "The current market price of this card in MTGO tickets."]
795        tix => Tix,
796        #[doc = "The number of unique art this card has had."]
797        illustration_count => IllustrationCount,
798        #[doc = "The number of unique prints of this card."]
799        print_count => PrintCount,
800        #[doc = "The number of sets this card has appeared in."]
801        set_count => SetCount,
802        #[doc = "The number of unique prints of this card, counting paper only."]
803        paper_print_count => PaperPrintCount,
804        #[doc = "The number of sets this card has appeared in, counting paper only."]
805        paper_set_count => PaperSetCount,
806        #[doc = "The year this card was released."]
807        year => Year,
808    }
809}