1#[cfg(not(feature = "boxed-trait"))]
2use std::future::Future;
3use std::{
4 borrow::Cow,
5 sync::{Arc, Weak},
6};
7
8use async_graphql_value::ConstValue;
9
10use crate::{
11 parser::types::Field,
12 registry::{self, Registry},
13 ContainerType, Context, ContextSelectionSet, Error, InputValueError, InputValueResult,
14 Positioned, Result, ServerResult, Value,
15};
16
17#[doc(hidden)]
18pub trait Description {
19 fn description() -> &'static str;
20}
21
22pub trait TypeName: Send + Sync {
24 fn type_name() -> Cow<'static, str>;
26}
27
28pub trait InputType: Send + Sync + Sized {
30 type RawValueType: ?Sized;
39
40 fn type_name() -> Cow<'static, str>;
42
43 fn qualified_type_name() -> String {
45 format!("{}!", Self::type_name())
46 }
47
48 fn create_type_info(registry: &mut registry::Registry) -> String;
50
51 fn parse(value: Option<Value>) -> InputValueResult<Self>;
53
54 fn to_value(&self) -> Value;
56
57 #[doc(hidden)]
59 fn federation_fields() -> Option<String> {
60 None
61 }
62
63 fn as_raw_value(&self) -> Option<&Self::RawValueType>;
65}
66
67#[cfg_attr(feature = "boxed-trait", async_trait::async_trait)]
69pub trait OutputType: Send + Sync {
70 fn type_name() -> Cow<'static, str>;
72
73 fn qualified_type_name() -> String {
75 format!("{}!", Self::type_name())
76 }
77
78 fn introspection_type_name(&self) -> Cow<'static, str> {
83 Self::type_name()
84 }
85
86 fn create_type_info(registry: &mut registry::Registry) -> String;
88
89 #[cfg(feature = "boxed-trait")]
91 async fn resolve(
92 &self,
93 ctx: &ContextSelectionSet<'_>,
94 field: &Positioned<Field>,
95 ) -> ServerResult<Value>;
96
97 #[cfg(not(feature = "boxed-trait"))]
99 fn resolve(
100 &self,
101 ctx: &ContextSelectionSet<'_>,
102 field: &Positioned<Field>,
103 ) -> impl Future<Output = ServerResult<Value>> + Send;
104}
105
106#[cfg_attr(feature = "boxed-trait", async_trait::async_trait)]
107impl<T: OutputType + ?Sized> OutputType for &T {
108 fn type_name() -> Cow<'static, str> {
109 T::type_name()
110 }
111
112 fn create_type_info(registry: &mut Registry) -> String {
113 T::create_type_info(registry)
114 }
115
116 #[allow(clippy::trivially_copy_pass_by_ref)]
117 async fn resolve(
118 &self,
119 ctx: &ContextSelectionSet<'_>,
120 field: &Positioned<Field>,
121 ) -> ServerResult<Value> {
122 T::resolve(*self, ctx, field).await
123 }
124}
125
126#[cfg_attr(feature = "boxed-trait", async_trait::async_trait)]
127impl<T: OutputType + Sync, E: Into<Error> + Send + Sync + Clone> OutputType for Result<T, E> {
128 fn type_name() -> Cow<'static, str> {
129 T::type_name()
130 }
131
132 fn create_type_info(registry: &mut Registry) -> String {
133 T::create_type_info(registry)
134 }
135
136 async fn resolve(
137 &self,
138 ctx: &ContextSelectionSet<'_>,
139 field: &Positioned<Field>,
140 ) -> ServerResult<Value> {
141 match self {
142 Ok(value) => value.resolve(ctx, field).await,
143 Err(err) => Err(ctx.set_error_path(err.clone().into().into_server_error(field.pos))),
144 }
145 }
146}
147
148pub trait ObjectType: ContainerType {}
150
151impl<T: ObjectType + ?Sized> ObjectType for &T {}
152
153impl<T: ObjectType + ?Sized> ObjectType for Box<T> {}
154
155impl<T: ObjectType + ?Sized> ObjectType for Arc<T> {}
156
157pub trait InterfaceType: ContainerType {}
159
160pub trait UnionType: ContainerType {}
162
163pub trait InputObjectType: InputType {}
165
166pub trait OneofObjectType: InputObjectType {}
168
169#[cfg_attr(feature = "boxed-trait", async_trait::async_trait)]
170impl<T: OutputType + ?Sized> OutputType for Box<T> {
171 fn type_name() -> Cow<'static, str> {
172 T::type_name()
173 }
174
175 fn create_type_info(registry: &mut Registry) -> String {
176 T::create_type_info(registry)
177 }
178
179 #[cfg(feature = "boxed-trait")]
180 async fn resolve(
181 &self,
182 ctx: &ContextSelectionSet<'_>,
183 field: &Positioned<Field>,
184 ) -> ServerResult<Value> {
185 T::resolve(self.as_ref(), ctx, field).await
186 }
187
188 #[allow(clippy::trivially_copy_pass_by_ref)]
189 #[cfg(not(feature = "boxed-trait"))]
190 fn resolve(
191 &self,
192 ctx: &ContextSelectionSet<'_>,
193 field: &Positioned<Field>,
194 ) -> impl Future<Output = ServerResult<Value>> + Send {
195 T::resolve(self.as_ref(), ctx, field)
196 }
197}
198
199impl<T: InputType> InputType for Box<T> {
200 type RawValueType = T::RawValueType;
201
202 fn type_name() -> Cow<'static, str> {
203 T::type_name()
204 }
205
206 fn create_type_info(registry: &mut Registry) -> String {
207 T::create_type_info(registry)
208 }
209
210 fn parse(value: Option<ConstValue>) -> InputValueResult<Self> {
211 T::parse(value)
212 .map(Box::new)
213 .map_err(InputValueError::propagate)
214 }
215
216 fn to_value(&self) -> ConstValue {
217 T::to_value(&self)
218 }
219
220 fn as_raw_value(&self) -> Option<&Self::RawValueType> {
221 self.as_ref().as_raw_value()
222 }
223}
224
225#[cfg_attr(feature = "boxed-trait", async_trait::async_trait)]
226impl<T: OutputType + ?Sized> OutputType for Arc<T> {
227 fn type_name() -> Cow<'static, str> {
228 T::type_name()
229 }
230
231 fn create_type_info(registry: &mut Registry) -> String {
232 T::create_type_info(registry)
233 }
234
235 #[allow(clippy::trivially_copy_pass_by_ref)]
236 async fn resolve(
237 &self,
238 ctx: &ContextSelectionSet<'_>,
239 field: &Positioned<Field>,
240 ) -> ServerResult<Value> {
241 T::resolve(&**self, ctx, field).await
242 }
243}
244
245impl<T: InputType> InputType for Arc<T> {
246 type RawValueType = T::RawValueType;
247
248 fn type_name() -> Cow<'static, str> {
249 T::type_name()
250 }
251
252 fn create_type_info(registry: &mut Registry) -> String {
253 T::create_type_info(registry)
254 }
255
256 fn parse(value: Option<ConstValue>) -> InputValueResult<Self> {
257 T::parse(value)
258 .map(Arc::new)
259 .map_err(InputValueError::propagate)
260 }
261
262 fn to_value(&self) -> ConstValue {
263 T::to_value(&self)
264 }
265
266 fn as_raw_value(&self) -> Option<&Self::RawValueType> {
267 self.as_ref().as_raw_value()
268 }
269}
270
271#[cfg_attr(feature = "boxed-trait", async_trait::async_trait)]
272impl<T: OutputType + ?Sized> OutputType for Weak<T> {
273 fn type_name() -> Cow<'static, str> {
274 <Option<Arc<T>> as OutputType>::type_name()
275 }
276
277 fn create_type_info(registry: &mut Registry) -> String {
278 <Option<Arc<T>> as OutputType>::create_type_info(registry)
279 }
280
281 async fn resolve(
282 &self,
283 ctx: &ContextSelectionSet<'_>,
284 field: &Positioned<Field>,
285 ) -> ServerResult<Value> {
286 self.upgrade().resolve(ctx, field).await
287 }
288}
289
290#[doc(hidden)]
291#[cfg_attr(feature = "boxed-trait", async_trait::async_trait)]
292pub trait ComplexObject {
293 fn fields(registry: &mut registry::Registry) -> Vec<(String, registry::MetaField)>;
294
295 #[cfg(feature = "boxed-trait")]
296 async fn resolve_field(&self, ctx: &Context<'_>) -> ServerResult<Option<Value>>;
297
298 #[cfg(not(feature = "boxed-trait"))]
299 fn resolve_field(
300 &self,
301 ctx: &Context<'_>,
302 ) -> impl Future<Output = ServerResult<Option<Value>>> + Send;
303}