#byte-array #tuple #heterogeneous #list #conversion #endianness #data

无std heterob

字节/位与异构列表(元组)之间转换的库

6个版本 (3个破坏性版本)

0.4.0 2024年6月19日
0.3.0 2022年8月26日
0.2.2 2022年8月9日
0.2.1 2022年7月28日
0.1.0 2022年4月5日

#239Rust模式

Download history 84/week @ 2024-05-04 93/week @ 2024-05-11 213/week @ 2024-05-18 56/week @ 2024-05-25 125/week @ 2024-06-01 59/week @ 2024-06-08 172/week @ 2024-06-15 109/week @ 2024-06-22 60/week @ 2024-06-29 58/week @ 2024-07-06 114/week @ 2024-07-13 105/week @ 2024-07-20 118/week @ 2024-07-27 89/week @ 2024-08-03 98/week @ 2024-08-10 100/week @ 2024-08-17

每月422次下载
用于 2 crates

MIT许可证

62KB
819

此crate提供字节/位与异构列表(元组)之间转换的库。

库特性

  • 实现编译时类型检查
  • 既不声明也不导出过程宏
  • 从单个字节数组中混合字节序

示例

解析复杂数据结构

use heterob::{P4, endianness::LeBytesInto, bit_numbering::LsbInto};

// Source is a [u8;6] bytes array
let data = [0x00u8,0x11,0x22,0x33,0x44,0x55,0b1010_1001];

// Target struct
#[derive(Debug, Clone, PartialEq, Eq)]
struct S {
    byte: u8,
    word: Option<u16>,
    bytes: [u8;3],
    is_byte6_bit0: bool,
    byte6_last_4_bits: u8,
}

// Parse bytes array as integers
let P4((byte, word, bytes, byte6)) = data.le_bytes_into();
// Parse last byte as bitfield. Unit type () used as placeholder
let (is_byte6_bit0, (), is_some_word, byte6_last_4_bits) =
    P4::<u8, 1, 2, 1, 4>(byte6).lsb_into();
// `is_some_word` coerce to bool via let statement
let _: bool = is_some_word;

// Final structure
let result = S {
    byte,
    word: is_some_word.then(|| word),
    bytes,
    is_byte6_bit0,
    byte6_last_4_bits,
};

let sample = S {
    byte: 0x00,
    word: Some(0x2211),
    bytes: [0x33,0x44,0x55],
    is_byte6_bit0: true,
    byte6_last_4_bits: 0b1010,
};

assert_eq!(sample, result);

混合字节序

use heterob::{T3, endianness::{Be, Le}};
#[derive(Debug, Clone, PartialEq, Eq)]
struct S {
    le: u16,
    be: u16,
    bytes: [u8;2]
}

let data = [0x00,0x11,0x22,0x33,0x44,0x55];

let (Le(le),Be(be),bytes) = T3::from(data).into();
let s = S { le, be, bytes };

assert_eq!(S { le: 0x1100, be: 0x2233, bytes: [0x44,0x55] }, s, "{:x}", s.be);

可能失败的字节数组切片解析

use heterob::{Seq, P3, endianness::Be};

// Source is a bytes slice
let data = [0x00u8,0x11,0x22,0x33,0x44,0x55,0b1010_1001].as_slice();

// Target struct
#[derive(Debug, Clone, PartialEq, Eq)]
struct S {
    byte: u8,
    word: u16,
    bytes: [u8;3],
}

// Parse bytes array as integers
let Seq { head: Be((byte, word, bytes)), .. } = P3(data).try_into().unwrap();

// Final structure
let result = S {
    byte,
    word,
    bytes,
};

let sample = S {
    byte: 0x00,
    word: 0x1122,
    bytes: [0x33,0x44,0x55],
};

assert_eq!(sample, result);

编译时类型检查

通过内联const表达式 + assert!实现编译时检查。不幸的是,使用此类编译时检查很难找到错误源。随着稳定化的常量泛型算术,这应该会容易得多。

编译时检查了三件事情

1. 数组在多个数组上的拆分

此检查断言输入数组的长度等于输出数组长度的总和

