hcl_edit/structure/
mod.rs

1//! Types to represent the HCL structural sub-language.
2
3// `Attribute` and `Block` have the same size, yet clippy complains about large size difference
4// between the enum variants of `Structure` because it determines the size of `Attribute` to be
5// zero. As pointed out in the issue below, clippy seems to choke on recursive types, which is the
6// case for the `Expression` type used as attribute value.
7//
8// The incorrect size calculation also produces false positives for result types like
9// `Result<Attribute, Structure>` and `Result<Block, Structure>`.
10//
11// See https://github.com/rust-lang/rust-clippy/issues/9798
12#![allow(clippy::large_enum_variant, clippy::result_large_err)]
13
14mod attribute;
15mod block;
16mod body;
17
18pub use self::attribute::{Attribute, AttributeMut};
19pub use self::block::{Block, BlockBuilder, BlockLabel};
20pub use self::body::{
21    Attributes, AttributesMut, Blocks, BlocksMut, Body, BodyBuilder, IntoAttributes, IntoBlocks,
22    IntoIter, Iter, IterMut,
23};
24use crate::{Decor, Decorate, Span};
25use std::ops::Range;
26
27/// Represents an HCL structure.
28///
29/// There are two possible structures that can occur in an HCL [`Body`]: [`Attribute`]s and [`Block`]s.
30#[derive(Debug, Clone, PartialEq, Eq)]
31pub enum Structure {
32    /// Represents an HCL attribute.
33    Attribute(Attribute),
34    /// Represents an HCL block.
35    Block(Block),
36}
37
38impl Structure {
39    /// Returns `true` if the structure represents an [`Attribute`].
40    pub fn is_attribute(&self) -> bool {
41        self.as_attribute().is_some()
42    }
43
44    /// Returns `true` if the structure represents a [`Block`].
45    pub fn is_block(&self) -> bool {
46        self.as_block().is_some()
47    }
48
49    /// If the `Structure` is an `Attribute`, returns it.
50    ///
51    /// # Errors
52    ///
53    /// An [`Err`] is returns with the same `Structure` that was passed in if it is not an
54    /// `Attribute`.
55    pub fn into_attribute(self) -> Result<Attribute, Structure> {
56        match self {
57            Structure::Attribute(attr) => Ok(attr),
58            Structure::Block(_) => Err(self),
59        }
60    }
61
62    /// If the `Structure` is an `Attribute`, returns a reference to it, otherwise `None`.
63    pub fn as_attribute(&self) -> Option<&Attribute> {
64        match self {
65            Structure::Attribute(attr) => Some(attr),
66            Structure::Block(_) => None,
67        }
68    }
69
70    /// If the `Structure` is an `Attribute`, returns a mutable reference to it, otherwise `None`.
71    pub fn as_attribute_mut(&mut self) -> Option<&mut Attribute> {
72        match self {
73            Structure::Attribute(attr) => Some(attr),
74            Structure::Block(_) => None,
75        }
76    }
77
78    /// If the `Structure` is a `Block`, returns it.
79    ///
80    /// # Errors
81    ///
82    /// An [`Err`] is returns with the same `Structure` that was passed in if it is not a `Block`.
83    pub fn into_block(self) -> Result<Block, Structure> {
84        match self {
85            Structure::Block(block) => Ok(block),
86            Structure::Attribute(_) => Err(self),
87        }
88    }
89
90    /// If the `Structure` is a `Block`, returns a reference to it, otherwise `None`.
91    pub fn as_block(&self) -> Option<&Block> {
92        match self {
93            Structure::Block(block) => Some(block),
94            Structure::Attribute(_) => None,
95        }
96    }
97
98    /// If the `Structure` is a `Block`, returns a mutable reference to it, otherwise `None`.
99    pub fn as_block_mut(&mut self) -> Option<&mut Block> {
100        match self {
101            Structure::Block(block) => Some(block),
102            Structure::Attribute(_) => None,
103        }
104    }
105
106    pub(crate) fn despan(&mut self, input: &str) {
107        match self {
108            Structure::Attribute(attr) => attr.despan(input),
109            Structure::Block(block) => block.despan(input),
110        }
111    }
112}
113
114impl From<Attribute> for Structure {
115    fn from(value: Attribute) -> Self {
116        Structure::Attribute(value)
117    }
118}
119
120impl From<Block> for Structure {
121    fn from(value: Block) -> Self {
122        Structure::Block(value)
123    }
124}
125
126forward_decorate_impl!(Structure => { Attribute, Block });
127forward_span_impl!(Structure => { Attribute, Block });
128
129/// Allows mutable access to a structure, except for attribute keys which are immutable.
130///
131/// This type wraps the structure in the iterator returned by
132/// [`Body::iter_mut`](crate::structure::Body::iter_mut).
133pub struct StructureMut<'a> {
134    structure: &'a mut Structure,
135}
136
137impl<'a> StructureMut<'a> {
138    pub(crate) fn new(structure: &'a mut Structure) -> StructureMut<'a> {
139        StructureMut { structure }
140    }
141
142    /// Returns `true` if the structure represents an [`Attribute`].
143    pub fn is_attribute(&self) -> bool {
144        self.as_attribute().is_some()
145    }
146
147    /// Returns `true` if the structure represents a [`Block`].
148    pub fn is_block(&self) -> bool {
149        self.as_block().is_some()
150    }
151
152    /// If the `Structure` is an `Attribute`, returns a reference to it, otherwise `None`.
153    pub fn as_attribute(&self) -> Option<&Attribute> {
154        self.structure.as_attribute()
155    }
156
157    /// If the `Structure` is an `Attribute`, returns a mutable reference to it, otherwise `None`.
158    pub fn as_attribute_mut(&mut self) -> Option<AttributeMut<'_>> {
159        self.structure.as_attribute_mut().map(AttributeMut::new)
160    }
161
162    /// If the `Structure` is a `Block`, returns a reference to it, otherwise `None`.
163    pub fn as_block(&self) -> Option<&Block> {
164        self.structure.as_block()
165    }
166
167    /// If the `Structure` is a `Block`, returns a mutable reference to it, otherwise `None`.
168    pub fn as_block_mut(&mut self) -> Option<&mut Block> {
169        self.structure.as_block_mut()
170    }
171}
172
173impl<'a> Decorate for StructureMut<'a> {
174    fn decor(&self) -> &Decor {
175        self.structure.decor()
176    }
177
178    fn decor_mut(&mut self) -> &mut Decor {
179        self.structure.decor_mut()
180    }
181}
182
183impl<'a> Span for StructureMut<'a> {
184    fn span(&self) -> Option<Range<usize>> {
185        self.structure.span()
186    }
187}