#toml-parser #toml #语法 #目标 #菜单 #食物 #

tomboy-toml-dom

对于那些在 Rust 的酷炫语法上感到困扰的人,我们的目标是提供一个像指向菜单吃快餐一样简单的 TOML 解析器。

22 个版本

0.1.21 2020 年 10 月 29 日
0.1.20 2020 年 10 月 29 日

#2398 in 解析器实现

Download history 73/week @ 2024-04-02 180/week @ 2024-07-02

180 每月下载次数

MIT 许可证

220KB
4.5K SLoC

Tomboy toml dom

对于那些在 Rust 的酷炫语法上感到困扰的人,我们的目标是提供一个像指向菜单吃快餐一样简单的 TOML 解析器。
Rust 的酷炫语法让人头疼?我们的目标是提供一个像点菜单吃快餐一样简单的 TOML 解析器。

不稳定版本。这是一个尝试和错误的过程。规范将会有所变化。
不稳定版。仍在试验和错误中。规范会不断变化。

Tomboy 是一个双关语。
Tomboy(淘气的小姑娘)是双关语。

参考资料

运行(実行)

看看仓库。
リポジトリを見てください。

cargo run --example advanced
cargo run --example comment
cargo run --example cover
cargo run --example deprecated
cargo run --example example
cargo run --example example-tail-comment
cargo run --example inline_table
cargo run --example main
cargo run --example mix_array
cargo run --example spot
cargo run --example table
cargo run --example toml-io-en-a-quick-tour-of-toml-v1-0-0rc3
cargo run --example toml-io-en-v1-0-0rc3-full-speck

规范(仕様)

规范将逐渐固化。
仕様は少しずつ固めていきます。

您可以认为,这里没有写出来的任何东西都无法完成。
ここに書かれていないことは何もできないと思ってもらって構いません。

./resource/example.toml

age = 40
weight = 93.5

# Long. 32bit size.
i32_max = 2_147_483_647
i32_min = -2_147_483_648
u32_max = 4_294_967_295

# Long long. 64bit size.
i64_max = 9_223_372_036_854_775_807
i64_min = -9_223_372_036_854_775_808
u64_max = 18_446_744_073_709_551_615

# 128bit size.
i128_max = 170_141_183_460_469_231_731_687_303_715_884_105_727
i128_min = -170_141_183_460_469_231_731_687_303_715_884_105_728
u128_max = 340_282_366_920_938_463_463_374_607_431_768_211_455

# hexadecimal with prefix `0x`
hex1 = 0xDEADBEEF
hex2 = 0xdeadbeef
hex3 = 0xdead_beef

# octal with prefix `0o`
oct1 = 0o01234567
oct2 = 0o755

# binary with prefix `0b`
bin1 = 0b11010110

# fractional
float1 = +1.0
float2 = 3.1415
float3 = -0.01

# exponent
float4 = 5e+22
float5 = 1e06
float6 = -2E-2

# both
float7 = 6.626e-34

# separators
float8 = 224_617.445_991_228

# infinity
infinite1 = inf # positive infinity
infinite2 = +inf # positive infinity
infinite3 = -inf # negative infinity

# not a number
not1 = nan
not2 = +nan
not3 = -nan

# basic string
apple = "pie"
basic_string_empty = ""
basic_string_escape_backslash = "\\"
basic_string_escape_double_quotation = "\""
basic_string_letter = "Hello, world!!"
basic_string_punctuation = "., ={}[]'\"\\!?"
basic_string_tab = "a\tb"

multiline_basic_string_letter = """Hello,
world!!"""
multiline_basic_string_punctuation = """., ={}[]"'""\\
!?"""
multiline_basic_string_trim_start = """\
  The quick brown \
  fox jumps over \
  the lazy dog.\
  """
multiline_basic_string_escape_double_quotation = """
\\
"""
multiline_basic_string_tab = """
a\tb
"""

literal_string_empty = ''
literal_string_letter = 'Hello, world!!'
literal_string_punctuation = '., ={}[]"\!?'

multiline_literal_string_letter = '''Hello,
world!!'''
multiline_literal_string_punctuation = '''., ={}[]'"\
!?'''
multiline_literal_string_first_newline_is_trimmed = '''
The first newline is
trimmed in raw strings.
All other whitespace
is preserved.
'''

