hcl/structure/
body.rs

1//! Types to represent and build HCL body structures.
2
3use super::iter::{
4    Attributes, AttributesMut, Blocks, BlocksMut, IntoAttributes, IntoBlocks, Iter, IterMut,
5};
6use super::ser::BodySerializer;
7use super::{Attribute, Block, Structure};
8use crate::ser::with_internal_serialization;
9use crate::{Error, Result};
10use serde::{Deserialize, Serialize};
11use std::str::FromStr;
12
13/// Represents an HCL config file body.
14///
15/// A `Body` consists of zero or more [`Attribute`] and [`Block`] HCL structures.
16#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Default, Clone)]
17#[serde(rename = "$hcl::Body")]
18pub struct Body(pub Vec<Structure>);
19
20impl Body {
21    #[doc(hidden)]
22    pub fn from_serializable<T>(value: &T) -> Result<Body>
23    where
24        T: ?Sized + Serialize,
25    {
26        with_internal_serialization(|| value.serialize(BodySerializer))
27    }
28
29    /// Consumes `self` and returns the wrapped `Vec<Structure>`.
30    pub fn into_inner(self) -> Vec<Structure> {
31        self.0
32    }
33
34    /// Creates a new [`BodyBuilder`] to start building a new `Body`.
35    pub fn builder() -> BodyBuilder {
36        BodyBuilder::default()
37    }
38
39    /// An iterator visiting all structures within the `Body`. The iterator element type is `&'a
40    /// Structure`.
41    ///
42    /// # Examples
43    ///
44    /// ```
45    /// use hcl::{Attribute, Body};
46    ///
47    /// let body = Body::from([
48    ///     Attribute::new("a", 1),
49    ///     Attribute::new("b", 2),
50    ///     Attribute::new("c", 3),
51    /// ]);
52    ///
53    /// for structure in body.iter() {
54    ///     println!("{structure:?}");
55    /// }
56    /// ```
57    pub fn iter(&self) -> Iter<'_> {
58        Iter::new(self)
59    }
60
61    /// An iterator visiting all structures within the `Body`. The iterator element type is `&'a
62    /// mut Structure`.
63    ///
64    /// # Examples
65    ///
66    /// ```
67    /// use hcl::{Attribute, Block, Body, Identifier, Structure};
68    ///
69    /// let mut body = Body::from([
70    ///     Structure::Attribute(Attribute::new("a", 1)),
71    ///     Structure::Block(Block::new("b")),
72    ///     Structure::Attribute(Attribute::new("c", 3)),
73    /// ]);
74    ///
75    /// // Update all attribute keys and block identifiers
76    /// for structure in body.iter_mut() {
77    ///     match structure {
78    ///         Structure::Attribute(attr) => {
79    ///             attr.key = Identifier::new(format!("attr_{}", attr.key)).unwrap();
80    ///         }
81    ///         Structure::Block(block) => {
82    ///             block.identifier = Identifier::new(format!("block_{}", block.identifier)).unwrap();
83    ///         }
84    ///     }
85    /// }
86    ///
87    /// assert_eq!(body.into_inner(), [
88    ///     Structure::Attribute(Attribute::new("attr_a", 1)),
89    ///     Structure::Block(Block::new("block_b")),
90    ///     Structure::Attribute(Attribute::new("attr_c", 3)),
91    /// ]);
92    /// ```
93    pub fn iter_mut(&mut self) -> IterMut<'_> {
94        IterMut::new(self)
95    }
96
97    /// An iterator visiting all attributes within the `Body`. The iterator element type is `&'a
98    /// Attribute`.
99    ///
100    /// # Examples
101    ///
102    /// ```
103    /// use hcl::{Attribute, Block, Body, Structure};
104    ///
105    /// let body = Body::from([
106    ///     Structure::Attribute(Attribute::new("a", 1)),
107    ///     Structure::Block(Block::new("b")),
108    ///     Structure::Attribute(Attribute::new("c", 3)),
109    /// ]);
110    ///
111    /// let vec: Vec<&Attribute> = body.attributes().collect();
112    /// assert_eq!(vec, [&Attribute::new("a", 1), &Attribute::new("c", 3)]);
113    /// ```
114    pub fn attributes(&self) -> Attributes<'_> {
115        Attributes::new(self)
116    }
117
118    /// An iterator visiting all attributes within the `Body`. The iterator element type is `&'a
119    /// mut Attribute`.
120    ///
121    /// # Examples
122    ///
123    /// ```
124    /// use hcl::{Attribute, Block, Body, Identifier, Structure};
125    ///
126    /// let mut body = Body::from([
127    ///     Structure::Attribute(Attribute::new("a", 1)),
128    ///     Structure::Block(Block::new("b")),
129    ///     Structure::Attribute(Attribute::new("c", 3)),
130    /// ]);
131    ///
132    /// // Update all attribute keys
133    /// for attr in body.attributes_mut() {
134    ///     attr.key = Identifier::new(format!("attr_{}", attr.key)).unwrap();
135    /// }
136    ///
137    /// assert_eq!(body.into_inner(), [
138    ///     Structure::Attribute(Attribute::new("attr_a", 1)),
139    ///     Structure::Block(Block::new("b")),
140    ///     Structure::Attribute(Attribute::new("attr_c", 3)),
141    /// ]);
142    /// ```
143    pub fn attributes_mut(&mut self) -> AttributesMut<'_> {
144        AttributesMut::new(self)
145    }
146
147    /// Creates a consuming iterator visiting all attributes within the `Body`. The object cannot
148    /// be used after calling this. The iterator element type is `Attribute`.
149    ///
150    /// # Examples
151    ///
152    /// ```
153    /// use hcl::{Attribute, Block, Body, Structure};
154    ///
155    /// let body = Body::from([
156    ///     Structure::Attribute(Attribute::new("a", 1)),
157    ///     Structure::Block(Block::new("b")),
158    ///     Structure::Attribute(Attribute::new("c", 3)),
159    /// ]);
160    ///
161    /// let vec: Vec<Attribute> = body.into_attributes().collect();
162    /// assert_eq!(vec, [Attribute::new("a", 1), Attribute::new("c", 3)]);
163    /// ```
164    pub fn into_attributes(self) -> IntoAttributes {
165        IntoAttributes::new(self)
166    }
167
168    /// An iterator visiting all blocks within the `Body`. The iterator element type is `&'a
169    /// Block`.
170    ///
171    /// # Examples
172    ///
173    /// ```
174    /// use hcl::{Attribute, Block, Body, Structure};
175    ///
176    /// let body = Body::from([
177    ///     Structure::Attribute(Attribute::new("a", 1)),
178    ///     Structure::Block(Block::new("b")),
179    ///     Structure::Attribute(Attribute::new("c", 3)),
180    /// ]);
181    ///
182    /// let vec: Vec<&Block> = body.blocks().collect();
183    /// assert_eq!(vec, [&Block::new("b")]);
184    /// ```
185    pub fn blocks(&self) -> Blocks<'_> {
186        Blocks::new(self)
187    }
188
189    /// An iterator visiting all blocks within the `Body`. The iterator element type is `&'a mut
190    /// Block`.
191    ///
192    /// # Examples
193    ///
194    /// ```
195    /// use hcl::{Attribute, Block, Body, Identifier, Structure};
196    ///
197    /// let mut body = Body::from([
198    ///     Structure::Attribute(Attribute::new("a", 1)),
199    ///     Structure::Block(Block::new("b")),
200    ///     Structure::Attribute(Attribute::new("c", 3)),
201    /// ]);
202    ///
203    /// // Update all block identifiers
204    /// for block in body.blocks_mut() {
205    ///     block.identifier = Identifier::new(format!("block_{}", block.identifier)).unwrap();
206    /// }
207    ///
208    /// assert_eq!(body.into_inner(), [
209    ///     Structure::Attribute(Attribute::new("a", 1)),
210    ///     Structure::Block(Block::new("block_b")),
211    ///     Structure::Attribute(Attribute::new("c", 3)),
212    /// ]);
213    /// ```
214    pub fn blocks_mut(&mut self) -> BlocksMut<'_> {
215        BlocksMut::new(self)
216    }
217
218    /// Creates a consuming iterator visiting all blocks within the `Body`. The object cannot
219    /// be used after calling this. The iterator element type is `Block`.
220    ///
221    /// # Examples
222    ///
223    /// ```
224    /// use hcl::{Attribute, Block, Body, Structure};
225    ///
226    /// let body = Body::from([
227    ///     Structure::Attribute(Attribute::new("a", 1)),
228    ///     Structure::Block(Block::new("b")),
229    ///     Structure::Attribute(Attribute::new("c", 3)),
230    /// ]);
231    ///
232    /// let vec: Vec<Block> = body.into_blocks().collect();
233    /// assert_eq!(vec, [Block::new("b")]);
234    /// ```
235    pub fn into_blocks(self) -> IntoBlocks {
236        IntoBlocks::new(self)
237    }
238}
239
240impl FromStr for Body {
241    type Err = Error;
242
243    #[inline]
244    fn from_str(s: &str) -> Result<Self, Self::Err> {
245        let body: hcl_edit::structure::Body = s.parse()?;
246        Ok(body.into())
247    }
248}
249
250impl<T> From<T> for Body
251where
252    T: Into<Structure>,
253{
254    fn from(value: T) -> Body {
255        Body(vec![value.into()])
256    }
257}
258
259impl<T> From<Vec<T>> for Body
260where
261    T: Into<Structure>,
262{
263    fn from(vec: Vec<T>) -> Self {
264        Body::from_iter(vec)
265    }
266}
267
268impl<T> From<&[T]> for Body
269where
270    T: Clone + Into<Structure>,
271{
272    fn from(slice: &[T]) -> Self {
273        Body::from_iter(slice.to_vec())
274    }
275}
276
277impl<T> From<&mut [T]> for Body
278where
279    T: Clone + Into<Structure>,
280{
281    fn from(slice: &mut [T]) -> Self {
282        Body::from_iter(slice.to_vec())
283    }
284}
285
286impl<T, const N: usize> From<[T; N]> for Body
287where
288    T: Into<Structure>,
289{
290    fn from(arr: [T; N]) -> Self {
291        Body::from_iter(arr)
292    }
293}
294
295/// `BodyBuilder` builds a HCL [`Body`].
296///
297/// The builder allows to build the `Body` by adding attributes and other nested blocks via chained
298/// method calls. A call to [`.build()`](BodyBuilder::build) produces the final `Body`.
299///
300/// ## Example
301///
302/// ```
303/// use hcl::{Body, Block};
304///
305/// let body = Body::builder()
306///     .add_block(
307///         Block::builder("resource")
308///             .add_label("aws_s3_bucket")
309///             .add_label("mybucket")
310///             .add_attribute(("name", "mybucket"))
311///             .build()
312///     )
313///     .build();
314/// ```
315#[derive(Debug, Default)]
316pub struct BodyBuilder(Vec<Structure>);
317
318impl BodyBuilder {
319    /// Adds an `Attribute` to the body.
320    ///
321    /// Consumes `self` and returns a new `BodyBuilder`.
322    pub fn add_attribute<A>(self, attr: A) -> BodyBuilder
323    where
324        A: Into<Attribute>,
325    {
326        self.add_structure(attr.into())
327    }
328
329    /// Adds `Attribute`s to the body from an iterator.
330    ///
331    /// Consumes `self` and returns a new `BodyBuilder`.
332    pub fn add_attributes<I>(self, iter: I) -> BodyBuilder
333    where
334        I: IntoIterator,
335        I::Item: Into<Attribute>,
336    {
337        self.add_structures(iter.into_iter().map(Into::into))
338    }
339
340    /// Adds a `Block` to the body.
341    ///
342    /// Consumes `self` and returns a new `BodyBuilder`.
343    pub fn add_block<B>(self, block: B) -> BodyBuilder
344    where
345        B: Into<Block>,
346    {
347        self.add_structure(block.into())
348    }
349
350    /// Adds `Block`s to the body from an iterator.
351    ///
352    /// Consumes `self` and returns a new `BodyBuilder`.
353    pub fn add_blocks<I>(self, iter: I) -> BodyBuilder
354    where
355        I: IntoIterator,
356        I::Item: Into<Block>,
357    {
358        self.add_structures(iter.into_iter().map(Into::into))
359    }
360
361    /// Adds a `Structure` to the body.
362    ///
363    /// Consumes `self` and returns a new `BodyBuilder`.
364    pub fn add_structure<S>(mut self, structure: S) -> BodyBuilder
365    where
366        S: Into<Structure>,
367    {
368        self.0.push(structure.into());
369        self
370    }
371
372    /// Adds `Structure`s to the body from an iterator.
373    ///
374    /// Consumes `self` and returns a new `BodyBuilder`.
375    pub fn add_structures<I>(mut self, iter: I) -> BodyBuilder
376    where
377        I: IntoIterator,
378        I::Item: Into<Structure>,
379    {
380        self.0.extend(iter.into_iter().map(Into::into));
381        self
382    }
383
384    /// Consumes `self` and builds the [`Body`] from the structures added via the builder methods.
385    pub fn build(self) -> Body {
386        Body::from_iter(self.0)
387    }
388}