msrt 0.1.1

Portable MSRT protocol implementation.
Documentation
//! Incoming wire byte handling.

use crate::core::{Error, ErrorKind};
use crate::reliability::{Dedup, DedupDecision};
use crate::wire::{Crc16, StreamDecodeOutcome};

use crate::engine::{
    Engine, EngineOutput, ReceiveReport,
    runtime::{
        outgoing::queue_ack,
        packet::{PacketBytes, PacketDecode, decode_packet_bytes},
    },
};

pub(crate) fn receive(engine: &mut Engine, bytes: &[u8]) -> ReceiveReport {
    receive_bytes(engine, bytes)
}

fn receive_bytes(engine: &mut Engine, bytes: &[u8]) -> ReceiveReport {
    let mut input = bytes;
    let mut report = ReceiveReport::Incomplete { needed: None };

    loop {
        let outcome = match engine.ingress.feed(input, &Crc16) {
            Ok(outcome) => outcome,
            Err(error) => return ReceiveReport::Error(error),
        };
        input = &[];

        match outcome {
            StreamDecodeOutcome::Packet {
                packet_bytes,
                consumed: _,
            } => {
                let packet = match PacketBytes::try_from_slice(packet_bytes) {
                    Ok(packet) => packet,
                    Err(error) => return ReceiveReport::Error(error),
                };
                report = receive_complete_packet(engine, packet.as_bytes());

                if matches!(report, ReceiveReport::Error(_)) {
                    return report;
                }
            }
            StreamDecodeOutcome::NeedMore { additional } => {
                return match report {
                    ReceiveReport::Incomplete { .. } => {
                        ReceiveReport::Incomplete { needed: additional }
                    }
                    other => other,
                };
            }
            StreamDecodeOutcome::Noise { skipped } => {
                report = ReceiveReport::Noise { skipped };
            }
            StreamDecodeOutcome::Corrupted { consumed: _ } => {
                report = ReceiveReport::Corrupted;
            }
            StreamDecodeOutcome::Resync { skipped } => {
                report = ReceiveReport::Noise { skipped };
            }
        }
    }
}

fn receive_complete_packet(engine: &mut Engine, bytes: &[u8]) -> ReceiveReport {
    match decode_packet_bytes(bytes) {
        PacketDecode::Data(fragment) => {
            let packet_number = fragment.packet_number;
            let ack_eliciting = fragment.ack_eliciting;

            if ack_eliciting && queue_ack(engine, packet_number).is_err() {
                return ReceiveReport::Error(Error::new(ErrorKind::Engine));
            }

            if engine.dedup.observe(packet_number) == DedupDecision::Duplicate {
                return ReceiveReport::Duplicate { packet_number };
            }

            match engine.reassembly.observe(fragment, engine.now_ms) {
                Ok(Some(mut message)) => {
                    message.profile = engine.channel_profile(message.channel_id);
                    if engine.events.push(EngineOutput::Message(message)).is_err() {
                        return ReceiveReport::Error(Error::new(ErrorKind::Engine));
                    }
                    ReceiveReport::Packet { packet_number }
                }
                Ok(None) => ReceiveReport::Packet { packet_number },
                Err(error) => ReceiveReport::Error(error),
            }
        }
        PacketDecode::Ack(ack) => {
            engine.in_flight.ack_frame(ack.frame);
            ReceiveReport::Ack {
                packet_number: ack.frame.largest_acknowledged,
            }
        }
        PacketDecode::Malformed => ReceiveReport::Error(Error::malformed()),
    }
}