Skip to content

Commit

Permalink
wire: generate trait for request handling
Browse files Browse the repository at this point in the history
  • Loading branch information
mahkoh committed Apr 8, 2024
1 parent e3a1a0b commit b1947d7
Show file tree
Hide file tree
Showing 102 changed files with 1,620 additions and 2,075 deletions.
137 changes: 119 additions & 18 deletions build/wire.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,10 +230,11 @@ struct Field {
struct Message {
name: String,
camel_name: String,
safe_name: String,
id: u32,
fields: Vec<Lined<Field>>,
#[allow(dead_code)]
attribs: MessageAttribs,
has_reference_type: bool,
}

#[derive(Debug, Default)]
Expand All @@ -246,22 +247,25 @@ struct Parser<'a> {
tokens: &'a [Token<'a>],
}

struct ParseResult {
requests: Vec<Lined<Message>>,
events: Vec<Lined<Message>>,
}

impl<'a> Parser<'a> {
fn parse(&mut self) -> Result<Vec<Lined<Message>>> {
let mut res = vec![];
let mut requests = 0;
let mut events = 0;
fn parse(&mut self) -> Result<ParseResult> {
let mut requests = vec![];
let mut events = vec![];
while !self.eof() {
let (line, ty) = self.expect_ident()?;
let num = match ty.as_bytes() {
let res = match ty.as_bytes() {
b"request" => &mut requests,
b"event" => &mut events,
_ => bail!("In line {}: Unexpected entry {:?}", line, ty),
};
res.push(self.parse_message(*num)?);
*num += 1;
res.push(self.parse_message(res.len() as _)?);
}
Ok(res)
Ok(ParseResult { requests, events })
}

fn eof(&self) -> bool {
Expand Down Expand Up @@ -320,14 +324,24 @@ impl<'a> Parser<'a> {
while !parser.eof() {
fields.push(parser.parse_field()?);
}
let has_reference_type = fields.iter().any(|f| match &f.val.ty.val {
Type::OptStr | Type::Str | Type::BStr | Type::Array(..) => true,
_ => false,
});
let safe_name = match name {
"move" => "move_",
_ => name,
};
Ok(Lined {
line,
val: Message {
name: name.to_owned(),
camel_name: to_camel(name),
safe_name: safe_name.to_string(),
id,
fields,
attribs,
has_reference_type,
},
})
})();
Expand Down Expand Up @@ -513,7 +527,7 @@ impl<'a> Parser<'a> {
}
}

fn parse_messages(s: &[u8]) -> Result<Vec<Lined<Message>>> {
fn parse_messages(s: &[u8]) -> Result<ParseResult> {
let tokens = tokenize(s)?;
let mut parser = Parser {
pos: 0,
Expand Down Expand Up @@ -610,10 +624,7 @@ fn write_message_type<W: Write>(
}

fn write_message<W: Write>(f: &mut W, obj: &str, message: &Message) -> Result<()> {
let has_reference_type = message.fields.iter().any(|f| match &f.val.ty.val {
Type::OptStr | Type::Str | Type::BStr | Type::Array(..) => true,
_ => false,
});
let has_reference_type = message.has_reference_type;
let uppercase = message.name.to_ascii_uppercase();
writeln!(f)?;
writeln!(f, " pub const {}: u32 = {};", uppercase, message.id)?;
Expand Down Expand Up @@ -706,6 +717,98 @@ fn write_message<W: Write>(f: &mut W, obj: &str, message: &Message) -> Result<()
Ok(())
}

fn write_request_handler<W: Write>(
f: &mut W,
camel_obj_name: &str,
messages: &ParseResult,
) -> Result<()> {
writeln!(f)?;
writeln!(
f,
" pub trait {camel_obj_name}RequestHandler: crate::object::Object + Sized {{"
)?;
writeln!(f, " type Error: std::error::Error;")?;
for message in &messages.requests {
let msg = &message.val;
let lt = match msg.has_reference_type {
true => "<'_>",
false => "",
};
writeln!(f)?;
writeln!(
f,
" fn {}(&self, req: {}{lt}, _slf: &Rc<Self>) -> Result<(), Self::Error>;",
msg.safe_name, msg.camel_name
)?;
}
writeln!(f)?;
writeln!(f, " fn handle_request_impl(")?;
writeln!(f, " self: Rc<Self>,")?;
writeln!(f, " client: &crate::client::Client,")?;
writeln!(f, " req: u32,")?;
writeln!(
f,
" parser: crate::utils::buffd::MsgParser<'_, '_>,"
)?;
writeln!(f, " ) -> Result<(), crate::client::ClientError> {{")?;
if messages.requests.is_empty() {
writeln!(f, " #![allow(unused_variables)]")?;
writeln!(
f,
" Err(crate::client::ClientError::InvalidMethod)"
)?;
} else {
writeln!(f, " let method;")?;
writeln!(
f,
" let error: Box<dyn std::error::Error> = match req {{"
)?;
for message in &messages.requests {
let msg = &message.val;
write!(f, " {} ", msg.id)?;
if let Some(since) = msg.attribs.since {
write!(f, "if self.version() >= {since} ")?;
}
writeln!(f, "=> {{")?;
writeln!(f, " method = \"{}\";", msg.name)?;
writeln!(
f,
" match client.parse(&*self, parser) {{"
)?;
writeln!(
f,
" Ok(req) => match self.{}(req, &self) {{",
msg.safe_name
)?;
writeln!(f, " Ok(()) => return Ok(()),")?;
writeln!(f, " Err(e) => Box::new(e),")?;
writeln!(f, " }},")?;
writeln!(
f,
" Err(e) => Box::new(crate::client::ParserError(e)),"
)?;
writeln!(f, " }}")?;
writeln!(f, " }},")?;
}
writeln!(
f,
" _ => return Err(crate::client::ClientError::InvalidMethod),"
)?;
writeln!(f, " }};")?;
writeln!(
f,
" Err(crate::client::ClientError::MethodError {{"
)?;
writeln!(f, " interface: {camel_obj_name},")?;
writeln!(f, " method,")?;
writeln!(f, " error,")?;
writeln!(f, " }})")?;
}
writeln!(f, " }}")?;
writeln!(f, " }}")?;
Ok(())
}

fn write_file<W: Write>(f: &mut W, file: &DirEntry) -> Result<()> {
let file_name = file.file_name();
let file_name = std::str::from_utf8(file_name.as_bytes())?;
Expand All @@ -722,15 +825,13 @@ fn write_file<W: Write>(f: &mut W, file: &DirEntry) -> Result<()> {
)?;
let contents = std::fs::read(file.path())?;
let messages = parse_messages(&contents)?;
if messages.is_empty() {
return Ok(());
}
writeln!(f)?;
writeln!(f, "pub mod {} {{", obj_name)?;
writeln!(f, " use super::*;")?;
for message in &messages {
for message in messages.requests.iter().chain(messages.events.iter()) {
write_message(f, &camel_obj_name, &message.val)?;
}
write_request_handler(f, &camel_obj_name, &messages)?;
writeln!(f, "}}")?;
Ok(())
}
Expand Down
2 changes: 1 addition & 1 deletion src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use {
uapi::{c, OwnedFd},
};
pub use {
error::{ClientError, MethodError, ObjectError},
error::{ClientError, ParserError},
objects::MIN_SERVER_ID,
};

Expand Down
32 changes: 11 additions & 21 deletions src/client/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ pub enum ClientError {
UnalignedMessage,
#[error("The requested client {0} does not exist")]
ClientDoesNotExist(ClientId),
#[error("Cannot parse the message")]
ParserError(#[source] Box<MsgParserError>),
#[error("Server tried to allocate more than 0x1_00_00_00 ids")]
TooManyIds,
#[error("The server object id is out of bounds")]
Expand All @@ -39,37 +37,29 @@ pub enum ClientError {
ClientIdOutOfBounds,
#[error("Object {0} is not a display")]
NotADisplay(WlDisplayId),
#[error(transparent)]
ObjectError(ObjectError),
#[error("Could not process a `{}.{}` request", .interface.name(), .method)]
MethodError {
interface: Interface,
method: &'static str,
#[source]
error: Box<dyn Error + 'static>,
},
#[error(transparent)]
LookupError(LookupError),
#[error("Could not add object {0} to the client")]
AddObjectError(ObjectId, #[source] Box<ClientError>),
}
efrom!(ClientError, ParserError, MsgParserError);

#[derive(Debug, Error)]
#[error("Parsing failed")]
pub struct ParserError(#[source] pub MsgParserError);

impl ClientError {
pub fn peer_closed(&self) -> bool {
matches!(self, ClientError::Io(BufFdError::Closed))
}
}

#[derive(Debug, Error)]
#[error("Could not process a `{method}` request")]
pub struct MethodError {
pub method: &'static str,
#[source]
pub error: Box<dyn Error + 'static>,
}

#[derive(Debug, Error)]
#[error("An error occurred in a `{}`", .interface.name())]
pub struct ObjectError {
pub interface: Interface,
#[source]
pub error: Box<dyn Error + 'static>,
}

#[derive(Debug, Error)]
#[error("There is no `{}` with id {}", .interface.name(), .id)]
pub struct LookupError {
Expand Down
2 changes: 1 addition & 1 deletion src/client/tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ async fn receive(data: Rc<Client>) {
}
// log::trace!("{:x?}", data_buf);
let parser = MsgParser::new(&mut buf, &data_buf[..]);
if let Err(e) = obj.handle_request(request, parser) {
if let Err(e) = obj.handle_request(&data, request, parser) {
if let ClientError::InvalidMethod = e {
if let Ok(obj) = data.objects.get_obj(obj_id) {
data.invalid_request(&*obj, request);
Expand Down
23 changes: 12 additions & 11 deletions src/ifs/ext_foreign_toplevel_handle_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ use {
crate::{
client::{Client, ClientError},
leaks::Tracker,
object::Object,
object::{Object, Version},
tree::ToplevelNode,
utils::buffd::{MsgParser, MsgParserError},
wire::{ext_foreign_toplevel_handle_v1::*, ExtForeignToplevelHandleV1Id},
},
std::rc::Rc,
Expand All @@ -16,6 +15,7 @@ pub struct ExtForeignToplevelHandleV1 {
pub client: Rc<Client>,
pub tracker: Tracker<Self>,
pub toplevel: Rc<dyn ToplevelNode>,
pub version: Version,
}

impl ExtForeignToplevelHandleV1 {
Expand All @@ -25,14 +25,19 @@ impl ExtForeignToplevelHandleV1 {
.handles
.remove(&(self.client.id, self.id));
}
}

impl ExtForeignToplevelHandleV1RequestHandler for ExtForeignToplevelHandleV1 {
type Error = ExtForeignToplevelHandleV1Error;

fn destroy(&self, msg: MsgParser<'_, '_>) -> Result<(), ExtSessionLockV1Error> {
let _req: Destroy = self.client.parse(self, msg)?;
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.detach();
self.client.remove_obj(self)?;
Ok(())
}
}

impl ExtForeignToplevelHandleV1 {
pub fn send_closed(&self) {
self.client.event(Closed { self_id: self.id });
}
Expand Down Expand Up @@ -65,8 +70,7 @@ impl ExtForeignToplevelHandleV1 {

object_base! {
self = ExtForeignToplevelHandleV1;

DESTROY => destroy,
version = self.version;
}

impl Object for ExtForeignToplevelHandleV1 {
Expand All @@ -78,11 +82,8 @@ impl Object for ExtForeignToplevelHandleV1 {
simple_add_obj!(ExtForeignToplevelHandleV1);

#[derive(Debug, Error)]
pub enum ExtSessionLockV1Error {
#[error("Parsing failed")]
MsgParserError(#[source] Box<MsgParserError>),
pub enum ExtForeignToplevelHandleV1Error {
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(ExtSessionLockV1Error, MsgParserError);
efrom!(ExtSessionLockV1Error, ClientError);
efrom!(ExtForeignToplevelHandleV1Error, ClientError);
Loading

0 comments on commit b1947d7

Please sign in to comment.