cynic_codegen/use_schema/
mod.rs

1mod argument;
2mod directive;
3mod fields;
4mod input_object;
5mod interface;
6mod named_type;
7mod object;
8mod params;
9mod schema_roots;
10mod subtype_markers;
11
12pub use params::UseSchemaParams;
13
14use {
15    proc_macro2::TokenStream,
16    quote::{quote, ToTokens},
17};
18
19use crate::{
20    error::Errors,
21    schema::{
22        types::{DirectiveLocation, Type},
23        Schema, SchemaInput, Validated,
24    },
25};
26
27use self::{
28    directive::FieldDirectiveOutput, input_object::InputObjectOutput, interface::InterfaceOutput,
29    named_type::NamedType, object::ObjectOutput, subtype_markers::SubtypeMarkers,
30};
31
32pub fn use_schema(input: UseSchemaParams) -> Result<TokenStream, Errors> {
33    let input = SchemaInput::from_schema_path(input.schema_filename)
34        .map_err(|e| e.into_syn_error(proc_macro2::Span::call_site()))?;
35
36    let schema = Schema::new(input).validate()?;
37    use_schema_impl(&schema)
38}
39
40pub(crate) fn use_schema_impl(schema: &Schema<'_, Validated>) -> Result<TokenStream, Errors> {
41    use quote::TokenStreamExt;
42
43    let mut output = TokenStream::new();
44    let mut field_module = TokenStream::new();
45
46    let root_types = schema.root_types()?;
47    output.append_all(quote! {
48        #root_types
49    });
50
51    let mut subtype_markers = Vec::new();
52    let mut named_types = Vec::new();
53
54    for definition in schema.iter() {
55        named_types.extend(NamedType::from_def(&definition));
56
57        match definition {
58            Type::Scalar(def) if !def.builtin => {
59                let name = proc_macro2::Literal::string(def.name.as_ref());
60                let ident = def.marker_ident().to_rust_ident();
61                output.append_all(quote! {
62                    pub struct #ident {}
63                    impl cynic::schema::NamedType for #ident {
64                        const NAME: &'static ::core::primitive::str = #name;
65                    }
66                });
67            }
68            Type::Scalar(_) => {}
69            Type::Object(def) => {
70                subtype_markers.extend(SubtypeMarkers::from_object(&def));
71
72                let object = ObjectOutput::new(def);
73                object.to_tokens(&mut output);
74                object.append_fields(&mut field_module);
75            }
76            Type::Interface(def) => {
77                subtype_markers.push(SubtypeMarkers::from_interface(&def));
78
79                let iface = InterfaceOutput::new(def);
80                iface.to_tokens(&mut output);
81                iface.append_fields(&mut field_module);
82            }
83            Type::Union(def) => {
84                subtype_markers.extend(SubtypeMarkers::from_union(&def));
85
86                let ident = def.marker_ident().to_rust_ident();
87                output.append_all(quote! {
88                    pub struct #ident {}
89                });
90            }
91            Type::Enum(def) => {
92                let ident = def.marker_ident().to_rust_ident();
93                output.append_all(quote! {
94                    pub struct #ident {}
95                });
96            }
97            Type::InputObject(def) => {
98                let object = InputObjectOutput::new(def);
99                object.to_tokens(&mut output);
100                object.append_fields(&mut field_module);
101            }
102        }
103    }
104
105    for directive in schema.directives() {
106        if !directive.locations.contains(&DirectiveLocation::Field) {
107            // We only support field directives for now
108            continue;
109        }
110        FieldDirectiveOutput {
111            directive: &directive,
112        }
113        .to_tokens(&mut output);
114    }
115
116    output.append_all(quote! {
117        #(#subtype_markers)*
118        #(#named_types)*
119
120        #[allow(non_snake_case, non_camel_case_types)]
121        pub mod __fields {
122            #field_module
123        }
124
125        pub type Boolean = bool;
126        pub type String = std::string::String;
127        pub type Float = f64;
128        pub type Int = i32;
129        pub type ID = cynic::Id;
130
131        pub mod variable {
132            use cynic::variables::VariableType;
133
134            /// Used to determine the type of a given variable that
135            /// appears in an argument struct.
136            pub trait Variable {
137                const TYPE: VariableType;
138            }
139
140            impl<T> Variable for &T
141            where
142                T: ?::core::marker::Sized + Variable,
143            {
144                const TYPE: VariableType = T::TYPE;
145            }
146
147            impl<T> Variable for Option<T>
148            where
149                T: Variable
150            {
151                const TYPE: VariableType = VariableType::Nullable(&T::TYPE);
152            }
153
154            impl<T> Variable for [T]
155            where
156                T: Variable,
157            {
158                const TYPE: VariableType = VariableType::List(&T::TYPE);
159            }
160
161            impl<T> Variable for Vec<T>
162            where
163                T: Variable,
164            {
165                const TYPE: VariableType = VariableType::List(&T::TYPE);
166            }
167
168            impl<T> Variable for Box<T>
169            where
170                T: Variable,
171            {
172                const TYPE: VariableType = T::TYPE;
173            }
174
175            impl<T> Variable for std::rc::Rc<T>
176            where
177                T: Variable,
178            {
179                const TYPE: VariableType = T::TYPE;
180            }
181
182            impl<T> Variable for std::sync::Arc<T>
183            where
184                T: Variable,
185            {
186                const TYPE: VariableType = T::TYPE;
187            }
188
189            impl<T> Variable for std::borrow::Cow<'_, T>
190            where
191                T: ?::core::marker::Sized + Variable + ToOwned,
192            {
193                const TYPE: VariableType = T::TYPE;
194            }
195
196            impl Variable for bool {
197                const TYPE: VariableType = VariableType::Named("Boolean");
198            }
199
200            impl Variable for str {
201                const TYPE: VariableType = VariableType::Named("String");
202            }
203
204            impl Variable for String {
205                const TYPE: VariableType = <str as Variable>::TYPE;
206            }
207
208            impl Variable for f64 {
209                const TYPE: VariableType = VariableType::Named("Float");
210            }
211
212            impl Variable for i32 {
213                const TYPE: VariableType = VariableType::Named("Int");
214            }
215
216            impl Variable for cynic::Id {
217                const TYPE: VariableType = VariableType::Named("ID");
218            }
219        }
220    });
221
222    Ok(output)
223}