-
-
Notifications
You must be signed in to change notification settings - Fork 135
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(twilight-model)!: Implement additional select menu types #2219
Conversation
This patch implements the additional select menu types `user`, `role`, `mentionable`, and `channel`. Moreover, it moves the type-specific data for the existing text select menu implementation into a separate enum variant. The new types are implemented by "semi-flattening" the `SelectMenu` struct: fields common to all select menu types are implemented in the struct itself, and type-specific fields like the available options or channel types are moved into a `SelectMenuData` enum. This enum is also used to select a select menu's type. This approach de-duplicates the common fields while preventing users from accessing fields irrelevant to the current select menu type. Finally, this commit updates the documentation and existing tests to reflect these changes. The tests, however, might require additional attention in case new behaviour introduced by this commit should be tested as well.
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.
Thanks for this PR, it looks good to me overall!
It seems that you should also add a resolved
field to MessageComponentInteractionData
(Discord documentation). This has been implemented in #2051 if you need a reference.
Moreover, those instances are Box-ed inside the enum to avoid unnecessarily increasing the enum's memory footprint if Discord adds new fields in the future.
This need to be discussed, but I personally think it just adds unnecessary complexity. Discord is unlikely to add fields that make the enum very large - and we can't anticipate everything anyway.
This patch makes `ComponentVisitor::visit_map` use `unreachable!` instead of `panic!` in case a select menu type was not implemented while being listed in a previous match statement. Moreover, this commit sneaks in a minor formatting fix inside `Components` doc-comment example.
This commit implements the `resolved` field for `MessageComponentInteraction`. This field holds resolved users, roles, channels, or attachments for select menu interactions. Unfortunately, the new field makes it impossible to implement `Eq` and `Hash` for `MessageComponentInteractionData`.
This commit adds a simple Discord bot that creates and responds to select menus using Twilight. The main purpose of this bot is to demonstrate the API introduced by GH-PR twilight-rs/twilight#2219. Specifically, the code in this repository is a "quick and dirty" test, and its code is not scalable, idiomatic, or in any way recommendable outside testing the API.
Indeed! I'm not sure how I missed this. I took the opportunity to create a small throwaway bot here: https://github.com/archer-321/twilight-select-menus. It responds to simple legacy text commands and sends a message with all select menu types.
I agree that it adds extra complexity and might be unnecessary. Still, I'm unsure whether the decreased complexity of removing it outweighs the benefit of having each variant be the size of a pointer. Let's wait for other reviews c: |
This commit fixes the tests testing the (de-)serialization of `InteractionDataResolved`. Previously, the tests were failing, as the type was renamed from `CommandInteractionDataResolved`. Moreover, this commit fixes the message component interaction tests by adding the missing `resolved` field to the expected fields in `message_component_interaction_data`.
It's not documented in Message Component Data Structure, I only saw it because the previous PR had implemented it 😅 Thanks for the throwaway bot, it's really useful for reviewing :)
The enum is 32 bytes without |
This commit unboxes `SelectMenuData`'s variants. They were boxed in a previous patch to prevent future fields from unnecessarily increasing the enum's memory footprint, but considering that, with the current structures, new fields are a breaking change already, it's OK to leave the variants unboxed for now and re-box as necessary. For the current code, this saves a heap allocation while only marginally increasing the enum's memory footprint. This change is only breaking in the context of PR twilight-rs#2219. When added to the commits in this PR, it doesn't add any breaking changes to the PR's list of breaking changes.
I see. Considering that additional fields would be a breaking change anyway, I agree that boxing the enum variants is unnecessary. As discussed on Discord, I marked the PR as ready. After all, approving the implementation implicitly approves the general design (and thus the RFC). |
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.
LGTM.
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 fundamentally disagree with the design choices in this PR, for several reasons. By "the design choices", I mean not flattening the struct.
- If we were to make the change from flattened structs back to enums, that should be done for all model structs and not for a single struct. That is inconsistent and, in my view, a code smell.
- We have in the past switched from enums to flattened structs for things like channel due to "[flattening] will prevent breaking changes and API oddities in the future" (a0ec109). Flip-flopping back and forth is not really desirable for maintainers or users.
- Field access gets really awkward with inner enums for fields present conditionally.
some_select_menu.options
asOption<Vec<SelectMenuOption>>
makes accessing the field much easier thanif let
matching on parts of a struct which are contained in an enum. - Flattened structs model the Discord API closer and will be less likely to cause breaking changes (this kind of repeats the argument from 2.). If
options
is ever going to be present for other types than 3, it won't require breaking public API changes. This also models the Discord documentation a bit closer (link).
TLDR: I don't see the added value at all. I'd be happy to accept this if we would just include the struct fields flattened as options, or if we revisit the entire model crate and make serious future commitments instead of changing model philosophy every few releases.
Nevermind, I read the documentation for one more time and it seems like flattening is better. |
There are 6 common fields and 2 conditional ones, you can check it here. |
I'm also for flattening. After using the flattened channel struct for a while now I find it much nicer than matching on an enum |
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.
As per comments made by @Gelbpunkt, flattening the structures will align better with the Discord API model as well as our design philosophy for model structures.
I'm a huge fan of static enforcement for types, and I aim to implement it through my libraries wherever possible - even if it comes at the cost of increasing the required boilerplate. E.g. it's less convenient to match an That said, it's way less dramatic with the entirely flattened approach. Instead of crashing the program, the struct would allow users to specify invalid select menus (e.g. a channel select menu that tries to set the Of course, I can flatten the struct in this PR, but I have a couple of questions regarding the desired implementation:
|
i think this discussion should be moved to #2217 and that discussion should be renamed to reflect an overall consistent change in the model crate and then we should merge or request changes in the pr before merging it based on the result we should first decide how we handle rfcs though |
Do we want a similar procedure with that of Rust’s? |
partially yeah i agree but i think we can keep it simpler since i scope is smaller i think the flow should be like rfc -> contributing.md (if accepted) -> adapting twilight for rfc changes |
Could we progress with the RFC or this PR? If the static enforcement introduced by this change isn't an option because it would differ from the rest of the library, I'd be OK with implementing the entirely flattened approach. However, I'm still unsure about the two questions listed in #2219 (comment) 😟 In my opinion, an RFC wouldn't be needed when going for the flattened approach that aligns with other types in Twilight. Instead, a more general RFC should discuss the benefits and drawbacks of changing structs to a partially flattened implementation throughout the library, in this case. |
Yeah, it would be nice if you could progress with implementing the flattened approach. |
I'm sorry if my last message sounded impatient or demanding; that wasn't my intention. I agree; for now, an approach that's more in line with the rest of the library is probably best. However, I still have the two questions I linked to in my last message. Specifically, I still have the two questions quoted below ⬇️
I can't think of a satisfying implementation that addresses both problems (preventing a duplicate Before I spend more hours creating another patch that fundamentally doesn't align with the crate's vision, I'd like some input before I start changing the API again. I hope you understand 🙂 |
A
Personally, I think it's best to focus on a simple implementation. We can't anticipate all the changes Discord will make, so it's not worth making our API more complicated for changes we don't know will happen. I'd be curious to know what others think about this. |
This commit removes the SelectMenuData type and embeds all variant-specific fields in the base struct. Moreover, it adds documentation indicating which fields are required variant-specific fields. This commit also updates the component validation module in `twilight-validate` by introducing a new error type for text select menus that don't have the necessary `options` field.
This commit updates the bot to reflect the most recent changes to twilight-rs/twilight#2219 introduced in c774adc0. Specifically, the `SelectMenu` struct was flattened to include all variant-specific fields. Moreover, a new `kind` field is used instead of `data` to determine the select menu variant.
I implemented the entirely flattened approach requested above and updated the test bot. If I missed something, please let me know.
Done ✔️
Considering that the API isn't stable across releases at this point in Twilight's development, this would likely be overkill. For now, I implemented the fields directly. |
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.
Overall code LGTM, I have some nits on documentation but I'm not a native speaker and there are other people who might disagree so I'd be fine with merging this as-is, consider my comments as what went through my mind when reading this
pub enum SelectMenuType { | ||
/// Select menus with a text-based `options` list. | ||
/// | ||
/// Select menus of this `kind` *must* set the `options` field to specify the options users |
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 don't think we should be writing API documentation for Discord in all places imaginable, one should be enough on the options
field
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 mention this in the enum documentation, as users may only read its documentation to see which select menu types are available.
Now that the options
field is an Option<_>
, I think the duplicated documentation is worth it if it saves some people from debugging a Discord API error.
However, I'm open to talking about this instance.
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.
any other opinions on this or do we leave it as is?
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 agree upon that this duplicated documentation is worth it; in terms of helping users understand the requirements on fields for specific select menu types.
As such, I believe that we can keep this as is.
This commit streamlines the language in the `SelectMenu` and `SelectMenuType` documentation. In particular, it removes duplicated sections outlining required and optional fields. Moreover, it makes language describing which menu types use a specific option more in line with the rest of the library.
This PR has three approvals but is still labled as unapproved. What's holding this up? |
Nothing, I forgot to remove the label after the PR switched to flattened models |
Then I presume that this pull request can be merged. |
Amazing work, thank you so much! 🎉 |
This merge request implements Discord's new select menu types (user, role, mentionable, and channel) using the fully-flattened approach outlined in this RFC.
General idea
The general idea is to implement all variant-specific fields as
Option
s inside theSelectMenu
struct. While this might require runtime validation, it's more in line with the rest of the Twilight ecosystem. Moreover, it doesn't duplicate fields that an approach with separate structs would duplicate.Notably, this differs from the RFC mentioned above. This RFC was indirectly denied with this review.
Breaking changes
This PR introduces multiple breaking changes:
ComponentType
'sSelectMenu
variant was renamed, and the enum was extended (breaking as it's not#[non_exhaustive]
).SelectMenu
'soptions
field was wrapped in anOption
.channel_types
andkind
fields were introduced inSelectMenu
.twilight_model::application::interaction::application_command::{CommandInteractionDataResolved, InteractionChannel, InteractionMember}
were moved intotwilight_model::application::interaction
.CommandInteractionDataResolved
was renamed toInteractionDataResolved
.MessageComponentInteractionData
no longer implementsEq + Hash
.resolved
field was introduced inMessageComponent
.InteractionData::MessageComponent
's single field wasBox
-ed.If I missed any breaking changes, please point them out.
Related work
Tests
This PR only updates the existing tests. If you'd like me to add other tests to verify the behaviour introduced by this patch, please feel free to request changes.
Signed commits
I'm unsure whether this is possible with Twilight's PR flow, but please ask me to squash any commits or edit commit messages if necessary. I prefer all commits attributed to me to be signed with my GPG key 🤓
Labels
Based on the current state, I believe you should assign the
d-api
andd-breaking
labels.