1#[cfg(test)]
4mod tests;
5
6use crate::encode::{Encode, EncodeState};
7use crate::expr::Expression;
8use crate::util::{dedent_by, min_leading_whitespace};
9use crate::{parser, Decor, Decorate, Decorated, Ident, RawString, Spanned};
10use std::fmt;
11use std::ops::{Deref, DerefMut, Range};
12use std::str::FromStr;
13
14#[doc(inline)]
16pub use hcl_primitives::template::Strip;
17
18pub type IntoIter = Box<dyn Iterator<Item = Element>>;
26
27pub type Iter<'a> = Box<dyn Iterator<Item = &'a Element> + 'a>;
34
35pub type IterMut<'a> = Box<dyn Iterator<Item = &'a mut Element> + 'a>;
42
43#[derive(Debug, Clone, Eq, Default)]
48pub struct StringTemplate {
49 template: Template,
50 decor: Decor,
51}
52
53impl StringTemplate {
54 #[inline]
56 pub fn new() -> Self {
57 StringTemplate::default()
58 }
59
60 #[inline]
62 pub fn with_capacity(capacity: usize) -> Self {
63 StringTemplate {
64 template: Template::with_capacity(capacity),
65 ..Default::default()
66 }
67 }
68
69 pub(crate) fn despan(&mut self, input: &str) {
70 self.decor.despan(input);
71 self.template.despan(input);
72 }
73}
74
75impl From<Vec<Element>> for StringTemplate {
76 fn from(elements: Vec<Element>) -> Self {
77 StringTemplate {
78 template: Template::from(elements),
79 decor: Decor::default(),
80 }
81 }
82}
83
84impl PartialEq for StringTemplate {
85 fn eq(&self, other: &Self) -> bool {
86 self.template == other.template
87 }
88}
89
90impl Deref for StringTemplate {
91 type Target = Template;
92
93 #[inline]
94 fn deref(&self) -> &Self::Target {
95 &self.template
96 }
97}
98
99impl DerefMut for StringTemplate {
100 #[inline]
101 fn deref_mut(&mut self) -> &mut Self::Target {
102 &mut self.template
103 }
104}
105
106impl<T> Extend<T> for StringTemplate
107where
108 T: Into<Element>,
109{
110 fn extend<I>(&mut self, iterable: I)
111 where
112 I: IntoIterator<Item = T>,
113 {
114 self.template.extend(iterable);
115 }
116}
117
118impl<T> FromIterator<T> for StringTemplate
119where
120 T: Into<Element>,
121{
122 fn from_iter<I>(iterable: I) -> Self
123 where
124 I: IntoIterator<Item = T>,
125 {
126 Template::from_iter(iterable).into()
127 }
128}
129
130impl IntoIterator for StringTemplate {
131 type Item = Element;
132 type IntoIter = IntoIter;
133
134 fn into_iter(self) -> Self::IntoIter {
135 self.template.into_iter()
136 }
137}
138
139impl<'a> IntoIterator for &'a StringTemplate {
140 type Item = &'a Element;
141 type IntoIter = Iter<'a>;
142
143 fn into_iter(self) -> Self::IntoIter {
144 self.template.iter()
145 }
146}
147
148impl<'a> IntoIterator for &'a mut StringTemplate {
149 type Item = &'a mut Element;
150 type IntoIter = IterMut<'a>;
151
152 fn into_iter(self) -> Self::IntoIter {
153 self.template.iter_mut()
154 }
155}
156
157#[derive(Debug, Clone, Eq)]
160pub struct HeredocTemplate {
161 pub delimiter: Ident,
163 pub template: Template,
165
166 indent: Option<usize>,
167 trailing: RawString,
168 decor: Decor,
169 span: Option<Range<usize>>,
170}
171
172impl HeredocTemplate {
173 pub fn new(delimiter: Ident, template: Template) -> HeredocTemplate {
175 HeredocTemplate {
176 delimiter,
177 template,
178 indent: None,
179 trailing: RawString::default(),
180 decor: Decor::default(),
181 span: None,
182 }
183 }
184
185 pub fn indent(&self) -> Option<usize> {
187 self.indent
188 }
189
190 pub fn set_indent(&mut self, indent: usize) {
192 self.indent = Some(indent);
193 }
194
195 pub fn trailing(&self) -> &RawString {
197 &self.trailing
198 }
199
200 pub fn set_trailing(&mut self, trailing: impl Into<RawString>) {
202 self.trailing = trailing.into();
203 }
204
205 pub fn dedent(&mut self) {
210 let stripped_indent = self.template.dedent();
211 self.indent = stripped_indent;
212 }
213
214 pub(crate) fn despan(&mut self, input: &str) {
215 self.decor.despan(input);
216 self.template.despan(input);
217 self.trailing.despan(input);
218 }
219}
220
221impl PartialEq for HeredocTemplate {
222 fn eq(&self, other: &Self) -> bool {
223 self.delimiter == other.delimiter
224 && self.template == other.template
225 && self.indent == other.indent
226 && self.trailing == other.trailing
227 }
228}
229
230#[derive(Debug, Clone, Eq, Default)]
235pub struct Template {
236 elements: Vec<Element>,
237 span: Option<Range<usize>>,
238}
239
240impl Template {
241 #[inline]
243 pub fn new() -> Self {
244 Template::default()
245 }
246
247 #[inline]
249 pub fn with_capacity(capacity: usize) -> Self {
250 Template {
251 elements: Vec::with_capacity(capacity),
252 ..Default::default()
253 }
254 }
255
256 #[inline]
258 pub fn is_empty(&self) -> bool {
259 self.elements.is_empty()
260 }
261
262 #[inline]
264 pub fn len(&self) -> usize {
265 self.elements.len()
266 }
267
268 #[inline]
270 pub fn clear(&mut self) {
271 self.elements.clear();
272 }
273
274 #[inline]
277 pub fn get(&self, index: usize) -> Option<&Element> {
278 self.elements.get(index)
279 }
280
281 #[inline]
284 pub fn get_mut(&mut self, index: usize) -> Option<&mut Element> {
285 self.elements.get_mut(index)
286 }
287
288 #[inline]
295 pub fn insert(&mut self, index: usize, element: impl Into<Element>) {
296 self.elements.insert(index, element.into());
297 }
298
299 #[inline]
305 pub fn push(&mut self, element: impl Into<Element>) {
306 self.elements.push(element.into());
307 }
308
309 #[inline]
311 pub fn pop(&mut self) -> Option<Element> {
312 self.elements.pop()
313 }
314
315 #[inline]
325 pub fn remove(&mut self, index: usize) -> Element {
326 self.elements.remove(index)
327 }
328
329 #[inline]
332 pub fn iter(&self) -> Iter<'_> {
333 Box::new(self.elements.iter())
334 }
335
336 #[inline]
339 pub fn iter_mut(&mut self) -> IterMut<'_> {
340 Box::new(self.elements.iter_mut())
341 }
342
343 pub fn as_single_element(&self) -> Option<&Element> {
362 match self.len() {
363 1 => self.get(0),
364 _ => None,
365 }
366 }
367
368 pub fn as_single_element_mut(&mut self) -> Option<&mut Element> {
390 match self.len() {
391 1 => self.get_mut(0),
392 _ => None,
393 }
394 }
395
396 pub(crate) fn despan(&mut self, input: &str) {
397 for element in &mut self.elements {
398 element.despan(input);
399 }
400 }
401
402 pub(crate) fn dedent(&mut self) -> Option<usize> {
405 let mut indent: Option<usize> = None;
406 let mut skip_first_line = false;
407
408 for element in &self.elements {
409 if let Element::Literal(literal) = element {
410 if let Some(leading_ws) = min_leading_whitespace(literal, skip_first_line) {
411 indent = Some(indent.map_or(leading_ws, |indent| indent.min(leading_ws)));
412 }
413 skip_first_line = !literal.ends_with('\n');
414 } else if !skip_first_line {
415 return None;
418 }
419 }
420
421 if let Some(indent) = indent {
422 skip_first_line = false;
423
424 for element in &mut self.elements {
425 if let Element::Literal(literal) = element {
426 let dedented = dedent_by(literal, indent, skip_first_line);
427 *literal.as_mut() = dedented.into();
428 skip_first_line = !literal.ends_with('\n');
429 } else if !skip_first_line {
430 skip_first_line = true;
431 }
432 }
433 }
434
435 indent
436 }
437}
438
439impl PartialEq for Template {
440 fn eq(&self, other: &Self) -> bool {
441 self.elements == other.elements
442 }
443}
444
445impl fmt::Display for Template {
446 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
447 let mut state = EncodeState::new(f);
448 self.encode(&mut state)
449 }
450}
451
452impl FromStr for Template {
453 type Err = parser::Error;
454
455 fn from_str(s: &str) -> Result<Self, Self::Err> {
456 parser::parse_template(s)
457 }
458}
459
460impl From<Vec<Element>> for Template {
461 fn from(elements: Vec<Element>) -> Self {
462 Template {
463 elements,
464 ..Default::default()
465 }
466 }
467}
468
469impl From<Template> for StringTemplate {
470 fn from(template: Template) -> Self {
471 StringTemplate {
472 template,
473 ..Default::default()
474 }
475 }
476}
477
478impl From<StringTemplate> for Template {
479 fn from(template: StringTemplate) -> Self {
480 template.template
481 }
482}
483
484impl<T> Extend<T> for Template
485where
486 T: Into<Element>,
487{
488 fn extend<I>(&mut self, iterable: I)
489 where
490 I: IntoIterator<Item = T>,
491 {
492 let iter = iterable.into_iter();
493 let reserve = if self.is_empty() {
494 iter.size_hint().0
495 } else {
496 (iter.size_hint().0 + 1) / 2
497 };
498 self.elements.reserve(reserve);
499 iter.for_each(|v| self.push(v));
500 }
501}
502
503impl<T> FromIterator<T> for Template
504where
505 T: Into<Element>,
506{
507 fn from_iter<I>(iterable: I) -> Self
508 where
509 I: IntoIterator<Item = T>,
510 {
511 let iter = iterable.into_iter();
512 let lower = iter.size_hint().0;
513 let mut template = Template::with_capacity(lower);
514 template.extend(iter);
515 template
516 }
517}
518
519impl IntoIterator for Template {
520 type Item = Element;
521 type IntoIter = IntoIter;
522
523 fn into_iter(self) -> Self::IntoIter {
524 Box::new(self.elements.into_iter())
525 }
526}
527
528impl<'a> IntoIterator for &'a Template {
529 type Item = &'a Element;
530 type IntoIter = Iter<'a>;
531
532 fn into_iter(self) -> Self::IntoIter {
533 self.iter()
534 }
535}
536
537impl<'a> IntoIterator for &'a mut Template {
538 type Item = &'a mut Element;
539 type IntoIter = IterMut<'a>;
540
541 fn into_iter(self) -> Self::IntoIter {
542 self.iter_mut()
543 }
544}
545
546#[derive(Debug, Clone, PartialEq, Eq)]
548pub enum Element {
549 Literal(Spanned<String>),
551 Interpolation(Interpolation),
554 Directive(Directive),
556}
557
558impl Element {
559 pub fn is_literal(&self) -> bool {
561 self.as_literal().is_some()
562 }
563
564 pub fn as_literal(&self) -> Option<&Spanned<String>> {
566 match self {
567 Element::Literal(value) => Some(value),
568 Element::Interpolation(_) | Element::Directive(_) => None,
569 }
570 }
571
572 pub fn is_interpolation(&self) -> bool {
574 self.as_interpolation().is_some()
575 }
576
577 pub fn as_interpolation(&self) -> Option<&Interpolation> {
579 match self {
580 Element::Interpolation(value) => Some(value),
581 Element::Literal(_) | Element::Directive(_) => None,
582 }
583 }
584
585 pub fn is_directive(&self) -> bool {
587 self.as_directive().is_some()
588 }
589
590 pub fn as_directive(&self) -> Option<&Directive> {
592 match self {
593 Element::Directive(value) => Some(value),
594 Element::Literal(_) | Element::Interpolation(_) => None,
595 }
596 }
597
598 pub(crate) fn despan(&mut self, input: &str) {
599 match self {
600 Element::Literal(_) => {}
601 Element::Interpolation(interp) => interp.despan(input),
602 Element::Directive(dir) => dir.despan(input),
603 }
604 }
605}
606
607impl From<&str> for Element {
608 fn from(value: &str) -> Self {
609 Element::from(value.to_string())
610 }
611}
612
613impl From<String> for Element {
614 fn from(value: String) -> Self {
615 Element::from(Spanned::new(value))
616 }
617}
618
619impl From<Spanned<String>> for Element {
620 fn from(value: Spanned<String>) -> Self {
621 Element::Literal(value)
622 }
623}
624
625impl From<Interpolation> for Element {
626 fn from(value: Interpolation) -> Self {
627 Element::Interpolation(value)
628 }
629}
630
631impl From<Directive> for Element {
632 fn from(value: Directive) -> Self {
633 Element::Directive(value)
634 }
635}
636
637#[derive(Debug, Clone, Eq)]
640pub struct Interpolation {
641 pub expr: Expression,
643 pub strip: Strip,
646
647 span: Option<Range<usize>>,
648}
649
650impl Interpolation {
651 pub fn new(expr: impl Into<Expression>) -> Interpolation {
653 Interpolation {
654 expr: expr.into(),
655 strip: Strip::default(),
656 span: None,
657 }
658 }
659
660 pub(crate) fn despan(&mut self, input: &str) {
661 self.expr.despan(input);
662 }
663}
664
665impl PartialEq for Interpolation {
666 fn eq(&self, other: &Self) -> bool {
667 self.expr == other.expr && self.strip == other.strip
668 }
669}
670
671#[derive(Debug, Clone, PartialEq, Eq)]
673pub enum Directive {
674 If(IfDirective),
676 For(ForDirective),
678}
679
680impl Directive {
681 pub(crate) fn despan(&mut self, input: &str) {
682 match self {
683 Directive::If(dir) => dir.despan(input),
684 Directive::For(dir) => dir.despan(input),
685 }
686 }
687}
688
689impl From<IfDirective> for Directive {
690 fn from(value: IfDirective) -> Self {
691 Directive::If(value)
692 }
693}
694
695impl From<ForDirective> for Directive {
696 fn from(value: ForDirective) -> Self {
697 Directive::For(value)
698 }
699}
700
701#[derive(Debug, Clone, Eq)]
704pub struct IfDirective {
705 pub if_expr: IfTemplateExpr,
707 pub else_expr: Option<ElseTemplateExpr>,
710 pub endif_expr: EndifTemplateExpr,
712
713 span: Option<Range<usize>>,
714}
715
716impl IfDirective {
717 pub fn new(
720 if_expr: IfTemplateExpr,
721 else_expr: Option<ElseTemplateExpr>,
722 endif_expr: EndifTemplateExpr,
723 ) -> IfDirective {
724 IfDirective {
725 if_expr,
726 else_expr,
727 endif_expr,
728 span: None,
729 }
730 }
731
732 pub(crate) fn despan(&mut self, input: &str) {
733 self.if_expr.despan(input);
734
735 if let Some(else_expr) = &mut self.else_expr {
736 else_expr.despan(input);
737 }
738
739 self.endif_expr.despan(input);
740 }
741}
742
743impl PartialEq for IfDirective {
744 fn eq(&self, other: &Self) -> bool {
745 self.if_expr == other.if_expr
746 && self.else_expr == other.else_expr
747 && self.endif_expr == other.endif_expr
748 }
749}
750
751#[derive(Debug, Clone, PartialEq, Eq)]
754pub struct IfTemplateExpr {
755 pub cond_expr: Expression,
757 pub template: Template,
760 pub strip: Strip,
763
764 preamble: RawString,
765}
766
767impl IfTemplateExpr {
768 pub fn new(cond_expr: impl Into<Expression>, template: Template) -> IfTemplateExpr {
770 IfTemplateExpr {
771 preamble: RawString::default(),
772 cond_expr: cond_expr.into(),
773 template,
774 strip: Strip::default(),
775 }
776 }
777
778 pub fn preamble(&self) -> &RawString {
780 &self.preamble
781 }
782
783 pub fn set_preamble(&mut self, preamble: impl Into<RawString>) {
785 self.preamble = preamble.into();
786 }
787
788 pub(crate) fn despan(&mut self, input: &str) {
789 self.preamble.despan(input);
790 self.cond_expr.despan(input);
791 self.template.despan(input);
792 }
793}
794
795#[derive(Debug, Clone, PartialEq, Eq)]
798pub struct ElseTemplateExpr {
799 pub template: Template,
802 pub strip: Strip,
805
806 preamble: RawString,
807 trailing: RawString,
808}
809
810impl ElseTemplateExpr {
811 pub fn new(template: Template) -> ElseTemplateExpr {
813 ElseTemplateExpr {
814 preamble: RawString::default(),
815 trailing: RawString::default(),
816 template,
817 strip: Strip::default(),
818 }
819 }
820
821 pub fn preamble(&self) -> &RawString {
823 &self.preamble
824 }
825
826 pub fn set_preamble(&mut self, preamble: impl Into<RawString>) {
828 self.preamble = preamble.into();
829 }
830
831 pub fn trailing(&self) -> &RawString {
833 &self.trailing
834 }
835
836 pub fn set_trailing(&mut self, trailing: impl Into<RawString>) {
838 self.trailing = trailing.into();
839 }
840
841 pub(crate) fn despan(&mut self, input: &str) {
842 self.preamble.despan(input);
843 self.template.despan(input);
844 self.trailing.despan(input);
845 }
846}
847
848#[derive(Debug, Clone, Default, PartialEq, Eq)]
850pub struct EndifTemplateExpr {
851 pub strip: Strip,
854
855 preamble: RawString,
856 trailing: RawString,
857}
858
859impl EndifTemplateExpr {
860 pub fn new() -> EndifTemplateExpr {
862 EndifTemplateExpr::default()
863 }
864
865 pub fn preamble(&self) -> &RawString {
867 &self.preamble
868 }
869
870 pub fn set_preamble(&mut self, preamble: impl Into<RawString>) {
872 self.preamble = preamble.into();
873 }
874
875 pub fn trailing(&self) -> &RawString {
877 &self.trailing
878 }
879
880 pub fn set_trailing(&mut self, trailing: impl Into<RawString>) {
882 self.trailing = trailing.into();
883 }
884
885 pub(crate) fn despan(&mut self, input: &str) {
886 self.preamble.despan(input);
887 self.trailing.despan(input);
888 }
889}
890
891#[derive(Debug, Clone, Eq)]
894pub struct ForDirective {
895 pub for_expr: ForTemplateExpr,
897 pub endfor_expr: EndforTemplateExpr,
899
900 span: Option<Range<usize>>,
901}
902
903impl ForDirective {
904 pub fn new(for_expr: ForTemplateExpr, endfor_expr: EndforTemplateExpr) -> ForDirective {
906 ForDirective {
907 for_expr,
908 endfor_expr,
909 span: None,
910 }
911 }
912
913 pub(crate) fn despan(&mut self, input: &str) {
914 self.for_expr.despan(input);
915 self.endfor_expr.despan(input);
916 }
917}
918
919impl PartialEq for ForDirective {
920 fn eq(&self, other: &Self) -> bool {
921 self.for_expr == other.for_expr && self.endfor_expr == other.endfor_expr
922 }
923}
924
925#[derive(Debug, Clone, PartialEq, Eq)]
928pub struct ForTemplateExpr {
929 pub key_var: Option<Decorated<Ident>>,
931 pub value_var: Decorated<Ident>,
933 pub collection_expr: Expression,
935 pub template: Template,
937 pub strip: Strip,
940
941 preamble: RawString,
942}
943
944impl ForTemplateExpr {
945 pub fn new(
948 key_var: Option<impl Into<Decorated<Ident>>>,
949 value_var: impl Into<Decorated<Ident>>,
950 collection_expr: impl Into<Expression>,
951 template: Template,
952 ) -> ForTemplateExpr {
953 ForTemplateExpr {
954 preamble: RawString::default(),
955 key_var: key_var.map(Into::into),
956 value_var: value_var.into(),
957 collection_expr: collection_expr.into(),
958 template,
959 strip: Strip::default(),
960 }
961 }
962
963 pub fn preamble(&self) -> &RawString {
965 &self.preamble
966 }
967
968 pub fn set_preamble(&mut self, preamble: impl Into<RawString>) {
970 self.preamble = preamble.into();
971 }
972
973 pub(crate) fn despan(&mut self, input: &str) {
974 self.preamble.despan(input);
975
976 if let Some(key_var) = &mut self.key_var {
977 key_var.decor_mut().despan(input);
978 }
979
980 self.value_var.decor_mut().despan(input);
981 self.collection_expr.despan(input);
982 self.template.despan(input);
983 }
984}
985
986#[derive(Debug, Clone, Default, PartialEq, Eq)]
988pub struct EndforTemplateExpr {
989 pub strip: Strip,
992
993 preamble: RawString,
994 trailing: RawString,
995}
996
997impl EndforTemplateExpr {
998 pub fn new() -> EndforTemplateExpr {
1000 EndforTemplateExpr::default()
1001 }
1002
1003 pub fn preamble(&self) -> &RawString {
1005 &self.preamble
1006 }
1007
1008 pub fn set_preamble(&mut self, preamble: impl Into<RawString>) {
1010 self.preamble = preamble.into();
1011 }
1012
1013 pub fn trailing(&self) -> &RawString {
1015 &self.trailing
1016 }
1017
1018 pub fn set_trailing(&mut self, trailing: impl Into<RawString>) {
1020 self.trailing = trailing.into();
1021 }
1022
1023 pub(crate) fn despan(&mut self, input: &str) {
1024 self.preamble.despan(input);
1025 self.trailing.despan(input);
1026 }
1027}
1028
1029decorate_impl! { StringTemplate, HeredocTemplate }
1030
1031span_impl! {
1032 StringTemplate, HeredocTemplate, Template,
1033 Interpolation, IfDirective, ForDirective
1034}
1035
1036forward_span_impl! {
1037 Element => { Literal, Interpolation, Directive },
1038 Directive => { If, For }
1039}