#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DebugRecord {
pub fmt_id: u32,
pub args: [u32; 3],
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[non_exhaustive]
pub enum ProtocolError {
#[error("{buffer} byte length overflow. Fix: {fix}")]
ByteLengthOverflow {
buffer: &'static str,
fix: &'static str,
},
#[error("{buffer} has {byte_len} bytes, not a whole number of u32 words. Fix: {fix}")]
MisalignedByteLength {
buffer: &'static str,
byte_len: usize,
fix: &'static str,
},
#[error("{buffer} is missing word {word_idx} in {byte_len} bytes. Fix: {fix}")]
MissingWord {
buffer: &'static str,
word_idx: usize,
byte_len: usize,
fix: &'static str,
},
}
pub const SLOT_WORDS: u32 = 16;
pub const STATUS_WORD: u32 = 0;
pub const OPCODE_WORD: u32 = 1;
pub const TENANT_WORD: u32 = 2;
pub const PRIORITY_WORD: u32 = 3;
pub const ARG0_WORD: u32 = 4;
pub const ARGS_PER_SLOT: u32 = SLOT_WORDS - ARG0_WORD;
pub mod control;
pub mod debug;
pub mod opcode;
pub mod slot;
pub const CONTROL_MIN_WORDS: u32 = 160;
pub const MAX_OBSERVABLE_SLOTS: u32 = u32::MAX - control::OBSERVABLE_BASE;
pub const MAX_ENCODED_OBSERVABLE_SLOTS: u32 = 1_048_576;
pub const MAX_RING_SLOTS: u32 = u32::MAX / SLOT_WORDS;
pub const MAX_ENCODED_RING_SLOTS: u32 = 1_048_576;
pub const MAX_DEBUG_RECORDS: u32 = u32::MAX / debug::RECORD_WORDS;
pub const MAX_ENCODED_DEBUG_RECORDS: u32 = 1_048_576;
mod codec;
pub use codec::{
control_byte_len, count_done_ring_slots, debug_log_byte_len, encode_control,
encode_empty_debug_log, encode_empty_ring, read_debug_log, read_debug_log_into,
read_done_count, read_epoch, read_metrics, read_metrics_into, read_observable, ring_byte_len,
try_count_done_ring_slots, try_encode_control, try_encode_control_into,
try_encode_empty_debug_log, try_encode_empty_debug_log_into, try_encode_empty_ring,
try_encode_empty_ring_into, try_read_debug_log, try_read_debug_log_into, try_read_done_count,
try_read_epoch, try_read_metrics, try_read_metrics_into, try_read_observable,
};
#[must_use]
pub fn encode_load_miss(resource_id: u32, prefetch: bool) -> Vec<u8> {
try_encode_load_miss(resource_id, prefetch).unwrap_or_default()
}
pub fn try_encode_load_miss(resource_id: u32, prefetch: bool) -> Result<Vec<u8>, ProtocolError> {
let total_bytes = try_slot_byte_len()?;
let mut bytes = Vec::new();
codec::try_reserve_protocol_capacity(
&mut bytes,
total_bytes,
"slot",
"load-miss slot encode could not reserve host staging bytes; reuse a preallocated slot buffer",
)?;
try_encode_load_miss_into(resource_id, prefetch, &mut bytes)?;
Ok(bytes)
}
pub fn try_encode_load_miss_into(
resource_id: u32,
prefetch: bool,
dst: &mut Vec<u8>,
) -> Result<(), ProtocolError> {
let total_bytes = try_slot_byte_len()?;
dst.clear();
codec::try_reserve_protocol_capacity(
dst,
total_bytes,
"slot",
"load-miss slot encode could not reserve caller-owned staging bytes; reuse a larger slot buffer",
)?;
dst.resize(total_bytes, 0);
codec::write_word(dst, try_slot_word_index(0, STATUS_WORD)?, slot::PUBLISHED);
codec::write_word(dst, try_slot_word_index(0, OPCODE_WORD)?, opcode::LOAD_MISS);
codec::write_word(dst, try_slot_word_index(0, TENANT_WORD)?, 0);
codec::write_word(dst, try_slot_word_index(0, PRIORITY_WORD)?, 0);
codec::write_word(dst, try_slot_word_index(0, ARG0_WORD)?, resource_id);
let prefetch_word = ARG0_WORD
.checked_add(1)
.ok_or(ProtocolError::ByteLengthOverflow {
buffer: "slot",
fix: "load-miss argument word overflows u32; keep ARG0_WORD within SLOT_WORDS",
})?;
codec::write_word(
dst,
try_slot_word_index(0, prefetch_word)?,
u32::from(prefetch),
);
Ok(())
}
#[must_use]
pub fn decode_load_miss(ring_bytes: &[u8], slot: u32) -> Option<(u32, bool)> {
let opcode_word = codec::read_word(ring_bytes, try_slot_word_index(slot, OPCODE_WORD).ok()?)?;
if opcode_word != opcode::LOAD_MISS {
return None;
}
let resource_id = codec::read_word(ring_bytes, try_slot_word_index(slot, ARG0_WORD).ok()?)?;
let prefetch_word = ARG0_WORD.checked_add(1)?;
let prefetch =
codec::read_word(ring_bytes, try_slot_word_index(slot, prefetch_word).ok()?)? != 0;
Some((resource_id, prefetch))
}
pub fn try_slot_byte_len() -> Result<usize, ProtocolError> {
codec::words_to_bytes(SLOT_WORDS).ok_or(ProtocolError::ByteLengthOverflow {
buffer: "slot",
fix: "slot byte length overflows host address space; keep SLOT_WORDS within the host index ABI",
})
}
pub fn try_word_index(word: u32) -> Result<usize, ProtocolError> {
usize::try_from(word).map_err(|_| ProtocolError::ByteLengthOverflow {
buffer: "slot",
fix: "protocol word index cannot fit host usize; keep protocol word constants within the host index ABI",
})
}
pub fn try_slot_word_base(slot: u32) -> Result<usize, ProtocolError> {
let base_words = slot
.checked_mul(SLOT_WORDS)
.ok_or(ProtocolError::ByteLengthOverflow {
buffer: "ring",
fix: "slot word base overflows the u32 protocol word ABI; shard the megakernel ring before host access",
})?;
try_word_index(base_words)
}
pub fn try_slot_word_index(slot: u32, word: u32) -> Result<usize, ProtocolError> {
if word >= SLOT_WORDS {
return Err(ProtocolError::ByteLengthOverflow {
buffer: "slot",
fix: "slot-local word is outside SLOT_WORDS; keep protocol constants within the slot layout",
});
}
try_slot_word_base(slot)?
.checked_add(try_word_index(word)?)
.ok_or(ProtocolError::ByteLengthOverflow {
buffer: "ring",
fix: "slot word index overflows host address space; shard the megakernel ring before host access",
})
}
#[deprecated(since = "0.5.0", note = "use `encode_load_miss`")]
#[must_use]
pub fn encode_expert_miss(resource_id: u32, prefetch: bool) -> Vec<u8> {
encode_load_miss(resource_id, prefetch)
}
#[deprecated(since = "0.5.0", note = "use `decode_load_miss`")]
#[must_use]
pub fn decode_expert_miss(ring_bytes: &[u8], slot: u32) -> Option<(u32, bool)> {
decode_load_miss(ring_bytes, slot)
}
#[cfg(test)]
mod tests;