crafter 0.3.0

Packet-level network interaction for Rust tools and agents.
Documentation
//! Shared transport protocol helpers.

use crate::error::Result;
use crate::field::Field;
use crate::packet::{LayerContext, TransportChecksumContext};

macro_rules! impl_layer_object {
    ($type:ty) => {
        fn clone_layer(&self) -> Box<dyn $crate::packet::Layer> {
            Box::new(self.clone())
        }

        fn as_any(&self) -> &dyn core::any::Any {
            self
        }

        fn as_any_mut(&mut self) -> &mut dyn core::any::Any {
            self
        }

        fn into_any(self: Box<Self>) -> Box<dyn core::any::Any> {
            self
        }
    };
}

macro_rules! impl_layer_div {
    ($type:ty) => {
        impl<R> core::ops::Div<R> for $type
        where
            R: $crate::packet::IntoPacket,
        {
            type Output = $crate::packet::Packet;

            fn div(self, rhs: R) -> Self::Output {
                $crate::packet::Packet::from_layer(self).concat(rhs)
            }
        }
    };
}

pub(crate) use impl_layer_div;
pub(crate) use impl_layer_object;

pub(crate) fn payload_bytes_after(ctx: LayerContext<'_>) -> Result<Vec<u8>> {
    let mut payload = Vec::new();
    ctx.packet()
        .compile_all_layers_after_into(ctx.index(), &mut payload)?;
    Ok(payload)
}

pub(super) fn transport_checksum_context(
    ctx: LayerContext<'_>,
    transport_protocol: u8,
) -> Option<TransportChecksumContext> {
    (0..ctx.index()).rev().find_map(|index| {
        ctx.packet()
            .get(index)
            .and_then(|layer| layer.transport_checksum_context(transport_protocol))
    })
}

pub(super) fn value_or_copy<T: Copy>(field: &Field<T>, default: T) -> T {
    field.value().copied().unwrap_or(default)
}

pub(crate) fn hex_bytes(bytes: &[u8]) -> String {
    let mut output = String::new();

    for (index, byte) in bytes.iter().enumerate() {
        if index > 0 {
            output.push(' ');
        }
        output.push_str(&format!("{byte:02x}"));
    }

    output
}