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}