vyre_runtime/megakernel/
protocol_api.rs1mod publish;
4pub use publish::RingSlotTransition;
5
6use crate::PipelineError;
7
8use super::protocol::{self, DebugRecord};
9use super::Megakernel;
10
11macro_rules! protocol_counter_readers {
12 () => {
13 pub fn try_read_done_count(control_bytes: &[u8]) -> Result<u32, PipelineError> {
20 map_protocol_counter(protocol::try_read_done_count(control_bytes))
21 }
22
23 pub fn try_read_epoch(control_bytes: &[u8]) -> Result<u32, PipelineError> {
30 map_protocol_counter(protocol::try_read_epoch(control_bytes))
31 }
32 };
33}
34
35macro_rules! empty_protocol_encoder_into {
36 ($name:ident, $capacity:ident, $encoder:path, $doc:literal) => {
37 #[doc = $doc]
38 pub fn $name($capacity: u32, dst: &mut Vec<u8>) -> Result<(), PipelineError> {
44 $encoder($capacity, dst).map_err(protocol_error)
45 }
46 };
47}
48
49impl Megakernel {
50 #[must_use]
52 pub fn control_byte_len(observable_slots: u32) -> Option<usize> {
53 protocol::control_byte_len(observable_slots)
54 }
55
56 #[must_use]
58 pub fn ring_byte_len(slot_count: u32) -> Option<usize> {
59 protocol::ring_byte_len(slot_count)
60 }
61
62 #[must_use]
64 pub fn debug_log_byte_len(record_capacity: u32) -> Option<usize> {
65 protocol::debug_log_byte_len(record_capacity)
66 }
67
68 #[must_use]
70 pub fn debug_record_capacity() -> u32 {
71 protocol::debug::RECORD_CAPACITY
72 }
73
74 pub fn encode_control(
81 shutdown: bool,
82 tenant_count: u32,
83 observable_slots: u32,
84 ) -> Result<Vec<u8>, PipelineError> {
85 protocol::encode_control(shutdown, tenant_count, observable_slots).map_err(protocol_error)
86 }
87
88 pub fn try_encode_control(
95 shutdown: bool,
96 tenant_count: u32,
97 observable_slots: u32,
98 ) -> Result<Vec<u8>, PipelineError> {
99 Self::encode_control(shutdown, tenant_count, observable_slots)
100 }
101
102 pub fn try_encode_control_into(
109 shutdown: bool,
110 tenant_count: u32,
111 observable_slots: u32,
112 dst: &mut Vec<u8>,
113 ) -> Result<(), PipelineError> {
114 protocol::try_encode_control_into(shutdown, tenant_count, observable_slots, dst)
115 .map_err(protocol_error)
116 }
117
118 pub fn encode_empty_ring(slot_count: u32) -> Result<Vec<u8>, PipelineError> {
125 protocol::encode_empty_ring(slot_count).map_err(protocol_error)
126 }
127
128 pub fn try_encode_empty_ring(slot_count: u32) -> Result<Vec<u8>, PipelineError> {
135 Self::encode_empty_ring(slot_count)
136 }
137
138 empty_protocol_encoder_into!(
139 try_encode_empty_ring_into,
140 slot_count,
141 protocol::try_encode_empty_ring_into,
142 "Fallible ring-buffer encoder into caller-owned storage."
143 );
144
145 pub fn encode_empty_debug_log(record_capacity: u32) -> Result<Vec<u8>, PipelineError> {
151 protocol::encode_empty_debug_log(record_capacity).map_err(protocol_error)
152 }
153
154 pub fn try_encode_empty_debug_log(record_capacity: u32) -> Result<Vec<u8>, PipelineError> {
160 Self::encode_empty_debug_log(record_capacity)
161 }
162
163 empty_protocol_encoder_into!(
164 try_encode_empty_debug_log_into,
165 record_capacity,
166 protocol::try_encode_empty_debug_log_into,
167 "Fallible debug-log encoder into caller-owned storage."
168 );
169
170 #[must_use]
172 pub fn read_done_count(control_bytes: &[u8]) -> u32 {
173 protocol::read_done_count(control_bytes)
174 }
175
176 protocol_counter_readers!();
177
178 pub fn try_count_done_ring_slots(
185 ring_bytes: &[u8],
186 item_count: usize,
187 ) -> Result<u64, PipelineError> {
188 protocol::try_count_done_ring_slots(ring_bytes, item_count).map_err(protocol_error)
189 }
190
191 #[must_use]
193 pub fn read_debug_log(debug_bytes: &[u8]) -> Vec<DebugRecord> {
194 protocol::read_debug_log(debug_bytes)
195 }
196
197 pub fn read_debug_log_into(debug_bytes: &[u8], out: &mut Vec<DebugRecord>) {
199 protocol::read_debug_log_into(debug_bytes, out);
200 }
201
202 pub fn try_read_debug_log(debug_bytes: &[u8]) -> Result<Vec<DebugRecord>, PipelineError> {
209 protocol::try_read_debug_log(debug_bytes).map_err(protocol_error)
210 }
211
212 pub fn try_read_debug_log_into(
219 debug_bytes: &[u8],
220 out: &mut Vec<DebugRecord>,
221 ) -> Result<(), PipelineError> {
222 protocol::try_read_debug_log_into(debug_bytes, out).map_err(protocol_error)
223 }
224
225 #[must_use]
229 pub fn read_epoch(control_bytes: &[u8]) -> u32 {
230 protocol::read_epoch(control_bytes)
231 }
232
233 #[must_use]
237 pub fn read_observable(control_bytes: &[u8], index: u32) -> u32 {
238 protocol::read_observable(control_bytes, index)
239 }
240
241 pub fn try_read_observable(control_bytes: &[u8], index: u32) -> Result<u32, PipelineError> {
248 protocol::try_read_observable(control_bytes, index).map_err(protocol_error)
249 }
250
251 #[must_use]
255 pub fn read_metrics(control_bytes: &[u8]) -> Vec<(u32, u32)> {
256 protocol::read_metrics(control_bytes)
257 }
258
259 pub fn read_metrics_into(control_bytes: &[u8], out: &mut Vec<(u32, u32)>) {
261 protocol::read_metrics_into(control_bytes, out);
262 }
263
264 pub fn try_read_metrics(control_bytes: &[u8]) -> Result<Vec<(u32, u32)>, PipelineError> {
271 protocol::try_read_metrics(control_bytes).map_err(protocol_error)
272 }
273
274 pub fn try_read_metrics_into(
281 control_bytes: &[u8],
282 out: &mut Vec<(u32, u32)>,
283 ) -> Result<(), PipelineError> {
284 protocol::try_read_metrics_into(control_bytes, out).map_err(protocol_error)
285 }
286}
287
288fn map_protocol_counter(
289 result: Result<u32, super::protocol::ProtocolError>,
290) -> Result<u32, PipelineError> {
291 result.map_err(protocol_error)
292}
293
294fn protocol_error(error: protocol::ProtocolError) -> PipelineError {
295 match error {
296 protocol::ProtocolError::ByteLengthOverflow { fix, .. } => PipelineError::QueueFull {
297 queue: "submission",
298 fix,
299 },
300 other => PipelineError::Backend(other.to_string()),
301 }
302}
303
304pub(super) fn validate_control_bytes(control_bytes: &[u8]) -> Result<(), PipelineError> {
305 let min = protocol::control_byte_len(0).ok_or_else(|| {
306 PipelineError::Backend(
307 "megakernel minimum control-buffer length overflowed usize. Fix: keep CONTROL_MIN_WORDS within host address limits."
308 .to_string(),
309 )
310 })?;
311 if control_bytes.len() < min || control_bytes.len() % 4 != 0 {
312 return Err(PipelineError::Backend(format!(
313 "megakernel control buffer has {} bytes, expected at least {min} bytes and 4-byte alignment. Fix: build it with Megakernel::encode_control.",
314 control_bytes.len()
315 )));
316 }
317 Ok(())
318}
319
320pub(super) fn validate_debug_log_bytes(debug_log_bytes: &[u8]) -> Result<(), PipelineError> {
321 let expected = protocol::debug_log_byte_len(protocol::debug::RECORD_CAPACITY)
322 .ok_or(PipelineError::QueueFull {
323 queue: "submission",
324 fix: "debug-log minimum length overflowed usize; keep debug ABI constants within host limits",
325 })?;
326 if debug_log_bytes.len() != expected {
327 return Err(PipelineError::Backend(format!(
328 "megakernel debug-log buffer has {} bytes, expected exactly {expected} bytes for {} PRINTF records. Fix: build it with Megakernel::encode_empty_debug_log(protocol::debug::RECORD_CAPACITY).",
329 debug_log_bytes.len(),
330 protocol::debug::RECORD_CAPACITY
331 )));
332 }
333 Ok(())
334}
335
336#[cfg(test)]
337mod tests;