use packtool::{Packed, View};
#[derive(Debug, PartialEq, Eq, Packed)]
#[packed(value = b"tuple")]
struct TagTuple();
#[derive(Debug, PartialEq, Eq, Packed)]
#[packed(value = b"struct")]
struct TagStruct {}
#[derive(Debug, PartialEq, Eq, Packed)]
struct Tuple1(u8);
#[derive(Debug, PartialEq, Eq, Packed)]
struct Tuple2(u32, u16);
#[derive(Debug, PartialEq, Eq, Packed)]
struct Tuple3(TagStruct, TagStruct, TagTuple);
#[derive(Debug, PartialEq, Eq, Packed)]
struct Struct2 {
tag: TagStruct,
value: u16,
}
macro_rules! internal_mk_test {
($Type:ty => ($cstr:expr_2021, $SLICE:expr_2021)) => {{
let view = View::<$Type>::try_from_slice($SLICE).unwrap();
let object: $Type = view.unpack();
assert_eq!(object, $cstr);
let mut slice = [0u8; <$Type as Packed>::SIZE];
($cstr).unchecked_write_to_slice(&mut slice);
assert_eq!($SLICE, &slice);
}};
($Type:ty => ( $SLICE:expr_2021 )) => {{
let _err = View::<$Type>::try_from_slice($SLICE).unwrap_err();
}};
}
#[test]
fn tuple1() {
internal_mk_test!(Tuple1 => ( Tuple1(0), &[0u8]));
internal_mk_test!(Tuple1 => ( Tuple1(42), &[42u8]));
internal_mk_test!(Tuple1 => ( &[0u8; 2]));
}
#[test]
fn tuple2() {
internal_mk_test!(Tuple2 => ( Tuple2(0xFF, 0), &[0xFFu8, 0, 0, 0, 0, 0]));
}
#[test]
fn tuple3() {
internal_mk_test!(Tuple3 => (
Tuple3(TagStruct {}, TagStruct {}, TagTuple ()),
b"structstructtuple")
);
}
#[test]
fn struct2() {
internal_mk_test!(Struct2 => (
Struct2 {
tag: TagStruct {},
value: 42,
},
b"struct\x2a\x00")
);
}
#[derive(Debug, PartialEq, Eq, Packed)]
struct Content {
nonce: u32,
flag: u8,
}
#[derive(Debug, PartialEq, Eq, Packed)]
struct Log<T> {
parent_id: [u8; 64],
author: [u8; 33],
content: T,
signature: [u8; 64],
}
#[test]
fn generic_log_round_trips() {
use packtool::Packet;
assert_eq!(
<Log<Content> as Packed>::SIZE,
64 + 33 + <Content as Packed>::SIZE + 64
);
let log = Log::<Content> {
parent_id: [1u8; 64],
author: [2u8; 33],
content: Content {
nonce: 0xDEAD_BEEF,
flag: 0x2a,
},
signature: [3u8; 64],
};
let packet = Packet::pack(&log);
assert_eq!(packet.unpack(), log);
let view = View::<Log<Content>>::try_from_slice(packet.as_ref()).unwrap();
assert_eq!(view.unpack(), log);
let content = Log::<Content>::content(packet.view());
assert_eq!(
content.unpack(),
Content {
nonce: 0xDEAD_BEEF,
flag: 0x2a,
}
);
let too_short = vec![0u8; <Log<Content> as Packed>::SIZE - 1];
let _err = View::<Log<Content>>::try_from_slice(&too_short).unwrap_err();
}
#[derive(Debug, PartialEq, Eq, Packed)]
struct Pair<A, B> {
left: A,
tag: u8,
right: B,
}
#[test]
fn generic_pair_two_type_params() {
use packtool::Packet;
assert_eq!(
<Pair<u32, Content> as Packed>::SIZE,
<u32 as Packed>::SIZE + 1 + <Content as Packed>::SIZE
);
let pair = Pair::<u32, Content> {
left: 0x0102_0304,
tag: 0x2a,
right: Content {
nonce: 0xDEAD_BEEF,
flag: 0x7f,
},
};
let packet = Packet::pack(&pair);
assert_eq!(packet.unpack(), pair);
let view = View::<Pair<u32, Content>>::try_from_slice(packet.as_ref()).unwrap();
assert_eq!(view.unpack(), pair);
}
#[derive(Debug, PartialEq, Eq, Packed)]
struct Guarded<T>
where
T: Copy,
{
value: T,
tag: u8,
}
#[test]
fn generic_struct_with_preexisting_where_clause() {
use packtool::Packet;
assert_eq!(<Guarded<u16> as Packed>::SIZE, <u16 as Packed>::SIZE + 1);
let guarded = Guarded::<u16> {
value: 0xBEEF,
tag: 0x11,
};
let packet = Packet::pack(&guarded);
assert_eq!(packet.unpack(), guarded);
}
#[test]
fn concrete_struct_unchanged() {
use packtool::Packet;
let content = Content {
nonce: 0x0011_2233,
flag: 0x44,
};
let packet = Packet::pack(&content);
assert_eq!(packet.unpack(), content);
assert_eq!(<Content as Packed>::SIZE, 5);
}