hcl/structure/
mod.rs

1//! Types to represent the HCL structural sub-language.
2//!
3//! The main types in this module are:
4//!
5//! - [`Attribute`]: represent an HCL attribute
6//! - [`Block`]: represent an HCL block
7//! - [`BlockBuilder`]: provides functionality for building `Block`s
8//! - [`Body`]: represent the body of an HCL configuration or block
9//! - [`BodyBuilder`]: provides functionality for building `Body`s
10//!
11//! ## Examples
12//!
13//! Building HCL structures:
14//!
15//! ```
16//! use hcl::{Body, Block, BlockLabel};
17//!
18//! let body = Body::builder()
19//!     .add_block(
20//!         Block::builder("resource")
21//!             .add_label("aws_s3_bucket")
22//!             .add_label("mybucket")
23//!             .add_attribute(("name", "mybucket"))
24//!             .add_block(
25//!                 Block::builder("logging")
26//!                     .add_attribute(("target_bucket", "mylogsbucket"))
27//!                     .build()
28//!             )
29//!             .build()
30//!     )
31//!     .build();
32//!
33//! let mut iter = body.attributes();
34//!
35//! assert_eq!(iter.next(), None);
36//!
37//! let mut iter = body.blocks();
38//!
39//! let block = iter.next().unwrap();
40//!
41//! assert_eq!(block.identifier(), "resource");
42//! assert_eq!(
43//!     block.labels().first(),
44//!     Some(&BlockLabel::from("aws_s3_bucket")),
45//! );
46//! ```
47
48mod attribute;
49mod block;
50mod body;
51pub(crate) mod de;
52mod edit;
53pub mod iter;
54mod json_spec;
55mod ser;
56#[cfg(test)]
57mod tests;
58
59pub(crate) use self::json_spec::IntoJsonSpec;
60pub use self::{
61    attribute::Attribute,
62    block::{Block, BlockBuilder, BlockLabel},
63    body::{Body, BodyBuilder},
64};
65use crate::Value;
66use serde::Deserialize;
67
68/// Represents an HCL structure.
69///
70/// There are two possible structures that can occur in an HCL [`Body`]: [`Attribute`]s and [`Block`]s.
71#[derive(Deserialize, Debug, PartialEq, Eq, Clone)]
72pub enum Structure {
73    /// Represents an HCL attribute.
74    Attribute(Attribute),
75    /// Represents an HCL block.
76    Block(Block),
77}
78
79impl Structure {
80    /// Returns `true` if the structure represents an [`Attribute`].
81    pub fn is_attribute(&self) -> bool {
82        self.as_attribute().is_some()
83    }
84
85    /// Returns `true` if the structure represents a [`Block`].
86    pub fn is_block(&self) -> bool {
87        self.as_block().is_some()
88    }
89
90    /// Takes ownership of the `Structure` and, if it is an `Attribute`, returns its value,
91    /// otherwise `None`.
92    pub fn into_attribute(self) -> Option<Attribute> {
93        match self {
94            Structure::Attribute(attr) => Some(attr),
95            Structure::Block(_) => None,
96        }
97    }
98
99    /// If the `Structure` is an `Attribute`, returns a reference to it, otherwise `None`.
100    pub fn as_attribute(&self) -> Option<&Attribute> {
101        match self {
102            Structure::Attribute(attr) => Some(attr),
103            Structure::Block(_) => None,
104        }
105    }
106
107    /// If the `Structure` is an `Attribute`, returns a mutable reference to it, otherwise `None`.
108    pub fn as_attribute_mut(&mut self) -> Option<&mut Attribute> {
109        match self {
110            Structure::Attribute(attr) => Some(attr),
111            Structure::Block(_) => None,
112        }
113    }
114
115    /// Takes ownership of the `Structure` and, if it is a `Block`, returns its value,
116    /// otherwise `None`.
117    pub fn into_block(self) -> Option<Block> {
118        match self {
119            Structure::Block(block) => Some(block),
120            Structure::Attribute(_) => None,
121        }
122    }
123
124    /// If the `Structure` is a `Block`, returns a reference to it, otherwise `None`.
125    pub fn as_block(&self) -> Option<&Block> {
126        match self {
127            Structure::Block(block) => Some(block),
128            Structure::Attribute(_) => None,
129        }
130    }
131
132    /// If the `Structure` is a `Block`, returns a mutable reference to it, otherwise `None`.
133    pub fn as_block_mut(&mut self) -> Option<&mut Block> {
134        match self {
135            Structure::Block(block) => Some(block),
136            Structure::Attribute(_) => None,
137        }
138    }
139}
140
141impl From<Structure> for Value {
142    fn from(s: Structure) -> Value {
143        match s {
144            Structure::Attribute(attr) => attr.into(),
145            Structure::Block(block) => block.into(),
146        }
147    }
148}
149
150impl From<Attribute> for Structure {
151    fn from(attr: Attribute) -> Structure {
152        Structure::Attribute(attr)
153    }
154}
155
156impl From<Block> for Structure {
157    fn from(block: Block) -> Structure {
158        Structure::Block(block)
159    }
160}