Skip to main content

vyre_runtime/megakernel/io/
encode.rs

1//! Encode/validate raw queue bytes.
2
3use crate::PipelineError;
4
5use super::helpers::validate_io_queue_view;
6use super::{IO_SLOT_COUNT, IO_SLOT_WORDS};
7
8/// contains a partial IO slot, or exceeds the compiled poll window.
9pub fn validate_io_queue_bytes(io_queue_bytes: &[u8]) -> Result<(), PipelineError> {
10    validate_io_queue_view(io_queue_bytes.len()).map(|_| ())
11}
12
13/// Strictly encode an empty IO queue buffer.
14///
15/// # Errors
16///
17/// Returns [`PipelineError::QueueFull`] when `slot_count` is zero, exceeds
18/// the compiled megakernel poll window, or overflows the host byte length.
19pub fn try_encode_empty_io_queue(slot_count: u32) -> Result<Vec<u8>, PipelineError> {
20    let byte_count = empty_io_queue_byte_len(slot_count)?;
21    let mut out = Vec::new();
22    reserve_io_queue_bytes(&mut out, byte_count)?;
23    out.resize(byte_count, 0);
24    Ok(out)
25}
26
27/// Strictly encode an empty IO queue buffer into caller-owned storage.
28///
29/// # Errors
30///
31/// Returns [`PipelineError::QueueFull`] when `slot_count` is zero, exceeds
32/// the compiled megakernel poll window, or overflows the host byte length.
33pub fn try_encode_empty_io_queue_into(
34    slot_count: u32,
35    dst: &mut Vec<u8>,
36) -> Result<(), PipelineError> {
37    let byte_count = empty_io_queue_byte_len(slot_count)?;
38    dst.clear();
39    reserve_io_queue_bytes(dst, byte_count)?;
40    dst.resize(byte_count, 0);
41    Ok(())
42}
43
44fn reserve_io_queue_bytes(dst: &mut Vec<u8>, byte_count: usize) -> Result<(), PipelineError> {
45    vyre_foundation::allocation::try_reserve_vec_to_capacity(dst, byte_count).map_err(|source| {
46        PipelineError::Backend(format!(
47            "megakernel io_queue byte reservation failed for {byte_count} bytes: {source}. Fix: shard IO queue encoding or reuse a larger caller-owned queue buffer."
48        ))
49    })
50}
51
52pub(crate) fn empty_io_queue_byte_len(slot_count: u32) -> Result<usize, PipelineError> {
53    if slot_count == 0 {
54        return Err(PipelineError::QueueFull {
55            queue: "submission",
56            fix: "io_queue requires at least one slot",
57        });
58    }
59    if slot_count > IO_SLOT_COUNT {
60        return Err(PipelineError::QueueFull {
61            queue: "submission",
62            fix: "io_queue exceeds the compiled IO poll window of 64 slots; enlarge IO_SLOT_COUNT and rebuild the megakernel before encoding a larger queue",
63        });
64    }
65    let word_count = slot_count
66        .checked_mul(IO_SLOT_WORDS)
67        .ok_or(PipelineError::QueueFull {
68            queue: "submission",
69            fix: "io_queue word count overflows u32; shard the queue before encoding",
70        })?;
71    usize::try_from(word_count)
72        .ok()
73        .and_then(|words| words.checked_mul(4))
74        .ok_or(PipelineError::QueueFull {
75            queue: "submission",
76            fix: "io_queue byte count overflows usize; shard the queue before encoding",
77        })
78}
79
80/// Encode an empty IO queue buffer.
81///
82/// # Errors
83///
84/// Returns [`PipelineError::QueueFull`] when `slot_count` is zero, exceeds
85/// the compiled megakernel poll window, or overflows the host byte length.
86pub fn encode_empty_io_queue(slot_count: u32) -> Result<Vec<u8>, PipelineError> {
87    try_encode_empty_io_queue(slot_count)
88}