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
70KB
1K SLoC
另一种标签长度值(YATLV)格式。
标签长度值格式是交换结构化数据的一种常见方式,这种方式既紧凑又定义明确。它们介于丰富的模式格式(如JSON
、YAML和
XML
)和不含模式信息的紧凑二进制格式(如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-16
和unsigned-32
使用大端进行编码。
根帧可以编码为frame
或packet-frame
。当在流中发送frame
时,使用packet-frame
编码很有用。
尽管可以在field-value
中存储任意数据,但通常应遵守以下约定
- 数字使用大端编码
- 布尔值使用单个字节进行编码(
0x00=
false
,0xFF=
true
) - 文本以UTF-8编码
读取和写入
该库试图使读取和写入可靠且不依赖于要写入的值。为此,数字的add_*
方法始终使用相同数量的字节,而不考虑实际写入的值。目前只有add_data
和add_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