Skip to main content

reed_compiler/ast/
serialize.rs

1use super::*;
2use crate::executable;
3use crate::schema;
4use std::fmt;
5use std::fmt::Display;
6
7/// Builder pattern for GraphQL serialization configuration.
8/// Implements [`Display`] and [`ToString`].
9#[derive(Debug, Clone)]
10pub struct Serialize<'a, T> {
11    pub(crate) node: &'a T,
12    pub(crate) config: Config<'a>,
13}
14
15#[derive(Debug, Clone)]
16pub(crate) struct Config<'a> {
17    indent_prefix: Option<&'a str>,
18    initial_indent_level: usize,
19}
20
21pub(crate) struct State<'config, 'fmt, 'fmt2> {
22    config: Config<'config>,
23    indent_level: usize,
24    output: &'fmt mut fmt::Formatter<'fmt2>,
25    /// Have we not written anything yet?
26    output_empty: bool,
27}
28
29impl<'a, T> Serialize<'a, T> {
30    /// Enable indentation and line breaks.
31    ///
32    /// `prefix` is repeated at the start of each line by the number of indentation levels.
33    /// The default is `"  "`, two spaces.
34    pub fn indent_prefix(mut self, prefix: &'a str) -> Self {
35        self.config.indent_prefix = Some(prefix);
36        self
37    }
38
39    /// Disable indentation and line breaks
40    pub fn no_indent(mut self) -> Self {
41        self.config.indent_prefix = None;
42        self
43    }
44
45    pub fn initial_indent_level(mut self, initial_indent_level: usize) -> Self {
46        self.config.initial_indent_level = initial_indent_level;
47        self
48    }
49}
50
51impl Default for Config<'_> {
52    fn default() -> Self {
53        Self {
54            indent_prefix: Some("  "),
55            initial_indent_level: 0,
56        }
57    }
58}
59
60macro_rules! display {
61    ($state: expr, $e: expr) => {
62        fmt::Display::fmt(&$e, $state.output)
63    };
64    ($state: expr, $($tt: tt)+) => {
65        display!($state, format_args!($($tt)+))
66    };
67
68}
69
70impl State<'_, '_, '_> {
71    pub(crate) fn write(&mut self, str: &str) -> fmt::Result {
72        self.output_empty = false;
73        self.output.write_str(str)
74    }
75
76    pub(crate) fn indent(&mut self) -> fmt::Result {
77        self.indent_level += 1;
78        self.new_line_common(false)
79    }
80
81    pub(crate) fn indent_or_space(&mut self) -> fmt::Result {
82        self.indent_level += 1;
83        self.new_line_common(true)
84    }
85
86    pub(crate) fn dedent(&mut self) -> fmt::Result {
87        self.indent_level -= 1; // checked underflow in debug mode
88        self.new_line_common(false)
89    }
90
91    pub(crate) fn dedent_or_space(&mut self) -> fmt::Result {
92        self.indent_level -= 1; // checked underflow in debug mode
93        self.new_line_common(true)
94    }
95
96    pub(crate) fn new_line_or_space(&mut self) -> fmt::Result {
97        self.new_line_common(true)
98    }
99
100    fn new_line_common(&mut self, space: bool) -> fmt::Result {
101        if let Some(prefix) = self.config.indent_prefix {
102            self.write("\n")?;
103            for _ in 0..self.indent_level {
104                self.write(prefix)?;
105            }
106        } else if space {
107            self.write(" ")?
108        }
109        Ok(())
110    }
111
112    /// Panics if newlines are disabled
113    fn require_new_line(&mut self) -> fmt::Result {
114        let prefix = self
115            .config
116            .indent_prefix
117            .expect("require_new_line called with newlines disabled");
118        self.write("\n")?;
119        for _ in 0..self.indent_level {
120            self.write(prefix)?;
121        }
122        Ok(())
123    }
124
125    pub(crate) fn newlines_enabled(&self) -> bool {
126        self.config.indent_prefix.is_some()
127    }
128
129    pub(crate) fn on_single_line<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
130        let indent_prefix = self.config.indent_prefix.take();
131        let result = f(self);
132        self.config.indent_prefix = indent_prefix;
133        result
134    }
135}
136
137impl Document {
138    pub(crate) fn serialize_impl(&self, state: &mut State) -> fmt::Result {
139        top_level(state, &self.definitions, |state, def| {
140            def.serialize_impl(state)
141        })
142    }
143}
144
145pub(crate) fn top_level<T>(
146    state: &mut State,
147    iter: impl IntoIterator<Item = T>,
148    serialize_one: impl Fn(&mut State, T) -> fmt::Result,
149) -> fmt::Result {
150    let mut iter = iter.into_iter();
151    if let Some(first) = iter.next() {
152        serialize_one(state, first)?;
153        iter.try_for_each(|item| {
154            if state.newlines_enabled() {
155                // Empty line between top-level definitions
156                state.write("\n")?;
157            }
158            state.new_line_or_space()?;
159            serialize_one(state, item)
160        })?;
161        // Trailing newline
162        if state.newlines_enabled() {
163            state.write("\n")?;
164        }
165    }
166    Ok(())
167}
168
169impl Definition {
170    pub(crate) fn serialize_impl(&self, state: &mut State) -> fmt::Result {
171        match self {
172            Definition::OperationDefinition(def) => def.serialize_impl(state),
173            Definition::FragmentDefinition(def) => def.serialize_impl(state),
174            Definition::DirectiveDefinition(def) => def.serialize_impl(state),
175            Definition::SchemaDefinition(def) => def.serialize_impl(state),
176            Definition::ScalarTypeDefinition(def) => def.serialize_impl(state),
177            Definition::ObjectTypeDefinition(def) => def.serialize_impl(state),
178            Definition::InterfaceTypeDefinition(def) => def.serialize_impl(state),
179            Definition::UnionTypeDefinition(def) => def.serialize_impl(state),
180            Definition::EnumTypeDefinition(def) => def.serialize_impl(state),
181            Definition::InputObjectTypeDefinition(def) => def.serialize_impl(state),
182            Definition::SchemaExtension(def) => def.serialize_impl(state),
183            Definition::DirectiveExtension(def) => def.serialize_impl(state),
184            Definition::ScalarTypeExtension(def) => def.serialize_impl(state),
185            Definition::ObjectTypeExtension(def) => def.serialize_impl(state),
186            Definition::InterfaceTypeExtension(def) => def.serialize_impl(state),
187            Definition::UnionTypeExtension(def) => def.serialize_impl(state),
188            Definition::EnumTypeExtension(def) => def.serialize_impl(state),
189            Definition::InputObjectTypeExtension(def) => def.serialize_impl(state),
190        }
191    }
192}
193
194impl OperationDefinition {
195    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
196        // Deconstruct to get a warning if we forget to serialize something
197        let Self {
198            operation_type,
199            name,
200            variables,
201            directives,
202            selection_set,
203        } = self;
204        // Only use shorthand when this is the first item.
205        // If not, it might be following a `[lookahead != "{"]` grammar production
206        let shorthand = state.output_empty
207            && *operation_type == OperationType::Query
208            && name.is_none()
209            && variables.is_empty()
210            && directives.is_empty();
211        if !shorthand {
212            state.write(operation_type.name())?;
213            if let Some(name) = &name {
214                state.write(" ")?;
215                state.write(name)?;
216            }
217            if !variables.is_empty() {
218                state.on_single_line(|state| {
219                    comma_separated(state, "(", ")", variables, |state, var| {
220                        var.serialize_impl(state)
221                    })
222                })?
223            }
224            directives.serialize_impl(state)?;
225            state.write(" ")?;
226        }
227        curly_brackets_space_separated(state, selection_set, |state, sel| sel.serialize_impl(state))
228    }
229}
230
231impl FragmentDefinition {
232    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
233        let Self {
234            name,
235            type_condition,
236            directives,
237            selection_set,
238        } = self;
239        display!(state, "fragment {} on {}", name, type_condition)?;
240        directives.serialize_impl(state)?;
241        state.write(" ")?;
242        curly_brackets_space_separated(state, selection_set, |state, sel| sel.serialize_impl(state))
243    }
244}
245
246impl DirectiveDefinition {
247    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
248        let Self {
249            description,
250            name,
251            arguments,
252            repeatable,
253            locations,
254            directives,
255        } = self;
256        serialize_description(state, description)?;
257        state.write("directive @")?;
258        state.write(name)?;
259        serialize_arguments_definition(state, arguments)?;
260        directives.serialize_impl(state)?;
261
262        if *repeatable {
263            state.write(" repeatable")?;
264        }
265        if let Some((first, rest)) = locations.split_first() {
266            state.write(" on ")?;
267            state.write(first.name())?;
268            for location in rest {
269                state.write(" | ")?;
270                state.write(location.name())?;
271            }
272        }
273        Ok(())
274    }
275}
276
277fn serialize_arguments_definition(
278    state: &mut State,
279    arguments: &[Node<InputValueDefinition>],
280) -> fmt::Result {
281    if !arguments.is_empty() {
282        let serialize_arguments = |state: &mut State| {
283            comma_separated(state, "(", ")", arguments, |state, arg| {
284                arg.serialize_impl(state)
285            })
286        };
287        if arguments
288            .iter()
289            .any(|arg| arg.description.is_some() || !arg.directives.is_empty())
290        {
291            serialize_arguments(state)?
292        } else {
293            state.on_single_line(serialize_arguments)?
294        }
295    }
296    Ok(())
297}
298
299impl SchemaDefinition {
300    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
301        let Self {
302            description,
303            directives,
304            root_operations,
305        } = self;
306        serialize_description(state, description)?;
307        state.write("schema")?;
308        directives.serialize_impl(state)?;
309        state.write(" ")?;
310        curly_brackets_space_separated(state, root_operations, |state, op| {
311            let (operation_type, operation_name) = &**op;
312            display!(state, "{}: {}", operation_type, operation_name)
313        })
314    }
315}
316
317impl ScalarTypeDefinition {
318    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
319        let Self {
320            description,
321            name,
322            directives,
323        } = self;
324        serialize_description(state, description)?;
325        state.write("scalar ")?;
326        state.write(name)?;
327        directives.serialize_impl(state)
328    }
329}
330
331impl ObjectTypeDefinition {
332    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
333        let Self {
334            description,
335            name,
336            implements_interfaces,
337            directives,
338            fields,
339        } = self;
340        serialize_description(state, description)?;
341        state.write("type ")?;
342        serialize_object_type_like(state, name, implements_interfaces, directives, fields)
343    }
344}
345
346fn serialize_object_type_like(
347    state: &mut State,
348    name: &str,
349    implements_interfaces: &[Name],
350    directives: &DirectiveList,
351    fields: &[Node<FieldDefinition>],
352) -> Result<(), fmt::Error> {
353    state.write(name)?;
354    if let Some((first, rest)) = implements_interfaces.split_first() {
355        state.write(" implements ")?;
356        state.write(first)?;
357        for name in rest {
358            state.write(" & ")?;
359            state.write(name)?;
360        }
361    }
362    directives.serialize_impl(state)?;
363
364    if !fields.is_empty() {
365        state.write(" ")?;
366        curly_brackets_space_separated(state, fields, |state, field| field.serialize_impl(state))?;
367    }
368    Ok(())
369}
370
371impl InterfaceTypeDefinition {
372    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
373        let Self {
374            description,
375            name,
376            implements_interfaces,
377            directives,
378            fields,
379        } = self;
380        serialize_description(state, description)?;
381        state.write("interface ")?;
382        serialize_object_type_like(state, name, implements_interfaces, directives, fields)
383    }
384}
385
386impl UnionTypeDefinition {
387    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
388        let Self {
389            description,
390            name,
391            directives,
392            members,
393        } = self;
394        serialize_description(state, description)?;
395        state.write("union ")?;
396        serialize_union(state, name, directives, members)
397    }
398}
399
400fn serialize_union(
401    state: &mut State,
402    name: &str,
403    directives: &DirectiveList,
404    members: &[Name],
405) -> fmt::Result {
406    state.write(name)?;
407    directives.serialize_impl(state)?;
408    if let Some((first, rest)) = members.split_first() {
409        state.write(" = ")?;
410        state.write(first)?;
411        for member in rest {
412            state.write(" | ")?;
413            state.write(member)?;
414        }
415    }
416    Ok(())
417}
418
419impl EnumTypeDefinition {
420    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
421        let Self {
422            description,
423            name,
424            directives,
425            values,
426        } = self;
427        serialize_description(state, description)?;
428        state.write("enum ")?;
429        state.write(name)?;
430        directives.serialize_impl(state)?;
431        if !values.is_empty() {
432            state.write(" ")?;
433            curly_brackets_space_separated(state, values, |state, value| {
434                value.serialize_impl(state)
435            })?;
436        }
437        Ok(())
438    }
439}
440
441impl InputObjectTypeDefinition {
442    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
443        let Self {
444            description,
445            name,
446            directives,
447            fields,
448        } = self;
449        serialize_description(state, description)?;
450        state.write("input ")?;
451        state.write(name)?;
452        directives.serialize_impl(state)?;
453        if !fields.is_empty() {
454            state.write(" ")?;
455            curly_brackets_space_separated(state, fields, |state, f| f.serialize_impl(state))?;
456        }
457        Ok(())
458    }
459}
460
461impl SchemaExtension {
462    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
463        let Self {
464            directives,
465            root_operations,
466        } = self;
467        state.write("extend schema")?;
468        directives.serialize_impl(state)?;
469        if !root_operations.is_empty() {
470            state.write(" ")?;
471            curly_brackets_space_separated(state, root_operations, |state, op| {
472                let (operation_type, operation_name) = &**op;
473                display!(state, "{}: {}", operation_type, operation_name)
474            })?;
475        }
476        Ok(())
477    }
478}
479
480impl DirectiveExtension {
481    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
482        let Self { name, directives } = self;
483        state.write("extend directive @")?;
484        state.write(name)?;
485        directives.serialize_impl(state)
486    }
487}
488
489impl ScalarTypeExtension {
490    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
491        let Self { name, directives } = self;
492        state.write("extend scalar ")?;
493        state.write(name)?;
494        directives.serialize_impl(state)
495    }
496}
497
498impl ObjectTypeExtension {
499    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
500        let Self {
501            name,
502            implements_interfaces,
503            directives,
504            fields,
505        } = self;
506        state.write("extend type ")?;
507        serialize_object_type_like(state, name, implements_interfaces, directives, fields)
508    }
509}
510
511impl InterfaceTypeExtension {
512    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
513        let Self {
514            name,
515            implements_interfaces,
516            directives,
517            fields,
518        } = self;
519        state.write("extend interface ")?;
520        serialize_object_type_like(state, name, implements_interfaces, directives, fields)
521    }
522}
523
524impl UnionTypeExtension {
525    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
526        let Self {
527            name,
528            directives,
529            members,
530        } = self;
531        state.write("extend union ")?;
532        serialize_union(state, name, directives, members)
533    }
534}
535
536impl EnumTypeExtension {
537    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
538        let Self {
539            name,
540            directives,
541            values,
542        } = self;
543        state.write("extend enum ")?;
544        state.write(name)?;
545        directives.serialize_impl(state)?;
546        if !values.is_empty() {
547            state.write(" ")?;
548            curly_brackets_space_separated(state, values, |state, value| {
549                value.serialize_impl(state)
550            })?;
551        }
552        Ok(())
553    }
554}
555
556impl InputObjectTypeExtension {
557    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
558        let Self {
559            name,
560            directives,
561            fields,
562        } = self;
563        state.write("extend input ")?;
564        state.write(name)?;
565        directives.serialize_impl(state)?;
566        if !fields.is_empty() {
567            state.write(" ")?;
568            curly_brackets_space_separated(state, fields, |state, f| f.serialize_impl(state))?;
569        }
570        Ok(())
571    }
572}
573
574impl DirectiveList {
575    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
576        for dir in self {
577            state.write(" ")?;
578            dir.serialize_impl(state)?;
579        }
580        Ok(())
581    }
582}
583
584impl Directive {
585    pub(crate) fn serialize_impl(&self, state: &mut State) -> fmt::Result {
586        let Self { name, arguments } = self;
587        state.write("@")?;
588        state.write(name)?;
589        serialize_arguments(state, arguments)
590    }
591}
592
593impl VariableDefinition {
594    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
595        let Self {
596            name,
597            ty,
598            default_value,
599            directives,
600        } = self;
601        state.write("$")?;
602        state.write(name)?;
603        state.write(": ")?;
604        display!(state, ty)?;
605        if let Some(value) = default_value {
606            state.write(" = ")?;
607            value.serialize_impl(state)?
608        }
609        directives.serialize_impl(state)
610    }
611}
612
613impl FieldDefinition {
614    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
615        let Self {
616            description,
617            name,
618            arguments,
619            ty,
620            directives,
621        } = self;
622        serialize_description(state, description)?;
623        state.write(name)?;
624        serialize_arguments_definition(state, arguments)?;
625        state.write(": ")?;
626        display!(state, ty)?;
627        directives.serialize_impl(state)
628    }
629}
630
631impl InputValueDefinition {
632    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
633        let Self {
634            description,
635            name,
636            ty,
637            default_value,
638            directives,
639        } = self;
640        serialize_description(state, description)?;
641        state.write(name)?;
642        state.write(": ")?;
643        display!(state, ty)?;
644        if let Some(value) = default_value {
645            state.write(" = ")?;
646            value.serialize_impl(state)?
647        }
648        directives.serialize_impl(state)
649    }
650}
651
652impl EnumValueDefinition {
653    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
654        let Self {
655            description,
656            value,
657            directives,
658        } = self;
659        serialize_description(state, description)?;
660        state.write(value)?;
661        directives.serialize_impl(state)
662    }
663}
664
665impl Selection {
666    pub(crate) fn serialize_impl(&self, state: &mut State) -> fmt::Result {
667        match self {
668            Selection::Field(x) => x.serialize_impl(state),
669            Selection::FragmentSpread(x) => x.serialize_impl(state),
670            Selection::InlineFragment(x) => x.serialize_impl(state),
671        }
672    }
673}
674
675impl Field {
676    pub(crate) fn serialize_impl(&self, state: &mut State) -> fmt::Result {
677        let Self {
678            alias,
679            name,
680            arguments,
681            directives,
682            selection_set_is_explicit,
683            selection_set,
684        } = self;
685        if let Some(alias) = alias {
686            state.write(alias)?;
687            state.write(": ")?;
688        }
689        state.write(name)?;
690        serialize_arguments(state, arguments)?;
691        directives.serialize_impl(state)?;
692        if *selection_set_is_explicit {
693            state.write(" ")?;
694            curly_brackets_space_separated(state, selection_set, |state, sel| {
695                sel.serialize_impl(state)
696            })?
697        }
698        Ok(())
699    }
700}
701
702impl FragmentSpread {
703    pub(crate) fn serialize_impl(&self, state: &mut State) -> fmt::Result {
704        let Self {
705            fragment_name,
706            directives,
707        } = self;
708        state.write("...")?;
709        state.write(fragment_name)?;
710        directives.serialize_impl(state)
711    }
712}
713
714impl InlineFragment {
715    pub(crate) fn serialize_impl(&self, state: &mut State) -> fmt::Result {
716        let Self {
717            type_condition,
718            directives,
719            selection_set,
720        } = self;
721        if let Some(type_name) = type_condition {
722            state.write("... on ")?;
723            state.write(type_name)?;
724        } else {
725            state.write("...")?;
726        }
727        directives.serialize_impl(state)?;
728        state.write(" ")?;
729        curly_brackets_space_separated(state, selection_set, |state, sel| sel.serialize_impl(state))
730    }
731}
732
733impl Value {
734    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
735        match self {
736            Value::Null => state.write("null"),
737            Value::Boolean(true) => state.write("true"),
738            Value::Boolean(false) => state.write("false"),
739            Value::Enum(name) => state.write(name),
740            Value::String(value) => {
741                let is_description = false;
742                serialize_string_value(state, is_description, value)
743            }
744            Value::Variable(name) => display!(state, "${}", name),
745            Value::Float(value) => display!(state, value),
746            Value::Int(value) => display!(state, value),
747            Value::List(value) => comma_separated(state, "[", "]", value, |state, value| {
748                value.serialize_impl(state)
749            }),
750            Value::Object(value) => {
751                comma_separated(state, "{", "}", value, |state, (name, value)| {
752                    state.write(name)?;
753                    state.write(": ")?;
754                    value.serialize_impl(state)
755                })
756            }
757        }
758    }
759}
760
761impl Argument {
762    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
763        state.write(&self.name)?;
764        state.write(": ")?;
765        self.value.serialize_impl(state)
766    }
767}
768
769fn serialize_arguments(state: &mut State, arguments: &[Node<Argument>]) -> fmt::Result {
770    if !arguments.is_empty() {
771        state.on_single_line(|state| {
772            comma_separated(state, "(", ")", arguments, |state, argument| {
773                argument.serialize_impl(state)
774            })
775        })?
776    }
777    Ok(())
778}
779
780/// Example output: `[a, b, c]` or
781///
782/// ```text
783/// [
784///     a,
785///     b,
786///     c,
787/// ]
788/// ```
789fn comma_separated<T>(
790    state: &mut State,
791    open: &str,
792    close: &str,
793    values: &[T],
794    serialize_one: impl Fn(&mut State, &T) -> fmt::Result,
795) -> fmt::Result {
796    state.write(open)?;
797    if let Some((first, rest)) = values.split_first() {
798        state.indent()?;
799        serialize_one(state, first)?;
800        for value in rest {
801            state.write(",")?;
802            state.new_line_or_space()?;
803            serialize_one(state, value)?;
804        }
805        // Trailing comma
806        if state.newlines_enabled() {
807            state.write(",")?;
808        }
809        state.dedent()?;
810    }
811    state.write(close)
812}
813
814/// Example output: `{ a b c }` or
815///
816/// ```text
817/// {
818///     a
819///     b
820///     c
821/// }
822/// ```
823pub(crate) fn curly_brackets_space_separated<T>(
824    state: &mut State,
825    values: &[T],
826    serialize_one: impl Fn(&mut State, &T) -> fmt::Result,
827) -> fmt::Result {
828    state.write("{")?;
829    if let Some((first, rest)) = values.split_first() {
830        state.indent_or_space()?;
831        serialize_one(state, first)?;
832        for value in rest {
833            state.new_line_or_space()?;
834            serialize_one(state, value)?;
835        }
836        state.dedent_or_space()?;
837    }
838    state.write("}")
839}
840
841fn serialize_string_value(state: &mut State, is_description: bool, mut str: &str) -> fmt::Result {
842    let contains_newline = str.contains('\n');
843    let prefer_block_string = is_description || contains_newline;
844    if state.newlines_enabled() && prefer_block_string && can_be_block_string(str) {
845        return serialize_block_string(state, contains_newline, str);
846    }
847    state.write("\"")?;
848    loop {
849        if let Some(i) = str.find(|c| (c < ' ' && c != '\t') || c == '"' || c == '\\') {
850            let (without_escaping, rest) = str.split_at(i);
851            state.write(without_escaping)?;
852            // All characters that need escaping are in the ASCII range,
853            // and so take a single byte in UTF-8.
854            match rest.as_bytes()[0] {
855                b'\x08' => state.write("\\b")?,
856                b'\n' => state.write("\\n")?,
857                b'\x0C' => state.write("\\f")?,
858                b'\r' => state.write("\\r")?,
859                b'"' => state.write("\\\"")?,
860                b'\\' => state.write("\\\\")?,
861                byte => display!(state, "\\u{:04X}", byte)?,
862            }
863            str = &rest[1..]
864        } else {
865            state.write(str)?;
866            break;
867        }
868    }
869    state.write("\"")
870}
871
872fn serialize_block_string(state: &mut State, contains_newline: bool, str: &str) -> fmt::Result {
873    const TRIPLE_QUOTE: &str = "\"\"\"";
874    const ESCAPED_TRIPLE_QUOTE: &str = "\\\"\"\"";
875    const _: () = assert!(TRIPLE_QUOTE.len() == 3);
876    const _: () = assert!(ESCAPED_TRIPLE_QUOTE.len() == 4);
877
878    fn serialize_line(state: &mut State, mut line: &str) -> Result<(), fmt::Error> {
879        while let Some((before, after)) = line.split_once(TRIPLE_QUOTE) {
880            state.write(before)?;
881            state.write(ESCAPED_TRIPLE_QUOTE)?;
882            line = after;
883        }
884        state.write(line)
885    }
886
887    let multi_line =
888        contains_newline || str.len() > 70 || str.ends_with('"') || str.ends_with('\\');
889
890    state.write(TRIPLE_QUOTE)?;
891    if !multi_line {
892        // """example""""
893        serialize_line(state, str)?
894    } else {
895        // """
896        // example
897        // """
898
899        // `can_be_block_string` excludes \r, so the only remaining line terminator is \n
900        for line in str.split('\n') {
901            if line.is_empty() {
902                // Skip indentation which would be trailing whitespace
903                state.write("\n")?;
904            } else {
905                state.require_new_line()?;
906                serialize_line(state, line)?;
907            }
908        }
909        state.require_new_line()?;
910    }
911    state.write(TRIPLE_QUOTE)
912}
913
914/// Is it possible to create a serialization that, when fed through
915/// [BlockStringValue](https://spec.graphql.org/October2021/#BlockStringValue()),
916/// returns exactly `value`?
917fn can_be_block_string(value: &str) -> bool {
918    // `BlockStringValue` splits its inputs at any `LineTerminator` (\n, \r\n, or \r)
919    // and eventually joins lines but always with \n. So its output can never contain \r
920    if value.contains('\r') {
921        return false;
922    }
923
924    /// <https://spec.graphql.org/October2021/#WhiteSpace>
925    fn trim_start_graphql_whitespace(value: &str) -> &str {
926        value.trim_start_matches([' ', '\t'])
927    }
928
929    // With the above, \n is the only remaining LineTerminator
930    let mut lines = value.split('\n');
931    if lines
932        .next()
933        .is_some_and(|first| trim_start_graphql_whitespace(first).is_empty())
934        || lines
935            .next_back()
936            .is_some_and(|last| trim_start_graphql_whitespace(last).is_empty())
937    {
938        // Leading or trailing whitespace-only line would be trimmed by `BlockStringValue`
939        return false;
940    }
941
942    let common_indent = {
943        let lines = value.split('\n');
944        let each_line_indent_utf8_len = lines.filter_map(|line| {
945            let after_indent = trim_start_graphql_whitespace(line);
946            if !after_indent.is_empty() {
947                Some(line.len() - after_indent.len())
948            } else {
949                None // skip whitespace-only lines
950            }
951        });
952        each_line_indent_utf8_len.min().unwrap_or(0)
953    };
954    // If there is common indent `BlockStringValue` would remove it
955    // and incorrectly round-trip to a different value.
956    common_indent == 0
957}
958
959fn serialize_description(state: &mut State, description: &Option<Node<str>>) -> fmt::Result {
960    if let Some(description) = description {
961        let is_description = true;
962        serialize_string_value(state, is_description, description)?;
963        state.new_line_or_space()?;
964    }
965    Ok(())
966}
967
968impl fmt::Display for Type {
969    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
970        match self {
971            Type::Named(name) => std::write!(f, "{name}"),
972            Type::NonNullNamed(name) => std::write!(f, "{name}!"),
973            Type::List(inner) => std::write!(f, "[{inner}]"),
974            Type::NonNullList(inner) => std::write!(f, "[{inner}]!"),
975        }
976    }
977}
978
979impl fmt::Display for OperationType {
980    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
981        self.name().fmt(f)
982    }
983}
984
985impl fmt::Display for DirectiveLocation {
986    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
987        self.name().fmt(f)
988    }
989}
990
991macro_rules! impl_display {
992    ($($ty: path)+) => {
993        $(
994            /// Serialize to GraphQL syntax with the default configuration
995            impl Display for $ty {
996                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
997                    self.serialize().fmt(f)
998                }
999            }
1000
1001            /// Serialize to GraphQL syntax
1002            impl Display for Serialize<'_, $ty> {
1003                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1004                    let mut state = State {
1005                        config: self.config.clone(),
1006                        indent_level: self.config.initial_indent_level,
1007                        output: f,
1008                        output_empty: true,
1009                    };
1010                    // Indent the first line.
1011                    // Subsequent lines will be indented when writing a line break.
1012                    if let Some(prefix) = state.config.indent_prefix {
1013                        for _ in 0..state.indent_level {
1014                            state.write(prefix)?;
1015                        }
1016                    }
1017                    self.node.serialize_impl(&mut state)
1018                }
1019            }
1020        )+
1021    }
1022}
1023
1024impl_display! {
1025    Document
1026    Definition
1027    OperationDefinition
1028    FragmentDefinition
1029    DirectiveDefinition
1030    SchemaDefinition
1031    ScalarTypeDefinition
1032    ObjectTypeDefinition
1033    InterfaceTypeDefinition
1034    UnionTypeDefinition
1035    EnumTypeDefinition
1036    InputObjectTypeDefinition
1037    SchemaExtension
1038    DirectiveExtension
1039    ScalarTypeExtension
1040    ObjectTypeExtension
1041    InterfaceTypeExtension
1042    UnionTypeExtension
1043    EnumTypeExtension
1044    InputObjectTypeExtension
1045    DirectiveList
1046    Directive
1047    VariableDefinition
1048    FieldDefinition
1049    InputValueDefinition
1050    EnumValueDefinition
1051    Selection
1052    Field
1053    FragmentSpread
1054    InlineFragment
1055    Value
1056    crate::Schema
1057    crate::ExecutableDocument
1058    schema::DirectiveList
1059    schema::ExtendedType
1060    schema::ScalarType
1061    schema::ObjectType
1062    schema::InterfaceType
1063    schema::EnumType
1064    schema::UnionType
1065    schema::InputObjectType
1066    executable::Operation
1067    executable::Fragment
1068    executable::SelectionSet
1069    executable::Selection
1070    executable::Field
1071    executable::InlineFragment
1072    executable::FragmentSpread
1073    executable::FieldSet
1074}