use bytes::Bytes;
pub mod datalink;
pub use datalink::*;
use dev_utils::format::*;
use std::fmt::{self, Display, Formatter};
pub type AddressPair<A> = (A, A);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Header<A> {
pub addresses: AddressPair<A>,
}
impl<A> Header<A> {
pub fn new(src: A, dst: A) -> Self {
Self {
addresses: (src, dst),
}
}
pub fn src(&self) -> &A {
&self.addresses.0
}
pub fn dst(&self) -> &A {
&self.addresses.1
}
}
macro_rules! define_addresses {
($($(#[$meta_d:meta])* $name:ident: $inner:ty, $default:expr),* $(,)?) => {
$(
$(#[$meta_d])*
pub type $name = $inner;
impl Default for Header<$name> {
fn default() -> Self {
let default_addr: $name = $default;
Self {addresses: (default_addr, default_addr),}
}
}
impl Header<$name> {
}
)*
};
}
define_addresses! {
MacAddress: [u8; 6], [0, 0, 0, 0, 0, 0],
Ipv4Address: u32, 0x7F000001, PortAddress: u16, 80,
}
macro_rules! impl_iterator_trait {
($name:ident, $payload_field:ident, $payload_ty:ty) => {
impl IntoIterator for $name {
type Item = <$payload_ty as IntoIterator>::Item;
type IntoIter = <$payload_ty as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
self.$payload_field.into_iter()
}
}
impl<'a> IntoIterator for &'a $name {
type Item = &'a <$payload_ty as IntoIterator>::Item;
type IntoIter = std::slice::Iter<'a, <$payload_ty as IntoIterator>::Item>;
fn into_iter(self) -> Self::IntoIter {
self.$payload_field.iter()
}
}
};
}
macro_rules! define_layer_struct {
(
$(
$(#[$meta:meta])*
$name:ident { header: $header_ty:ty, $payload_field:ident: $payload_ty:ty $(,)? }
),* $(,)?
) => {
$(
// Apply any doc comments or attributes provided.
$(#[$meta])*
#[derive(Clone, PartialEq, Debug)]
pub struct $name {
pub header: Header<$header_ty>,
pub $payload_field: $payload_ty,
}
impl $name {
pub fn new(header: Header<$header_ty>, $payload_field: $payload_ty) -> Self {
Self {
header,
$payload_field,
}
}
}
impl Default for $name {
fn default() -> Self {
Self {
header: Header::<$header_ty>::default(),
$payload_field: Default::default(),
}
}
}
impl Display for $name {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
writeln!( f, "{}", format!(
"src: {:X?} -> dst: {:X?} | {:>4} {}'s |",
self.header.addresses.0,
self.header.addresses.1,
self.$payload_field.len(),
stringify!($payload_field)
).style(Style::Italic)
)?;
for (idx, item) in self.$payload_field.iter().enumerate() {
writeln!(f, "\t{} {}: {}", stringify!($payload_field), idx, item)?;
}
Ok(())
}
}
impl_iterator_trait!($name, $payload_field, $payload_ty);
)*
}
}
define_layer_struct! {
Segment { header: PortAddress, payload: Bytes },
Packet { header: Ipv4Address, pdu: Vec<Segment> },
Frame { header: MacAddress, network_pdu: Vec<Packet> },
}
pub trait ToBytes {
fn to_bytes(&self) -> Vec<u8>;
fn try_to_bytes(&self, buffer: &mut [u8]) -> Result<usize, std::io::Error> {
let bytes = self.to_bytes();
let len = bytes.len();
buffer[..len].copy_from_slice(&bytes);
Ok(len)
}
}
pub trait LayerSize {
fn payload_size(&self) -> usize;
fn total_size(&self) -> usize {
self.payload_size();
todo!("Implement a correct total size calculation")
}
}
pub trait LayerBuilder {
type Output; fn build(&self) -> Self::Output;
}