hcl/
macros.rs

1/// Construct an `hcl::Body` from HCL blocks and attributes.
2///
3/// The macro supports a subset of the HCL syntax. If you need more flexibility, use the
4/// [`BlockBuilder`][crate::structure::BlockBuilder] instead.
5///
6/// # Supported Syntax
7///
8/// - Attribute keys and block identifiers can be raw identifiers (`identifier`) or parenthesized
9///   expressions (`(expr)`).
10/// - Block labels can be string literals (`"label"`), identifiers (`label`) or parenthesized
11///   expressions (`(label_expr)`).
12/// - Object keys can be string literals (`"key"`), identifiers (`key`) or parenthesized
13///   expressions (`(key_expr)`).
14/// - Attribute expression values can be any valid primitive, collection or expression.
15///
16/// # Unsupported syntax
17///
18/// Heredocs are not supported by the `hcl::body` macro.
19///
20/// # Related macros
21///
22/// The `body!` macro is composed out of different other macros that can be used on their own to
23/// construct HCL data structures:
24///
25/// - [`attribute!`][`crate::attribute!`]: constructs an [`Attribute`][crate::structure::Attribute]
26/// - [`block!`][`crate::block!`]: constructs a [`Block`][crate::structure::Block]
27/// - [`expression!`][`crate::expression!`]: constructs an [`Expression`][crate::expr::Expression]
28/// - [`structure!`][`crate::structure!`]: constructs a [`Structure`][crate::structure::Structure]
29///
30/// Additionally the [`value!`][`crate::value!`] macro is provided for constructing a
31/// [`Value`][crate::value::Value].
32///
33/// # Example
34///
35/// ```
36/// use hcl::{Block, Body};
37///
38/// let body = hcl::body!({
39///     resource "aws_sns_topic" "topic" {
40///         name = "my-topic"
41///     }
42/// });
43///
44/// let expected = Body::builder()
45///     .add_block(
46///         Block::builder("resource")
47///             .add_label("aws_sns_topic")
48///             .add_label("topic")
49///             .add_attribute(("name", "my-topic"))
50///             .build()
51///     )
52///     .build();
53///
54/// assert_eq!(body, expected);
55/// ```
56///
57/// Attribute keys, block identifiers and object keys can be expressions by wrapping them in
58/// parenthesis:
59///
60/// ```
61/// use hcl::{Block, Body};
62///
63/// let block_identifier = "resource";
64/// let attribute_key = "name";
65///
66/// let body = hcl::body!({
67///     (block_identifier) "aws_sns_topic" "topic" {
68///         (attribute_key) = "my-topic"
69///     }
70/// });
71///
72/// let expected = Body::builder()
73///     .add_block(
74///         Block::builder(block_identifier)
75///             .add_label("aws_sns_topic")
76///             .add_label("topic")
77///             .add_attribute((attribute_key, "my-topic"))
78///             .build()
79///     )
80///     .build();
81///
82/// assert_eq!(body, expected);
83/// ```
84#[macro_export]
85macro_rules! body {
86    // Hide distracting implementation details from the generated rustdoc.
87    ($($body:tt)*) => {
88        $crate::body_internal!($($body)*)
89    };
90}
91
92#[macro_export]
93#[doc(hidden)]
94macro_rules! body_internal {
95    //////////////////////////////////////////////////////////////////////////
96    // TT muncher for parsing zero or more HCL structures (attributes and blocks).
97    //
98    // Produces a vec![...] of the elements.
99    //
100    // Must be invoked as: body_internal!(@structures [] $($tt)*)
101    //////////////////////////////////////////////////////////////////////////
102
103    // No tokens left, done.
104    (@structures [$(($elems:expr))*]) => {
105        std::vec![$($elems),*]
106    };
107
108    // Next element is an attribute, munch into elems and proceed with next structure.
109    (@structures [$(($elems:expr))*] $key:tt = $expr:tt $($rest:tt)*) => {
110        $crate::body_internal!(@structures [$(($elems))* ($crate::structure!($key = $expr))] $($rest)*)
111    };
112
113    // Next element must be a block, invoke block muncher.
114    (@structures [$(($elems:expr))*] $ident:tt $($rest:tt)+) => {
115        $crate::body_internal!(@block [$(($elems))*] $ident $($rest)+)
116    };
117
118    //////////////////////////////////////////////////////////////////////////
119    // TT muncher for parsing an HCL block.
120    //
121    // Must be invoked as: body_internal!(@block [$(($elems))*] $ident $($rest)+)
122    //////////////////////////////////////////////////////////////////////////
123
124    // Found block body, munch block into elems and proceed with next structure.
125    (@block [$(($elems:expr))*] ($ident:expr) [$(($labels:expr))*] { $($body:tt)* } $($rest:tt)*) => {
126        $crate::body_internal!(@structures [$(($elems))* ($crate::structure!(($ident) [$(($labels))*] { $($body)* }))] $($rest)*)
127    };
128
129    // Munch an identifier block label.
130    (@block [$(($elems:expr))*] ($ident:expr) [$(($labels:expr))*] $label:ident $($rest:tt)+) => {
131        $crate::body_internal!(@block [$(($elems))*] ($ident) [$(($labels))* ($crate::block_label!($label))] $($rest)+)
132    };
133
134    // Munch a literal expression block label.
135    (@block [$(($elems:expr))*] ($ident:expr) [$(($labels:expr))*] $label:literal $($rest:tt)+) => {
136        $crate::body_internal!(@block [$(($elems))*] ($ident) [$(($labels))* ($crate::block_label!($label))] $($rest)+)
137    };
138
139    // Munch an expression block label.
140    (@block [$(($elems:expr))*] ($ident:expr) [$(($labels:expr))*] ($label:expr) $($rest:tt)+) => {
141        $crate::body_internal!(@block [$(($elems))*] ($ident) [$(($labels))* ($crate::block_label!(($label)))] $($rest)+)
142    };
143
144    // Block with identifier.
145    (@block [$(($elems:expr))*] $ident:ident $($rest:tt)+) => {
146        $crate::body_internal!(@block [$(($elems))*] (std::stringify!($ident)) [] $($rest)+)
147    };
148
149    // Block with expression as identifier.
150    (@block [$(($elems:expr))*] ($ident:expr) $($rest:tt)+) => {
151        $crate::body_internal!(@block [$(($elems))*] ($ident) [] $($rest)+)
152    };
153
154    //////////////////////////////////////////////////////////////////////////
155    // The main implementation.
156    //
157    // Must be invoked as: body_internal!($($tt)+)
158    //////////////////////////////////////////////////////////////////////////
159
160    // Body in curly braces.
161    ({ $($tt:tt)* }) => {
162        $crate::body_internal!($($tt)*)
163    };
164
165    // Invoke structure muncher.
166    ($($tt:tt)*) => {
167        $crate::structure::Body($crate::body_internal!(@structures [] $($tt)*))
168    };
169}
170
171/// Construct an `hcl::Structure` which may be either an HCL attribute or block.
172///
173/// For supported syntax see the [`body!`] macro documentation.
174///
175/// # Example
176///
177/// ```
178/// use hcl::{Attribute, Block, Structure};
179///
180/// assert_eq!(
181///     hcl::structure!(foo = "bar"),
182///     Structure::Attribute(Attribute::new("foo", "bar")),
183/// );
184///
185/// assert_eq!(
186///     hcl::structure!(
187///         resource "aws_s3_bucket" "bucket" {
188///             name = "the-bucket"
189///         }
190///     ),
191///     Structure::Block(
192///         Block::builder("resource")
193///             .add_labels(["aws_s3_bucket", "bucket"])
194///             .add_attribute(("name", "the-bucket"))
195///             .build()
196///     ),
197/// );
198/// ```
199#[macro_export]
200macro_rules! structure {
201    // Hide distracting implementation details from the generated rustdoc.
202    ($($structure:tt)+) => {
203        $crate::structure_internal!($($structure)+)
204    };
205}
206
207#[macro_export]
208#[doc(hidden)]
209macro_rules! structure_internal {
210    // Structure in braces.
211    ({ $($structure:tt)+ }) => {
212        $crate::structure_internal!($($structure)+)
213    };
214
215    // An attribute structure.
216    ($key:tt = $($expr:tt)+) => {
217        $crate::structure::Structure::Attribute($crate::attribute!($key = $($expr)+))
218    };
219
220    // A block structure.
221    ($($block:tt)+) => {
222        $crate::structure::Structure::Block($crate::block!($($block)+))
223    };
224}
225
226/// Construct an `hcl::Attribute` from a key and a value expression.
227///
228/// For supported syntax see the [`body!`] macro documentation.
229///
230/// # Example
231///
232/// ```
233/// use hcl::Attribute;
234///
235/// assert_eq!(hcl::attribute!(foo = "bar"), Attribute::new("foo", "bar"));
236/// ```
237#[macro_export]
238macro_rules! attribute {
239    // Hide distracting implementation details from the generated rustdoc.
240    ($($attr:tt)+) => {
241        $crate::attribute_internal!($($attr)+)
242    };
243}
244
245#[macro_export]
246#[doc(hidden)]
247macro_rules! attribute_internal {
248    // Attribute in curly braces.
249    ({ $($attribute:tt)+ }) => {
250        $crate::attribute_internal!($($attribute)+)
251    };
252
253    // Attribute with expression as key.
254    (($key:expr) = $($expr:tt)+) => {
255        $crate::Attribute {
256            key: ($key).into(),
257            expr: $crate::expression_internal!($($expr)+),
258        }
259    };
260
261    // Attribute with identifier as key.
262    ($key:ident = $($expr:tt)+) => {
263        $crate::attribute_internal!((std::stringify!($key)) = $($expr)+)
264    };
265}
266
267/// Construct an `hcl::Block` from a block identifier, optional block labels and a block body.
268///
269/// For supported syntax see the [`body!`] macro documentation.
270///
271/// # Example
272///
273/// ```
274/// use hcl::Block;
275///
276/// assert_eq!(
277///     hcl::block!(
278///         resource "aws_s3_bucket" "bucket" {
279///             name = "the-bucket"
280///         }
281///     ),
282///     Block::builder("resource")
283///         .add_labels(["aws_s3_bucket", "bucket"])
284///         .add_attribute(("name", "the-bucket"))
285///         .build(),
286/// );
287/// ```
288#[macro_export]
289macro_rules! block {
290    // Hide distracting implementation details from the generated rustdoc.
291    ($($block:tt)+) => {
292        $crate::block_internal!($($block)+)
293    };
294}
295
296#[macro_export]
297#[doc(hidden)]
298macro_rules! block_internal {
299    // Block in curly braces.
300    ({ $($block:tt)+ }) => {
301        $crate::block_internal!($($block)+)
302    };
303
304    // Munch an identifier label.
305    (($ident:expr) [$(($labels:expr))*] $label:ident $($rest:tt)+) => {
306        $crate::block_internal!(($ident) [$(($labels))* ($crate::block_label!($label))] $($rest)+)
307    };
308
309    // Munch a literal expression label.
310    (($ident:expr) [$(($labels:expr))*] $label:literal $($rest:tt)+) => {
311        $crate::block_internal!(($ident) [$(($labels))* ($crate::block_label!($label))] $($rest)+)
312    };
313
314    // Munch an expression label.
315    (($ident:expr) [$(($labels:expr))*] ($label:expr) $($rest:tt)+) => {
316        $crate::block_internal!(($ident) [$(($labels))* ($crate::block_label!(($label)))] $($rest)+)
317    };
318
319    // Found block body, done.
320    (($ident:expr) [$(($labels:expr))*] {$($body:tt)*}) => {
321        $crate::Block {
322            identifier: ($ident).into(),
323            labels: std::vec![$($labels),*],
324            body: $crate::body!($($body)*),
325        }
326    };
327
328    // Munch expression as block identifier.
329    (($ident:expr) $($rest:tt)+) => {
330        $crate::block_internal!(($ident) [] $($rest)+)
331    };
332
333    // Munch normal block identifier.
334    ($ident:ident $($rest:tt)+) => {
335        $crate::block_internal!((std::stringify!($ident)) [] $($rest)+)
336    };
337}
338
339#[macro_export]
340#[doc(hidden)]
341macro_rules! block_label {
342    ($ident:ident) => {
343        $crate::structure::BlockLabel::Identifier($crate::Identifier::unchecked(std::stringify!(
344            $ident
345        )))
346    };
347
348    (($expr:expr)) => {
349        $crate::structure::BlockLabel::String(($expr).into())
350    };
351
352    ($literal:literal) => {
353        $crate::block_label!(($literal))
354    };
355}
356
357#[macro_export]
358#[doc(hidden)]
359macro_rules! object_key {
360    ($ident:ident) => {
361        $crate::expr::ObjectKey::Identifier($crate::Identifier::unchecked(std::stringify!($ident)))
362    };
363
364    (($expr:expr)) => {
365        $crate::expr::ObjectKey::Expression($crate::expression!($expr))
366    };
367
368    ($literal:literal) => {
369        $crate::object_key!(($literal))
370    };
371}
372
373/// Construct an `hcl::Expression` from an HCL attribute value expression literal.
374///
375/// For supported syntax see the [`body!`] macro documentation.
376///
377/// # Example
378///
379/// ```
380/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
381/// use hcl::{Expression, Identifier, Object, ObjectKey};
382///
383/// let other = "hello";
384///
385/// let expression = hcl::expression!({
386///     foo       = true
387///     "baz qux" = [1, 2]
388///     (other)   = "world"
389/// });
390///
391/// let expected = Expression::Object(Object::from([
392///     (ObjectKey::from(Identifier::new("foo")?), true.into()),
393///     (ObjectKey::from("baz qux"), vec![1u64, 2].into()),
394///     (ObjectKey::from("hello"), "world".into()),
395/// ]));
396///
397/// assert_eq!(expression, expected);
398/// #     Ok(())
399/// # }
400/// ```
401#[macro_export]
402macro_rules! expression {
403    // Hide distracting implementation details from the generated rustdoc.
404    ($($expr:tt)+) => {
405        $crate::expression_internal!($($expr)+)
406    };
407}
408
409#[macro_export]
410#[doc(hidden)]
411macro_rules! expression_internal {
412    //////////////////////////////////////////////////////////////////////////
413    // TT muncher for parsing the inside of an array [...].
414    //
415    // Produces a vec![...] of the elements.
416    //
417    // Must be invoked as: expression_internal!(@array [] $($tt)*)
418    //////////////////////////////////////////////////////////////////////////
419
420    // Done with trailing comma.
421    (@array [$($elems:expr,)*]) => {
422        std::vec![$($elems,)*]
423    };
424
425    // Done without trailing comma.
426    (@array [$($elems:expr),*]) => {
427        std::vec![$($elems),*]
428    };
429
430    // Next element is `null`.
431    (@array [$($elems:expr,)*] null $($rest:tt)*) => {
432        $crate::expression_internal!(@array [$($elems,)* $crate::expression_internal!(null)] $($rest)*)
433    };
434
435    // Next element is `true`.
436    (@array [$($elems:expr,)*] true $($rest:tt)*) => {
437        $crate::expression_internal!(@array [$($elems,)* $crate::expression_internal!(true)] $($rest)*)
438    };
439
440    // Next element is `false`.
441    (@array [$($elems:expr,)*] false $($rest:tt)*) => {
442        $crate::expression_internal!(@array [$($elems,)* $crate::expression_internal!(false)] $($rest)*)
443    };
444
445    // Next element is an array.
446    (@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => {
447        $crate::expression_internal!(@array [$($elems,)* $crate::expression_internal!([$($array)*])] $($rest)*)
448    };
449
450    // Next element is a map.
451    (@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => {
452        $crate::expression_internal!(@array [$($elems,)* $crate::expression_internal!({$($map)*})] $($rest)*)
453    };
454
455    // Next element is an expression followed by comma.
456    (@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => {
457        $crate::expression_internal!(@array [$($elems,)* $crate::expression_internal!($next),] $($rest)*)
458    };
459
460    // Last element is an expression with no trailing comma.
461    (@array [$($elems:expr,)*] $last:expr) => {
462        $crate::expression_internal!(@array [$($elems,)* $crate::expression_internal!($last)])
463    };
464
465    // Comma after the most recent element.
466    (@array [$($elems:expr),*] , $($rest:tt)*) => {
467        $crate::expression_internal!(@array [$($elems,)*] $($rest)*)
468    };
469
470    // Unexpected token after most recent element.
471    (@array [$($elems:expr),*] $unexpected:tt $($rest:tt)*) => {
472        $crate::hcl_unexpected!($unexpected)
473    };
474
475    //////////////////////////////////////////////////////////////////////////
476    // TT muncher for parsing the inside of an object {...}. Each entry is
477    // inserted into the given map variable.
478    //
479    // Must be invoked as: expression_internal!(@object $map () ($($tt)*) ($($tt)*))
480    //
481    // We require two copies of the input tokens so that we can match on one
482    // copy and trigger errors on the other copy.
483    //////////////////////////////////////////////////////////////////////////
484
485    // Done.
486    (@object $object:ident () () ()) => {};
487
488    // Insert the current entry followed by trailing comma.
489    (@object $object:ident [$key:expr] ($value:expr) , $($rest:tt)*) => {
490        let _ = $object.insert($key, $value);
491        $crate::expression_internal!(@object $object () ($($rest)*) ($($rest)*));
492    };
493
494    // Insert the current entry not followed by trailing comma.
495    (@object $object:ident [$key:expr] ($value:expr) $($rest:tt)*) => {
496        let _ = $object.insert($key, $value);
497        $crate::expression_internal!(@object $object () ($($rest)*) ($($rest)*));
498    };
499
500    // Insert the last entry without trailing comma.
501    (@object $object:ident [$key:expr] ($value:expr)) => {
502        let _ = $object.insert($key, $value);
503    };
504
505    // Next value is `null`.
506    (@object $object:ident ($key:expr) (= null $($rest:tt)*) $copy:tt) => {
507        $crate::expression_internal!(@object $object [$key] ($crate::expression_internal!(null)) $($rest)*);
508    };
509
510    // Next value is `true`.
511    (@object $object:ident ($key:expr) (= true $($rest:tt)*) $copy:tt) => {
512        $crate::expression_internal!(@object $object [$key] ($crate::expression_internal!(true)) $($rest)*);
513    };
514
515    // Next value is `false`.
516    (@object $object:ident ($key:expr) (= false $($rest:tt)*) $copy:tt) => {
517        $crate::expression_internal!(@object $object [$key] ($crate::expression_internal!(false)) $($rest)*);
518    };
519
520    // Next value is an array.
521    (@object $object:ident ($key:expr) (= [$($array:tt)*] $($rest:tt)*) $copy:tt) => {
522        $crate::expression_internal!(@object $object [$key] ($crate::expression_internal!([$($array)*])) $($rest)*);
523    };
524
525    // Next value is a map.
526    (@object $object:ident ($key:expr) (= {$($map:tt)*} $($rest:tt)*) $copy:tt) => {
527        $crate::expression_internal!(@object $object [$key] ($crate::expression_internal!({$($map)*})) $($rest)*);
528    };
529
530    // Next value is an expression followed by comma.
531    (@object $object:ident ($key:expr) (= $value:expr , $($rest:tt)*) $copy:tt) => {
532        $crate::expression_internal!(@object $object [$key] ($crate::expression_internal!($value)) , $($rest)*);
533    };
534
535    // Next value is an expression not followed by comma.
536    (@object $object:ident ($key:expr) (= $value:tt $($rest:tt)*) $copy:tt) => {
537        $crate::expression_internal!(@object $object [$key] ($crate::expression_internal!($value)) $($rest)*);
538    };
539
540    // Last value is an expression with no trailing comma.
541    (@object $object:ident ($key:expr) (= $value:expr) $copy:tt) => {
542        $crate::expression_internal!(@object $object [$key] ($crate::expression_internal!($value)));
543    };
544
545    // Missing value for last entry. Trigger a reasonable error message.
546    (@object $object:ident ($key:expr) (=) $copy:tt) => {
547        // "unexpected end of macro invocation"
548        $crate::expression_internal!();
549    };
550
551    // Missing equals and value for last entry. Trigger a reasonable error
552    // message.
553    (@object $object:ident ($key:expr) () $copy:tt) => {
554        // "unexpected end of macro invocation"
555        $crate::expression_internal!();
556    };
557
558    // Misplaced equals. Trigger a reasonable error message.
559    (@object $object:ident () (= $($rest:tt)*) ($equals:tt $($copy:tt)*)) => {
560        // Takes no arguments so "no rules expected the token `:`".
561        $crate::hcl_unexpected!($equals);
562    };
563
564    // Found a comma inside a key. Trigger a reasonable error message.
565    (@object $object:ident ($key:expr) (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => {
566        // Takes no arguments so "no rules expected the token `,`".
567        $crate::hcl_unexpected!($comma);
568    };
569
570    // Refuse to absorb equals token into key expression.
571    (@object $object:ident ($key:expr) (= $($unexpected:tt)+) $copy:tt) => {
572        $crate::hcl_expect_expr_comma!($($unexpected)+);
573    };
574
575    // Munch an identifier key.
576    (@object $object:ident () ($key:ident $($rest:tt)*) $copy:tt) => {
577        $crate::expression_internal!(@object $object ($crate::object_key!($key)) ($($rest)*) ($($rest)*));
578    };
579
580    // Munch a literal key.
581    (@object $object:ident () ($key:literal $($rest:tt)*) $copy:tt) => {
582        $crate::expression_internal!(@object $object ($crate::object_key!($key)) ($($rest)*) ($($rest)*));
583    };
584
585    // Munch a parenthesized expression key.
586    (@object $object:ident () (($key:expr) $($rest:tt)*) $copy:tt) => {
587        $crate::expression_internal!(@object $object ($crate::object_key!(($key))) ($($rest)*) ($($rest)*));
588    };
589
590    //////////////////////////////////////////////////////////////////////////
591    // The main implementation.
592    //
593    // Must be invoked as: expression_internal!($($expr)+)
594    //////////////////////////////////////////////////////////////////////////
595
596    (null) => {
597        $crate::expr::Expression::Null
598    };
599
600    (true) => {
601        $crate::expr::Expression::Bool(true)
602    };
603
604    (false) => {
605        $crate::expr::Expression::Bool(false)
606    };
607
608    ([]) => {
609        $crate::expr::Expression::Array(std::vec![])
610    };
611
612    ([ $($tt:tt)+ ]) => {
613        $crate::expr::Expression::Array($crate::expression_internal!(@array [] $($tt)+))
614    };
615
616    ({}) => {
617        $crate::expr::Expression::Object($crate::expr::Object::new())
618    };
619
620    ({ $($tt:tt)+ }) => {
621        $crate::expr::Expression::Object({
622            let mut object = $crate::expr::Object::new();
623            $crate::expression_internal!(@object object () ($($tt)+) ($($tt)+));
624            object
625        })
626    };
627
628    // Any Serialize type: numbers, strings, struct literals, variables etc.
629    // Must be below every other rule.
630    ($other:expr) => {
631        $crate::expr::to_expression(&$other).unwrap()
632    };
633}
634
635/// Construct an `hcl::Value` from an HCL attribute value value literal.
636///
637/// Supports the same input syntax as the [`expression!`] macro, with the exception of raw value
638/// expressions.
639///
640/// For supported syntax see the [`body!`] macro documentation.
641///
642/// # Example
643///
644/// ```
645/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
646/// use hcl::{Value, Identifier, Map};
647///
648/// let other = "hello";
649///
650/// let value = hcl::value!({
651///     foo       = true
652///     "baz qux" = [1, 2]
653///     (other)   = "world"
654/// });
655///
656/// let expected = Value::Object({
657///     let mut object = Map::new();
658///     object.insert("foo".into(), true.into());
659///     object.insert("baz qux".into(), vec![1u64, 2].into());
660///     object.insert("hello".into(), "world".into());
661///     object
662/// });
663///
664/// assert_eq!(value, expected);
665/// #     Ok(())
666/// # }
667/// ```
668#[macro_export]
669macro_rules! value {
670    // Hide distracting implementation details from the generated rustdoc.
671    ($($expr:tt)+) => {
672        $crate::value_internal!($($expr)+)
673    };
674}
675
676#[macro_export]
677#[doc(hidden)]
678macro_rules! value_internal {
679    //////////////////////////////////////////////////////////////////////////
680    // TT muncher for parsing the inside of an array [...].
681    //
682    // Produces a vec![...] of the elements.
683    //
684    // Must be invoked as: value_internal!(@array [] $($tt)*)
685    //////////////////////////////////////////////////////////////////////////
686
687    // Done with trailing comma.
688    (@array [$($elems:expr,)*]) => {
689        std::vec![$($elems,)*]
690    };
691
692    // Done without trailing comma.
693    (@array [$($elems:expr),*]) => {
694        std::vec![$($elems),*]
695    };
696
697    // Next element is `null`.
698    (@array [$($elems:expr,)*] null $($rest:tt)*) => {
699        $crate::value_internal!(@array [$($elems,)* $crate::value_internal!(null)] $($rest)*)
700    };
701
702    // Next element is `true`.
703    (@array [$($elems:expr,)*] true $($rest:tt)*) => {
704        $crate::value_internal!(@array [$($elems,)* $crate::value_internal!(true)] $($rest)*)
705    };
706
707    // Next element is `false`.
708    (@array [$($elems:expr,)*] false $($rest:tt)*) => {
709        $crate::value_internal!(@array [$($elems,)* $crate::value_internal!(false)] $($rest)*)
710    };
711
712    // Next element is an array.
713    (@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => {
714        $crate::value_internal!(@array [$($elems,)* $crate::value_internal!([$($array)*])] $($rest)*)
715    };
716
717    // Next element is a map.
718    (@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => {
719        $crate::value_internal!(@array [$($elems,)* $crate::value_internal!({$($map)*})] $($rest)*)
720    };
721
722    // Next element is an value followed by comma.
723    (@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => {
724        $crate::value_internal!(@array [$($elems,)* $crate::value_internal!($next),] $($rest)*)
725    };
726
727    // Last element is an value with no trailing comma.
728    (@array [$($elems:expr,)*] $last:expr) => {
729        $crate::value_internal!(@array [$($elems,)* $crate::value_internal!($last)])
730    };
731
732    // Comma after the most recent element.
733    (@array [$($elems:expr),*] , $($rest:tt)*) => {
734        $crate::value_internal!(@array [$($elems,)*] $($rest)*)
735    };
736
737    // Unexpected token after most recent element.
738    (@array [$($elems:expr),*] $unexpected:tt $($rest:tt)*) => {
739        $crate::hcl_unexpected!($unexpected)
740    };
741
742    //////////////////////////////////////////////////////////////////////////
743    // TT muncher for parsing the inside of an object {...}. Each entry is
744    // inserted into the given map variable.
745    //
746    // Must be invoked as: value_internal!(@object $map () ($($tt)*) ($($tt)*))
747    //
748    // We require two copies of the input tokens so that we can match on one
749    // copy and trigger errors on the other copy.
750    //////////////////////////////////////////////////////////////////////////
751
752    // Done.
753    (@object $object:ident () () ()) => {};
754
755    // Insert the current entry followed by trailing comma.
756    (@object $object:ident [$key:expr] ($value:expr) , $($rest:tt)*) => {
757        let _ = $object.insert(($key).into(), $value);
758        $crate::value_internal!(@object $object () ($($rest)*) ($($rest)*));
759    };
760
761    // Insert the current entry not followed by trailing comma.
762    (@object $object:ident [$key:expr] ($value:expr) $($rest:tt)*) => {
763        let _ = $object.insert(($key).into(), $value);
764        $crate::value_internal!(@object $object () ($($rest)*) ($($rest)*));
765    };
766
767    // Insert the last entry without trailing comma.
768    (@object $object:ident [$key:expr] ($value:expr)) => {
769        let _ = $object.insert(($key).into(), $value);
770    };
771
772    // Next value is `null`.
773    (@object $object:ident ($key:expr) (= null $($rest:tt)*) $copy:tt) => {
774        $crate::value_internal!(@object $object [$key] ($crate::value_internal!(null)) $($rest)*);
775    };
776
777    // Next value is `true`.
778    (@object $object:ident ($key:expr) (= true $($rest:tt)*) $copy:tt) => {
779        $crate::value_internal!(@object $object [$key] ($crate::value_internal!(true)) $($rest)*);
780    };
781
782    // Next value is `false`.
783    (@object $object:ident ($key:expr) (= false $($rest:tt)*) $copy:tt) => {
784        $crate::value_internal!(@object $object [$key] ($crate::value_internal!(false)) $($rest)*);
785    };
786
787    // Next value is an array.
788    (@object $object:ident ($key:expr) (= [$($array:tt)*] $($rest:tt)*) $copy:tt) => {
789        $crate::value_internal!(@object $object [$key] ($crate::value_internal!([$($array)*])) $($rest)*);
790    };
791
792    // Next value is a map.
793    (@object $object:ident ($key:expr) (= {$($map:tt)*} $($rest:tt)*) $copy:tt) => {
794        $crate::value_internal!(@object $object [$key] ($crate::value_internal!({$($map)*})) $($rest)*);
795    };
796
797    // Next value is an value followed by comma.
798    (@object $object:ident ($key:expr) (= $value:expr , $($rest:tt)*) $copy:tt) => {
799        $crate::value_internal!(@object $object [$key] ($crate::value_internal!($value)) , $($rest)*);
800    };
801
802    // Next value is an value not followed by comma.
803    (@object $object:ident ($key:expr) (= $value:tt $($rest:tt)*) $copy:tt) => {
804        $crate::value_internal!(@object $object [$key] ($crate::value_internal!($value)) $($rest)*);
805    };
806
807    // Last value is an value with no trailing comma.
808    (@object $object:ident ($key:expr) (= $value:expr) $copy:tt) => {
809        $crate::value_internal!(@object $object [$key] ($crate::value_internal!($value)));
810    };
811
812    // Missing value for last entry. Trigger a reasonable error message.
813    (@object $object:ident ($key:expr) (=) $copy:tt) => {
814        // "unexpected end of macro invocation"
815        $crate::value_internal!();
816    };
817
818    // Missing equals and value for last entry. Trigger a reasonable error
819    // message.
820    (@object $object:ident ($key:expr) () $copy:tt) => {
821        // "unexpected end of macro invocation"
822        $crate::value_internal!();
823    };
824
825    // Misplaced equals. Trigger a reasonable error message.
826    (@object $object:ident () (= $($rest:tt)*) ($equals:tt $($copy:tt)*)) => {
827        // Takes no arguments so "no rules expected the token `:`".
828        $crate::hcl_unexpected!($equals);
829    };
830
831    // Found a comma inside a key. Trigger a reasonable error message.
832    (@object $object:ident ($key:expr) (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => {
833        // Takes no arguments so "no rules expected the token `,`".
834        $crate::hcl_unexpected!($comma);
835    };
836
837    // Refuse to absorb equals token into key value.
838    (@object $object:ident ($key:expr) (= $($unexpected:tt)+) $copy:tt) => {
839        $crate::hcl_expect_expr_comma!($($unexpected)+);
840    };
841
842    // Munch an identifier key.
843    (@object $object:ident () ($key:ident $($rest:tt)*) $copy:tt) => {
844        $crate::value_internal!(@object $object ((std::stringify!($key))) ($($rest)*) ($($rest)*));
845    };
846
847    // Munch a literal key.
848    (@object $object:ident () ($key:literal $($rest:tt)*) $copy:tt) => {
849        $crate::value_internal!(@object $object (($key)) ($($rest)*) ($($rest)*));
850    };
851
852    // Munch a parenthesized value key.
853    (@object $object:ident () (($key:expr) $($rest:tt)*) $copy:tt) => {
854        $crate::value_internal!(@object $object (($key)) ($($rest)*) ($($rest)*));
855    };
856
857    //////////////////////////////////////////////////////////////////////////
858    // The main implementation.
859    //
860    // Must be invoked as: value_internal!($($expr)+)
861    //////////////////////////////////////////////////////////////////////////
862
863    (null) => {
864        $crate::value::Value::Null
865    };
866
867    (true) => {
868        $crate::value::Value::Bool(true)
869    };
870
871    (false) => {
872        $crate::value::Value::Bool(false)
873    };
874
875    ([]) => {
876        $crate::value::Value::Array(std::vec![])
877    };
878
879    ([ $($tt:tt)+ ]) => {
880        $crate::value::Value::Array($crate::value_internal!(@array [] $($tt)+))
881    };
882
883    ({}) => {
884        $crate::value::Value::Object($crate::value::Map::new())
885    };
886
887    ({ $($tt:tt)+ }) => {
888        $crate::value::Value::Object({
889            let mut object = $crate::value::Map::new();
890            $crate::value_internal!(@object object () ($($tt)+) ($($tt)+));
891            object
892        })
893    };
894
895    // Any Serialize type: numbers, strings, struct literals, variables etc.
896    // Must be below every other rule.
897    ($other:expr) => {
898        $crate::value::to_value(&$other).unwrap()
899    };
900}
901
902#[macro_export]
903#[doc(hidden)]
904macro_rules! hcl_unexpected {
905    () => {};
906}
907
908#[macro_export]
909#[doc(hidden)]
910macro_rules! hcl_expect_expr_comma {
911    ($e:expr , $($tt:tt)*) => {};
912}
913
914#[macro_export]
915#[doc(hidden)]
916macro_rules! serialize_unsupported {
917    (bool) => {
918        $crate::serialize_unsupported_method!{serialize_bool(v: bool)}
919    };
920    (i8) => {
921        $crate::serialize_unsupported_method!{serialize_i8(v: i8)}
922    };
923    (i16) => {
924        $crate::serialize_unsupported_method!{serialize_i16(v: i16)}
925    };
926    (i32) => {
927        $crate::serialize_unsupported_method!{serialize_i32(v: i32)}
928    };
929    (i64) => {
930        $crate::serialize_unsupported_method!{serialize_i64(v: i64)}
931    };
932    (i128) => {
933        serde::serde_if_integer128! {
934            $crate::serialize_unsupported_method!{serialize_i128(v: i128)}
935        }
936    };
937    (u8) => {
938        $crate::serialize_unsupported_method!{serialize_u8(v: u8)}
939    };
940    (u16) => {
941        $crate::serialize_unsupported_method!{serialize_u16(v: u16)}
942    };
943    (u32) => {
944        $crate::serialize_unsupported_method!{serialize_u32(v: u32)}
945    };
946    (u64) => {
947        $crate::serialize_unsupported_method!{serialize_u64(v: u64)}
948    };
949    (u128) => {
950        serde::serde_if_integer128! {
951            $crate::serialize_unsupported_method!{serialize_u128(v: u128)}
952        }
953    };
954    (f32) => {
955        $crate::serialize_unsupported_method!{serialize_f32(v: f32)}
956    };
957    (f64) => {
958        $crate::serialize_unsupported_method!{serialize_f64(v: f64)}
959    };
960    (char) => {
961        $crate::serialize_unsupported_method!{serialize_char(v: char)}
962    };
963    (str) => {
964        $crate::serialize_unsupported_method!{serialize_str(v: &str)}
965    };
966    (bytes) => {
967        $crate::serialize_unsupported_method!{serialize_bytes(v: &[u8])}
968    };
969    (some) => {
970        $crate::serialize_unsupported_method!{serialize_some<T>(value: &T)}
971    };
972    (none) => {
973        $crate::serialize_unsupported_method!{serialize_none()}
974    };
975    (unit) => {
976        $crate::serialize_unsupported_method!{serialize_unit()}
977    };
978    (unit_struct) => {
979        $crate::serialize_unsupported_method!{serialize_unit_struct(name: &'static str)}
980    };
981    (unit_variant) => {
982        $crate::serialize_unsupported_method!{serialize_unit_variant(name: &'static str, variant_index: u32, variant: &'static str)}
983    };
984    (newtype_struct) => {
985        $crate::serialize_unsupported_method!{serialize_newtype_struct<T>(name: &'static str, value: &T)}
986    };
987    (newtype_variant) => {
988        $crate::serialize_unsupported_method!{serialize_newtype_variant<T>(name: &'static str, variant_index: u32, variant: &'static str, value: &T)}
989    };
990    (seq) => {
991        $crate::serialize_unsupported_method!{serialize_seq(len: Option<usize>) -> Result<SerializeSeq>}
992    };
993    (tuple) => {
994        $crate::serialize_unsupported_method!{serialize_tuple(len: usize) -> Result<SerializeTuple>}
995    };
996    (tuple_struct) => {
997        $crate::serialize_unsupported_method!{serialize_tuple_struct(name: &'static str, len: usize) -> Result<SerializeTupleStruct>}
998    };
999    (tuple_variant) => {
1000        $crate::serialize_unsupported_method!{serialize_tuple_variant(name: &'static str, variant_index: u32, variant: &'static str, len: usize) -> Result<SerializeTupleVariant>}
1001    };
1002    (map) => {
1003        $crate::serialize_unsupported_method!{serialize_map(len: Option<usize>) -> Result<SerializeMap>}
1004    };
1005    (struct) => {
1006        $crate::serialize_unsupported_method!{serialize_struct(name: &'static str, len: usize) -> Result<SerializeStruct>}
1007    };
1008    (struct_variant) => {
1009        $crate::serialize_unsupported_method!{serialize_struct_variant(name: &'static str, variant_index: u32, variant: &'static str, len: usize) -> Result<SerializeStructVariant>}
1010    };
1011    ($($func:ident)*) => {
1012        $($crate::serialize_unsupported!{$func})*
1013    };
1014}
1015
1016#[macro_export]
1017#[doc(hidden)]
1018macro_rules! serialize_unsupported_method {
1019    ($func:ident<T>($($arg:ident : $ty:ty),*)) => {
1020        #[inline]
1021        fn $func<T>(self, $($arg: $ty,)*) -> $crate::Result<Self::Ok, Self::Error>
1022        where
1023            T: ?Sized + serde::ser::Serialize,
1024        {
1025            $(
1026                let _ = $arg;
1027            )*
1028            Err(serde::ser::Error::custom(std::format!("`{}` not supported", std::stringify!($func))))
1029        }
1030    };
1031    ($func:ident($($arg:ident : $ty:ty),*) -> Result<$rty:ident>) => {
1032        #[inline]
1033        fn $func(self, $($arg: $ty,)*) -> $crate::Result<Self::$rty, Self::Error> {
1034            $(
1035                let _ = $arg;
1036            )*
1037            Err(serde::ser::Error::custom(std::format!("`{}` not supported", std::stringify!($func))))
1038        }
1039    };
1040    ($func:ident($($arg:ident : $ty:ty),*)) => {
1041        #[inline]
1042        fn $func(self, $($arg: $ty,)*) -> $crate::Result<Self::Ok, Self::Error> {
1043            $(
1044                let _ = $arg;
1045            )*
1046            Err(serde::ser::Error::custom(std::format!("`{}` not supported", std::stringify!($func))))
1047        }
1048    };
1049}
1050
1051#[macro_export]
1052#[doc(hidden)]
1053macro_rules! serialize_self {
1054    (some) => {
1055        $crate::serialize_self_method!{serialize_some()}
1056    };
1057    (newtype_struct) => {
1058        $crate::serialize_self_method!{serialize_newtype_struct(name: &'static str)}
1059    };
1060    (newtype_variant) => {
1061        $crate::serialize_self_method!{serialize_newtype_variant(name: &'static str, variant_index: u32, variant: &'static str)}
1062    };
1063    ($($func:ident)*) => {
1064        $($crate::serialize_self!{$func})*
1065    };
1066}
1067
1068#[macro_export]
1069#[doc(hidden)]
1070macro_rules! serialize_self_method {
1071    ($func:ident($($arg:ident : $ty:ty),*)) => {
1072        #[inline]
1073        fn $func<T>(self, $($arg: $ty,)* value: &T) -> $crate::Result<Self::Ok, Self::Error>
1074        where
1075            T: ?Sized + serde::ser::Serialize,
1076        {
1077            $(
1078                let _ = $arg;
1079            )*
1080            value.serialize(self)
1081        }
1082    };
1083}
1084
1085#[macro_export]
1086#[doc(hidden)]
1087macro_rules! forward_to_serialize_seq {
1088    (tuple) => {
1089        $crate::forward_to_serialize_seq_method!{serialize_tuple() -> Result<SerializeTuple>}
1090    };
1091    (tuple_struct) => {
1092        $crate::forward_to_serialize_seq_method!{serialize_tuple_struct(name: &'static str) -> Result<SerializeTupleStruct>}
1093    };
1094    ($($func:ident)*) => {
1095        $($crate::forward_to_serialize_seq!{$func})*
1096    };
1097}
1098
1099#[macro_export]
1100#[doc(hidden)]
1101macro_rules! forward_to_serialize_seq_method {
1102    ($func:ident($($arg:ident : $ty:ty),*) -> Result<$rty:ident>) => {
1103        #[inline]
1104        fn $func(self, $($arg: $ty,)* len: usize) -> $crate::Result<Self::$rty, Self::Error> {
1105            $(
1106                let _ = $arg;
1107            )*
1108            self.serialize_seq(Some(len))
1109        }
1110    };
1111}
1112
1113#[macro_export]
1114#[doc(hidden)]
1115macro_rules! impl_forward_to_serialize_seq {
1116    ($method:ident, $ok:ty, $error:ty) => {
1117        type Ok = $ok;
1118        type Error = $error;
1119        impl_forward_to_serialize_seq!($method);
1120    };
1121    ($method:ident, $ok:ty) => {
1122        impl_forward_to_serialize_seq!($method, $ok, $crate::Error);
1123    };
1124    ($method:ident) => {
1125        fn $method<T>(&mut self, value: &T) -> $crate::Result<(), Self::Error>
1126        where
1127            T: ?Sized + serde::ser::Serialize,
1128        {
1129            serde::ser::SerializeSeq::serialize_element(self, value)
1130        }
1131
1132        fn end(self) -> $crate::Result<Self::Ok, Self::Error> {
1133            serde::ser::SerializeSeq::end(self)
1134        }
1135    };
1136}
1137
1138#[macro_export]
1139#[doc(hidden)]
1140macro_rules! impl_forward_to_inner {
1141    ($ty:ty, $($tt:tt)+) => {
1142        type Ok = $ty;
1143        type Error = $crate::Error;
1144
1145        impl_forward_to_inner_internal!($($tt)+);
1146
1147        fn end(self) -> $crate::Result<Self::Ok, Self::Error> {
1148            self.inner.end().map(Into::into)
1149        }
1150    };
1151}
1152
1153#[macro_export]
1154#[doc(hidden)]
1155macro_rules! impl_forward_to_inner_internal {
1156    ($method:ident($($arg:ident: $ty:ty),*) $(,$rest:tt)*) => {
1157        fn $method<T>(&mut self, $($arg: $ty,)* value: &T) -> $crate::Result<(), Self::Error>
1158        where
1159            T: ?Sized + serde::ser::Serialize,
1160        {
1161            self.inner.$method($($arg,)* value)
1162        }
1163
1164        impl_forward_to_inner_internal!($($rest),*);
1165    };
1166    ($method:ident $(,$rest:tt)*) => {
1167        impl_forward_to_inner_internal!($method() $(,$rest)*);
1168    };
1169    () => {};
1170}
1171
1172#[macro_export]
1173#[doc(hidden)]
1174macro_rules! impl_deserialize_enum {
1175    () => {
1176        fn deserialize_enum<V>(
1177            self,
1178            _name: &'static str,
1179            _variants: &'static [&'static str],
1180            visitor: V,
1181        ) -> $crate::Result<V::Value, Self::Error>
1182        where
1183            V: serde::de::Visitor<'de>,
1184        {
1185            visitor.visit_enum($crate::de::EnumAccess::new(self))
1186        }
1187    };
1188}
1189
1190#[macro_export]
1191#[doc(hidden)]
1192macro_rules! impl_variant_name {
1193    ($($ty:ident => { $($variant:ident),+ }),*) => {
1194        $(
1195            impl $crate::de::VariantName for $ty {
1196                fn variant_name(&self) -> &'static str {
1197                    match self {
1198                        $(
1199                            $ty::$variant { .. } => std::stringify!($variant),
1200                        )*
1201                    }
1202                }
1203            }
1204        )*
1205    };
1206}
1207
1208#[macro_export]
1209#[doc(hidden)]
1210macro_rules! impl_into_map_access_deserializer {
1211    ($($ty:ty => $access:ident),*) => {
1212        $(
1213            impl<'de> serde::de::IntoDeserializer<'de, Error> for $ty {
1214                type Deserializer = serde::de::value::MapAccessDeserializer<$access>;
1215
1216                fn into_deserializer(self) -> Self::Deserializer {
1217                    serde::de::value::MapAccessDeserializer::new($access::new(self))
1218                }
1219            }
1220        )*
1221    };
1222}