1 个不稳定版本
0.1.0 | 2019年2月25日 |
---|
#2220 在 编码
37KB
542 行
endio
简单易用的二进制数据读写。
std::io::{Read, Write}
仅允许读取和写入原始字节。当尝试读取/写入数据,例如整数时,它们必须先转换为字节,这可能会很麻烦。这个包允许直接读取/写入数据类型,这使得它变得和以下一样简单:
letvalue: u8 =reader.read()?;
and
writer.write(42u8);
.
自动端序转换
当处理由多个字节组成的整数时,有两种可能的字节顺序:大端和小端。当读取/写入时,这个包可以自动将整数从/到所需的端序转换,而无需你为每个读取/写入调用指定端序。这是通过将端序作为读取/写入实现者的类型的一部分通过不同的特质来实现的。这个包永远不会尝试猜测端序,你总是必须显式指定它(但只需一次)。
在 I/O 的整个过程中,你不受指定端序的约束。如果你需要处理在中间改变端序的数据,你可以使用带有 _be
-/_le
后缀的方法显式覆盖端序。
完全基于特质的 I/O
这个包完全基于特质,这意味着它在运行时不会添加任何状态。所有需要的信息都编码在类型级别。所有功能都委托给(反)序列化代码。
零成本抽象
由于这个包完全基于特质,编译器通常会对这个包的所有调用进行积极内联和优化。剩下的只有(反)序列化代码,这在使用这个包的情况下也是必要的。因此,使用这个包不会对你的代码产生任何惩罚,无论是在速度上还是在内存使用上。
当我比较了使用这个包的字节级 I/O 的代码与使用等效的原始 std::io
功能的代码时,编译为发布模式,在反汇编器中,我只发现了几条操作码的差异,对这个包的所有函数调用都已被完全优化掉。
我还没有进行过任何严肃的基准测试,也没有检查所有类型和功能的反汇编,但这些初步结果看起来很有希望。
可扩展性:读取 & 写入你自己的类型
您可以通过为您的类型实现此crate的特性和 read
/write
方法来利用此crate的功能。用户类型和已由此crate提供(反)序列化的类型之间没有区别,您将能够像使用原始类型一样使用 read
和 write
对您的类型进行操作。
您可以编写根据字节序不同而不同的(反)序列化,或者编写不区分字节序而是使用此crate的自动字节序推断来将字节序区分委托给子结构的(反)序列化。
在编写(反)序列化时,您不仅限于使用 std::io::{Read, Write}
或此crate的抽象,您还可以通过适当的特型界限使用其他功能。例如,也可以编写使用其代码中的 std::io::Seek
的(反)序列化。
简单迁移
如果您之前使用过原始的 std::io::{Read, Write}
与手动(反)序列化代码,或者提供了一个在 {Read, Write}
之上的抽象的crate,那么转向使用此crate的过程极为直接。只需将 std::io 特型与 crate中的字节序特定特型交换,您就可以访问直接读写方法。您不需要编写任何额外的代码,实现了 std::io::Read
或 std::io::Write
的所有内容都将自动实现字节序特定特型。
如果对Rust的原始类型进行(反)序列化是有意义的,则已经实现了它们的(反)序列化。例如,isize
和 usize
没有实现,因为它们本质上具有可变大小,因此不能有可移植的字节表示形式。然而,其他整数和浮点类型已经实现,如果您只想读取/写入一些简单的原始类型,则使用 read
/write
方法将正常工作。
请参阅下面的示例,了解一些典型的使用此crate的I/O操作。
示例
以下是使用此crate的两种典型方式
从小端字节数据中读取数据
// This will make the read calls use little endian.
use endio::LERead;
// Works with any object implementing std::io::Read.
let mut reader = &b"\x2a\x01\x2c\xf3\xfe\xcf"[..];
let a: u8 = reader.read().unwrap(); // Reads in little endian (specified by trait).
let b: bool = reader.read().unwrap(); // Deserialization code is automatically inferred.
let c: u32 = reader.read_be().unwrap(); // Reads in forced big endian.
// The results are already converted into the appropriate types and ready for use.
assert_eq!(a, 42);
assert_eq!(b, true);
assert_eq!(c, 754187983);
将数据写入字节数组,大端格式
// This time we'll use big endian.
use endio::BEWrite;
// Vec implements std::io::Write.
let mut writer = vec![];
writer.write(42u8); // Directly specifying values works fine.
writer.write(true); // Everything is automatically converted to bytes.
writer.write_le(754187983); // The trait endianness can be overwritten if necessary.
// Done!
assert_eq!(writer, b"\x2a\x01\xcf\xfe\xf3\x2c");
有关此crate的工作原理的更多示例和说明包含在接口的文档中。还包括如何实现您自己的类型的示例。
入门
要进行I/O操作,您需要使用特性 use
BERead
和 BEWrite
,或者 LERead
和 LEWrite
。选择 BERead
和 BEWrite
进行大端I/O,选择 LERead
和 LEWrite
进行小端I/O。这将为您在结构体上提供 read
和 write
方法。 read
返回所需类型的值,而 write
接受值作为参数。反序列化要使用的数据类型和返回的数据类型通过类型推断处理,所以大多数情况下您甚至不需要显式地注释类型。
您可以通过实现 Serialize
/Deserialize
来读取和写入自己的类型。请参阅它们的文档以获取详细信息。