1
0
Fork 0
forked from wry/wry

wayland: optimize parsing of fixed-size messages

This commit is contained in:
Julian Orth 2026-03-28 22:07:41 +01:00
parent b745e20f7f
commit 755bfdd661
6 changed files with 92 additions and 25 deletions

View file

@ -6,7 +6,7 @@ use {
wire::parser::{Field, Lined, Message, Type, parse_messages, to_camel}, wire::parser::{Field, Lined, Message, Type, parse_messages, to_camel},
}, },
anyhow::{Context, Result}, anyhow::{Context, Result},
std::{fs::DirEntry, io::Write, os::unix::ffi::OsStrExt}, std::{fmt, fs::DirEntry, io::Write, os::unix::ffi::OsStrExt},
}; };
fn write_type<W: Write>(f: &mut W, ty: &Type) -> Result<()> { fn write_type<W: Write>(f: &mut W, ty: &Type) -> Result<()> {
@ -110,26 +110,81 @@ fn write_message<W: Write>(f: &mut W, obj: &str, message: &Message) -> Result<()
" fn parse({}: &mut MsgParser<'_, 'a>) -> Result<Self, MsgParserError> {{", " fn parse({}: &mut MsgParser<'_, 'a>) -> Result<Self, MsgParserError> {{",
parser parser
)?; )?;
writeln!(f, " Ok(Self {{")?; if message.is_fixed_size {
writeln!(f, " self_id: {}Id::NONE,", obj)?; writeln!(f, " let [")?;
for field in &message.fields { for (i, field) in message.fields.iter().enumerate() {
let p = match &field.val.ty.val { match &field.val.ty.val {
Type::Id(..) => "object", Type::U64 => {
Type::U32 => "uint", writeln!(f, " arg{i}_hi,")?;
Type::I32 => "int", writeln!(f, " arg{i}_lo,")?;
Type::U64 => "u64", }
Type::U64Rev => "u64_rev", Type::U64Rev => {
Type::OptStr => "optstr", writeln!(f, " arg{i}_lo,")?;
Type::Str => "str", writeln!(f, " arg{i}_hi,")?;
Type::Fixed => "fixed", }
Type::Fd => "fd", Type::Fd => {}
Type::BStr => "bstr", _ => {
Type::Array(_) => "binary_array", writeln!(f, " arg{i},")?;
Type::Pod(_) => "binary", }
}; }
writeln!(f, " {}: parser.{}()?,", field.val.name, p)?; }
writeln!(f, " ] = *{parser}.data() else {{")?;
writeln!(
f,
" return Err(MsgParserError::UnexpectedMessageSize);"
)?;
writeln!(f, " }};")?;
writeln!(f, " Ok(Self {{")?;
writeln!(f, " self_id: {}Id::NONE,", obj)?;
for (i, field) in message.fields.iter().enumerate() {
writeln!(
f,
" {}: {},",
field.val.name,
fmt::from_fn(|f| {
match &field.val.ty.val {
Type::Id(_, name) => write!(f, "{name}Id(arg{i})"),
Type::U32 => write!(f, "arg{i}"),
Type::I32 => write!(f, "arg{i} as i32"),
Type::U64 | Type::U64Rev => {
write!(f, "((arg{i}_hi as u64) << 32) | (arg{i}_lo as u64)")
}
Type::OptStr => unreachable!(),
Type::Str => unreachable!(),
Type::Fixed => write!(f, "Fixed(arg{i} as i32)"),
Type::Fd => write!(f, "parser.fd()?"),
Type::BStr => unreachable!(),
Type::Array(_) => unreachable!(),
Type::Pod(_) => unreachable!(),
}
})
)?;
}
writeln!(f, " }})")?;
} else {
writeln!(f, " let res = Ok(Self {{")?;
writeln!(f, " self_id: {}Id::NONE,", obj)?;
for field in &message.fields {
let p = match &field.val.ty.val {
Type::Id(..) => "object",
Type::U32 => "uint",
Type::I32 => "int",
Type::U64 => "u64",
Type::U64Rev => "u64_rev",
Type::OptStr => "optstr",
Type::Str => "str",
Type::Fixed => "fixed",
Type::Fd => "fd",
Type::BStr => "bstr",
Type::Array(_) => "binary_array",
Type::Pod(_) => "binary",
};
writeln!(f, " {}: parser.{}()?,", field.val.name, p)?;
}
writeln!(f, " }});")?;
writeln!(f, " parser.eof()?;")?;
writeln!(f, " res")?;
} }
writeln!(f, " }})")?;
writeln!(f, " }}")?; writeln!(f, " }}")?;
writeln!(f, " }}")?; writeln!(f, " }}")?;
writeln!( writeln!(

View file

@ -235,6 +235,7 @@ pub struct Message {
pub fields: Vec<Lined<Field>>, pub fields: Vec<Lined<Field>>,
pub attribs: MessageAttribs, pub attribs: MessageAttribs,
pub has_reference_type: bool, pub has_reference_type: bool,
pub is_fixed_size: bool,
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
@ -344,6 +345,11 @@ impl<'a> Parser<'a> {
Type::OptStr | Type::Str | Type::BStr | Type::Array(..) => true, Type::OptStr | Type::Str | Type::BStr | Type::Array(..) => true,
_ => false, _ => false,
}); });
let is_variable_size = fields.iter().any(|f| match &f.val.ty.val {
Type::OptStr | Type::Str | Type::BStr | Type::Array(..) | Type::Pod(..) => true,
_ => false,
});
let is_fixed_size = !is_variable_size;
let safe_name = match name { let safe_name = match name {
"move" => "move_", "move" => "move_",
"type" => "type_", "type" => "type_",
@ -361,6 +367,7 @@ impl<'a> Parser<'a> {
fields, fields,
attribs, attribs,
has_reference_type, has_reference_type,
is_fixed_size,
}, },
}) })
})(); })();

