Expand description
Serialize a Rust data structure into HCL data.
This module provides the Serializer type and the convienince functions to_string,
to_vec and to_writer for serializing data to HCL.
Furthermore, the Block and LabeledBlock wrapper types, and the
block, labeled_block and doubly_labeled_block functions can be
used to construct HCL block structures from custom types. See the type and function level
documentation for usage examples.
If you want to serialize the data structures provided by this crate (e.g. Body) consider
using the functionality in the format module instead because it is more
efficient.
§Supported top-level types
The Serializer supports serialization to HCL for types that are either structured like
maps or sequences of maps. For example, at the top level a struct with one or more named
fields is supported, while a newtype struct wrapping a primitive type like u8 is not.
Other example of supported top-level types:
- tuple or newtype structs wrapping a map-like type
- enums with newtype or tuple variants wrapping map-like types, or struct variants
Please note that these restrictions only apply to the top-level type that is serialized. Nested fields can have any type that is serializable.
§Serializing a custom type
The following example will serialize the data as a deeply nested HCL attribute.
use serde::Serialize;
#[derive(Serialize)]
struct User {
age: u8,
username: &'static str,
email: &'static str,
}
#[derive(Serialize)]
struct Data {
users: Vec<User>,
}
let data = Data {
users: vec![
User {
age: 34,
username: "johndoe",
email: "johndoe@example.com",
},
User {
age: 27,
username: "janedoe",
email: "janedoe@example.com",
},
],
};
let expected = r#"
users = [
{
"age" = 34
"username" = "johndoe"
"email" = "johndoe@example.com"
},
{
"age" = 27
"username" = "janedoe"
"email" = "janedoe@example.com"
}
]
"#.trim_start();
let serialized = hcl::to_string(&data)?;
assert_eq!(serialized, expected);§Serializing context-aware HCL
If you need full control over the way data is serialized to HCL, you can make use of the Body type which can be constructed using the builder pattern.
The following example uses HCL blocks to format the same data from above in a different way.
use hcl::{Block, Body};
let body = Body::builder()
.add_block(
Block::builder("user")
.add_label("johndoe")
.add_attribute(("age", 34))
.add_attribute(("email", "johndoe@example.com"))
.build(),
)
.add_block(
Block::builder("user")
.add_label("janedoe")
.add_attribute(("age", 27))
.add_attribute(("email", "janedoe@example.com"))
.build(),
)
.build();
let expected = r#"
user "johndoe" {
age = 34
email = "johndoe@example.com"
}
user "janedoe" {
age = 27
email = "janedoe@example.com"
}
"#.trim_start();
let serialized = hcl::to_string(&body)?;
assert_eq!(serialized, expected);The same result could be acheived using the block! macro:
use serde::Serialize;
#[derive(Serialize)]
struct User {
age: u8,
username: &'static str,
email: &'static str,
}
let users = vec![
User {
age: 34,
username: "johndoe",
email: "johndoe@example.com",
},
User {
age: 27,
username: "janedoe",
email: "janedoe@example.com",
},
];
let body: hcl::Body = users
.into_iter()
.map(|user| {
hcl::block! {
user (user.username) {
age = (user.age)
email = (user.email)
}
}
})
.collect();
let expected = r#"
user "johndoe" {
age = 34
email = "johndoe@example.com"
}
user "janedoe" {
age = 27
email = "janedoe@example.com"
}
"#
.trim_start();
let serialized = hcl::to_string(&body)?;
assert_eq!(serialized, expected);§Serializing HCL blocks using a custom type
An example to serialize a terraform configuration block using a custom type and the
LabeledBlock and Block marker types from this module:
use hcl::expr::{Expression, Traversal, Variable};
use indexmap::{indexmap, IndexMap};
use serde::Serialize;
#[derive(Serialize)]
struct Config {
#[serde(
rename = "resource",
serialize_with = "hcl::ser::labeled_block"
)]
resources: Resources,
}
#[derive(Serialize)]
struct Resources {
#[serde(
rename = "aws_sns_topic_subscription",
serialize_with = "hcl::ser::labeled_block"
)]
aws_sns_topic_subscriptions: IndexMap<String, AwsSnsTopicSubscription>,
}
#[derive(Serialize)]
struct AwsSnsTopicSubscription {
topic_arn: Traversal,
protocol: Expression,
endpoint: Traversal,
}
let subscription = AwsSnsTopicSubscription {
topic_arn: Traversal::builder(Variable::new("aws_sns_topic").unwrap())
.attr("my-topic")
.attr("arn")
.build(),
protocol: "sqs".into(),
endpoint: Traversal::builder(Variable::new("aws_sqs_queue").unwrap())
.attr("my-queue")
.attr("arn")
.build()
};
let config = Config {
resources: Resources {
aws_sns_topic_subscriptions: indexmap! {
"my-subscription".into() => subscription,
},
},
};
let expected = r#"
resource "aws_sns_topic_subscription" "my-subscription" {
topic_arn = aws_sns_topic.my-topic.arn
protocol = "sqs"
endpoint = aws_sqs_queue.my-queue.arn
}
"#.trim_start();
let serialized = hcl::to_string(&config).unwrap();
assert_eq!(serialized, expected);Structs§
- Block
- A transparent wrapper type which hints the
Serializerto serializeTas an HCL block. - Labeled
Block - A transparent wrapper type which hints the
Serializerto serializeTas a labeled HCL block. - Serializer
- A structure for serializing Rust values into HCL.
Functions§
- block
- Hints the
Serializerto serializeTas an HCL block. - doubly_
labeled_ block - Hints the
Serializerto serializeTas an HCL block with two labels. - labeled_
block - Hints the
Serializerto serializeTas a labeled HCL block. - to_
string - Serialize the given value as an HCL string.
- to_vec
- Serialize the given value as an HCL byte vector.
- to_
writer - Serialize the given value as HCL into the IO stream.