cynic_parser/type_system/
types.rs

1use crate::{
2    common::{TypeWrappers, TypeWrappersIter, WrappingType},
3    type_system::ids::TypeId,
4    AstLookup, Span,
5};
6
7use super::{iter::Iter, Definition, ReadContext, StringId, TypeDefinition, TypeSystemId};
8
9pub struct TypeRecord {
10    pub name: StringId,
11    pub name_start: usize,
12    pub wrappers: TypeWrappers,
13    pub span: Span,
14}
15
16#[derive(Clone, Copy)]
17pub struct Type<'a>(ReadContext<'a, TypeId>);
18
19impl PartialEq for Type<'_> {
20    fn eq(&self, other: &Self) -> bool {
21        self.name() == other.name() && self.wrappers().eq(other.wrappers())
22    }
23}
24
25impl Eq for Type<'_> {}
26
27impl<'a> Type<'a> {
28    pub fn name(&self) -> &'a str {
29        self.0
30            .document
31            .lookup(self.0.document.lookup(self.0.id).name)
32    }
33
34    /// The span of this types named type
35    pub fn name_span(&self) -> Span {
36        let record = self.0.document.lookup(self.0.id);
37
38        Span::new(
39            record.name_start,
40            record.name_start + self.0.document.lookup(record.name).len(),
41        )
42    }
43
44    pub fn is_list(&self) -> bool {
45        self.wrappers().any(|wrapper| wrapper == WrappingType::List)
46    }
47
48    pub fn is_non_null(&self) -> bool {
49        self.wrappers().next() == Some(WrappingType::NonNull)
50    }
51
52    /// The span of the the type, including any wrapppers
53    pub fn span(&self) -> Span {
54        self.0.document.lookup(self.0.id).span
55    }
56
57    /// The wrapper types from the outermost to innermost
58    pub fn wrappers(&self) -> TypeWrappersIter {
59        self.0.document.lookup(self.0.id).wrappers.iter()
60    }
61
62    /// Returns any definitions of the inner named type
63    ///
64    /// Note that this iterator scales linearly with the number of types present
65    /// in a schema, so should not be used if large schemas are expected.
66    pub fn definitions(&self) -> NamedTypeDefinitions<'a> {
67        let document = self.0.document;
68        NamedTypeDefinitions {
69            name: self.name(),
70            iter: document.definitions(),
71        }
72    }
73}
74
75impl std::fmt::Display for Type<'_> {
76    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77        let ast = &self.0.document;
78
79        let TypeRecord { name, wrappers, .. } = ast.lookup(self.0.id);
80
81        let wrappers = wrappers.iter().collect::<Vec<_>>();
82        for wrapping in &wrappers {
83            if let WrappingType::List = wrapping {
84                write!(f, "[")?;
85            }
86        }
87        write!(f, "{}", ast.lookup(*name))?;
88        for wrapping in wrappers.iter().rev() {
89            match wrapping {
90                WrappingType::NonNull => write!(f, "!")?,
91                WrappingType::List => write!(f, "]")?,
92            }
93        }
94
95        Ok(())
96    }
97}
98
99impl std::fmt::Debug for Type<'_> {
100    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101        f.debug_tuple("Type").field(&self.to_string()).finish()
102    }
103}
104
105impl TypeSystemId for TypeId {
106    type Reader<'a> = Type<'a>;
107
108    fn read(self, document: &super::TypeSystemDocument) -> Self::Reader<'_> {
109        Type(ReadContext { id: self, document })
110    }
111}
112
113impl<'a> From<ReadContext<'a, TypeId>> for Type<'a> {
114    fn from(value: ReadContext<'a, TypeId>) -> Self {
115        Self(value)
116    }
117}
118
119/// An Iterator over the definitions of a named [Type]
120///
121/// Note that this is not optimised and scales linearly with the number of definitions in
122/// the schema.
123#[derive(Clone)]
124pub struct NamedTypeDefinitions<'a> {
125    name: &'a str,
126    iter: Iter<'a, Definition<'a>>,
127}
128
129/// A [TypeDefintion] associated with a named [Type]
130pub enum NamedTypeDefinition<'a> {
131    Definition(TypeDefinition<'a>),
132    Extension(TypeDefinition<'a>),
133}
134
135impl<'a> Iterator for NamedTypeDefinitions<'a> {
136    type Item = NamedTypeDefinition<'a>;
137
138    fn next(&mut self) -> Option<Self::Item> {
139        loop {
140            match self.iter.next()? {
141                Definition::Type(type_definition) if type_definition.name() == self.name => {
142                    return Some(NamedTypeDefinition::Definition(type_definition))
143                }
144                Definition::TypeExtension(type_definition)
145                    if type_definition.name() == self.name =>
146                {
147                    return Some(NamedTypeDefinition::Extension(type_definition))
148                }
149                _ => continue,
150            }
151        }
152    }
153}