adult = true
student = false

dob = 1979-05-27T07:32:00-08:00

#offset datetime
odt1 = 1979-05-27T07:32:00Z
odt2 = 1979-05-27T00:32:00-07:00
odt3 = 1979-05-27T00:32:00.999999-07:00

# local datetime
ldt1 = 1979-05-27T07:32:00
ldt2 = 1979-05-27T00:32:00.999999

# local date
ld1 = 1979-05-27

# local time
lt1 = 07:32:00
lt2 = 00:32:00.999999

# Array
# int_array = [-1, 0, 1]
# float_array = [0.0, 0.5, 1.0]
string_array = ["a", 'b', '"c"']

examples/example.rs

//! An exemplary program.
//! 模範的なプログラム。
//!
//! `cargo run --example example`

extern crate tomboy_toml_dom;

use chrono::{
    prelude::{DateTime, Utc},
    FixedOffset, NaiveDate, NaiveDateTime, NaiveTime,
};
use tomboy_toml_dom::Toml;

fn main() {
    // Read a toml.
    // Toml読取。
    let doc = Toml::from_file("./resource/example.toml");

    // Read a number.
    // 数値読取。
    assert!(doc.contains_key("age"));
    assert_eq!(doc.get_i128_by_key_v2("age"), Ok(Some(40)));
    assert_eq!(doc.get_isize_by_key_v2("age"), Ok(Some(40)));
    assert_eq!(doc.get_u128_by_key_v2("age"), Ok(Some(40)));
    assert_eq!(doc.get_usize_by_key_v2("age"), Ok(Some(40)));
    assert_eq!(doc.get_f64_by_key_v2("weight"), Ok(Some(93.5)));

    assert_eq!(doc.get_i128_by_key_v2("i32_max"), Ok(Some(2147483647)));
    assert_eq!(doc.get_i128_by_key_v2("i32_min"), Ok(Some(-2147483648)));

    assert_eq!(
        doc.get_i128_by_key_v2("i128_max"),
        Ok(Some(170_141_183_460_469_231_731_687_303_715_884_105_727))
    );
    assert_eq!(
        doc.get_i128_by_key_v2("i128_min"),
        Ok(Some(-170_141_183_460_469_231_731_687_303_715_884_105_728))
    );
    assert_eq!(
        doc.get_u128_by_key_v2("u128_max"),
        Ok(Some(340_282_366_920_938_463_463_374_607_431_768_211_455))
    );

    assert_eq!(doc.get_i128_by_key_v2("hex1"), Ok(Some(0xDEADBEEF)));
    assert_eq!(doc.get_i128_by_key_v2("hex2"), Ok(Some(0xdeadbeef)));
    assert_eq!(doc.get_i128_by_key_v2("hex3"), Ok(Some(0xdead_beef)));
    assert_eq!(doc.get_i128_by_key_v2("oct1"), Ok(Some(0o01234567)));
    assert_eq!(doc.get_i128_by_key_v2("oct2"), Ok(Some(0o755)));
    assert_eq!(doc.get_i128_by_key_v2("bin1"), Ok(Some(0b11010110)));
    assert_eq!(doc.get_f64_by_key_v2("float1"), Ok(Some(1.0)));
    assert_eq!(doc.get_f64_by_key_v2("float2"), Ok(Some(3.1415)));
    assert_eq!(doc.get_f64_by_key_v2("float3"), Ok(Some(-0.01)));
    assert_eq!(doc.get_f64_by_key_v2("float4"), Ok(Some(5e+22)));
    assert_eq!(doc.get_f64_by_key_v2("float5"), Ok(Some(1e06)));
    assert_eq!(doc.get_f64_by_key_v2("float6"), Ok(Some(-2E-2)));
    assert_eq!(doc.get_f64_by_key_v2("float7"), Ok(Some(6.626e-34)));
    assert_eq!(
        doc.get_f64_by_key_v2("float8"),
        Ok(Some(224_617.445_991_228))
    );
    assert_eq!(doc.get_f64_by_key_v2("infinite1"), Ok(Some(f64::INFINITY)));
    assert_eq!(doc.get_f64_by_key_v2("infinite2"), Ok(Some(f64::INFINITY)));
    assert_eq!(doc.get_f64_by_key_v2("infinite3"), Ok(Some(-f64::INFINITY)));
    assert!(if let Ok(Some(n)) = doc.get_f64_by_key_v2("not1") {
        n.is_nan() && n.is_sign_positive()
    } else {
        false
    });
    assert!(if let Ok(Some(n)) = doc.get_f64_by_key_v2("not2") {
        n.is_nan() && n.is_sign_positive()
    } else {
        false
    });
    assert!(if let Ok(Some(n)) = doc.get_f64_by_key_v2("not3") {
        n.is_nan() && n.is_sign_negative()
    } else {
        false
    });

    // WIP. Read a string.
    // 作業中。 文字列読取。
    assert_eq!(doc.get_string_by_key("apple"), Some("pie".to_string()));

    assert_eq!(
        doc.get_string_by_key("basic_string_letter"),
        Some("Hello, world!!".to_string())
    );
    assert_eq!(
        doc.get_string_by_key("basic_string_empty"),
        Some("".to_string())
    );
    assert_eq!(
        doc.get_string_by_key("basic_string_escape_backslash"),
        Some("\\".to_string())
    );
    assert_eq!(
        doc.get_string_by_key("basic_string_escape_double_quotation"),
        Some("\"".to_string())
    );
    assert_eq!(
        doc.get_string_by_key("basic_string_punctuation"),
        Some("., ={}[]'\"\\!?".to_string())
    );
    assert_eq!(
        doc.get_string_by_key("basic_string_tab"),
        Some("a\tb".to_string())
    );

    assert_eq!(
        doc.get_string_by_key("multiline_basic_string_letter"),
        Some(
            "Hello,
world!!"
                .to_string()
        )
    );

    assert_eq!(
        doc.get_string_by_key("multiline_basic_string_punctuation"),
        Some(
            "., ={}[]\"'\"\"\\
!?"
            .to_string()
        )
    );
    assert_eq!(
        doc.get_string_by_key("multiline_basic_string_trim_start"),
        Some("The quick brown fox jumps over the lazy dog.".to_string())
    );
    assert_eq!(
        doc.get_string_by_key("multiline_basic_string_escape_double_quotation"),
        Some(
            "
\\
"
            .to_string()
        )
    );
    /*
    // Fixed.
    println!(
        "debug|multiline_basic_string_tab|{}",
        doc.get_debug_string_by_key("multiline_basic_string_tab")
    );
    */
    assert_eq!(
        doc.get_string_by_key("multiline_basic_string_tab"),
        Some(
            "
a\tb
"
            .to_string()
        )
    );

    assert_eq!(
        doc.get_string_by_key("literal_string_empty"),
        Some("".to_string())
    );
    assert_eq!(
        doc.get_string_by_key("literal_string_letter"),
        Some("Hello, world!!".to_string())
    );
    assert_eq!(
        doc.get_string_by_key("literal_string_punctuation"),
        Some("., ={}[]\"\\!?".to_string())
    );
    assert_eq!(
        doc.get_string_by_key("multiline_literal_string_letter"),
        Some(
            "Hello,
world!!"
                .to_string()
        )
    );
    assert_eq!(
        doc.get_string_by_key("multiline_literal_string_punctuation"),
        Some(
            "., ={}[]'\"\\
!?"
            .to_string()
        )
    );
    assert_eq!(
        doc.get_string_by_key("multiline_literal_string_first_newline_is_trimmed"),
        Some(
            "The first newline is
trimmed in raw strings.
All other whitespace
is preserved.
"
            .to_string()
        )
    );

    // Read a boolean.
    // 論理値読取。
    assert_eq!(doc.get_bool_by_key("adult"), Some(true));
    assert_eq!(doc.get_bool_by_key("student"), Some(false));

    // DateTime.
    // 日付と時刻。
    assert_eq!(
        doc.get_datetime_utc_by_key("dob"),
        Some(
            "1979-05-27T07:32:00-08:00"
                .parse::<DateTime<Utc>>()
                .unwrap()
        )
    );

    assert_eq!(
        doc.get_datetime_utc_by_key("odt1"),
        Some("1979-05-27T07:32:00Z".parse::<DateTime<Utc>>().unwrap())
    );

    assert_eq!(
        doc.get_datetime_fixed_offset_by_key("odt2"),
        Some(
            "1979-05-27T00:32:00-07:00"
                .parse::<DateTime<FixedOffset>>()
                .unwrap()
        )
    );

    assert_eq!(
        doc.get_datetime_fixed_offset_by_key("odt3"),
        Some(
            "1979-05-27T00:32:00.999999-07:00"
                .parse::<DateTime<FixedOffset>>()
                .unwrap()
        )
    );

    // TODO Local datetime
    assert_eq!(
        // "1979-05-27T07:32:00". Toml の独自書式か。該当するフォーマット定義見つからず。
        doc.get_naive_datetime_by_key("ldt1"),
        Some(
            match NaiveDateTime::parse_from_str("1979-05-27T07:32:00", "%Y-%m-%dT%H:%M:%S") {
                Ok(n) => n,
                Err(why) => panic!("{}", why),
            }
        )
    );

    assert_eq!(
        // "1979-05-27T00:32:00.999999".
        doc.get_naive_datetime_by_key("ldt2"),
        Some(
            NaiveDateTime::parse_from_str("1979-05-27T00:32:00.999999", "%Y-%m-%dT%H:%M:%S%.6f")
                .unwrap()
        )
    );

    assert_eq!(
        // "1979-05-27".
        doc.get_naive_date_by_key("ld1"),
        Some(match NaiveDate::parse_from_str("1979-05-27", "%Y-%m-%d") {
            Ok(n) => n,
            Err(why) => panic!("{}", why),
        })
    );

    assert_eq!(
        doc.get_naive_time_by_key("lt1"),
        Some(NaiveTime::parse_from_str("07:32:00", "%H:%M:%S").unwrap())
    );

    assert_eq!(
        doc.get_naive_time_by_key("lt2"),
        Some(NaiveTime::parse_from_str("00:32:00.999999", "%H:%M:%S%.6f").unwrap())
    );

    // Read a array.
    // 配列読取。
    assert_eq!(
        doc.get_string_array_by_key("string_array"),
        Ok(Some(vec![
            "a".to_string(),
            "b".to_string(),
            "\"c\"".to_string()
        ]))
    );
}

