bluejay_core/definition/
output_type.rs

1use crate::definition::{
2    EnumTypeDefinition, InterfaceTypeDefinition, ObjectTypeDefinition, ScalarTypeDefinition,
3    SchemaDefinition, TypeDefinition, TypeDefinitionReference, UnionTypeDefinition,
4};
5use crate::BuiltinScalarDefinition;
6
7#[derive(Debug)]
8pub enum BaseOutputTypeReference<'a, O: OutputType> {
9    BuiltinScalar(BuiltinScalarDefinition),
10    CustomScalar(&'a O::CustomScalarTypeDefinition),
11    Enum(&'a O::EnumTypeDefinition),
12    Object(&'a O::ObjectTypeDefinition),
13    Interface(&'a O::InterfaceTypeDefinition),
14    Union(&'a O::UnionTypeDefinition),
15}
16
17impl<'a, O: OutputType> BaseOutputTypeReference<'a, O> {
18    pub fn name(&self) -> &'a str {
19        match self {
20            Self::BuiltinScalar(bstd) => bstd.name(),
21            Self::CustomScalar(cstd) => cstd.name(),
22            Self::Enum(etd) => etd.name(),
23            Self::Object(otd) => otd.name(),
24            Self::Interface(itd) => itd.name(),
25            Self::Union(utd) => utd.name(),
26        }
27    }
28
29    pub fn is_scalar_or_enum(&self) -> bool {
30        matches!(
31            self,
32            Self::BuiltinScalar(_) | Self::CustomScalar(_) | Self::Enum(_)
33        )
34    }
35
36    pub fn is_composite(&self) -> bool {
37        matches!(self, Self::Object(_) | Self::Interface(_) | Self::Union(_))
38    }
39}
40
41impl<O: OutputType> Clone for BaseOutputTypeReference<'_, O> {
42    fn clone(&self) -> Self {
43        *self
44    }
45}
46
47impl<O: OutputType> Copy for BaseOutputTypeReference<'_, O> {}
48
49pub enum OutputTypeReference<'a, O: OutputType> {
50    Base(BaseOutputTypeReference<'a, O>, bool),
51    List(&'a O, bool),
52}
53
54impl<O: OutputType> Clone for OutputTypeReference<'_, O> {
55    fn clone(&self) -> Self {
56        *self
57    }
58}
59
60impl<O: OutputType> Copy for OutputTypeReference<'_, O> {}
61
62impl<'a, O: OutputType> OutputTypeReference<'a, O> {
63    pub fn is_required(&self) -> bool {
64        match self {
65            Self::Base(_, r) => *r,
66            Self::List(_, r) => *r,
67        }
68    }
69
70    pub fn base<
71        S: SchemaDefinition<
72            CustomScalarTypeDefinition = O::CustomScalarTypeDefinition,
73            EnumTypeDefinition = O::EnumTypeDefinition,
74            ObjectTypeDefinition = O::ObjectTypeDefinition,
75            InterfaceTypeDefinition = O::InterfaceTypeDefinition,
76            UnionTypeDefinition = O::UnionTypeDefinition,
77        >,
78    >(
79        &self,
80        schema_definition: &'a S,
81    ) -> BaseOutputTypeReference<'a, O> {
82        match self {
83            Self::Base(b, _) => *b,
84            Self::List(l, _) => l.base(schema_definition),
85        }
86    }
87}
88
89#[derive(Clone)]
90pub enum ShallowOutputTypeReference<'a, O: OutputType> {
91    Base(&'a str, bool),
92    List(&'a O, bool),
93}
94
95impl<'a, O: OutputType> ShallowOutputTypeReference<'a, O> {
96    pub fn is_required(&self) -> bool {
97        match self {
98            Self::Base(_, r) => *r,
99            Self::List(_, r) => *r,
100        }
101    }
102
103    pub fn base_name(&self) -> &'a str {
104        match self {
105            Self::Base(b, _) => b,
106            Self::List(inner, _) => inner.as_shallow_ref().base_name(),
107        }
108    }
109}
110
111impl<O: OutputType> PartialEq for ShallowOutputTypeReference<'_, O> {
112    fn eq(&self, other: &Self) -> bool {
113        match (self, other) {
114            (
115                ShallowOutputTypeReference::Base(name1, required1),
116                ShallowOutputTypeReference::Base(name2, required2),
117            ) => required1 == required2 && name1 == name2,
118            (
119                ShallowOutputTypeReference::List(inner1, required1),
120                ShallowOutputTypeReference::List(inner2, required2),
121            ) => required1 == required2 && inner1.as_shallow_ref() == inner2.as_shallow_ref(),
122            _ => false,
123        }
124    }
125}
126
127impl<O: OutputType> std::fmt::Display for ShallowOutputTypeReference<'_, O> {
128    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
129        match self {
130            ShallowOutputTypeReference::Base(name, required) => {
131                write!(f, "{}{}", name, if *required { "!" } else { "" })
132            }
133            ShallowOutputTypeReference::List(inner, required) => {
134                write!(
135                    f,
136                    "[{}]{}",
137                    inner.as_shallow_ref(),
138                    if *required { "!" } else { "" }
139                )
140            }
141        }
142    }
143}
144
145pub trait OutputType: Sized {
146    type CustomScalarTypeDefinition: ScalarTypeDefinition;
147    type EnumTypeDefinition: EnumTypeDefinition;
148    type ObjectTypeDefinition: ObjectTypeDefinition;
149    type InterfaceTypeDefinition: InterfaceTypeDefinition;
150    type UnionTypeDefinition: UnionTypeDefinition;
151
152    fn as_ref<
153        'a,
154        S: SchemaDefinition<
155            CustomScalarTypeDefinition = Self::CustomScalarTypeDefinition,
156            EnumTypeDefinition = Self::EnumTypeDefinition,
157            ObjectTypeDefinition = Self::ObjectTypeDefinition,
158            InterfaceTypeDefinition = Self::InterfaceTypeDefinition,
159            UnionTypeDefinition = Self::UnionTypeDefinition,
160        >,
161    >(
162        &'a self,
163        schema_definition: &'a S,
164    ) -> OutputTypeReference<'a, Self>;
165
166    fn as_shallow_ref(&self) -> ShallowOutputTypeReference<'_, Self>;
167
168    fn display_name(&self) -> String {
169        self.as_shallow_ref().to_string()
170    }
171
172    fn is_required(&self) -> bool {
173        self.as_shallow_ref().is_required()
174    }
175
176    fn base_name(&self) -> &str {
177        self.as_shallow_ref().base_name()
178    }
179
180    fn base<
181        'a,
182        S: SchemaDefinition<
183            CustomScalarTypeDefinition = Self::CustomScalarTypeDefinition,
184            EnumTypeDefinition = Self::EnumTypeDefinition,
185            ObjectTypeDefinition = Self::ObjectTypeDefinition,
186            InterfaceTypeDefinition = Self::InterfaceTypeDefinition,
187            UnionTypeDefinition = Self::UnionTypeDefinition,
188        >,
189    >(
190        &'a self,
191        schema_definition: &'a S,
192    ) -> BaseOutputTypeReference<'a, Self> {
193        self.as_ref(schema_definition).base(schema_definition)
194    }
195}
196
197impl<
198        'a,
199        T: TypeDefinition,
200        O: OutputType<
201            CustomScalarTypeDefinition = T::CustomScalarTypeDefinition,
202            EnumTypeDefinition = T::EnumTypeDefinition,
203            ObjectTypeDefinition = T::ObjectTypeDefinition,
204            InterfaceTypeDefinition = T::InterfaceTypeDefinition,
205            UnionTypeDefinition = T::UnionTypeDefinition,
206        >,
207    > TryFrom<TypeDefinitionReference<'a, T>> for BaseOutputTypeReference<'a, O>
208{
209    type Error = ();
210
211    fn try_from(value: TypeDefinitionReference<'a, T>) -> Result<Self, Self::Error> {
212        match value {
213            TypeDefinitionReference::BuiltinScalar(bstd) => Ok(Self::BuiltinScalar(bstd)),
214            TypeDefinitionReference::CustomScalar(cstd) => Ok(Self::CustomScalar(cstd)),
215            TypeDefinitionReference::Enum(etd) => Ok(Self::Enum(etd)),
216            TypeDefinitionReference::Interface(itd) => Ok(Self::Interface(itd)),
217            TypeDefinitionReference::Object(otd) => Ok(Self::Object(otd)),
218            TypeDefinitionReference::Union(utd) => Ok(Self::Union(utd)),
219            TypeDefinitionReference::InputObject(_) => Err(()),
220        }
221    }
222}