Skip to main content

juniper/schema/
meta.rs

1//! Types used to describe a `GraphQL` schema
2
3use std::borrow::ToOwned;
4
5use arcstr::ArcStr;
6use derive_more::with_trait::Debug;
7
8use crate::{
9    FieldError, IntoFieldError,
10    ast::{FromInputValue, InputValue, Type},
11    parser::{ParseError, ScalarToken},
12    schema::model::SchemaType,
13    types::base::TypeKind,
14    value::{DefaultScalarValue, ParseScalarValue},
15};
16
17/// Whether an item is deprecated, with context.
18#[derive(Clone, Debug, Eq, Hash, PartialEq)]
19pub enum DeprecationStatus {
20    /// The field/variant is not deprecated.
21    Current,
22
23    /// The field/variant is deprecated, with an optional reason
24    Deprecated(Option<ArcStr>),
25}
26
27impl DeprecationStatus {
28    /// If this deprecation status indicates the item is deprecated.
29    pub fn is_deprecated(&self) -> bool {
30        match self {
31            Self::Current => false,
32            Self::Deprecated(_) => true,
33        }
34    }
35
36    /// An optional reason for the deprecation, or none if `Current`.
37    pub fn reason(&self) -> Option<&ArcStr> {
38        match self {
39            Self::Current => None,
40            Self::Deprecated(rsn) => rsn.as_ref(),
41        }
42    }
43}
44
45/// Scalar type metadata
46#[derive(Debug)]
47pub struct ScalarMeta<S> {
48    #[doc(hidden)]
49    pub name: ArcStr,
50    #[doc(hidden)]
51    pub description: Option<ArcStr>,
52    #[doc(hidden)]
53    pub specified_by_url: Option<ArcStr>,
54    #[debug(ignore)]
55    pub(crate) try_parse_fn: InputValueParseFn<S>,
56    #[debug(ignore)]
57    pub(crate) parse_fn: ScalarTokenParseFn<S>,
58}
59
60impl<S> ScalarMeta<S> {
61    /// Builds a new [`ScalarMeta`] type with the specified `name`.
62    pub fn new<T>(name: impl Into<ArcStr>) -> Self
63    where
64        T: FromInputValue<S> + ParseScalarValue<S>,
65        T::Error: IntoFieldError<S>,
66    {
67        Self {
68            name: name.into(),
69            description: None,
70            specified_by_url: None,
71            try_parse_fn: try_parse_fn::<S, T>,
72            parse_fn: <T as ParseScalarValue<S>>::from_str,
73        }
74    }
75
76    /// Sets the `description` of this [`ScalarMeta`] type.
77    ///
78    /// Overwrites any previously set description.
79    #[must_use]
80    pub fn description(mut self, description: impl Into<ArcStr>) -> Self {
81        self.description = Some(description.into());
82        self
83    }
84
85    /// Sets the [specification URL][0] for this [`ScalarMeta`] type.
86    ///
87    /// Overwrites any previously set [specification URL][0].
88    ///
89    /// [0]: https://spec.graphql.org/October2021#sec--specifiedBy
90    #[must_use]
91    pub fn specified_by_url(mut self, url: impl Into<ArcStr>) -> Self {
92        self.specified_by_url = Some(url.into());
93        self
94    }
95
96    /// Wraps this [`ScalarMeta`] type into a generic [`MetaType`].
97    pub fn into_meta(self) -> MetaType<S> {
98        MetaType::Scalar(self)
99    }
100}
101
102/// Shortcut for an [`InputValue`] parsing function.
103pub type InputValueParseFn<S> = for<'b> fn(&'b InputValue<S>) -> Result<(), FieldError<S>>;
104
105/// Shortcut for a [`ScalarToken`] parsing function.
106pub type ScalarTokenParseFn<S> = for<'b> fn(ScalarToken<'b>) -> Result<S, ParseError>;
107
108/// List type metadata
109#[derive(Debug)]
110pub struct ListMeta {
111    #[doc(hidden)]
112    pub of_type: Type,
113
114    #[doc(hidden)]
115    pub expected_size: Option<usize>,
116}
117
118impl ListMeta {
119    /// Builds a new [`ListMeta`] type by wrapping the specified [`Type`].
120    ///
121    /// Specifying `expected_size` will be used to ensure that values of this type will always match
122    /// it.
123    pub fn new(of_type: Type, expected_size: Option<usize>) -> Self {
124        Self {
125            of_type,
126            expected_size,
127        }
128    }
129
130    /// Wraps this [`ListMeta`] type into a generic [`MetaType`].
131    pub fn into_meta<S>(self) -> MetaType<S> {
132        MetaType::List(self)
133    }
134}
135
136/// Nullable type metadata
137#[derive(Debug)]
138pub struct NullableMeta {
139    #[doc(hidden)]
140    pub of_type: Type,
141}
142
143impl NullableMeta {
144    /// Builds a new [`NullableMeta`] type by wrapping the specified [`Type`].
145    pub fn new(of_type: Type) -> Self {
146        Self { of_type }
147    }
148
149    /// Wraps this [`NullableMeta`] type into a generic [`MetaType`].
150    pub fn into_meta<S>(self) -> MetaType<S> {
151        MetaType::Nullable(self)
152    }
153}
154
155/// Object type metadata
156#[derive(Debug)]
157pub struct ObjectMeta<S> {
158    #[doc(hidden)]
159    pub name: ArcStr,
160    #[doc(hidden)]
161    pub description: Option<ArcStr>,
162    #[doc(hidden)]
163    pub fields: Vec<Field<S>>,
164    #[doc(hidden)]
165    pub interface_names: Vec<ArcStr>,
166}
167
168impl<S> ObjectMeta<S> {
169    /// Builds a new [`ObjectMeta`] type with the specified `name` and `fields`.
170    pub fn new(name: impl Into<ArcStr>, fields: &[Field<S>]) -> Self
171    where
172        S: Clone,
173    {
174        Self {
175            name: name.into(),
176            description: None,
177            fields: fields.to_vec(),
178            interface_names: vec![],
179        }
180    }
181
182    /// Sets the `description` of this [`ObjectMeta`] type.
183    ///
184    /// Overwrites any previously set description.
185    #[must_use]
186    pub fn description(mut self, description: impl Into<ArcStr>) -> Self {
187        self.description = Some(description.into());
188        self
189    }
190
191    /// Sets the `interfaces` this [`ObjectMeta`] type implements.
192    ///
193    /// Overwrites any previously set list of interfaces.
194    #[must_use]
195    pub fn interfaces(mut self, interfaces: &[Type]) -> Self {
196        self.interface_names = interfaces
197            .iter()
198            .map(|t| t.innermost_name().into())
199            .collect();
200        self
201    }
202
203    /// Wraps this [`ObjectMeta`] type into a generic [`MetaType`].
204    pub fn into_meta(self) -> MetaType<S> {
205        MetaType::Object(self)
206    }
207}
208
209/// Enum type metadata
210#[derive(Debug)]
211pub struct EnumMeta<S> {
212    #[doc(hidden)]
213    pub name: ArcStr,
214    #[doc(hidden)]
215    pub description: Option<ArcStr>,
216    #[doc(hidden)]
217    pub values: Vec<EnumValue>,
218    #[debug(ignore)]
219    pub(crate) try_parse_fn: InputValueParseFn<S>,
220}
221
222impl<S> EnumMeta<S> {
223    /// Builds a new [`EnumMeta`] type with the specified `name` and possible `values`.
224    pub fn new<T>(name: impl Into<ArcStr>, values: &[EnumValue]) -> Self
225    where
226        T: FromInputValue<S>,
227        T::Error: IntoFieldError<S>,
228    {
229        Self {
230            name: name.into(),
231            description: None,
232            values: values.to_owned(),
233            try_parse_fn: try_parse_fn::<S, T>,
234        }
235    }
236
237    /// Sets the `description` of this [`EnumMeta`] type.
238    ///
239    /// Overwrites any previously set description.
240    #[must_use]
241    pub fn description(mut self, description: impl Into<ArcStr>) -> Self {
242        self.description = Some(description.into());
243        self
244    }
245
246    /// Wraps this [`EnumMeta`] type into a generic [`MetaType`].
247    pub fn into_meta(self) -> MetaType<S> {
248        MetaType::Enum(self)
249    }
250}
251
252/// Interface type metadata
253#[derive(Debug)]
254pub struct InterfaceMeta<S> {
255    #[doc(hidden)]
256    pub name: ArcStr,
257    #[doc(hidden)]
258    pub description: Option<ArcStr>,
259    #[doc(hidden)]
260    pub fields: Vec<Field<S>>,
261    #[doc(hidden)]
262    pub interface_names: Vec<ArcStr>,
263}
264
265impl<S> InterfaceMeta<S> {
266    /// Builds a new [`InterfaceMeta`] type with the specified `name` and `fields`.
267    pub fn new(name: impl Into<ArcStr>, fields: &[Field<S>]) -> Self
268    where
269        S: Clone,
270    {
271        Self {
272            name: name.into(),
273            description: None,
274            fields: fields.to_vec(),
275            interface_names: Vec::new(),
276        }
277    }
278
279    /// Sets the `description` of this [`InterfaceMeta`] type.
280    ///
281    /// Overwrites any previously set description.
282    #[must_use]
283    pub fn description(mut self, description: impl Into<ArcStr>) -> Self {
284        self.description = Some(description.into());
285        self
286    }
287
288    /// Sets the `interfaces` this [`InterfaceMeta`] interface implements.
289    ///
290    /// Overwrites any previously set list of interfaces.
291    #[must_use]
292    pub fn interfaces(mut self, interfaces: &[Type]) -> Self {
293        self.interface_names = interfaces
294            .iter()
295            .map(|t| t.innermost_name().into())
296            .collect();
297        self
298    }
299
300    /// Wraps this [`InterfaceMeta`] type into a generic [`MetaType`].
301    pub fn into_meta(self) -> MetaType<S> {
302        MetaType::Interface(self)
303    }
304}
305
306/// Union type metadata
307#[derive(Debug)]
308pub struct UnionMeta {
309    #[doc(hidden)]
310    pub name: ArcStr,
311    #[doc(hidden)]
312    pub description: Option<ArcStr>,
313    #[doc(hidden)]
314    pub of_type_names: Vec<ArcStr>,
315}
316
317impl UnionMeta {
318    /// Builds a new [`UnionMeta`] type with the specified `name` and possible [`Type`]s.
319    pub fn new(name: impl Into<ArcStr>, of_types: &[Type]) -> Self {
320        Self {
321            name: name.into(),
322            description: None,
323            of_type_names: of_types.iter().map(|t| t.innermost_name().into()).collect(),
324        }
325    }
326
327    /// Sets the `description` of this [`UnionMeta`] type.
328    ///
329    /// Overwrites any previously set description.
330    #[must_use]
331    pub fn description(mut self, description: impl Into<ArcStr>) -> Self {
332        self.description = Some(description.into());
333        self
334    }
335
336    /// Wraps this [`UnionMeta`] type into a generic [`MetaType`].
337    pub fn into_meta<S>(self) -> MetaType<S> {
338        MetaType::Union(self)
339    }
340}
341
342/// Input object metadata
343#[derive(Debug)]
344pub struct InputObjectMeta<S> {
345    #[doc(hidden)]
346    pub name: ArcStr,
347    #[doc(hidden)]
348    pub description: Option<ArcStr>,
349    #[doc(hidden)]
350    pub input_fields: Vec<Argument<S>>,
351    #[debug(ignore)]
352    pub(crate) try_parse_fn: InputValueParseFn<S>,
353}
354
355impl<S> InputObjectMeta<S> {
356    /// Builds a new [`InputObjectMeta`] type with the specified `name` and `input_fields`.
357    pub fn new<T>(name: impl Into<ArcStr>, input_fields: &[Argument<S>]) -> Self
358    where
359        T: FromInputValue<S>,
360        T::Error: IntoFieldError<S>,
361        S: Clone,
362    {
363        Self {
364            name: name.into(),
365            description: None,
366            input_fields: input_fields.to_vec(),
367            try_parse_fn: try_parse_fn::<S, T>,
368        }
369    }
370
371    /// Sets the `description` of this [`InputObjectMeta`] type.
372    ///
373    /// Overwrites any previously set description.
374    #[must_use]
375    pub fn description(mut self, description: impl Into<ArcStr>) -> Self {
376        self.description = Some(description.into());
377        self
378    }
379
380    /// Wraps this [`InputObjectMeta`] type into a generic [`MetaType`].
381    pub fn into_meta(self) -> MetaType<S> {
382        MetaType::InputObject(self)
383    }
384}
385
386/// A placeholder for not-yet-registered types
387///
388/// After a type's `meta` method has been called but before it has returned, a placeholder type
389/// is inserted into a registry to indicate existence.
390#[derive(Debug)]
391pub struct PlaceholderMeta {
392    #[doc(hidden)]
393    pub of_type: Type,
394}
395
396/// Metadata for a field
397#[derive(Debug, Clone)]
398pub struct Field<S> {
399    #[doc(hidden)]
400    pub name: ArcStr,
401    #[doc(hidden)]
402    pub description: Option<ArcStr>,
403    #[doc(hidden)]
404    pub arguments: Option<Vec<Argument<S>>>,
405    #[doc(hidden)]
406    pub field_type: Type,
407    #[doc(hidden)]
408    pub deprecation_status: DeprecationStatus,
409}
410
411impl<S> Field<S> {
412    /// Sets the `description` of this [`Field`].
413    ///
414    /// Overwrites any previously set description.
415    #[must_use]
416    pub fn description(mut self, description: impl Into<ArcStr>) -> Self {
417        self.description = Some(description.into());
418        self
419    }
420
421    /// Adds an `argument` to this [`Field`].
422    ///
423    /// Arguments are unordered and can't contain duplicates by name.
424    #[must_use]
425    pub fn argument(mut self, argument: Argument<S>) -> Self {
426        match self.arguments {
427            None => {
428                self.arguments = Some(vec![argument]);
429            }
430            Some(ref mut args) => {
431                args.push(argument);
432            }
433        };
434        self
435    }
436
437    /// Indicates whether this [`Field`] is GraphQL built-in.
438    #[must_use]
439    pub fn is_builtin(&self) -> bool {
440        // "used exclusively by GraphQL’s introspection system"
441        self.name.starts_with("__")
442    }
443
444    /// Sets this [`Field`] as deprecated with an optional `reason`.
445    ///
446    /// Overwrites any previously set deprecation reason.
447    #[must_use]
448    pub fn deprecated(mut self, reason: Option<impl Into<ArcStr>>) -> Self {
449        self.deprecation_status = DeprecationStatus::Deprecated(reason.map(Into::into));
450        self
451    }
452}
453
454/// Metadata for an argument to a field
455#[derive(Debug, Clone)]
456pub struct Argument<S> {
457    #[doc(hidden)]
458    pub name: ArcStr,
459    #[doc(hidden)]
460    pub description: Option<ArcStr>,
461    #[doc(hidden)]
462    pub arg_type: Type,
463    #[doc(hidden)]
464    pub default_value: Option<InputValue<S>>,
465}
466
467impl<S> Argument<S> {
468    /// Builds a new [`Argument`] of the given [`Type`] with the given `name`.
469    pub fn new(name: impl Into<ArcStr>, arg_type: Type) -> Self {
470        Self {
471            name: name.into(),
472            description: None,
473            arg_type,
474            default_value: None,
475        }
476    }
477
478    /// Sets the `description` of this [`Argument`].
479    ///
480    /// Overwrites any previously set description.
481    #[must_use]
482    pub fn description(mut self, description: impl Into<ArcStr>) -> Self {
483        self.description = Some(description.into());
484        self
485    }
486
487    /// Indicates whether this [`Argument`] is GraphQL built-in.
488    #[must_use]
489    pub fn is_builtin(&self) -> bool {
490        // "used exclusively by GraphQL’s introspection system"
491        self.name.starts_with("__")
492    }
493
494    /// Sets the default value of this [`Argument`].
495    ///
496    /// Overwrites any previously set default value.
497    #[must_use]
498    pub fn default_value(mut self, val: InputValue<S>) -> Self {
499        self.default_value = Some(val);
500        self
501    }
502}
503
504/// Metadata for a single value in an enum
505#[derive(Debug, Clone)]
506pub struct EnumValue {
507    /// The name of the enum value
508    ///
509    /// This is the string literal representation of the enum in responses.
510    pub name: ArcStr,
511
512    /// The optional description of the enum value.
513    ///
514    /// Note: this is not the description of the enum itself; it's the
515    /// description of this enum _value_.
516    pub description: Option<ArcStr>,
517
518    /// Whether the field is deprecated or not, with an optional reason.
519    pub deprecation_status: DeprecationStatus,
520}
521
522impl EnumValue {
523    /// Constructs a new [`EnumValue`] with the provided `name`.
524    pub fn new(name: impl Into<ArcStr>) -> Self {
525        Self {
526            name: name.into(),
527            description: None,
528            deprecation_status: DeprecationStatus::Current,
529        }
530    }
531
532    /// Sets the `description` of this [`EnumValue`].
533    ///
534    /// Overwrites any previously set description.
535    #[must_use]
536    pub fn description(mut self, description: impl Into<ArcStr>) -> Self {
537        self.description = Some(description.into());
538        self
539    }
540
541    /// Sets this [`EnumValue`] as deprecated with an optional `reason`.
542    ///
543    /// Overwrites any previously set deprecation reason.
544    #[must_use]
545    pub fn deprecated(mut self, reason: Option<impl Into<ArcStr>>) -> Self {
546        self.deprecation_status = DeprecationStatus::Deprecated(reason.map(Into::into));
547        self
548    }
549}
550
551/// Generic type metadata
552#[derive(Debug)]
553pub enum MetaType<S = DefaultScalarValue> {
554    #[doc(hidden)]
555    Scalar(ScalarMeta<S>),
556    #[doc(hidden)]
557    List(ListMeta),
558    #[doc(hidden)]
559    Nullable(NullableMeta),
560    #[doc(hidden)]
561    Object(ObjectMeta<S>),
562    #[doc(hidden)]
563    Enum(EnumMeta<S>),
564    #[doc(hidden)]
565    Interface(InterfaceMeta<S>),
566    #[doc(hidden)]
567    Union(UnionMeta),
568    #[doc(hidden)]
569    InputObject(InputObjectMeta<S>),
570    #[doc(hidden)]
571    Placeholder(PlaceholderMeta),
572}
573
574impl<S> MetaType<S> {
575    /// Returns the name of the represented type, if applicable.
576    ///
577    /// [Lists][`ListMeta`], [`null`ables][`NullableMeta`] and [placeholders][`PlaceholderMeta`]
578    /// don't have a name.
579    pub fn name(&self) -> Option<&ArcStr> {
580        match self {
581            Self::Enum(EnumMeta { name, .. })
582            | Self::InputObject(InputObjectMeta { name, .. })
583            | Self::Interface(InterfaceMeta { name, .. })
584            | Self::Object(ObjectMeta { name, .. })
585            | Self::Scalar(ScalarMeta { name, .. })
586            | Self::Union(UnionMeta { name, .. }) => Some(name),
587            Self::List(..) | Self::Nullable(..) | Self::Placeholder(..) => None,
588        }
589    }
590
591    /// Returns the description of the represented type, if applicable.
592    ///
593    /// [Lists][`ListMeta`], [`null`ables][`NullableMeta`] and [placeholders][`PlaceholderMeta`]
594    /// don't have a description.
595    pub fn description(&self) -> Option<&ArcStr> {
596        match self {
597            Self::Enum(EnumMeta { description, .. })
598            | Self::InputObject(InputObjectMeta { description, .. })
599            | Self::Interface(InterfaceMeta { description, .. })
600            | Self::Object(ObjectMeta { description, .. })
601            | Self::Scalar(ScalarMeta { description, .. })
602            | Self::Union(UnionMeta { description, .. }) => description.as_ref(),
603            Self::List(..) | Self::Nullable(..) | Self::Placeholder(..) => None,
604        }
605    }
606
607    /// Returns the [specification URL][0] of the represented type, if applicable.
608    ///
609    /// Only custom GraphQL scalars can have a [specification URL][0].
610    ///
611    /// [0]: https://spec.graphql.org/October2021#sec--specifiedBy
612    pub fn specified_by_url(&self) -> Option<&ArcStr> {
613        match self {
614            Self::Scalar(ScalarMeta {
615                specified_by_url, ..
616            }) => specified_by_url.as_ref(),
617            Self::Enum(..)
618            | Self::InputObject(..)
619            | Self::Interface(..)
620            | Self::List(..)
621            | Self::Nullable(..)
622            | Self::Object(..)
623            | Self::Placeholder(..)
624            | Self::Union(..) => None,
625        }
626    }
627
628    /// Construct a [`TypeKind`] out of this [`MetaType`].
629    ///
630    /// # Panics
631    ///
632    /// If this is [`MetaType::Nullable`] or [``MetaType::Placeholder`].
633    pub fn type_kind(&self) -> TypeKind {
634        match self {
635            Self::Scalar(..) => TypeKind::Scalar,
636            Self::List(..) => TypeKind::List,
637            Self::Nullable(..) => panic!("сan't take `type_kind` of `MetaType::Nullable`"),
638            Self::Object(..) => TypeKind::Object,
639            Self::Enum(..) => TypeKind::Enum,
640            Self::Interface(..) => TypeKind::Interface,
641            Self::Union(..) => TypeKind::Union,
642            Self::InputObject(..) => TypeKind::InputObject,
643            Self::Placeholder(..) => panic!("сan't take `type_kind` of `MetaType::Placeholder`"),
644        }
645    }
646
647    /// Returns a [`Field`]'s metadata by its `name`.
648    ///
649    /// Only [objects][`ObjectMeta`] and [interfaces][`InterfaceMeta`] have fields.
650    pub fn field_by_name(&self, name: &str) -> Option<&Field<S>> {
651        match self {
652            Self::Interface(InterfaceMeta { fields, .. })
653            | Self::Object(ObjectMeta { fields, .. }) => fields.iter().find(|f| f.name == name),
654            Self::Enum(..)
655            | Self::InputObject(..)
656            | Self::List(..)
657            | Self::Nullable(..)
658            | Self::Placeholder(..)
659            | Self::Scalar(..)
660            | Self::Union(..) => None,
661        }
662    }
663
664    /// Returns an input field's metadata by its `name`.
665    ///
666    /// Only [input objects][`InputObjectMeta`] have input fields.
667    pub fn input_field_by_name(&self, name: &str) -> Option<&Argument<S>> {
668        match self {
669            Self::InputObject(InputObjectMeta { input_fields, .. }) => {
670                input_fields.iter().find(|f| f.name == name)
671            }
672            Self::Enum(..)
673            | Self::Interface(..)
674            | Self::List(..)
675            | Self::Nullable(..)
676            | Self::Object(..)
677            | Self::Placeholder(..)
678            | Self::Scalar(..)
679            | Self::Union(..) => None,
680        }
681    }
682
683    /// Construct a [`Type`] literal out of this [`MetaType`].
684    pub fn as_type(&self) -> Type {
685        match self {
686            Self::Enum(EnumMeta { name, .. })
687            | Self::InputObject(InputObjectMeta { name, .. })
688            | Self::Interface(InterfaceMeta { name, .. })
689            | Self::Object(ObjectMeta { name, .. })
690            | Self::Scalar(ScalarMeta { name, .. })
691            | Self::Union(UnionMeta { name, .. }) => Type::nullable(name.clone()).wrap_non_null(),
692            Self::List(ListMeta {
693                of_type,
694                expected_size,
695            }) => of_type.clone().wrap_list(*expected_size).wrap_non_null(),
696            Self::Nullable(NullableMeta { of_type }) => of_type.clone().into_nullable(),
697            Self::Placeholder(PlaceholderMeta { of_type }) => of_type.clone(),
698        }
699    }
700
701    /// Returns the [`InputValueParseFn`] of the represented type, if applicable.
702    ///
703    /// Only [scalars][`ScalarMeta`], [enums][`EnumMeta`] and [input objects][`InputObjectMeta`]
704    /// have an [`InputValueParseFn`].
705    pub fn input_value_parse_fn(&self) -> Option<InputValueParseFn<S>> {
706        match self {
707            Self::Enum(EnumMeta { try_parse_fn, .. })
708            | Self::InputObject(InputObjectMeta { try_parse_fn, .. })
709            | Self::Scalar(ScalarMeta { try_parse_fn, .. }) => Some(*try_parse_fn),
710            Self::Interface(..)
711            | Self::List(..)
712            | Self::Nullable(..)
713            | Self::Object(..)
714            | Self::Placeholder(..)
715            | Self::Union(..) => None,
716        }
717    }
718
719    /// Indicates whether the represented type is a composite one.
720    ///
721    /// [Objects][`ObjectMeta`], [interfaces][`InterfaceMeta`] and [unions][`UnionMeta`] are
722    /// composite types.
723    pub fn is_composite(&self) -> bool {
724        matches!(
725            self,
726            Self::Interface(..) | Self::Object(..) | Self::Union(..)
727        )
728    }
729
730    /// Indicates whether the represented type can occur in leaf positions of queries.
731    ///
732    /// Only [enums][`EnumMeta`] and [scalars][`ScalarMeta`] are leaf types.
733    pub fn is_leaf(&self) -> bool {
734        matches!(self, Self::Enum(..) | Self::Scalar(..))
735    }
736
737    /// Indicates whether the represented type is abstract.
738    ///
739    /// Only [interfaces][`InterfaceMeta`] and [unions][`UnionMeta`] are abstract types.
740    pub fn is_abstract(&self) -> bool {
741        matches!(self, Self::Interface(..) | Self::Union(..))
742    }
743
744    /// Indicates whether the represented type can be used in input positions (e.g. arguments or
745    /// variables).
746    ///
747    /// Only [scalars][`ScalarMeta`], [enums][`EnumMeta`] and [input objects][`InputObjectMeta`] are
748    /// input types.
749    pub fn is_input(&self) -> bool {
750        matches!(
751            self,
752            Self::Enum(..) | Self::InputObject(..) | Self::Scalar(..)
753        )
754    }
755
756    /// Indicates whether the represented type is GraphQL built-in.
757    pub fn is_builtin(&self) -> bool {
758        if let Some(name) = self.name() {
759            // "used exclusively by GraphQL’s introspection system"
760            {
761                name.starts_with("__") ||
762            // https://spec.graphql.org/October2021#sec-Scalars
763            name == "Boolean" || name == "String" || name == "Int" || name == "Float" || name == "ID" ||
764            // Our custom empty markers
765            name == "_EmptyMutation" || name == "_EmptySubscription"
766            }
767        } else {
768            false
769        }
770    }
771
772    pub(crate) fn fields<'s>(&self, schema: &'s SchemaType<S>) -> Option<Vec<&'s Field<S>>> {
773        schema
774            .lookup_type(&self.as_type())
775            .and_then(|tpe| match tpe {
776                Self::Interface(i) => Some(i.fields.iter().collect()),
777                Self::Object(o) => Some(o.fields.iter().collect()),
778                Self::Union(u) => Some(
779                    u.of_type_names
780                        .iter()
781                        .filter_map(|n| schema.concrete_type_by_name(n))
782                        .filter_map(|t| t.fields(schema))
783                        .flatten()
784                        .collect(),
785                ),
786                Self::Enum(..)
787                | Self::InputObject(..)
788                | Self::List(..)
789                | Self::Nullable(..)
790                | Self::Placeholder(..)
791                | Self::Scalar(..) => None,
792            })
793    }
794}
795
796fn try_parse_fn<S, T>(v: &InputValue<S>) -> Result<(), FieldError<S>>
797where
798    T: FromInputValue<S>,
799    T::Error: IntoFieldError<S>,
800{
801    T::from_input_value(v)
802        .map_err(T::Error::into_field_error)
803        .map(drop)
804}