bluejay_parser/ast/executable/
field.rs

1use crate::ast::executable::SelectionSet;
2use crate::ast::{
3    DepthLimiter, FromTokens, IsMatch, ParseError, Tokens, TryFromTokens, VariableArguments,
4    VariableDirectives,
5};
6use crate::lexical_token::{Name, PunctuatorType};
7use crate::{HasSpan, Span};
8use std::cmp::{Eq, PartialEq};
9use std::hash::{Hash, Hasher};
10
11#[derive(Debug)]
12pub struct Field<'a> {
13    alias: Option<Name<'a>>,
14    name: Name<'a>,
15    arguments: Option<VariableArguments<'a>>,
16    directives: Option<VariableDirectives<'a>>,
17    selection_set: Option<SelectionSet<'a>>,
18    span: Span,
19}
20
21impl<'a> FromTokens<'a> for Field<'a> {
22    #[inline]
23    fn from_tokens(
24        tokens: &mut impl Tokens<'a>,
25        depth_limiter: DepthLimiter,
26    ) -> Result<Self, ParseError> {
27        let has_alias = tokens.peek_punctuator_matches(1, PunctuatorType::Colon);
28        let (alias, name) = if has_alias {
29            let alias = Some(tokens.expect_name()?);
30            tokens.expect_punctuator(PunctuatorType::Colon)?;
31            let name = tokens.expect_name()?;
32            (alias, name)
33        } else {
34            (None, tokens.expect_name()?)
35        };
36        let arguments =
37            VariableArguments::try_from_tokens(tokens, depth_limiter.bump()?).transpose()?;
38        let directives =
39            VariableDirectives::try_from_tokens(tokens, depth_limiter.bump()?).transpose()?;
40        let selection_set =
41            SelectionSet::try_from_tokens(tokens, depth_limiter.bump()?).transpose()?;
42        let start_span = alias.as_ref().unwrap_or(&name).span();
43        let directives_span = directives.as_ref().and_then(|directives| directives.span());
44        let end_span = if let Some(selection_set) = &selection_set {
45            selection_set.span()
46        } else if let Some(directive_span) = directives_span {
47            directive_span
48        } else if let Some(arguments) = &arguments {
49            arguments.span()
50        } else {
51            name.span()
52        };
53        let span = start_span.merge(end_span);
54        Ok(Self {
55            alias,
56            name,
57            arguments,
58            directives,
59            selection_set,
60            span,
61        })
62    }
63}
64
65impl<'a> IsMatch<'a> for Field<'a> {
66    #[inline]
67    fn is_match(tokens: &mut impl Tokens<'a>) -> bool {
68        tokens.peek_name(0).is_some()
69    }
70}
71
72impl<'a> Field<'a> {
73    pub fn response_key(&self) -> &str {
74        if let Some(alias) = &self.alias {
75            alias.as_ref()
76        } else {
77            self.name.as_ref()
78        }
79    }
80
81    pub fn name(&self) -> &Name<'a> {
82        &self.name
83    }
84
85    pub fn arguments(&self) -> Option<&VariableArguments> {
86        self.arguments.as_ref()
87    }
88
89    pub fn selection_set(&self) -> Option<&SelectionSet> {
90        self.selection_set.as_ref()
91    }
92}
93
94impl<'a> bluejay_core::executable::Field for Field<'a> {
95    type Arguments = VariableArguments<'a>;
96    type Directives = VariableDirectives<'a>;
97    type SelectionSet = SelectionSet<'a>;
98
99    fn alias(&self) -> Option<&str> {
100        self.alias.as_ref().map(|name| name.as_ref())
101    }
102
103    fn name(&self) -> &str {
104        self.name.as_ref()
105    }
106
107    fn arguments(&self) -> Option<&Self::Arguments> {
108        self.arguments.as_ref()
109    }
110
111    fn directives(&self) -> Option<&Self::Directives> {
112        self.directives.as_ref()
113    }
114
115    fn selection_set(&self) -> Option<&Self::SelectionSet> {
116        self.selection_set.as_ref()
117    }
118}
119
120impl HasSpan for Field<'_> {
121    fn span(&self) -> &Span {
122        &self.span
123    }
124}
125
126impl Hash for Field<'_> {
127    fn hash<H: Hasher>(&self, state: &mut H) {
128        self.span().hash(state);
129    }
130}
131
132impl PartialEq for Field<'_> {
133    fn eq(&self, other: &Self) -> bool {
134        self.span() == other.span()
135    }
136}
137
138impl Eq for Field<'_> {}