View file

@ -427,7 +427,6 @@ impl Client {
mut parser: MsgParser<'_, 'a>, mut parser: MsgParser<'_, 'a>,
) -> Result<R, MsgParserError> { ) -> Result<R, MsgParserError> {
let res = R::parse(&mut parser)?; let res = R::parse(&mut parser)?;
parser.eof()?;
log::trace!( log::trace!(
"Client {} -> {}@{}.{:?}", "Client {} -> {}@{}.{:?}",
self.id, self.id,

View file

@ -146,9 +146,7 @@ pub trait ParseFull<'a>: Sized {
impl<'a, T: RequestParser<'a>> ParseFull<'a> for T { impl<'a, T: RequestParser<'a>> ParseFull<'a> for T {
fn parse_full(mut parser: MsgParser<'_, 'a>) -> Result<Self, TestError> { fn parse_full(mut parser: MsgParser<'_, 'a>) -> Result<Self, TestError> {
let res = T::parse(&mut parser)?; T::parse(&mut parser).map_err(Into::into)
parser.eof()?;
Ok(res)
} }
} }

View file

@ -22,6 +22,8 @@ pub enum MsgParserError {
TrailingData, TrailingData,
#[error("String is not UTF-8")] #[error("String is not UTF-8")]
NonUtf8, NonUtf8,
#[error("The message has an unexpected size")]
UnexpectedMessageSize,
} }
pub struct MsgParser<'a, 'b> { pub struct MsgParser<'a, 'b> {
@ -35,6 +37,11 @@ impl<'a, 'b> MsgParser<'a, 'b> {
Self { buf, pos: 0, data } Self { buf, pos: 0, data }
} }
#[inline(always)]
pub fn data(&self) -> &[u32] {
self.data
}
pub fn int(&mut self) -> Result<i32, MsgParserError> { pub fn int(&mut self) -> Result<i32, MsgParserError> {
if self.pos >= self.data.len() { if self.pos >= self.data.len() {
return Err(MsgParserError::UnexpectedEof); return Err(MsgParserError::UnexpectedEof);
@ -48,12 +55,14 @@ impl<'a, 'b> MsgParser<'a, 'b> {
self.int().map(|i| i as u32) self.int().map(|i| i as u32)
} }
#[expect(dead_code)]
pub fn u64(&mut self) -> Result<u64, MsgParserError> { pub fn u64(&mut self) -> Result<u64, MsgParserError> {
let hi = self.uint()?; let hi = self.uint()?;
let lo = self.uint()?; let lo = self.uint()?;
Ok(((hi as u64) << 32) | lo as u64) Ok(((hi as u64) << 32) | lo as u64)
} }
#[expect(dead_code)]
pub fn u64_rev(&mut self) -> Result<u64, MsgParserError> { pub fn u64_rev(&mut self) -> Result<u64, MsgParserError> {
let lo = self.uint()?; let lo = self.uint()?;
let hi = self.uint()?; let hi = self.uint()?;

View file

@ -257,7 +257,6 @@ impl UsrCon {
mut parser: MsgParser<'_, 'a>, mut parser: MsgParser<'_, 'a>,
) -> Result<R, MsgParserError> { ) -> Result<R, MsgParserError> {
let res = R::parse(&mut parser)?; let res = R::parse(&mut parser)?;
parser.eof()?;
log::trace!( log::trace!(
"Server {} -> {}@{}.{:?}", "Server {} -> {}@{}.{:?}",
self.server_id, self.server_id,