mod macro_ {
use bnb::{BitError, Sink, Source, bin, u4};
fn parse_lp<S: Source>(r: &mut S) -> Result<Vec<u8>, BitError> {
let n: u8 = r.read()?;
let mut v = Vec::new();
for _ in 0..n {
v.push(r.read::<u8>()?);
}
Ok(v)
}
fn write_lp<K: Sink>(v: &[u8], w: &mut K) -> Result<(), BitError> {
w.write(v.len() as u8)?;
for b in v {
w.write(*b)?;
}
Ok(())
}
#[bin]
#[derive(Debug, PartialEq, Eq, Clone)]
struct Frame {
tag: u4,
#[br(parse_with = parse_lp)]
#[bw(write_with = write_lp)]
data: Vec<u8>,
}
#[test]
fn custom_codec_round_trips() {
let f = Frame {
tag: u4::new(0x5),
data: vec![0xAA, 0xBB, 0xCC],
};
let bytes = f.to_bytes().unwrap();
assert_eq!(Frame::decode_exact(&bytes).unwrap(), f);
}
#[test]
fn empty_custom_run() {
let f = Frame {
tag: u4::new(0),
data: vec![],
};
assert_eq!(Frame::decode_exact(&f.to_bytes().unwrap()).unwrap(), f);
}
#[bin]
#[derive(Debug, PartialEq)]
struct Varints {
#[br(parse_with = bnb::codecs::leb128::parse)]
#[bw(write_with = bnb::codecs::leb128::write)]
length: u32,
#[br(parse_with = bnb::codecs::leb128::parse)]
#[bw(write_with = bnb::codecs::leb128::write)]
timestamp: u64,
}
#[test]
fn shipped_leb128_width_inference() {
let v = Varints {
length: 300,
timestamp: u64::MAX,
};
let bytes = v.to_bytes().unwrap();
assert_eq!(&bytes[..2], &[0xAC, 0x02]); assert_eq!(Varints::decode_exact(&bytes).unwrap(), v);
}
#[test]
fn shipped_leb128_adversarial_names_the_field() {
let wire = [0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00];
let err = Varints::decode_exact(&wire).unwrap_err();
assert_eq!(err.field, Some("length"));
}
#[bin]
#[derive(Debug, PartialEq)]
struct CStrings {
#[br(parse_with = bnb::codecs::cstring::parse)]
#[bw(write_with = bnb::codecs::cstring::write)]
#[try_str]
raw: Vec<u8>,
#[br(parse_with = bnb::codecs::cstring::parse_utf8)]
#[bw(write_with = bnb::codecs::cstring::write_utf8)]
title: String,
}
#[test]
fn shipped_cstring_both_forms() {
let c = CStrings {
raw: b"abc".to_vec(),
title: "héllo".into(),
};
let bytes = c.to_bytes().unwrap();
assert_eq!(CStrings::decode_exact(&bytes).unwrap(), c);
}
#[bin]
#[derive(Debug, PartialEq)]
struct Prefixed {
#[br(parse_with = bnb::codecs::prefixed::parse_string::<_, u16>)]
#[bw(write_with = bnb::codecs::prefixed::write_string::<_, u16>)]
wide: String,
#[br(parse_with = bnb::codecs::prefixed::parse_string::<_, bnb::u12>)]
#[bw(write_with = bnb::codecs::prefixed::write_string::<_, bnb::u12>)]
packed: String,
}
#[test]
fn shipped_prefixed_turbofish_and_un() {
let p = Prefixed {
wide: "hello".into(),
packed: "hi".into(),
};
let bytes = p.to_bytes().unwrap();
assert_eq!(&bytes[..7], &[0x00, 0x05, b'h', b'e', b'l', b'l', b'o']);
assert_eq!(Prefixed::decode_exact(&bytes).unwrap(), p);
}
#[bin]
#[derive(Debug, PartialEq)]
enum Item {
#[bin(magic = 0x01u8)]
Named {
#[br(parse_with = bnb::codecs::cstring::parse_utf8)]
#[bw(write_with = bnb::codecs::cstring::write_utf8)]
name: String,
},
#[bin(magic = 0x02u8)]
Sized {
#[br(parse_with = bnb::codecs::leb128::parse)]
#[bw(write_with = bnb::codecs::leb128::write)]
size: u64,
},
}
#[test]
fn shipped_codecs_in_enum_variants() {
let n = Item::Named { name: "x".into() };
let bytes = n.to_bytes().unwrap();
assert_eq!(bytes, [0x01, b'x', 0x00]);
assert_eq!(Item::decode_exact(&bytes).unwrap(), n);
let s = Item::Sized { size: 300 };
let bytes = s.to_bytes().unwrap();
assert_eq!(bytes, [0x02, 0xAC, 0x02]);
assert_eq!(Item::decode_exact(&bytes).unwrap(), s);
}
}