1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
use crate::ast::executable::{Field, FragmentSpread, InlineFragment};
use crate::ast::{FromTokens, IsMatch, ParseError, Tokens};
use crate::lexical_token::PunctuatorType;
use bluejay_core::executable::{Selection as CoreSelection, SelectionReference};

#[derive(Debug)]
pub enum Selection<'a> {
    Field(Field<'a>),
    FragmentSpread(FragmentSpread<'a>),
    InlineFragment(InlineFragment<'a>),
}

impl<'a> CoreSelection for Selection<'a> {
    type Field = Field<'a>;
    type FragmentSpread = FragmentSpread<'a>;
    type InlineFragment = InlineFragment<'a>;

    fn as_ref(&self) -> SelectionReference<'_, Self> {
        match self {
            Self::Field(f) => SelectionReference::Field(f),
            Self::FragmentSpread(fs) => SelectionReference::FragmentSpread(fs),
            Self::InlineFragment(i) => SelectionReference::InlineFragment(i),
        }
    }
}

impl<'a> FromTokens<'a> for Selection<'a> {
    fn from_tokens(tokens: &mut impl Tokens<'a>) -> Result<Self, ParseError> {
        if Field::is_match(tokens) {
            Field::from_tokens(tokens).map(Self::Field)
        } else if FragmentSpread::is_match(tokens) {
            FragmentSpread::from_tokens(tokens).map(Self::FragmentSpread)
        } else if InlineFragment::is_match(tokens) {
            InlineFragment::from_tokens(tokens).map(Self::InlineFragment)
        } else {
            Err(tokens.unexpected_token())
        }
    }
}

impl<'a> IsMatch<'a> for Selection<'a> {
    fn is_match(tokens: &mut impl Tokens<'a>) -> bool {
        Field::is_match(tokens) || tokens.peek_punctuator_matches(0, PunctuatorType::Ellipse)
    }
}