4个稳定版本

1.3.0 2021年11月2日
1.2.0 2021年6月6日
1.1.0 2021年5月15日
1.0.0 2021年4月24日

解析器实现中排名第2149

MIT/Apache

70KB
1K SLoC

Rust Docs

另一种标签长度值(YATLV)格式。

标签长度值格式是交换结构化数据的一种常见方式,这种方式既紧凑又定义明确。它们介于丰富的模式格式(如JSONYAMLXML)和不含模式信息的紧凑二进制格式(如bincode)之间。

标签长度值格式的一个优点是,与无模式格式的同类相比,它们支持更好的向前兼容性,因为它们只包含解析器跳过它们不认识的字段所需的信息。

与许多标签长度值格式不同,没有尝试使用可变长度编码来减少'长度'占用空间。这确实导致了更大的编码,但大大简化了解析器和构建器的工作。

格式的结构

packet-frame = frame-size frame
frame-size   = unsigned32
frame        = frame-format field-count *field
frame-format = 0x01
field-count  = unsigned32
field        = field-tag field-length field-value
field-tag    = unsigned16
field-length = unsigned32
field-value  = octet-array
unsigned16   = 0x0000-0xFFFF
unsigned32   = 0x00000000-0xFFFFFFFF
octet-array  = *0x00-0xFF

其中

  • frame-format始终为0x01,但以后可能添加其他格式
  • 字段的数字必须与field-count匹配
  • field-value的长度必须与field-length匹配。
  • unsigned-16unsigned-32使用大端进行编码。

根帧可以编码为framepacket-frame。当在流中发送frame时,使用packet-frame编码很有用。

尽管可以在field-value中存储任意数据,但通常应遵守以下约定

  • 数字使用大端编码
  • 布尔值使用单个字节进行编码(0x00=false0xFF=true
  • 文本以UTF-8编码

读取和写入

该库试图使读取和写入可靠且不依赖于要写入的值。为此,数字的add_*方法始终使用相同数量的字节,而不考虑实际写入的值。目前只有add_dataadd_str可以添加可变数量的字节到帧中。

读取尝试保持向前兼容性,并保证以下内容:

  • 使用较小的 add_u* 方法写入的任何数字都可以被较大的方法安全读取。(例如,使用 add_u16 写入的数字可以安全地使用 get_u32 读取)。
  • 使用较大的 add_u* 方法写入的任何数字,如果值足够小,则可以被较小的方法读取。

这意味着在升级程序时,应始终安全地增加字段的范围,但如果字段的范围将要减小,则需要特殊处理。

创建功能

Yatlv 有一个可选功能

  • uuid 支持读取和写入 uuid。

示例用法

use yatlv::Result;

use yatlv::{FrameBuilder, FrameBuilderLike, FrameParser};

const TAG1: u16 = 1;
const TAG2: u16 = 2;
const TAG3: u16 = 3;
const TAG4: u16 = 4;

// the FrameBuilder will expand the buffer as needed, but it is more
// efficient to allocate enough capacity up front.
let mut buf = Vec::with_capacity(1000);

{
    let mut bld1 = FrameBuilder::new(&mut buf);
    bld1.add_str(TAG1, "hello");

    {
        // child FrameBuilders retain a mutable reference
        // to their parent - so you cannot have two child
        // FrameBuilders in the same scope.
        let mut bld2a = bld1.add_frame(TAG2);
        bld2a.add_u32(TAG4, 78);
        bld2a.add_u32(TAG4, 109);
    }

    {
        let mut bld2b = bld1.add_frame(TAG3);
        bld2b.add_str(TAG4, "goodbye");
    }
}

let parser1 = FrameParser::new(&buf)?;
assert_eq!(Some("hello"), parser1.get_str(TAG1)?);

// FrameParsers only have an immutable reference to their parent,
// so you can hold references to multiple child frames when parsing.
let parser2a = parser1.get_frame(TAG2)?.unwrap();
let parser2b = parser1.get_frame(TAG3)?.unwrap();

// Here we are using iterator access to get all the values with the same tag (TAG4)
let frame2a_values: Vec<_> = parser2a.get_u32s(TAG4).map(|v| v.unwrap()).collect();
assert_eq!(vec![78, 109], frame2a_values);

let frame2b_value = parser2b.get_str(TAG4)?;
assert_eq!(Some("goodbye"), frame2b_value);

当前版本:1.2.0

这是一个兴趣爱好项目;我没有足够的时间和资源来维护它。欢迎您使用和分叉,但我不建议将此 crate 用于任何重要工作。

许可证:MIT/Apache-2.0

依赖关系

~240KB