-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Generate and use structs to serialize requests. #439
Conversation
This will make things easier once we create request structs, which cannot have unnamed lifetimes.
@@ -32,26 +33,41 @@ pub const X11_EXTENSION_NAME: &str = "BIG-REQUESTS"; | |||
/// send the maximum version of the extension that you need. | |||
pub const X11_XML_VERSION: (u32, u32) = (0, 0); | |||
|
|||
/// Opcode for the Enable request | |||
pub const ENABLE_REQUEST: u8 = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One could do both: Have a pub const
and then have an opcode()
method (that just returns ENABLE_REQUEST
instead of 0
in this case).
Would that make sense? (I came up with this proposal when I saw the diff for multithread_test
which changes a match
into a series of if
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I think it can make sense (see my comment at the top of the thread). Want me to do it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, please do.
It just occurred to me: This also makes sense for symmetry with errors and events. They also have this constant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about using associated constants?
impl FooRequest {
pub const OPCODE: u8 = 1;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Google finds https://doc.rust-lang.org/edition-guide/rust-2018/trait-system/associated-constants.html which says that associated constants needs Rust 1.20
Edit: Which is great, since that's less than 1.37 and so we can use that.
Follow-up question would be: Should the existing opcodes be turned into associated constants as well?
Follow-follow-up question would be: Should that be done in this PR or shall we just open an issue about it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It just occurred to me: This also makes sense for symmetry with errors and events. They also have this constant.
If we want this, we will have to revert #391
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've reverted to the previous way of having a global unassociated constant.
If you wanted to do associated constants I think it makes sense to do it for requests, events, and replies all at the same time.
But you do want to add that in a later PR, right? What are your plans with decoding protocol traffic? Do you want to build something like Also, since I always wonder about something like this: This PR adds 15k lines of code, making the generated code co over 100k lines (90247 -> 106746 according to
|
Yes.
More or less. I have a recording of all traffic over the X socket and I want to decode it to pick out some things.
Yes, I think that's largely that each field and each request now appears on two more lines (once in the struct definition and once in the function where it copies arguments into the struct). |
Looking at the clippy warnings regarding 'too complex types', I have thought of the following idea: Then, we can also have a 'proper' serialize function that returns a |
You didn't ask me, but: I always get lost in the code generator. This was also the case with the Python version. I am always happy when I do not have to look at it. For example, the current clippy warning about unnecessary lifetimes is something that I wouldn't want to look into. (And on the "more comments" front: My "add comments" PRs were for those parts of the code that I looked at, aka xcbgen-rs. For the actual code generator: I never read it much, I only tinkered with the places that Dunno if "more comments" really help here, but I also do not feel like writing some kind of overview document that describes the general flow would help...
Also thanks from me. I am looking forward to your next one. :-) |
I felt it was fairly straightforward. I did modify the |
If you wanted to write the intercept-and-forward an X socket part of |
This PR creates a
FooRequest
struct for every X11 requestFoo
with the appropriate parameters, and then moves the existing serialization logic out of the generated helper functions and into a method that consumes the request struct. My motivation for this is that I want to use these structs to parse X11 requests to decode protocol traffic, but the parsing code is not included in this PR. It would be straightforward to build on this to complete #212 as well (by breaking the serialize method off into its own trait and addingsend_request_struct_...
methods onConnection
).This is largely boilerplate. It passes all the automated tests and I've done some visual inspection of bits of the generated code as well, though obviously there's too much to go through everything line by line.
Things that I think are worth paying attention to in a review:
FOO_REQUEST
constants and replaced them with aFooRequest::opcode()
. I think this is cleaner but it a) does break compatibility to some extent and b) despite being a const fnopcode()
cannot be used in a match arm until Tracking issue forconst fn
integration with pattern matching rust-lang/rust#57240 is fixed, so you may want that added back.IoSlice
behavior, butIoSlice
cannot own buffers, so the serialization method on the struct now returns aVec<Cow<'input, [u8]>>
which areCow::Owned
s for the byte buffers generated in serialization andCow::Borrowed
for external buffers that are embedded in the struct or static data like padding.SendEventRequest
is a bit tricky. I've chosen for now to make its event just be an&'input [u8; 32]
. I think aCow
would be better in some ways but fixed length arrays do not implement ToOwned so they don't play well withCow
, and erasing the length didn't feel right.