我试图使用hcl-rs = 0.7.0来解析一些HCL。我只是在试验任意的HCL,所以我不想解析terraform特定的代码。
我希望能够解析这样的块并获得它的标签作为结果的一部分
nested_block "nested_block_label" {
foo = 123
}这目前不起作用,但希望它显示了我的意图。这样的事有可能吗?
#[test]
fn deserialize_struct_with_label() {
#[derive(Deserialize, PartialEq, Debug)]
struct TestRoot {
nested_block: TestNested,
}
#[derive(Deserialize, PartialEq, Debug)]
struct TestNested {
label: String,
foo: u32,
}
let input = r#"
nested_block "nested_block_label" {
foo = 123
}"#;
let expected = TestRoot{ nested_block: TestNested { label: String::from("nested_block_label"), foo: 123 } };
assert_eq!(expected, from_str::<TestRoot>(input).unwrap());
}发布于 2022-09-10 05:09:39
你的问题是hcl在默认情况下似乎解释
nested_block "nested_block_label" {
foo = 123
}作为以下"serde结构“:
"nested_block" -> {
"nested_block_label" -> {
"foo" -> 123
}
}如果不是你的铁锈结构,它必须是
"nested_block" -> {
"label" -> "nested_block_label"
"foo" -> 123
}我不知道有任何属性允许您将前者弯曲为后者。
与往常一样,当遇到这种情况时,通常最容易的方法是首先反序列化为泛型结构(如hcl::Block ),然后手动转换为任何您想要的结构。不利之处在于,您必须对每个结构分别执行此操作。
理论上,您可以实现一个泛型反序列化函数,它封装它接收到的Deserializer,并使您进入所需的一级结构的两级结构变平。但是实现反序列化需要大量的样板。也许,以前有人这样做过,但我也不知道有什么箱子能帮到你。
作为一种中等努力的解决方案,您可以有一个特殊的Labelled包装结构,它总是捕获和平放这个中间级别:
#[derive(Debug, PartialEq)]
struct Labelled<T> {
label: String,
t: T,
}
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Labelled<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct V<T>(std::marker::PhantomData<T>);
impl<'de, T: Deserialize<'de>> serde::de::Visitor<'de> for V<T> {
type Value = Labelled<T>;
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: serde::de::MapAccess<'de>,
{
if let (Some((label, t)), None) =
(map.next_entry()?, map.next_entry::<String, ()>()?)
{
Ok(Labelled { label, t })
} else {
Err(serde::de::Error::invalid_type(
serde::de::Unexpected::Other("Singleton map"),
&self,
))
}
}
}
deserializer.deserialize_map(V::<T>(Default::default()))
}
}会被这样使用:
#[derive(Deserialize, PartialEq, Debug)]
struct TestRoot {
nested_block: Labelled<TestNested>,
}
#[derive(Deserialize, PartialEq, Debug)]
struct TestNested {
foo: u32,
}最后,可能会有一些技巧,比如添加#[serde(rename = "$hcl::label")]。其他序列化库(例如quick-xml)也有类似的,并且允许以这种方式将字段标记为特殊的东西。hcl-rs在内部也这样做,但是它是没有文档的,我无法从源代码中判断您所需要的是否可能。
https://stackoverflow.com/questions/73667260
复制相似问题