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