hcl_primitives/
expr.rs

1//! Primitives for the HCL expression sub-language.
2
3use crate::Error;
4use core::fmt;
5use core::str::FromStr;
6
7/// An operator that can be applied to an expression.
8///
9/// For more details, check the section about operations in the [HCL syntax
10/// specification](https://github.com/hashicorp/hcl/blob/main/hclsyntax/spec.md#operations).
11#[derive(Debug, PartialEq, Eq, Clone, Copy)]
12pub enum UnaryOperator {
13    /// Negate operator (`-`).
14    Neg,
15    /// Not operator (`!`).
16    Not,
17}
18
19impl UnaryOperator {
20    /// Returns the `UnaryOperator` as a static `&str`.
21    pub fn as_str(&self) -> &'static str {
22        match self {
23            UnaryOperator::Neg => "-",
24            UnaryOperator::Not => "!",
25        }
26    }
27}
28
29impl fmt::Display for UnaryOperator {
30    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
31        f.write_str(self.as_str())
32    }
33}
34
35impl FromStr for UnaryOperator {
36    type Err = Error;
37
38    fn from_str(s: &str) -> Result<Self, Self::Err> {
39        match s {
40            "-" => Ok(UnaryOperator::Neg),
41            "!" => Ok(UnaryOperator::Not),
42            _ => Err(Error::new(format!("invalid unary operator: `{s}`"))),
43        }
44    }
45}
46
47/// An operator that can be applied to two expressions.
48///
49/// For more details, check the section about operations in the [HCL syntax
50/// specification](https://github.com/hashicorp/hcl/blob/main/hclsyntax/spec.md#operations).
51#[derive(Debug, PartialEq, Eq, Clone, Copy)]
52pub enum BinaryOperator {
53    /// Equal operator (`==`).
54    Eq,
55    /// Not-equal operator (`!=`).
56    NotEq,
57    /// Less-equal operator (`<=`).
58    LessEq,
59    /// Greater-equal operator (`>=`).
60    GreaterEq,
61    /// Less operator (`<`).
62    Less,
63    /// Greater operator (`>`).
64    Greater,
65    /// Plus operator (`+`).
66    Plus,
67    /// Minus operator (`-`).
68    Minus,
69    /// Multiply operator (`*`).
70    Mul,
71    /// Division operator (`/`).
72    Div,
73    /// Modulo operator (`%`).
74    Mod,
75    /// And operator (`&&`).
76    And,
77    /// Or operator (`||`).
78    Or,
79}
80
81impl BinaryOperator {
82    /// Returns the `BinaryOperator` as a static `&str`.
83    pub fn as_str(&self) -> &'static str {
84        match self {
85            BinaryOperator::Eq => "==",
86            BinaryOperator::NotEq => "!=",
87            BinaryOperator::LessEq => "<=",
88            BinaryOperator::GreaterEq => ">=",
89            BinaryOperator::Less => "<",
90            BinaryOperator::Greater => ">",
91            BinaryOperator::Plus => "+",
92            BinaryOperator::Minus => "-",
93            BinaryOperator::Mul => "*",
94            BinaryOperator::Div => "/",
95            BinaryOperator::Mod => "%",
96            BinaryOperator::And => "&&",
97            BinaryOperator::Or => "||",
98        }
99    }
100
101    /// Returns the operator precedence level. Higher numbers mean higher precedence.
102    pub fn precedence(self) -> u8 {
103        match self {
104            BinaryOperator::Mul | BinaryOperator::Div | BinaryOperator::Mod => 6,
105            BinaryOperator::Plus | BinaryOperator::Minus => 5,
106            BinaryOperator::LessEq
107            | BinaryOperator::GreaterEq
108            | BinaryOperator::Less
109            | BinaryOperator::Greater => 4,
110            BinaryOperator::Eq | BinaryOperator::NotEq => 3,
111            BinaryOperator::And => 2,
112            BinaryOperator::Or => 1,
113        }
114    }
115}
116
117impl fmt::Display for BinaryOperator {
118    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
119        f.write_str(self.as_str())
120    }
121}
122
123impl FromStr for BinaryOperator {
124    type Err = Error;
125
126    fn from_str(s: &str) -> Result<Self, Self::Err> {
127        match s {
128            "==" => Ok(BinaryOperator::Eq),
129            "!=" => Ok(BinaryOperator::NotEq),
130            "<=" => Ok(BinaryOperator::LessEq),
131            ">=" => Ok(BinaryOperator::GreaterEq),
132            "<" => Ok(BinaryOperator::Less),
133            ">" => Ok(BinaryOperator::Greater),
134            "+" => Ok(BinaryOperator::Plus),
135            "-" => Ok(BinaryOperator::Minus),
136            "*" => Ok(BinaryOperator::Mul),
137            "/" => Ok(BinaryOperator::Div),
138            "%" => Ok(BinaryOperator::Mod),
139            "&&" => Ok(BinaryOperator::And),
140            "||" => Ok(BinaryOperator::Or),
141            _ => Err(Error::new(format!("invalid binary operator: `{s}`"))),
142        }
143    }
144}
145
146#[cfg(feature = "serde")]
147impl serde::Serialize for UnaryOperator {
148    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
149    where
150        S: serde::Serializer,
151    {
152        serializer.serialize_str(self.as_str())
153    }
154}
155
156#[cfg(feature = "serde")]
157impl serde::Serialize for BinaryOperator {
158    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
159    where
160        S: serde::Serializer,
161    {
162        serializer.serialize_str(self.as_str())
163    }
164}
165
166#[cfg(feature = "serde")]
167impl<'de> serde::Deserialize<'de> for UnaryOperator {
168    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
169    where
170        D: serde::Deserializer<'de>,
171    {
172        deserializer.deserialize_any(crate::de::FromStrVisitor::<Self>::new("unary operator"))
173    }
174}
175
176#[cfg(feature = "serde")]
177impl<'de> serde::de::IntoDeserializer<'de, Error> for UnaryOperator {
178    type Deserializer = serde::de::value::StrDeserializer<'static, Error>;
179
180    fn into_deserializer(self) -> Self::Deserializer {
181        self.as_str().into_deserializer()
182    }
183}
184
185#[cfg(feature = "serde")]
186impl<'de> serde::Deserialize<'de> for BinaryOperator {
187    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
188    where
189        D: serde::Deserializer<'de>,
190    {
191        deserializer.deserialize_any(crate::de::FromStrVisitor::<Self>::new("binary operator"))
192    }
193}
194
195#[cfg(feature = "serde")]
196impl<'de> serde::de::IntoDeserializer<'de, Error> for BinaryOperator {
197    type Deserializer = serde::de::value::StrDeserializer<'static, Error>;
198
199    fn into_deserializer(self) -> Self::Deserializer {
200        self.as_str().into_deserializer()
201    }
202}