Rust的CDDL验证库cddl-cat使用指南:高效解析和验证符合CDDL规范的数据结构

Rust的CDDL验证库cddl-cat使用指南:高效解析和验证符合CDDL规范的数据结构

cddl-cat是一个用于验证编码数据是否符合CDDL文档描述的预期结构的库。CDDL是RFC8610描述的文本文档,用于描述数据结构。CDDL不绑定任何特定的序列化或编码方法,可用于验证CBOR或JSON格式的数据。

实现细节

  • 支持CBOR和JSON编码,由serde_cborserde_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..71...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);
}

性能建议

  1. 对于重复验证,预解析CDDL规范
  2. 对于大型CDDL文件,考虑拆分为多个小文件
  3. 在验证前先进行基本的JSON/CBOR语法检查

cddl-cat是Rust生态中处理CDDL验证的高效工具,特别适合需要严格数据格式验证的场景,如通信协议、配置文件验证等。

回到顶部