diff --git a/build/wire.rs b/build/wire.rs index 2b952f64..5862e3fd 100644 --- a/build/wire.rs +++ b/build/wire.rs @@ -6,7 +6,7 @@ use { wire::parser::{Field, Lined, Message, Type, parse_messages, to_camel}, }, 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(f: &mut W, ty: &Type) -> Result<()> { @@ -110,26 +110,81 @@ fn write_message(f: &mut W, obj: &str, message: &Message) -> Result<() " fn parse({}: &mut MsgParser<'_, 'a>) -> Result {{", parser )?; - writeln!(f, " 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)?; + if message.is_fixed_size { + writeln!(f, " let [")?; + for (i, field) in message.fields.iter().enumerate() { + match &field.val.ty.val { + Type::U64 => { + writeln!(f, " arg{i}_hi,")?; + writeln!(f, " arg{i}_lo,")?; + } + Type::U64Rev => { + writeln!(f, " arg{i}_lo,")?; + writeln!(f, " arg{i}_hi,")?; + } + Type::Fd => {} + _ => { + writeln!(f, " arg{i},")?; + } + } + } + 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!( diff --git a/build/wire/parser.rs b/build/wire/parser.rs index e8e8b822..ee09a5dd 100644 --- a/build/wire/parser.rs +++ b/build/wire/parser.rs @@ -235,6 +235,7 @@ pub struct Message { pub fields: Vec>, pub attribs: MessageAttribs, pub has_reference_type: bool, + pub is_fixed_size: bool, } #[derive(Debug, Default)] @@ -344,6 +345,11 @@ impl<'a> Parser<'a> { Type::OptStr | Type::Str | Type::BStr | Type::Array(..) => true, _ => 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 { "move" => "move_", "type" => "type_", @@ -361,6 +367,7 @@ impl<'a> Parser<'a> { fields, attribs, has_reference_type, + is_fixed_size, }, }) })(); diff --git a/src/client.rs b/src/client.rs index 11c673a7..8ce8ee5d 100644 --- a/src/client.rs +++ b/src/client.rs @@ -427,7 +427,6 @@ impl Client { mut parser: MsgParser<'_, 'a>, ) -> Result { let res = R::parse(&mut parser)?; - parser.eof()?; log::trace!( "Client {} -> {}@{}.{:?}", self.id, diff --git a/src/it/testrun.rs b/src/it/testrun.rs index ac14a734..2547e6f9 100644 --- a/src/it/testrun.rs +++ b/src/it/testrun.rs @@ -146,9 +146,7 @@ pub trait ParseFull<'a>: Sized { impl<'a, T: RequestParser<'a>> ParseFull<'a> for T { fn parse_full(mut parser: MsgParser<'_, 'a>) -> Result { - let res = T::parse(&mut parser)?; - parser.eof()?; - Ok(res) + T::parse(&mut parser).map_err(Into::into) } } diff --git a/src/utils/buffd/parser.rs b/src/utils/buffd/parser.rs index fa6b75f5..e7a12280 100644 --- a/src/utils/buffd/parser.rs +++ b/src/utils/buffd/parser.rs @@ -22,6 +22,8 @@ pub enum MsgParserError { TrailingData, #[error("String is not UTF-8")] NonUtf8, + #[error("The message has an unexpected size")] + UnexpectedMessageSize, } pub struct MsgParser<'a, 'b> { @@ -35,6 +37,11 @@ impl<'a, 'b> MsgParser<'a, 'b> { Self { buf, pos: 0, data } } + #[inline(always)] + pub fn data(&self) -> &[u32] { + self.data + } + pub fn int(&mut self) -> Result { if self.pos >= self.data.len() { return Err(MsgParserError::UnexpectedEof); @@ -48,12 +55,14 @@ impl<'a, 'b> MsgParser<'a, 'b> { self.int().map(|i| i as u32) } + #[expect(dead_code)] pub fn u64(&mut self) -> Result { let hi = self.uint()?; let lo = self.uint()?; Ok(((hi as u64) << 32) | lo as u64) } + #[expect(dead_code)] pub fn u64_rev(&mut self) -> Result { let lo = self.uint()?; let hi = self.uint()?; diff --git a/src/wl_usr.rs b/src/wl_usr.rs index dcaa79bf..c5a60b52 100644 --- a/src/wl_usr.rs +++ b/src/wl_usr.rs @@ -257,7 +257,6 @@ impl UsrCon { mut parser: MsgParser<'_, 'a>, ) -> Result { let res = R::parse(&mut parser)?; - parser.eof()?; log::trace!( "Server {} -> {}@{}.{:?}", self.server_id,