#![deny(missing_docs)]
#![no_std]
#[cfg(test)]
#[macro_use]
extern crate std;
mod impls;
mod sized;
mod slice;
pub mod endian;
pub use self::sized::*;
pub use self::slice::*;
#[cfg(feature = "derive")]
pub use collum_derive::*;
pub trait Collum: crate::Sized + core::marker::Sized {
fn take_from_bit_slice(slice: BitSlice<'_>) -> Option<(Self, BitSlice<'_>)>;
fn take_from_bytes(slice: &[u8]) -> Option<(Self, BitSlice<'_>)> {
Self::take_from_bit_slice(slice.into())
}
fn from_bit_slice(slice: BitSlice<'_>) -> Option<Self> {
Self::take_from_bit_slice(slice).map(|(s, ..)| s)
}
fn from_bytes(slice: &[u8]) -> Option<Self> {
Self::take_from_bit_slice(slice.into()).map(|(s, ..)| s)
}
}
#[cfg(test)]
mod tests {
extern crate self as collum;
use collum::{Collum, Sized};
use collum_derive::{Collum, Sized};
use crate::BitOffset;
use crate::BitSlice;
#[test]
fn parse_udp_header() {
#[derive(Collum, Sized, Debug, PartialEq)]
#[collum(endian = "big")]
struct UdpHeader {
src: u16,
dst: u16,
len: u16,
checksum: u16,
}
assert_eq!(UdpHeader::bits(), 8 * 8);
assert_eq!(
UdpHeader::from_bytes(&[0x01, 0xbb, 0xbf, 0xe5, 0x00, 0x21, 0x00, 0x00]),
Some(UdpHeader {
src: 443,
dst: 49125,
len: 33,
checksum: 0,
})
);
}
#[test]
fn parse_u2_manual() {
#[derive(Debug, PartialEq)]
struct U2(u8);
impl Sized for U2 {
fn bits() -> usize {
2
}
}
impl Collum for U2 {
fn take_from_bit_slice(slice: BitSlice) -> Option<(Self, BitSlice)> {
let [b] = slice.copy_bits::<1>(2)?;
Some((U2((b & 0xc0) >> 6), slice.offset_by_sized::<U2>()?))
}
}
assert_eq!(U2::from_bytes(&[1, 2, 3]), Some(U2(0)));
assert_eq!(U2::from_bytes(&[0b11111111, 0]), Some(U2(0b11)));
assert_eq!(U2::from_bytes(&[0b10000000, 0]), Some(U2(0b10)));
assert_eq!(
<[U2; 10]>::from_bytes(&[0b00000001, 0b00000010, 0b00000011]),
Some([
U2(0b00),
U2(0b00),
U2(0b00),
U2(0b01),
U2(0b00),
U2(0b00),
U2(0b00),
U2(0b10),
U2(0b00),
U2(0b00)
])
);
assert_eq!(
<[U2; 4]>::from_bytes(&[0b11111111]),
Some([const { U2(0b11) }; 4])
);
assert_eq!(<[U2; 5]>::from_bytes(&[0b11000110]), None);
assert_eq!(
<[U2; 4]>::from_bytes(&[0b11000110]),
Some([U2(0b11), U2(0b00), U2(0b01), U2(0b10)])
);
assert_eq!(
<[U2; 5]>::take_from_bit_slice((&[0b11000110, 0b10011100]).into()),
Some((
[U2(0b11), U2(0b00), U2(0b01), U2(0b10), U2(0b10)],
BitSlice {
data: &[0b0011100],
bit_offset: BitOffset::Bit2,
}
))
);
}
#[test]
fn parse_u2_derived() {
#[derive(Collum, Sized, Debug, PartialEq)]
struct U2(bool, bool);
assert_eq!(U2::from_bytes(&[1, 2, 3]), Some(U2(false, false)));
assert_eq!(U2::from_bytes(&[0b11111111, 0]), Some(U2(true, true)));
assert_eq!(U2::from_bytes(&[0b10000000, 0]), Some(U2(true, false)));
assert_eq!(
<[U2; 10]>::from_bytes(&[0b00000001, 0b00000010, 0b00000011]),
Some([
U2(false, false),
U2(false, false),
U2(false, false),
U2(false, true),
U2(false, false),
U2(false, false),
U2(false, false),
U2(true, false),
U2(false, false),
U2(false, false)
])
);
assert_eq!(
<[U2; 4]>::from_bytes(&[0b11111111]),
Some([const { U2(true, true) }; 4])
);
assert_eq!(<[U2; 5]>::from_bytes(&[0b11000110]), None);
assert_eq!(
<[U2; 4]>::from_bytes(&[0b11000110]),
Some([
U2(true, true),
U2(false, false),
U2(false, true),
U2(true, false)
])
);
assert_eq!(
<[U2; 5]>::take_from_bit_slice((&[0b11000110, 0b10011100]).into()),
Some((
[
U2(true, true),
U2(false, false),
U2(false, true),
U2(true, false),
U2(true, false)
],
BitSlice {
data: &[0b0011100],
bit_offset: BitOffset::Bit2,
}
))
);
}
#[test]
fn parse_empty() {
#[derive(Collum, Sized, Debug, PartialEq)]
struct Unit;
assert_eq!(Unit::bits(), 0);
assert_eq!(Unit::from_bytes(&[1, 2, 3]), Some(Unit));
}
}