hcl/format/
impls.rs

1use super::{private, Format, Formatter};
2use crate::expr::{
3    BinaryOp, Conditional, Expression, ForExpr, FuncCall, FuncName, Heredoc, HeredocStripMode,
4    ObjectKey, Operation, TemplateExpr, Traversal, TraversalOperator, UnaryOp, Variable,
5};
6use crate::structure::{Attribute, Block, BlockLabel, Body, Structure};
7use crate::template::{
8    Directive, Element, ForDirective, IfDirective, Interpolation, Strip, Template,
9};
10use crate::util::is_templated;
11use crate::{Identifier, Number, Result, Value};
12use hcl_primitives::ident::is_ident;
13use hcl_primitives::template::escape_markers;
14use std::io;
15
16impl<T> private::Sealed for &T where T: Format {}
17
18impl<T> Format for &T
19where
20    T: Format,
21{
22    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
23    where
24        W: io::Write,
25    {
26        (*self).format(fmt)
27    }
28}
29
30impl private::Sealed for Body {}
31
32impl Format for Body {
33    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
34    where
35        W: io::Write,
36    {
37        for structure in self {
38            structure.format(fmt)?;
39        }
40
41        Ok(())
42    }
43}
44
45impl private::Sealed for Structure {}
46
47impl Format for Structure {
48    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
49    where
50        W: io::Write,
51    {
52        match self {
53            Structure::Attribute(attr) => attr.format(fmt),
54            Structure::Block(block) => block.format(fmt),
55        }
56    }
57}
58
59impl private::Sealed for Attribute {}
60
61impl Format for Attribute {
62    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
63    where
64        W: io::Write,
65    {
66        fmt.begin_attribute()?;
67        self.key.format(fmt)?;
68        fmt.begin_attribute_value()?;
69        self.expr.format(fmt)?;
70        fmt.end_attribute()
71    }
72}
73
74impl private::Sealed for Block {}
75
76impl Format for Block {
77    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
78    where
79        W: io::Write,
80    {
81        fmt.begin_block()?;
82        self.identifier.format(fmt)?;
83
84        for label in &self.labels {
85            fmt.write_bytes(b" ")?;
86            label.format(fmt)?;
87        }
88
89        fmt.begin_block_body()?;
90        self.body.format(fmt)?;
91        fmt.end_block()
92    }
93}
94
95impl private::Sealed for BlockLabel {}
96
97impl Format for BlockLabel {
98    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
99    where
100        W: io::Write,
101    {
102        match self {
103            BlockLabel::Identifier(ident) => ident.format(fmt),
104            BlockLabel::String(string) => string.format(fmt),
105        }
106    }
107}
108
109impl private::Sealed for Expression {}
110
111impl Format for Expression {
112    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
113    where
114        W: io::Write,
115    {
116        match self {
117            Expression::Null => Ok(fmt.write_null()?),
118            Expression::Bool(b) => Ok(fmt.write_bool(*b)?),
119            Expression::Number(num) => num.format(fmt),
120            Expression::String(string) => string.format(fmt),
121            Expression::Array(array) => format_array(fmt, array.iter()),
122            Expression::Object(object) => format_object(fmt, object.iter()),
123            Expression::TemplateExpr(expr) => expr.format(fmt),
124            Expression::Variable(var) => var.format(fmt),
125            Expression::Traversal(traversal) => traversal.format(fmt),
126            Expression::FuncCall(func_call) => func_call.format(fmt),
127            Expression::Parenthesis(expr) => {
128                fmt.write_bytes(b"(")?;
129                expr.format(fmt)?;
130                fmt.write_bytes(b")")
131            }
132            Expression::Conditional(cond) => cond.format(fmt),
133            Expression::Operation(op) => op.format(fmt),
134            Expression::ForExpr(expr) => expr.format(fmt),
135        }
136    }
137}
138
139impl private::Sealed for Value {}
140
141impl Format for Value {
142    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
143    where
144        W: io::Write,
145    {
146        match self {
147            Value::Null => Ok(fmt.write_null()?),
148            Value::Bool(b) => Ok(fmt.write_bool(*b)?),
149            Value::Number(num) => num.format(fmt),
150            Value::String(string) => {
151                if is_templated(string) {
152                    fmt.write_quoted_string(string)
153                } else {
154                    fmt.write_quoted_string_escaped(string)
155                }
156            }
157            Value::Array(array) => format_array(fmt, array.iter()),
158            Value::Object(object) => format_object(fmt, object.iter().map(|(k, v)| (StrKey(k), v))),
159        }
160    }
161}
162
163impl private::Sealed for Number {}
164
165impl Format for Number {
166    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
167    where
168        W: io::Write,
169    {
170        fmt.write_string_fragment(&self.to_string())
171    }
172}
173
174impl private::Sealed for ObjectKey {}
175
176impl Format for ObjectKey {
177    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
178    where
179        W: io::Write,
180    {
181        match self {
182            ObjectKey::Identifier(ident) => ident.format(fmt),
183            ObjectKey::Expression(Expression::String(s)) => StrKey(s).format(fmt),
184            ObjectKey::Expression(expr) => expr.format(fmt),
185        }
186    }
187}
188
189struct StrKey<'a>(&'a str);
190
191impl<'a> private::Sealed for StrKey<'a> {}
192
193impl<'a> Format for StrKey<'a> {
194    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
195    where
196        W: io::Write,
197    {
198        if fmt.config.prefer_ident_keys && is_ident(self.0) {
199            fmt.write_string_fragment(self.0)
200        } else {
201            fmt.write_quoted_string_escaped(self.0)
202        }
203    }
204}
205
206impl private::Sealed for TemplateExpr {}
207
208impl Format for TemplateExpr {
209    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
210    where
211        W: io::Write,
212    {
213        match self {
214            TemplateExpr::QuotedString(string) => fmt.write_quoted_string(string),
215            TemplateExpr::Heredoc(heredoc) => heredoc.format(fmt),
216        }
217    }
218}
219
220impl private::Sealed for Heredoc {}
221
222impl Format for Heredoc {
223    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
224    where
225        W: io::Write,
226    {
227        fmt.write_string_fragment(self.strip.as_str())?;
228        fmt.write_string_fragment(&self.delimiter)?;
229        fmt.write_bytes(b"\n")?;
230        fmt.write_string_fragment(&self.template)?;
231
232        if !self.template.ends_with('\n') {
233            fmt.write_bytes(b"\n")?;
234        }
235
236        match self.strip {
237            HeredocStripMode::None => fmt.write_string_fragment(&self.delimiter),
238            HeredocStripMode::Indent => fmt.write_indented(fmt.current_indent, &self.delimiter),
239        }
240    }
241}
242
243impl private::Sealed for Identifier {}
244
245impl Format for Identifier {
246    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
247    where
248        W: io::Write,
249    {
250        fmt.write_string_fragment(self)
251    }
252}
253
254impl private::Sealed for Variable {}
255
256impl Format for Variable {
257    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
258    where
259        W: io::Write,
260    {
261        fmt.write_string_fragment(self)
262    }
263}
264
265impl private::Sealed for Traversal {}
266
267impl Format for Traversal {
268    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
269    where
270        W: io::Write,
271    {
272        self.expr.format(fmt)?;
273        for operator in &self.operators {
274            operator.format(fmt)?;
275        }
276        Ok(())
277    }
278}
279
280impl private::Sealed for TraversalOperator {}
281
282impl Format for TraversalOperator {
283    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
284    where
285        W: io::Write,
286    {
287        match self {
288            TraversalOperator::AttrSplat => fmt.write_bytes(b".*"),
289            TraversalOperator::FullSplat => fmt.write_bytes(b"[*]"),
290            TraversalOperator::GetAttr(ident) => {
291                fmt.write_bytes(b".")?;
292                ident.format(fmt)
293            }
294            TraversalOperator::LegacyIndex(index) => {
295                fmt.write_bytes(b".")?;
296                fmt.write_int(*index)
297            }
298            TraversalOperator::Index(expr) => {
299                fmt.write_bytes(b"[")?;
300                expr.format(fmt)?;
301                fmt.write_bytes(b"]")
302            }
303        }
304    }
305}
306
307impl private::Sealed for FuncCall {}
308
309impl Format for FuncCall {
310    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
311    where
312        W: io::Write,
313    {
314        self.name.format(fmt)?;
315        fmt.write_bytes(b"(")?;
316
317        fmt.with_compact_mode(|fmt| {
318            for (i, arg) in self.args.iter().enumerate() {
319                if i > 0 {
320                    fmt.write_bytes(b", ")?;
321                }
322
323                arg.format(fmt)?;
324            }
325
326            Ok(())
327        })?;
328
329        if self.expand_final {
330            fmt.write_bytes(b"...)")
331        } else {
332            fmt.write_bytes(b")")
333        }
334    }
335}
336
337impl private::Sealed for FuncName {}
338
339impl Format for FuncName {
340    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
341    where
342        W: io::Write,
343    {
344        for component in &self.namespace {
345            component.format(fmt)?;
346            fmt.write_bytes(b"::")?;
347        }
348
349        self.name.format(fmt)
350    }
351}
352
353impl private::Sealed for Conditional {}
354
355impl Format for Conditional {
356    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
357    where
358        W: io::Write,
359    {
360        fmt.with_compact_mode(|fmt| {
361            self.cond_expr.format(fmt)?;
362            fmt.write_bytes(b" ? ")?;
363            self.true_expr.format(fmt)?;
364            fmt.write_bytes(b" : ")?;
365            self.false_expr.format(fmt)
366        })
367    }
368}
369
370impl private::Sealed for Operation {}
371
372impl Format for Operation {
373    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
374    where
375        W: io::Write,
376    {
377        match self {
378            Operation::Unary(op) => op.format(fmt),
379            Operation::Binary(op) => op.format(fmt),
380        }
381    }
382}
383
384impl private::Sealed for UnaryOp {}
385
386impl Format for UnaryOp {
387    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
388    where
389        W: io::Write,
390    {
391        fmt.write_string_fragment(self.operator.as_str())?;
392        self.expr.format(fmt)
393    }
394}
395
396impl private::Sealed for BinaryOp {}
397
398impl Format for BinaryOp {
399    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
400    where
401        W: io::Write,
402    {
403        self.lhs_expr.format(fmt)?;
404        fmt.write_bytes(b" ")?;
405        fmt.write_string_fragment(self.operator.as_str())?;
406        fmt.write_bytes(b" ")?;
407        self.rhs_expr.format(fmt)
408    }
409}
410
411impl private::Sealed for ForExpr {}
412
413impl Format for ForExpr {
414    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
415    where
416        W: io::Write,
417    {
418        let object_result = self.key_expr.is_some();
419
420        if object_result {
421            fmt.write_bytes(b"{")?;
422        } else {
423            fmt.write_bytes(b"[")?;
424        }
425
426        fmt.write_bytes(b"for ")?;
427        if let Some(key) = &self.key_var {
428            key.format(fmt)?;
429            fmt.write_bytes(b", ")?;
430        }
431        self.value_var.format(fmt)?;
432        fmt.write_bytes(b" in ")?;
433        self.collection_expr.format(fmt)?;
434        fmt.write_bytes(b" : ")?;
435
436        if let Some(key_expr) = &self.key_expr {
437            key_expr.format(fmt)?;
438            fmt.write_bytes(b" => ")?;
439        }
440        self.value_expr.format(fmt)?;
441        if object_result && self.grouping {
442            fmt.write_bytes(b"...")?;
443        }
444        if let Some(cond) = &self.cond_expr {
445            fmt.write_bytes(b" if ")?;
446            cond.format(fmt)?;
447        }
448
449        if object_result {
450            fmt.write_bytes(b"}")
451        } else {
452            fmt.write_bytes(b"]")
453        }
454    }
455}
456
457impl private::Sealed for Template {}
458
459impl Format for Template {
460    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
461    where
462        W: io::Write,
463    {
464        for element in self.elements() {
465            element.format(fmt)?;
466        }
467
468        Ok(())
469    }
470}
471
472impl private::Sealed for Element {}
473
474impl Format for Element {
475    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
476    where
477        W: io::Write,
478    {
479        match self {
480            Element::Literal(lit) => {
481                let escaped = escape_markers(lit);
482                fmt.write_string_fragment(&escaped)
483            }
484            Element::Interpolation(interp) => interp.format(fmt),
485            Element::Directive(dir) => dir.format(fmt),
486        }
487    }
488}
489
490impl private::Sealed for Interpolation {}
491
492impl Format for Interpolation {
493    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
494    where
495        W: io::Write,
496    {
497        format_interpolation(fmt, self.strip, |fmt| self.expr.format(fmt))
498    }
499}
500
501impl private::Sealed for Directive {}
502
503impl Format for Directive {
504    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
505    where
506        W: io::Write,
507    {
508        match self {
509            Directive::If(if_dir) => if_dir.format(fmt),
510            Directive::For(for_dir) => for_dir.format(fmt),
511        }
512    }
513}
514
515impl private::Sealed for IfDirective {}
516
517impl Format for IfDirective {
518    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
519    where
520        W: io::Write,
521    {
522        format_directive(fmt, self.if_strip, |fmt| {
523            fmt.write_bytes(b"if ")?;
524            self.cond_expr.format(fmt)
525        })?;
526        self.true_template.format(fmt)?;
527
528        if let Some(false_template) = &self.false_template {
529            format_directive(fmt, self.else_strip, |fmt| fmt.write_bytes(b"else"))?;
530            false_template.format(fmt)?;
531        }
532
533        format_directive(fmt, self.endif_strip, |fmt| fmt.write_bytes(b"endif"))
534    }
535}
536
537impl private::Sealed for ForDirective {}
538
539impl Format for ForDirective {
540    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
541    where
542        W: io::Write,
543    {
544        format_directive(fmt, self.for_strip, |fmt| {
545            fmt.write_bytes(b"for ")?;
546
547            if let Some(key_var) = &self.key_var {
548                key_var.format(fmt)?;
549                fmt.write_bytes(b", ")?;
550            }
551
552            self.value_var.format(fmt)?;
553            fmt.write_bytes(b" in ")?;
554            self.collection_expr.format(fmt)
555        })?;
556
557        self.template.format(fmt)?;
558        format_directive(fmt, self.endfor_strip, |fmt| fmt.write_bytes(b"endfor"))
559    }
560}
561
562impl private::Sealed for String {}
563
564impl Format for String {
565    fn format<W>(&self, fmt: &mut Formatter<W>) -> Result<()>
566    where
567        W: io::Write,
568    {
569        fmt.write_quoted_string_escaped(self)
570    }
571}
572
573fn format_array<W, T>(fmt: &mut Formatter<W>, array: impl Iterator<Item = T>) -> Result<()>
574where
575    W: io::Write,
576    T: Format,
577{
578    fmt.begin_array()?;
579
580    for value in array {
581        fmt.begin_array_value()?;
582        value.format(fmt)?;
583        fmt.end_array_value()?;
584    }
585
586    fmt.end_array()
587}
588
589fn format_object<W, K, V>(
590    fmt: &mut Formatter<W>,
591    object: impl Iterator<Item = (K, V)>,
592) -> Result<()>
593where
594    W: io::Write,
595    K: Format,
596    V: Format,
597{
598    fmt.begin_object()?;
599
600    for (key, value) in object {
601        fmt.begin_object_key()?;
602        key.format(fmt)?;
603        fmt.begin_object_value()?;
604        value.format(fmt)?;
605        fmt.end_object_value()?;
606    }
607
608    fmt.end_object()
609}
610
611fn format_strip<W, F>(fmt: &mut Formatter<W>, strip: Strip, f: F) -> Result<()>
612where
613    W: io::Write,
614    F: FnOnce(&mut Formatter<W>) -> Result<()>,
615{
616    if strip.strip_start() {
617        fmt.write_bytes(b"~")?;
618    }
619
620    f(fmt)?;
621
622    if strip.strip_end() {
623        fmt.write_bytes(b"~")?;
624    }
625
626    Ok(())
627}
628
629fn format_interpolation<W, F>(fmt: &mut Formatter<W>, strip: Strip, f: F) -> Result<()>
630where
631    W: io::Write,
632    F: FnOnce(&mut Formatter<W>) -> Result<()>,
633{
634    fmt.write_bytes(b"${")?;
635    format_strip(fmt, strip, f)?;
636    fmt.write_bytes(b"}")
637}
638
639fn format_directive<W, F>(fmt: &mut Formatter<W>, strip: Strip, f: F) -> Result<()>
640where
641    W: io::Write,
642    F: FnOnce(&mut Formatter<W>) -> Result<()>,
643{
644    fmt.write_bytes(b"%{")?;
645    format_strip(fmt, strip, |fmt| {
646        fmt.write_bytes(b" ")?;
647        f(fmt)?;
648        fmt.write_bytes(b" ")
649    })?;
650    fmt.write_bytes(b"}")
651}