#little-endian #big-endian #endian #byte #binary #binary-data

endio

简单易用的二进制数据读写,具有自动端序转换和可扩展性

1 个不稳定版本

0.1.0 2019年2月25日

#2220编码

AGPL-3.0-or-later

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提供(反)序列化的类型之间没有区别,您将能够像使用原始类型一样使用 readwrite 对您的类型进行操作。

您可以编写根据字节序不同而不同的(反)序列化,或者编写不区分字节序而是使用此crate的自动字节序推断来将字节序区分委托给子结构的(反)序列化。

在编写(反)序列化时,您不仅限于使用 std::io::{Read, Write} 或此crate的抽象,您还可以通过适当的特型界限使用其他功能。例如,也可以编写使用其代码中的 std::io::Seek 的(反)序列化。

简单迁移

如果您之前使用过原始的 std::io::{Read, Write} 与手动(反)序列化代码,或者提供了一个在 {Read, Write} 之上的抽象的crate,那么转向使用此crate的过程极为直接。只需将 std::io 特型与 crate中的字节序特定特型交换,您就可以访问直接读写方法。您不需要编写任何额外的代码,实现了 std::io::Readstd::io::Write 的所有内容都将自动实现字节序特定特型。

如果对Rust的原始类型进行(反)序列化是有意义的,则已经实现了它们的(反)序列化。例如,isizeusize 没有实现,因为它们本质上具有可变大小,因此不能有可移植的字节表示形式。然而,其他整数和浮点类型已经实现,如果您只想读取/写入一些简单的原始类型,则使用 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 BEReadBEWrite,或者 LEReadLEWrite。选择 BEReadBEWrite 进行大端I/O,选择 LEReadLEWrite 进行小端I/O。这将为您在结构体上提供 readwrite 方法。 read 返回所需类型的值,而 write 接受值作为参数。反序列化要使用的数据类型和返回的数据类型通过类型推断处理,所以大多数情况下您甚至不需要显式地注释类型。

您可以通过实现 Serialize/Deserialize 来读取和写入自己的类型。请参阅它们的文档以获取详细信息。

无运行时依赖