待办事项(TODO)

  • 注释
    • 在空行中。
    • 在键值对之后。
    • 在表格之后。
  • 文字面
    • 文字面数字...
      • 整数
        • 0b - 二进制。
        • 0o - 八进制。
        • 0x - 十六进制。
        • _ - 分隔符。
      • 浮点数
        • . - 小数点。例如:3.14
        • _ - 分隔符。
        • inf - 正无穷。
        • +inf - 正无穷。
        • -inf - 负无穷。
        • nan - 非数。正数。
        • +nan - 非数。正数。
        • -nan - 非数。负数。
    • 日期时间
      • 1979-05-27 - 本地日期。(天真日期)
      • 1979-05-27T07:32:00 - 本地日期时间。(天真日期时间)
      • 1979-05-27T07:32:00Z - UTC日期时间。(UTC日期时间)
      • 1979-05-27T00:32:00.999999 - 本地日期时间。(原始日期时间)
      • 1979-05-27T00:32:00-07:00 - UTC日期时间。(固定偏移量日期时间)
      • 1979-05-27T00:32:00.999999-07:00 - UTC日期时间。(固定偏移量日期时间)
      • 07:32:00 - 本地时间。(原始时间)
      • 00:32:00.999999 - 本地时间。(原始时间)
  • 字符串(非str)
    • "abc" - 基本字符串。
      • 纯文本。
      • 转义序列。
    • """abc""" - 多行基本字符串。
      • 纯文本。
      • 转义序列。
      • 自动删除结尾的反斜杠。
    • 'abc' - 字面量字符串。
      • 纯文本。
    • '''abc''' - 多行字面量字符串。
      • 纯文本。
      • 原始字符串中删除第一行换行符。
    • 转义序列。
      • \r - 回车。
      • \n - 换行。
      • \t - 制表符。
      • \\ - 反斜杠。
      • \" - 双引号。
      • \u0000 - Unicode。
      • \U00000000 - Unicode。
  • 数组
    • [-1, 0, 1] - 整数数组。
    • [0.1, 0.5, 1.0] - 浮点数组。
    • ["a", 'b', '"c"'] - 字符串数组。

依赖项

~4.5–6.5MB
~108K SLoC