#标记语言 #模式 #数据结构 #解析器 #加载 #转换

keytree

一种简单的标记语言,旨在将配置文件和模式直接加载到Rust类型中

5 个版本

0.2.4 2020年1月23日
0.2.3 2020年1月21日
0.2.2 2020年1月16日
0.2.1 2020年1月16日
0.2.0 2020年1月16日

#1969解析器实现

MIT 许可证

76KB
1.5K SLoC

KeyTree

KeyTree 是一种优雅的标记语言,旨在将可读信息转换为Rust数据结构。它设计得快速,以减少认知负荷,并且易于为自己的类型实现。它不依赖于其他crate,因此编译速度快。其格式如下

hobbit:
    name:           Frodo Baggins
    age:            60
    friends:
        hobbit:
            name:   Bilbo Baggins
            age:    111
        hobbit:
            name:   Samwise Gamgee
            age:    38

这样数据可以递归。此外,使用路径如 hobbit::friends::hobbit 可以轻松引用一组数据。

此库不遵循标准的Rust错误处理模式。如果有解析错误,它将崩溃;如果将值转换为Rust类型的操作中出错,它也将崩溃(并带有友好的错误消息)。如果您不希望出现这种情况,您需要将其在自己的线程/进程中运行。

数据格式规则

  • 缩进具有意义,为4个空格,相对于顶级键。由于缩进相对于顶级键,因此可以整齐地对代码中的嵌入式字符串进行对齐。

  • 每行可以是空行、只有空白、注释、键或键/值对。

  • 存在键和值。键/值对看起来像

name: Frodo

用于 struct 字段和 enum 变体。

键引用其下缩进的一行中的子键或子键/值对,例如

hobbit:
    name: Frodo

hobbit 引用结构体或枚举的名称。这样,数据简单映射到Rust数据结构。

  • 如果一个键有多个具有相同键的子键,它将形成一个集合,例如
hobbit:
    name: Frodo
    name: Bilbo

是一个hobbits的集合。

  • 键不能包含冒号 :,但必须紧随其后。

  • 值是 ':' 和空白之间的所有字符以及行尾之间的所有字符。值在两端都进行了空白修剪。

  • 注释需要在行的开头有 //。例如

// comment
hobbit:
    name: Frodo

示例

IntoKeyTree 到 Rust 类型的自动实现已经为 Vec<T>Option<T> 和基本的 Rust 类型提供。可以使用类型推断将 KeyTree 文本自动转换为这些数据类型。函数 at() 返回一个遍历 KeyTree 类型的迭代器,可用于为您的类型实现 Into。以下示例应涵盖90%的使用场景。

use keytree::KeyTree;
use keytree::parser::KeyTreeBuilder;

#[derive(Debug)]
struct Hobbit {
    name:    String,
    age:     u32,
    friends: Vec<Hobbit>,
    nick:    Option<String>,
}

impl<'a> Into<Hobbit> for KeyTree<'a> {
    fn into(self) -> Hobbit {
        Hobbit {
            name:       self.at("hobbit::name"),
            age:        self.at("hobbit::age"),
            friends:    self.at("hobbit::friends::hobbit"),
            nick:       self.op("hobbit::nick"),
        }
    }
}

fn main() {
    let s = r#"
         hobbit:
             name:         Frodo Baggins
             age:          98
             friends:
                 hobbit:
                     name: Bilbo Baggins
                     age:  176
                 hobbit:
                     name: Samwise Gamgee
                     age:  66
                     nick: Sam"#;

    
    let core = KeyTreeBuilder::parse(s);
    let hobbit: Hobbit = KeyTree::from_core(&core).into();
    dbg!(&hobbit);
}

详细信息

我们将详细查看示例中第几行发生的事情:

friends:    self.at("hobbit::friends::hobbit"),

Into 特性实现中,我们希望 Bilbo Baggins 和 Samwise Gamgee 成为 Frodo 的朋友。我们使用路径 "hobbit::friends::hobbit" 来指定他们在 KeyTree 字符串中的位置,这指向树中的两个分支(两个霍比特人)。与 op() 函数不同,at() 函数要求这些分支存在。Rust 推断它们需要转换为 Hobbit 结构体中指定的类型 Vec<Hobbit>。实际上,KeyTreeIntoVec<T> 实现提供了支持。事实上,at() 函数提供了一个霍比特人的迭代器,该迭代器被 Vec<T> 实现使用。

无运行时依赖