Expand description
Evaluate HCL templates and expressions.
This module provides the Evaluate
trait which enables HCL template and expression
evaluation. It is implemented for various types that either directly or transitively contain
templates or expressions that need to be evaluated.
Additionally, the Context
type is used to declare variables and functions to make them
available during expression evaluation.
For convenience, the from_str
and to_string
functions are provided which enable
expression evaluation during (de-)serialization directly. Check out their function docs for
usage examples.
§Examples
HCL expressions can contain variables and functions which are made available through the
Context
value passed to Evaluate::evaluate
.
Here’s a short example which evaluates a template expression that contains a variable:
use hcl::Value;
use hcl::eval::{Context, Evaluate};
use hcl::expr::TemplateExpr;
let expr = TemplateExpr::from("Hello ${name}!");
let mut ctx = Context::new();
ctx.declare_var("name", "World");
assert_eq!(expr.evaluate(&ctx)?, Value::from("Hello World!"));
Template directives like for
loops can be evaluated as well, this time using a Template
instead of TemplateExpr
:
use hcl::Template;
use hcl::eval::{Context, Evaluate};
use std::str::FromStr;
let input = r#"
Bill of materials:
%{ for item in items ~}
- ${item}
%{ endfor ~}
"#;
let template = Template::from_str(input)?;
let mut ctx = Context::new();
ctx.declare_var("items", vec!["time", "code", "sweat"]);
let evaluated = r#"
Bill of materials:
- time
- code
- sweat
"#;
assert_eq!(template.evaluate(&ctx)?, evaluated);
If you need to include the literal representation of variable reference, you can escape ${
with $${
:
use hcl::eval::{Context, Evaluate};
use hcl::Template;
use std::str::FromStr;
let template = Template::from_str("Value: ${value}, escaped: $${value}")?;
let mut ctx = Context::new();
ctx.declare_var("value", 1);
let evaluated = "Value: 1, escaped: ${value}";
assert_eq!(template.evaluate(&ctx)?, evaluated);
Here’s another example which evaluates some attribute expressions using from_str
as
described in the deserialization
example below:
use hcl::Body;
use hcl::eval::Context;
let input = r#"
operation = 1 + 1
conditional = cond ? "yes" : "no"
for_expr = [for item in items: item if item <= 3]
"#;
let mut ctx = Context::new();
ctx.declare_var("cond", true);
ctx.declare_var("items", vec![1, 2, 3, 4, 5]);
let body: Body = hcl::eval::from_str(input, &ctx)?;
let expected = Body::builder()
.add_attribute(("operation", 2))
.add_attribute(("conditional", "yes"))
.add_attribute(("for_expr", vec![1, 2, 3]))
.build();
assert_eq!(body, expected);
§Function calls in expressions
To evaluate functions calls, you need to create a function definition and make it available to
the evaluation context. Function definitions are created via the FuncDef
type which
contains more information in its type-level documentation.
Here’s the example from above, updated to also include a function call to make the name
uppercase:
use hcl::Value;
use hcl::eval::{Context, Evaluate, FuncArgs, FuncDef, ParamType};
use hcl::expr::TemplateExpr;
// A template expression which needs to be evaluated. It needs access
// to the `uppercase` function and `name` variable.
let expr = TemplateExpr::from("Hello ${uppercase(name)}!");
// A function that is made available to expressions via the `Context` value.
fn uppercase(args: FuncArgs) -> Result<Value, String> {
// We know that there is one argument and it is of type `String`
// because the function arguments are validated using the parameter
// type information in the `FuncDef` before calling the function.
Ok(Value::from(args[0].as_str().unwrap().to_uppercase()))
}
// Create a definition for the `uppercase` function.
let uppercase_func = FuncDef::builder()
.param(ParamType::String)
.build(uppercase);
// Create the context and add variables and functions to it.
let mut ctx = Context::new();
ctx.declare_var("name", "world");
ctx.declare_func("uppercase", uppercase_func);
// Evaluate the expression.
assert_eq!(expr.evaluate(&ctx)?, Value::from("Hello WORLD!"));
§Expression evaluation during (de-)serialization
It’s possible to evaluate expressions directly when deserializing HCL into a Rust value, or when serializing a Rust value that contains HCL expressions into HCL.
For these use cases the convenience functions hcl::eval::from_str
and
hcl::eval::to_string
are provided. Their usage is similar to
hcl::from_str
and hcl::to_string
but they receive a
reference to a Context
value as second parameter.
Here’s a deserialization example using from_str
:
use hcl::Body;
use hcl::eval::Context;
let input = r#"hello_world = "Hello, ${name}!""#;
let mut ctx = Context::new();
ctx.declare_var("name", "Rust");
let body: Body = hcl::eval::from_str(input, &ctx)?;
let expected = Body::builder()
.add_attribute(("hello_world", "Hello, Rust!"))
.build();
assert_eq!(body, expected);
And here’s how expression evaluation during serialization via to_string
works:
use hcl::Body;
use hcl::eval::Context;
use hcl::expr::TemplateExpr;
let expr = TemplateExpr::from("Hello, ${name}!");
let body = Body::builder()
.add_attribute(("hello_world", expr))
.build();
let mut ctx = Context::new();
ctx.declare_var("name", "Rust");
let string = hcl::eval::to_string(&body, &ctx)?;
assert_eq!(string, "hello_world = \"Hello, Rust!\"\n");
Structs§
- A type holding the evaluation context.
- The error type returned by all fallible operations within this module.
- A type holding multiple errors that occurred during in-place expression evaluation via
Evaluate::evaluate_in_place
. - Wrapper type for function argument values.
- The definition of a function that can be called in HCL expressions.
- A builder for
FuncDef
values. - An iterator over positional function arguments.
- An iterator over variadic function arguments.
Enums§
- An enum representing all kinds of errors that can happen during the evaluation of HCL expressions and templates.
- A type hint for a function parameter.
Traits§
- A trait for evaluating the HCL template and expression sub-languages.
Functions§
- Deserialize an instance of type
T
from a string of HCL text and evaluate all expressions using the given context. - Serialize the given value as an HCL string after evaluating all expressions using the given context.
Type Aliases§
- The result type used by this module.
- A type alias for the signature of functions expected by the
FuncDef
type.