# use heterob::T2;
let data = [0u8; 13];
let _ = T2::<[u8;4], [u8;3]>::from(data);

尝试将13字节长度的数组拆分为长度为4 + 3 = 7的2个数组将引发错误

error[E0080]: evaluation of `<heterob::T2<[u8; 4], [u8; 3]> as std::convert::From<[u8; 13]>>::from::{constant#1}` failed
   --> heterob/src/common.rs:402:1
    |
402 | common_impl!(2; A,B);
    | ^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'The sum AN + BN should be equal to N', heterob/src/
common.rs:402:1
    |
    = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `common_impl` (in Nightly builds, r
un with -Z macro-backtrace for more info)

note: erroneous constant encountered
   --> heterob/src/common.rs:402:1
    |
402 | common_impl!(2; A,B);
    | ^^^^^^^^^^^^^^^^^^^^
    |
    = note: this note originates in the macro `common_impl` (in Nightly builds, run with -Z macro-backtrace for more info)

note: the above error was encountered while instantiating `fn <heterob::T2<[u8; 4], [u8; 3]> as std::convert::From<[u8; 13]>>::from`
 --> src/lib.rs:9:13
  |
9 |     let _ = T2::<[u8; 4], [u8; 3]>::from(data);
  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

2. 随机值中的位索引

此检查断言位索引的总和小于值位数的数量

# use heterob::{P3, bit_numbering::LsbInto};
let data = 0u16;
let ((),(),()) = P3::<_, 2, 11, 5>(data).lsb_into();

尝试从16位值中提取12-17位将引发错误

err(https://doc.rust-lang.net.cn/core/macro.assert.html): evaluation of `<((), (), ()) as heterob::bit_numbering::FromLsb<heterob::P3<u16, 2, 11, 5>>>::from_lsb::{constant#0}` failed
   --> heterob/src/bit_numbering.rs:227:1
    |
227 | bit_numbering_impl!(3: A,B,C);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'The bits number in TY in P3<TY, ...> is less than sum AN + BN + CN', heterob/src/t(https://doc.rust-lang.net.cn/core/macro.assert.html)ring.rs:227:1
    |
    = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `bit_numbering_impl` (in Nightly builds, run with -Z macro-backtrace for more info)

note: erroneous constant encountered
   --> heterob/src/bit_numbering.rs:227:1
    |
227 | bit_numbering_impl!(3: A,B,C);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: this note originates in the macro `bit_numbering_impl` (in Nightly builds, run with -Z macro-backtrace for more info)

note: the above error was encountered while instantiating `fn <((), (), ()) as heterob::bit_numbering::FromLsb<heterob::P3<u16, 2, 11, 5>>>::from_lsb`
   --> heterob/src/bit_numbering.rs:136:9
    |
136 |         U::from_lsb(self)
    |         ^^^^^^^^^^^^^^^^^

3. 字节序转换

此检查检查源和结果中的字节数是否相等。

# use heterob::endianness::FromBeBytes;
let _: [u32; 2] = FromBeBytes::from_be_bytes([0u8; 7]);

尝试将7字节数组转换为8字节类型(u32 * 2)将引发类似以下错误的错误

error[E0080]: evaluation of `<[u32; 2] as heterob::endianness::FromBeBytes<7>>::from_be_bytes::{constant#1}` failed
   --> heterob/src/endianness.rs:352:1
    |
352 | endianness_integers!(u16, u32, u64, u128, usize);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'The size of [u32; M] and [u8; N] are different', heterob/src/endianness.rs:352:1
    |
    = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `endianness_integers` (in Nightly builds, run with -Z macro-backtrace for more info)

note: erroneous constant encountered
   --> heterob/src/endianness.rs:352:1
    |
352 | endianness_integers!(u16, u32, u64, u128, usize);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: this note originates in the macro `endianness_integers` (in Nightly builds, run with -Z macro-backtrace for more info)

note: the above error was encountered while instantiating `fn <[u32; 2] as heterob::endianness::FromBeBytes<7>>::from_be_bytes`
 --> src/lib.rs:8:23
  |
8 |     let _: [u32; 2] = FromBeBytes::from_be_bytes([0u8; 7]);

依赖项

~83KB