use std::io::{self, Read, Write};
use egui::accesskit;
pub const PROTOCOL_VERSION: u32 = 1;
pub const PROTOCOL_MAGIC: [u8; 4] = *b"eins";
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub enum Request {
GetInfo,
GetTree,
GetScreenshot { pixels_per_point: Option<f32> },
ApplyEvents { events: Vec<egui::Event> },
Resize { width: u32, height: u32 },
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub enum Response {
Info {
label: Option<String>,
egui_version: String,
},
Tree {
step: u64,
pixels_per_point: f32,
accesskit: Option<accesskit::TreeUpdate>,
},
Screenshot(EncodedPng),
Done,
Error { message: String },
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct EncodedPng {
pub size: [u32; 2],
#[serde(with = "serde_bytes")]
pub bytes: Vec<u8>,
}
pub const MAX_MESSAGE_BYTES: usize = 256 * 1024 * 1024;
fn invalid_data(err: impl std::fmt::Display) -> io::Error {
io::Error::new(io::ErrorKind::InvalidData, err.to_string())
}
pub fn write_handshake<W: Write>(mut writer: W) -> io::Result<()> {
writer.write_all(&PROTOCOL_MAGIC)?;
writer.write_all(&PROTOCOL_VERSION.to_be_bytes())?;
writer.flush()
}
pub fn decode_handshake(bytes: [u8; 8]) -> io::Result<u32> {
let (magic, version) = bytes.split_at(4);
if magic != PROTOCOL_MAGIC {
return Err(invalid_data(
"not an egui_inspection peer (bad handshake magic)",
));
}
Ok(u32::from_be_bytes(
version.try_into().expect("split_at(4) leaves 4 bytes"),
))
}
pub fn read_handshake<R: Read>(mut reader: R) -> io::Result<u32> {
let mut bytes = [0u8; 8];
reader.read_exact(&mut bytes)?;
decode_handshake(bytes)
}
pub fn encode_frame<T: serde::Serialize>(value: &T) -> io::Result<Vec<u8>> {
let body = rmp_serde::to_vec(value).map_err(invalid_data)?;
let len = u32::try_from(body.len()).map_err(invalid_data)?;
let mut frame = Vec::with_capacity(4 + body.len());
frame.extend_from_slice(&len.to_be_bytes());
frame.extend_from_slice(&body);
Ok(frame)
}
pub fn decode_frame_len(header: [u8; 4]) -> io::Result<usize> {
let len = u32::from_be_bytes(header) as usize;
if len > MAX_MESSAGE_BYTES {
return Err(invalid_data(format!("message too large: {len} bytes")));
}
Ok(len)
}
pub fn decode_frame_body<T: for<'de> serde::Deserialize<'de>>(body: &[u8]) -> io::Result<T> {
rmp_serde::from_slice(body).map_err(invalid_data)
}
pub fn encode_body<T: serde::Serialize>(value: &T) -> io::Result<Vec<u8>> {
rmp_serde::to_vec(value).map_err(invalid_data)
}
pub fn decode_body<T: for<'de> serde::Deserialize<'de>>(body: &[u8]) -> io::Result<T> {
rmp_serde::from_slice(body).map_err(invalid_data)
}
pub fn read_message<R, T>(mut reader: R) -> io::Result<T>
where
R: Read,
T: for<'de> serde::Deserialize<'de>,
{
let mut header = [0u8; 4];
reader.read_exact(&mut header)?;
let mut body = vec![0u8; decode_frame_len(header)?];
reader.read_exact(&mut body)?;
decode_frame_body(&body)
}
pub fn write_message<W, T>(mut writer: W, value: &T) -> io::Result<()>
where
W: Write,
T: serde::Serialize,
{
writer.write_all(&encode_frame(value)?)?;
writer.flush()
}