///|
/// ZeroCopyNic defines the zero-allocation network interface contract.
///
/// Unlike `Nic` which allocates Bytes on every recv, ZeroCopyNic operates
/// on pre-allocated FramePool slots. The hot path has zero GC allocations.
///
/// Platform backends:
/// - Windows Npcap: FramePool in MoonBit heap, pcap_sendpacket via #borrow
/// - Linux Raw Socket: FramePool in MoonBit heap, send/recv via #borrow
/// - Linux AF_XDP: FramePool backed by UMEM shared memory
/// - Embedded MCU: FramePool mapped to DMA descriptor ring in .DMA_SRAM
pub(open) trait ZeroCopyNic {
/// Open a network interface by name, with an associated frame pool.
fn open_(String, FramePool) -> Self raise EcError
/// Acquire a TX frame slot from the pool (zero allocation).
fn acquire_tx(Self) -> FrameRef raise EcError
/// Get the writable buffer for a TX frame slot.
fn tx_buffer(Self, FrameRef) -> FixedArray[Byte]
/// Submit a filled frame for sending. The frame is consumed.
fn submit(Self, FrameRef, length~ : Int) -> Unit raise EcError
/// Receive a frame into a pre-allocated RX slot (zero allocation).
fn recv(Self, timeout~ : Duration) -> FrameRef raise EcError
/// Get the read buffer for a received frame.
fn rx_buffer(Self, FrameRef) -> FixedArray[Byte]
/// Get the data length of a received frame.
fn rx_length(Self, FrameRef) -> Int
/// Release a frame slot back to the pool.
fn release(Self, FrameRef) -> Unit
/// Close the network interface and release all resources.
fn close(Self) -> Unit
}
///|
/// MutableProcessImage uses FixedArray[Byte] for in-place read/write,
/// eliminating per-cycle Bytes allocation in the PDO hot path.
pub(all) struct MutableProcessImage {
outputs : FixedArray[Byte]
inputs : FixedArray[Byte]
output_size : Int
input_size : Int
} derive(Debug)
///|
/// Create a new MutableProcessImage with pre-allocated buffers.
pub fn MutableProcessImage::new(
output_size : Int,
input_size : Int,
) -> MutableProcessImage {
{
outputs: FixedArray::make(output_size, b'\x00'),
inputs: FixedArray::make(input_size, b'\x00'),
output_size,
input_size,
}
}
///|
/// Zero out inputs buffer (called before receiving new PDO data).
pub fn MutableProcessImage::clear_inputs(self : MutableProcessImage) -> Unit {
for i = 0; i < self.input_size; i = i + 1 {
self.inputs[i] = b'\x00'
}
}