use bytes::Bytes;
use crate::{
codec::{decode_frames, encode_frames},
control::{ControlOutput, ControlRequest},
error::{Error, Result},
msgpack::Decoder,
output::BatchTokenIDOutSlim,
request::TokenizedGenerateReqInput,
};
pub const REQ_TYPE_ADD: u8 = 0x00;
pub const REQ_TYPE_ABORT: u8 = 0x01;
pub const REQ_TYPE_CONTROL: u8 = 0x02;
pub const ENGINE_CORE_DEAD: &[u8] = b"ENGINE_CORE_DEAD";
pub fn engine_identity(engine_index: u16) -> [u8; 2] {
engine_index.to_le_bytes()
}
#[derive(Debug, Clone, PartialEq)]
pub enum EngineRequest {
Add(Box<TokenizedGenerateReqInput>),
Abort(Vec<String>),
Control(Box<ControlRequest>),
}
impl EngineRequest {
pub fn to_frames(&self) -> Vec<Bytes> {
let (type_frame, payload): (&'static [u8], _) = match self {
EngineRequest::Add(request) => (&[REQ_TYPE_ADD], encode_frames(request.as_ref())),
EngineRequest::Abort(rids) => (&[REQ_TYPE_ABORT], encode_frames(rids)),
EngineRequest::Control(request) => {
(&[REQ_TYPE_CONTROL], encode_frames(request.as_ref()))
}
};
let mut frames = Vec::with_capacity(1 + payload.len());
frames.push(Bytes::from_static(type_frame));
frames.extend(payload);
frames
}
pub fn from_frames(frames: &[Bytes]) -> Result<Self> {
let [type_frame, payload @ ..] = frames else {
return Err(Error::Invalid("an input message has no frames".to_owned()));
};
if payload.is_empty() {
return Err(Error::Invalid(
"an input message needs a type frame and a payload".to_owned(),
));
}
match type_frame.as_ref() {
[REQ_TYPE_ADD] => Ok(EngineRequest::Add(Box::new(decode_frames(payload)?))),
[REQ_TYPE_ABORT] => Ok(EngineRequest::Abort(decode_frames(payload)?)),
[REQ_TYPE_CONTROL] => Ok(EngineRequest::Control(Box::new(decode_frames(payload)?))),
other => Err(Error::Invalid(format!(
"unknown request type frame {other:02x?}"
))),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum EngineOutput {
Batch(Box<BatchTokenIDOutSlim>),
Control(Box<ControlOutput>),
Dead,
}
impl EngineOutput {
pub fn to_frames(&self) -> Vec<Bytes> {
match self {
EngineOutput::Batch(batch) => encode_frames(batch.as_ref()),
EngineOutput::Control(output) => encode_frames(output.as_ref()),
EngineOutput::Dead => vec![Bytes::from_static(ENGINE_CORE_DEAD)],
}
}
pub fn from_frames(frames: &[Bytes]) -> Result<Self> {
match frames {
[] => Err(Error::Invalid("an output message has no frames".to_owned())),
[only] if only.as_ref() == ENGINE_CORE_DEAD => Ok(EngineOutput::Dead),
_ if ControlOutput::knows(Decoder::new(frames).peek_tag()?) => {
Ok(EngineOutput::Control(Box::new(decode_frames(frames)?)))
}
_ => Ok(EngineOutput::Batch(Box::new(decode_frames(frames)?))),
}
}
}