使用 InlineTables 序列化 toml ArrayOfTables

问题描述 投票:0回答:1

我的结构如下所示:

#[derive(Serialize, Deserialize)]
pub struct TestItem {
    pub a: String,
    pub b: String,
}

#[derive(Serialize, Deserialize)]
pub struct Test {
    pub items: Vec<TestItem>,
}

我想使用

InlineTable
来序列化它,因为它更具可读性,但是
toml
板条箱默认为常规表格。例如我想要:

items = [
    { a = "testa1", b = "testb1" },
    # etc
]

但是

toml::to_string(...)
给出

[[items]]
a = "testa1"
b = "testb1"

#etc

这似乎是一个相当常见的请求,例如,请参阅 toml#592,并且 toml_edit

 crate
中有一个 示例,在这种情况下似乎不起作用,因为
items
是一个
ArrayOfTables 
.

我尝试过以下访客


impl VisitMut for TestVisitor {
    fn visit_table_mut(&mut self, node: &mut Table) {
        visit_table_mut(self, node);
        node.set_implicit(true);
    }

    fn visit_table_like_kv_mut(&mut self, mut key: KeyMut<'_>, node: &mut Item) {
        println!("This is hit: {:?} -> {node:?}", key.get());
        if let Item::Table(table) = node {
            println!("This is never hit, as its an ArrayOfTables");
            let table = std::mem::replace(table, Table::new());
            let inline_table = table.into_inline_table();
            key.fmt();
            *node = Item::Value(Value::InlineTable(inline_table));
        }

        // Recurse further into the document tree.
        visit_table_like_kv_mut(self, key, node);
    }

    fn visit_array_mut(&mut self, node: &mut Array) {
        node.fmt();
    }
}

但这似乎跳过了

Table
内的
ArrayOfTables
,所以
if
永远不会被击中。输出是:

This is hit: "items" -> ArrayOfTables(...)
This is hit: "a" -> Value(String(...)
// etc - the tables are never visited

我将如何构建一个可以将

items
中的任何表转换为
InlineTable
的访问者?似乎
VisitMut
中的所有其他方法都采用
Table
,所以我无法将它们转变为
 InlineTable
如示例所要求。

rust serde toml
1个回答
0
投票

好的,所以看看这两种不同的 TOML 格式实际上以不同的方式解析。

[[items]]
a = "testa1"
b = "testb1"

解析为

Item::ArrayOfTables
,仅接受
Table
作为其项目,而:

items = [
    { a = "testa1", b = "testb1" },
    # etc
]

解析为

Item::Value(Value::Array(...))
,其中元素为
Value::InlineTable
。这意味着像下面这样的访客似乎会成功。

struct TestVisitor;

// I could be wrong here, but it seems I have to use the `kv` variant here
// because `visit_table_like_mut` has `node: &mut dyn toml_edit::TableLike`
// as the second argument, which `ArrayOfTables` doesn't seem to impl
impl VisitMut for TestVisitor {
    fn visit_table_like_kv_mut(&mut self, key: KeyMut<'_>, node: &mut Item) {
        if let Item::ArrayOfTables(tables) = node {
            let new_tables = tables
                .iter_mut()
                .map(|t| {
                    let table = std::mem::replace(t, Table::new());
                    Value::InlineTable(table.into_inline_table())
                })
                .collect::<Vec<_>>();

            *node = Item::Value(Value::Array(Array::from_iter(new_tables.iter())));
        }

        // Recurse further into the document tree.
        visit_table_like_kv_mut(self, key, node);
    }
}

我可以这样使用:

impl Test {
    pub fn to_toml(&self) -> anyhow::Result<String> {
        let raw_string = toml::to_string(self)?;

        let mut doc = raw_string.parse::<DocumentMut>()?;

        let mut visitor = TestVisitor;
        visitor.visit_document_mut(&mut doc);

        Ok(doc.to_string())
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.