swsml-0.1.0 has been yanked.
swsml
SML — SNOWARE Markup Language 的 Rust 实现:声明式数据/配置格式,JSON/YAML 的替代品。
SML 源于 eclog,在其基础上演进为独立格式。
- 仓库:https://gitee.com/snoware/sml
- 许可:MulanPSL-2.0
包名是
swsml而非sml-rs——后者已被无关项目占用 (Smart Message Language 智能电表协议解析器)。 lib 名仍为sml,因此use sml::{...}不受影响。
Logo:黑花括号 {} 表示语法骨架(块的边界),蓝色雪花 ❄ 表示精确的取值点。
特性
| 特性 | 说明 |
|---|---|
| 引号可选 | 裸词即字符串(state: NY) |
| 块冒号可省 | address { } ≡ address: { } |
| 数组分隔灵活 | [ a b c ]、每行一个、逗号可选 |
| 片段继承 | @name { } 定义,&name 引用 |
| include 指令 | 拆分配置,可嵌套、可在块内注入字段 |
| 版本声明 | @version v1,便于将来演进不破坏旧文档 |
| 环境变量内联 | $env.VAR |
| 类型自识别 | true/false/null / 数字 / 字符串 |
版本声明
@version v1
app: resender
v1为当前版本;未声明时默认按当前版本处理,既有文档不受影响- 声明了实现不支持的版本会报错,而非静默按错误语法解析
- 允许多次声明(include 进来的文件可各自声明),但必须一致
version是保留字,不可作为片段名
use ;
let = parse_versioned?;
assert_eq!;
// 只需数据时用 parse 即可,它会自动剥离版本声明
let v = parse?;
文件版本:parse_file_versioned("app.sml")。
firstName: John
age: 27
address:
{
streetAddress: "21 2nd Street"
state: NY
}
phoneNumbers: [ { type: home } { type: office } ]
@base { region: cn-north-1 }
server web { &base port: 8080 }
用法
[]
= "0.1"
# 需要 serde 互操作时:
# swsml = { version = "0.1", features = ["serde"] }
use ;
let v = parse?;
assert_eq!;
assert_eq!;
println!;
include 指令
# app.sml
app: resender
database {
include "conf.d/db.sml" # 在块内注入一组字段
pool: 16
}
use parse_file;
let v = parse_file?;
- 相对路径按被包含文件自身所在目录解析(同 C 预处理器),嵌套时行为可预期
- 语义是文本内联而非对象合并,因此可出现在块内部
- 循环引用、文件缺失均返回错误,不静默跳过;嵌套上限 32 层
- 引号内的
#不会被误判为注释
parse()是纯函数(不做 IO),include 由parse_file()/resolve_includes()处理。 这样在无文件系统的环境(WASM / 沙箱)中仍可安全嵌入parse()。
运行示例:
serde 支持(可选)
启用 serde feature 后,Value 实现 Serialize/Deserialize,可与任意 serde 后端互操作:
let v = parse?;
let json = to_string?; // {"name":"John","age":27}
let back: Value = from_str?;
采用手写实现而非 #[derive],以保证数据形状自然:
Value::Int(27) 序列化为 27,而非 derive 会产生的 {"Int":27}。
不启用该 feature 时,本 crate 为零依赖。
多语言实现
| 语言 | 位置 |
|---|---|
| Soup / Lua | ../lua/(lib/sml.soup) |
| Rust | 本目录(sml-rs) |
| C | ../c/sml.h |
| JavaScript | ../js/sml.mjs |
License
MulanPSL-2.0