-
Notifications
You must be signed in to change notification settings - Fork 474
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
Fix bug in Keycode type #1378
Fix bug in Keycode type #1378
Conversation
It fixes #1377 |
Using transmute to me is a big no no, especially since the output is an enum, and an illegal value of an enum in rust is the best way to have a rust panic or unexpected behavior. Likewise, I do'nt really know where does this I haven't seen this issue in detail, but I think there is probably an alternative, probably somewhere in |
Defining But right now I just want to fix
|
I think there are ways to fix this, yes we would break some specific code, but we have ways to make the fix easier. The main problem that I have is that it's extremely illegal code. Take this playground link #[repr(i32)]
enum Keycode {
A = 1,
B = 2,
}
fn main() {
let k: Keycode = unsafe { std::mem::transmute(5) };
match k {
Keycode::A => { println!("A") }
Keycode::B => { println!("B") }
}
} Notice that debug and release do not give the same results (debug is just wrong, and release crashes, which is a BIG no no). I'm sure there are many ways we could fix this, but to me the easier would be something like this: #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[non_exhaustive]
pub struct Keycode(pub i32)
impl Keycode {
pub const Backspace: Keycode = Keycode(sys::SDL_KeyCode::SDLK_BACKSPACE as i32);
pub const Tab: Keycode = Keycode(sys::SDL_KeyCode::SDLK_TAB as i32);
...
} There are probably things that I have missed with that, but at least it would fix this specific issue. The few who use pattern matching with this struct will have a bit of refactoring to do but it would not be major. The only big issue that I see is that the struct would not be |
Oh, wow. You're actually totally right. I didn't want to drastically change Update: actually |
Ok, so let's change Solution with There's actually a third problem: if we make the i32 field public, the user can now put any integers into the #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct Keycode(i32);
impl Keycode {
pub fn into_i32(&self) -> i32 {
self.0
}
pub fn from_i32(n: i32) -> Option<Keycode> { ... }
...
} |
It's only a warning and we can suppress it. People will prefer that to breaking a good portion of their code.
Isn't that the point? Keycode can have a lot of possible values depending on the locale, and there are a lot of them that are NOT in the enum. I think this complex check should only exist for scancode, but not for keycode. Although you are right you could put anycode integer inside, we need to do some tests to see how well does SDL2 handle unknown keycodes. |
Ok, I made Keycode into
So now if a user puts a random number into a variable of type Keycode the worst thing that will happen is that this user will get unprintable string from the P.S. The code still checks that argument is non-zero in |
Thank you for doing the tests! So a few changes I would do:
Otherwise it seems good! |
Hey. The uppercase constants should be the same names as in C code, or just uppercase version of their old names in Rust? I mean if we had variants
I feel like the first option might be frustrating for new users coming from C, because some constants they remember by heart have now acquired underscores in random places. So currently I implemented the second option. |
I think copying C here for the naming is better, but honestly it should not matter that much. It will just fail to compile if someone makes a typo, and most people have autocomplete on anyway. It looks good to me, before merging I'll try to make a few tests on my own locally with a few projects I have had, we might see new issues arise. Thanks for the PR anyway! |
In libsdl2 type SDL_Keycode represents unicode characters plus some special codes for keys that don't have representation in unicode. But in rust-sdl2 Keycode is defined as enum of few keys and could not contain all values that are represented by SDL_Keycode in libsdl2.
Because of this mismatch, the
Keycode::from_scancode
function could not work correctly.I fixed it by marking Keycode as non-exhaustive enum and changing
Keycode::from_i32
to accept all non-Cc unicode codepoints, not just few keys listed in type definition.