47次发布
0.9.4 | 2023年12月14日 |
---|---|
0.9.3 |
|
0.9.1 | 2022年10月27日 |
0.9.0-beta.1 | 2022年3月23日 |
0.3.4 | 2019年7月25日 |
#90 in 解析实现
13,080 每月下载量
在cddlconv中使用
740KB
19K SLoC
cddl-rs
此crate最初作为了解Rust和解析的一般方法的个人学习练习而开发。可能还有更高效和更稳定的CDDL解析库。虽然有一些此crate在生产中使用的示例,但在使用此crate作为此类用途之前应谨慎考虑。
CDDL(简明数据定义语言)的Rust实现。CDDL是IETF标准,它“提出了一种表示CBOR和JSON数据结构的记法约定。”截至2019年6月12日,它作为RFC 8610(提议标准)发布于https://tools.ietf.org/html/rfc8610。
此crate包含CDDL的手写解析器和词法分析器,其开发受到了Thorsten Ball的书籍"用Go编写解释器"中概述的技术的极大启发。AST已构建以紧密匹配规范中ABNF语法的规则附录B。所有CDDL都必须根据规范使用UTF-8进行编码。
此crate支持验证CBOR和JSON数据结构。最低支持的Rust版本(MSRV)是1.67.0。
此外,此仓库还包括一个基本的语言服务器实现和Visual Studio Code扩展,用于编辑CDDL。实现由此crate中包含的编译WebAssembly目标支持。
目标
- 将CDDL文档解析到AST
- 验证CDDL文档与RFC 8610的一致性
- 验证CBOR数据结构
- 验证JSON文档
- 从符合CDDL的文档生成示例JSON
- 尽可能接近零复制
- 为浏览器和Node.js编译WebAssembly目标
-
无std
支持(仅词法和解析) - 语言服务器实现和Visual Studio Code扩展
非目标
- 性能(如果这个crate(软件包)获得足够的关注,进行更正式的性能分析或探索使用像nom这样的解析器组合框架可能是谨慎的)
- 支持CBOR诊断表示法
- I-JSON兼容性
为什么选择Rust?
Rust是一种围绕安全性设计的系统编程语言,非常适合资源受限的系统。CDDL和CBOR都是针对小型代码和消息大小以及受限节点设计的,Rust也为此类场景进行了设计。
命令行界面(CLI)
适用于各种平台。该工具支持解析CDDL文件以验证是否符合RFC 8610。它还可以用于验证JSON文档和CBOR二进制文件是否符合CDDL文档。有关JSON和CBOR验证实现的详细信息,请参阅下面的部分。
安装
GitHub发行版
可以从GitHub 发行版下载Linux、macOS和Windows的二进制文件。
Cargo
cargo install cddl
Docker
docker pull ghcr.io/anweiss/cddl-cli:latest
CLI使用
可以通过执行help
子命令来查看使用此工具的说明。
cddl help
如果使用Docker
将
<version>
替换为适当的发行版标签。在执行命令时,需要使用--volume
参数将CDDL文档挂载到容器中。JSON或CBOR文件可以包含在卷挂载中,或者通过STDIN传递给命令。
docker run -it --rm -v $PWD:/cddl -w /cddl ghcr.io/anweiss/cddl-cli:<version> help
您可以使用它来验证JSON文档和/或CBOR二进制文件
cddl validate [OPTIONS] --cddl <CDDL> <--stdin|--json <JSON>...|--cbor <CBOR>...>
它还支持验证STDIN中的文件(如果它检测到输入为有效的UTF-8,则将尝试将输入作为JSON进行验证,否则将其视为CBOR)
cat reputon.json | cddl validate --cddl reputon.cddl --stdin
cat reputon.cbor | cddl validate --cddl reputon.cddl --stdin
或使用Docker
docker run -i --rm -v $PWD:/data -w /data ghcr.io/anweiss/cddl-cli:0.9.3 validate --cddl reputon.cddl --stdin < reputon.json
网站
您还可以在https://cddl.anweiss.tech找到简单的RFC 8610兼容性工具。此相同的代码库已编译为通过WebAssembly在浏览器中使用。
Visual Studio Code扩展
一个用于在Visual Studio Code中编辑CDDL文档的扩展已发布到市场这里。您可以在README中找到更多信息。
支持的功能
- 映射
- 结构体
- 表
- 裁剪
- 组
- 数组
- 值
- 选择
- 范围
- 枚举(从组构建选择)
- 根类型
- 出现次数
- 预定义类型
- 标签
- 展开
- 控制
- 插座/插头
- 泛型
- 操作符优先级
- 注释
- 数值int/uint
- 数值十六进制浮点数
- 具有指数的数值
- 无前缀的字节字符串
- 有前缀的字节字符串
使用方法
只需将依赖关系添加到Cargo.toml
[dependencies]
cddl = "0.9.3"
JSON和CBOR验证都需要std
。
功能标志
包含了一些便利功能,以使抽象语法树(AST)更加简洁,并启用额外的功能。您可以使用default-features = false
构建no_std
版本,并选择性地启用以下任何功能。
--feature ast-span
将Span
类型添加到AST中,以跟踪词法分析和解析器的位置。默认启用。
--feature ast-comments
在AST中包含注释字符串。默认启用。
--feature ast-parent
添加ParentVisitor
实现,以便可以使用父指针遍历AST。默认启用。
--feature json
启用JSON验证。默认启用。
--feature cbor
启用CBOR验证。默认启用。
--功能:额外的控件
启用对在RFC 9165中定义的额外控件操作符的验证支持。默认启用。
解析 CDDL
use cddl::parser::cddl_from_str;
let input = r#"myrule = int"#;
assert!(cddl_from_str(input, true).is_ok())
验证 JSON
use cddl::validate_json_from_str;
let cddl = r#"person = {
name: tstr,
age: uint,
address: tstr,
}"#;
let json = r#"{
"name": "John",
"age": 50,
"address": "1234 Lakeshore Dr"
}"#;
assert!(validate_json_from_str(cddl, json).is_ok())
此 crate 使用 Serde 框架,特别是 serde_json crate,用于解析和验证 JSON。选择 Serde 是因为它在生态系统中的成熟度以及它通过 ciborium crate 支持序列化和反序列化 CBOR。
如标准附录 E(附录 E)所述,只能使用 CBOR 数据模型子集的 JSON 进行验证。以下为为了简洁而包含的有限预置:
any = #
uint = #0
nint = #1
int = uint / nint
tstr = #3
text = tstr
number = int / float
float16 = #7.25
float32 = #7.26
float64 = #7.27
float16-32 = float16 / float32
float32-64 = float32 / float64
float = float16-32 / float64
false = #7.20
true = #7.21
bool = false / true
nil = #7.22
null = nil
此外,以下标准预置中的数据类型可用于验证 JSON 字符串和数字
tdate = #6.0(tstr)
uri = #6.32(tstr)
b64url = #6.33(tstr)
time = #6.1(number)
CDDL 数据结构定义中定义的第一个非组规则确定了根类型,随后用于验证顶层 JSON 数据类型。
支持的 JSON 验证功能
以下 CDDL 类型和支持的功能可用于此 crate 验证 JSON
CDDL | JSON |
---|---|
结构体 | 对象 |
数组 | 数组1 |
文本/tstr |
字符串 |
uri |
字符串(有效的 RFC3986 URI) |
tdate |
字符串(有效的 RFC3339 日期/时间) |
b64url |
字符串(base64url 编码) |
时间 |
数字(有效的 UNIX 时间戳整数,以秒为单位) |
数字/int/float |
数字2 |
bool / true / false |
布尔值 |
null/nil |
null |
任何 |
任何有效的 JSON |
字节字符串 | 尚未实现 |
unwrap (~ ) |
与映射、数组或标签中的 unwrapped 类型匹配的任何 JSON |
CDDL 组、泛型、插座/插头和组到选择枚举都可以用于验证 JSON。
由于 JSON 对象仅支持键的类型为 JSON 字符串,因此当验证 JSON 时,CDDL 结构中定义的成员键必须使用冒号语法(mykey: tstr
或 "mykey": tstr
)或双箭头语法(如果成员键是文本字符串值("mykey" => tstr
)或裸词,它解析为字符串数据类型(text
或 tstr
)或另一个文本字符串值(* tstr => any
))。
可以使用出现指示符来验证 JSON 对象中的键/值对以及 JSON 数组中的元素数量;具体取决于在 CDDL 数据定义中如何定义指示符。
以下是支持的控件操作符表
控件操作符 | 支持 |
---|---|
.pcre |
✔️3 |
.regex |
✔️3(.pcre 的别称) |
.size |
✔️ |
.bits |
在验证 JSON 时忽略 |
.cbor |
在验证 JSON 时忽略 |
.cborseq |
在验证 JSON 时忽略 |
.within |
✔️ |
.and |
✔️ |
.lt |
✔️ |
.le |
✔️ |
.gt |
✔️ |
.ge |
✔️ |
.eq |
✔️ |
.ne |
✔️ |
.default |
✔️ |
1:当使用具有多个组条目的组进行数组验证时,出现指示器是“贪婪”的,因为在验证过程中只使用遇到的第一个出现指示器。由于处理这些歧义所涉及的复杂性,后续带有出现指示器的条目将被忽略。为了进行适当的JSON验证,请避免编写类似以下内容的CDDL:[ * a: int, b: tstr, ? c: int ]
。
2:虽然JSON本身不区分整数和浮点数,但这个crate提供了对更具体的数值CBOR类型的验证能力,前提是它的等效表示形式被JSON允许。有关使用CDDL与JSON数字使用影响的更多详细信息,请参阅标准的附录E:附录E。
3:由于Perl兼容正则表达式(PCREs)比XSD正则表达式更广泛使用,这个crate还提供了对提议的.pcre
控制扩展的支持,以替代.regexp
运算符(参见讨论和CDDL-Freezer提议)。在使用此控制时,请确保您的正则表达式字符串已正确进行JSON转义。
如果您已启用additional-controls
功能,下表中的控制表也可供使用
控件操作符 | 支持 |
---|---|
.加上 |
✔️ |
.猫 |
✔️ |
.检测 |
✔️ |
.ABNF |
✔️ |
.ABNF-B |
在验证 JSON 时忽略 |
.特性 |
✔️ |
您可以在验证过程中按以下方式激活功能
use cddl::validate_json_from_str;
let cddl = r#"
v = JC<"v", 2>
JC<J, C> = C .feature "cbor" / J .feature "json"
"#;
let json = r#""v""#;
assert!(validate_json_from_str(cddl, json, Some(&["json"])).is_ok())
与JSON模式和JSON模式语言比较
CDDL、JSON模式和JSON模式语言都可以用来定义JSON数据结构。然而,开发每种格式的方法差异很大。要找到有关这些格式之间差异的过去讨论的好地方是IETF邮件存档IETF邮件存档,特别是JSON和CBOR列表。这个crate的目的不是为使用CDDL而不是这些格式中的任何一个而辩护,而只是在Rust中提供一个示例实现。
验证CBOR
use cddl::validate_cbor_from_slice;
let cddl = r#"rule = false"#;
let cbor = b"\xF4";
assert!(validate_cbor_from_slice(cddl, cbor).is_ok())
该包还使用 Serde 和 ciborium 来验证 CBOR 数据结构。CBOR 验证是通过松散类型化的 ciborium::value::Value
枚举完成的。除了实现了 JSON 验证器的所有相同功能外,该包还支持验证 CBOR 标签(例如 #6.32(tstr)
),CBOR 主要类型(例如 #1.2
),表格类型(例如 { [ + tstr ] => int }
)和字节字符串。同样支持 .bits
、.cbor
和 .cborseq
控制运算符。
在验证 CBOR 时支持以下标签
标签 | 支持 |
---|---|
tdate= #6.0(tstr) |
✔️ |
时间= #6.1(数字) |
✔️ |
biguint= #6.2(bstr) |
✔️ |
bignint= #6.3(bstr) |
✔️ |
decfrac= #6.4([e10:int,m:integer]) |
尚未实现 |
bigfloat= #6.5([e2:int,m:integer]) |
尚未实现 |
eb64url= #6.21(任何) |
✔️ |
eb64legacy= #6.22(任何) |
✔️ |
eb16= #6.23(任何) |
✔️ |
encoded-cbor= #6.24(bstr) |
✔️ |
uri= #6.32(tstr) |
✔️ |
b64url= #6.33(tstr) |
✔️ |
b64legacy= #6.34(tstr) |
✔️ |
regexp= #6.35(tstr) |
✔️ |
mime-message= #6.36(tstr) |
✔️ |
cbor-任何= #6.55799(任何) |
✔️ |
如果您已启用additional-controls
功能,下表中的控制表也可供使用
控件操作符 | 支持 |
---|---|
.加上 |
✔️ |
.猫 |
✔️ |
.检测 |
✔️ |
.ABNF |
✔️ |
.ABNF-B |
✔️ |
.特性 |
✔️ |
您可以通过传递以下方式的功能字符串切片来在验证期间激活功能
use cddl::validate_cbor_from_slice;
let cddl = r#"
v = JC<"v", 2>
JC<J, C> = C .feature "cbor" / J .feature "json"
"#;
let cbor = b"\x02";
assert!(validate_cbor_from_slice(cddl, cbor, Some(&["cbor"])).is_ok())
no_std
支持
在提供堆分配器的情况下,no_std
上下文中只能使用词法分析和解析器。可以通过如下方式在您的 Cargo.toml
文件中禁用默认功能来启用此功能
[dependencies]
cddl = { version = "0.9.3", default-features = false }
实现了尽可能多的零拷贝解析。错误处理和诊断需要分配。
JSON 和 CBOR 验证都依赖于它们各自堆分配的 Value
类型,但由于这些类型在 no_std
上下文中不受支持,因此该包在 no_std
中也不支持。
使用此包的项目
以下是利用此包的一些已知项目
依赖项
~9–20MB
~258K SLoC