Rust的CDDL验证库cddl-cat使用指南:高效解析和验证符合CDDL规范的数据结构
Rust的CDDL验证库cddl-cat使用指南:高效解析和验证符合CDDL规范的数据结构
cddl-cat
是一个用于验证编码数据是否符合CDDL文档描述的预期结构的库。CDDL是RFC8610描述的文本文档,用于描述数据结构。CDDL不绑定任何特定的序列化或编码方法,可用于验证CBOR或JSON格式的数据。
实现细节
- 支持CBOR和JSON编码,由
serde_cbor
和serde_json
特性控制 - 从CDDL AST构建"中间验证树"(IVT),简化了验证过程
- 验证代码使用
LookupContext
对象执行所有规则查找 - 包含全面的测试(覆盖率90%+)
示例
验证JSON数据
use cddl_cat::validate_json_str;
let cddl_input = "person = {name: tstr, age: int}";
let json_str = r#"{ "name": "Bob", "age": 43 }"#;
validate_json_str("person", cddl_input, &json_str).unwrap();
如果JSON数据不符合预期结构,会返回错误:
use cddl_cat::validate_json_str;
let cddl_input = "person = {name: tstr, age: int}";
let json_str = r#"{ "name": "Bob", "age": "forty three" }"#;
assert!(validate_json_str("person", cddl_input, &json_str).is_err());
验证CBOR数据
use cddl_cat::validate_cbor_bytes;
use serde::Serialize;
#[derive(Serialize)]
struct PersonStruct {
name: String,
age: u32,
}
let input = PersonStruct {
name: "Bob".to_string(),
age: 43,
};
let cbor_bytes = serde_cbor::to_vec(&input).unwrap();
let cddl_input = "person = {name: tstr, age: int}";
validate_cbor_bytes("person", cddl_input, &cbor_bytes).unwrap();
完整示例代码
// 添加依赖到Cargo.toml
// [dependencies]
// cddl-cat = "0.6.2"
// serde = { version = "1.0", features = ["derive"] }
// serde_cbor = "0.11"
use cddl_cat::{validate_json_str, validate_cbor_bytes};
use serde::Serialize;
fn main() {
// 示例1: 验证JSON数据
json_validation_example();
// 示例2: 验证CBOR数据
cbor_validation_example();
}
fn json_validation_example() {
// CDDL schema定义
let cddl_schema = r#"
person = {
name: tstr,
age: int,
address?: {
street: tstr,
city: tstr,
zip: uint
}
}
"#;
// 有效的JSON数据
let valid_json = r#"
{
"name": "Alice",
"age": 30,
"address": {
"street": "123 Main St",
"city": "Anytown",
"zip": 12345
}
}
"#;
// 无效的JSON数据(age应该是int)
let invalid_json = r#"
{
"name": "Bob",
"age": "thirty"
}
"#;
// 验证有效数据
validate_json_str("person", cddl_schema, valid_json).unwrap();
println!("JSON validation passed for valid data!");
// 验证无效数据
assert!(validate_json_str("person", cddl_schema, invalid_json).is_err());
println!("JSON validation correctly failed for invalid data!");
}
fn cbor_validation_example() {
// CDDL schema定义
let cddl_schema = r#"
product = {
id: uint,
name: tstr,
price: float,
in_stock: bool
}
"#;
// 定义数据结构
#[derive(Serialize)]
struct Product {
id: u32,
name: String,
price: f32,
in_stock: bool,
}
// 创建有效产品
let valid_product = Product {
id: 1001,
name: "Rust Programming Book".to_string(),
price: 39.99,
in_stock: true,
};
// 序列化为CBOR
let cbor_data = serde_cbor::to_vec(&valid_product).unwrap();
// 验证CBOR数据
validate_cbor_bytes("product", cddl_schema, &cbor_data).unwrap();
println!("CBOR validation passed for valid data!");
}
支持的类型和特性
支持的预定义类型
any
,uint
,nint
,int
,bstr
,bytes
,tstr
,text
float
,float16
,float32
,float64
,float16-32
,float32-64
支持的CDDL特性
- 基本预定义类型
- 字面量(int, float, bool, UTF-8文本字符串)
- 字节字符串(UTF-8, hex或base64)
- 数组和映射
- 规则名称查找
- 组
- 选择(使用
/
或//
语法) - 出现次数(
?
,*
,+
, 或m*n
) - 范围(如
1..7
或1...8
) - 解包(
~
) - 将组转换为选择(
&
) - 带cut语法的映射键(
^ =>
) - 泛型类型
- 控制运算符
.cbor
,.size
, 和.regexp
安装
在项目目录中运行以下Cargo命令:
cargo add cddl-cat
或在Cargo.toml中添加:
cddl-cat = "0.6.2"
1 回复
Rust的CDDL验证库cddl-cat使用指南:高效解析和验证符合CDDL规范的数据结构
介绍
cddl-cat
是一个Rust库,用于根据CDDL(Concise Data Definition Language)规范验证数据结构。CDDL是一种用于描述数据格式的简洁语言,类似于JSON Schema但更简单直观。
cddl-cat
提供了以下核心功能:
- 解析CDDL规范
- 验证JSON或CBOR数据是否符合CDDL定义
- 生成符合CDDL规范的数据结构
- 支持CDDL的大部分特性,包括类型、组、选择器等
安装
在Cargo.toml中添加依赖:
[dependencies]
cddl-cat = "0.6"
基本使用方法
1. 定义CDDL规范
首先创建一个CDDL文件,例如person.cddl
:
; 定义一个人物结构
person = {
name: tstr,
age: uint,
? nickname: tstr,
* tstr => any
}
2. 验证JSON数据
use cddl_cat::validate_json_str;
fn main() {
let cddl_input = "person = { name: tstr, age: uint, ? nickname: tstr }";
let json_str = r#"{ "name": "Alice", "age": 30 }"#;
let validation_result = validate_json_str("person", cddl_input, json_str);
assert!(validation_result.is_ok());
}
3. 验证CBOR数据
use cddl_cat::validate_cbor_bytes;
use serde::Serialize;
#[derive(Serialize)]
struct Person {
name: String,
age: u32,
}
fn main() {
let cddl_input = "person = { name: tstr, age: uint }";
let person = Person {
name: "Bob".to_string(),
age: 25,
};
let cbor_data = serde_cbor::to_vec(&person).unwrap();
let validation_result = validate_cbor_bytes("person", cddl_input, &cbor_data);
assert!(validation_result.is_ok());
}
高级用法
使用预解析的CDDL
对于需要多次验证的情况,可以预解析CDDL提高性能:
use cddl_cat::{validate_cbor_bytes, parse_cddl};
use std::collections::HashMap;
fn main() {
let cddl_input = "
person = { name: tstr, age: uint }
employee = { name: tstr, department: tstr }
";
// 预解析CDDL
let parsed_cddl = parse_cddl(cddl_input).unwrap();
// 创建验证器
let validator = parsed_cddl.get_validator("person").unwrap();
// 验证数据
let json_str = r#"{ "name": "Charlie", "age": 40 }"#;
let validation_result = validator.validate_json_str(json_str);
assert!(validation_result.is_ok());
}
处理复杂结构
use cddl_cat::validate_json_str;
fn validate_vehicle() {
let cddl_input = r#"
vehicle = {
type: "car" / "truck" / "motorcycle",
wheels: uint .ge 2 .le 18,
engine: {
type: "electric" / "combustion",
? power: uint,
},
* tstr => any
}
"#;
let valid_car = r#"
{
"type": "car",
"wheels": 4,
"engine": { "type": "combustion", "power": 150 },
"color": "red"
}
"#;
assert!(validate_json_str("vehicle", cddl_input, valid_car).is_ok());
}
错误处理
cddl-cat
提供了详细的错误信息:
use cddl_cat::validate_json_str;
fn main() {
let cddl_input = "person = { name: tstr, age: uint }";
let invalid_json = r#"{ "name": "Dave", "age": "thirty" }"#;
match validate_json_str("person", cddl_input, invalid_json) {
Ok(_) => println!("Valid!"),
Err(e) => println!("Validation error: {}", e),
}
}
生成符合CDDL的数据
cddl-cat
还可以生成符合CDDL规范的随机数据:
use cddl_cat::generate_json_from_cddl;
fn main() {
let cddl_input = "person = { name: tstr, age: uint }";
let generated = generate_json_from_cddl("person", cddl_input).unwrap();
println!("Generated person: {}", generated);
}
性能建议
- 对于重复验证,预解析CDDL规范
- 对于大型CDDL文件,考虑拆分为多个小文件
- 在验证前先进行基本的JSON/CBOR语法检查
cddl-cat
是Rust生态中处理CDDL验证的高效工具,特别适合需要严格数据格式验证的场景,如通信协议、配置文件验证等。