msrt 0.1.4

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

use crate::core::{ChannelId, Error, ErrorKind};
use crate::integrity::Integrity;
use crate::reliability::{Dedup, DedupDecision};
use crate::wire::{StreamDecodeOutcome, StreamingDecoder};

use crate::engine::{
    EngineConfig, ReceiveReport,
    codec::packet::{PacketBytes, PacketDecode},
    config::MAX_INGRESS_BYTES,
    state::EngineState,
};

/// Incoming byte stream decode state.
#[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) struct IngressState {
    decoder: StreamingDecoder<MAX_INGRESS_BYTES>,
}

impl IngressState {
    pub(crate) const fn new() -> Self {
        Self {
            decoder: StreamingDecoder::new(),
        }
    }

    pub(crate) fn feed(
        &mut self,
        bytes: &[u8],
        integrity: &impl Integrity,
    ) -> crate::core::Result<StreamDecodeOutcome<'_>> {
        self.decoder.feed(bytes, integrity)
    }
}

impl EngineState {
    pub(super) fn receive_ingress(&mut self, config: &EngineConfig, bytes: &[u8]) -> ReceiveReport {
        self.receive_bytes(config, bytes)
    }

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

        loop {
            let outcome = match self.ingress.feed(input, &config.integrity) {
                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 = self.receive_complete_packet(config, &packet);

                    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(
        &mut self,
        config: &EngineConfig,
        packet: &PacketBytes,
    ) -> ReceiveReport {
        match packet.decode() {
            PacketDecode::Data(fragment) => {
                let packet_index = fragment.header.packet_index;
                let key = fragment.header.key();
                let ack_eliciting = fragment.header.is_ack_eliciting();

                if ack_eliciting && self.queue_ack(key).is_err() {
                    return ReceiveReport::Error(Error::new(ErrorKind::Engine));
                }

                if self.receive.dedup().observe(key) == DedupDecision::Duplicate {
                    return ReceiveReport::Duplicate { packet_index };
                }

                match self.reassembly.observe(fragment, self.clock.now_ms()) {
                    Ok(Some(mut message)) => {
                        message.profile = config.channel_profile(message.channel_id);
                        self.message.push(message);
                        ReceiveReport::Packet { packet_index }
                    }
                    Ok(None) => ReceiveReport::Packet { packet_index },
                    Err(error) => ReceiveReport::Error(error),
                }
            }
            PacketDecode::Ack(ack) => {
                let packet_index = ack.header.packet_index;
                self.recovery.apply_ack(ack.header.key());
                ReceiveReport::Ack { packet_index }
            }
            PacketDecode::Ping(ping) => {
                let packet_index = ping.header.packet_index;
                if self.queue_pong(config, ping.header.message_id).is_err() {
                    return ReceiveReport::Error(Error::new(ErrorKind::Engine));
                }
                ReceiveReport::Ping {
                    packet_index,
                    message_id: ping.header.message_id,
                }
            }
            PacketDecode::Pong(pong) => {
                self.recovery
                    .remove_message(ChannelId::LIVENESS, pong.header.message_id);
                ReceiveReport::Pong {
                    packet_index: pong.header.packet_index,
                    message_id: pong.header.message_id,
                }
            }
            PacketDecode::Malformed => ReceiveReport::Corrupted,
        }
    }
}