-
Notifications
You must be signed in to change notification settings - Fork 707
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
Using rustified enums in function signatures is (almost?) always wrong #3051
Comments
Is this #2646, but about changing the current Cc @tgross35 @y86-dev in case they are interested (from https://rust-for-linux.zulipchat.com/#narrow/channel/288089-General/topic/Enum.20handling) |
this is only about changing I think #2646 goes more in the direction of #3050 where you want to generate multiple representations for a single C enum. |
Maybe a reasonable way forward here would be to implement first #3050 and then add an extra feature to the Rust enum representations where the ctype is used instead of the enum itself ( bindgen --enum-style const,rust(safe_conversion,unsafe_conversion,use_ctype)=<REGEX> |
Yeah, I think it should be done everywhere. Otherwise you may get e.g. a type from C that contains the
So, to clarify, #2646 came from that Zulip thread (https://rust-for-linux.zulipchat.com/#narrow/channel/288089-General/topic/Enum.20handling) which was about generating conversion functions from a raw "C" type (i.e. without UB) to a Rust enum. This came up because in many cases what we want to end up with is an (exhaustive) Rust enum, but we want to remain sound, yet avoid writing manually all the boilerplate code, with all that it entails (e.g. mistakes over time, since C APIs may change at any time within the kernel). It is true that the issue mentions both So the fundamental idea is about generating all that boilerplate in (Please @tgross35 et al correct me if I misremember!) |
I don't know what would be best here. I think the most important thing is that there should be some form that uses Rust enums but uses an integer for everything
One note, it is probably a bit cleaner if the C type is just in the Rust enum's impl block. impl State {
pub type CType = core::ffi::c_int;
pub const C_WORKING: Self::CType = 1; // if applicable
} |
One important part is that we want to exhaustively match on the enum coming from the C side. Because we want to ensure a compilation error when a C developer adds/removes/renames a variant without checking the rust side. Then we get notified "this doesn't build for me!" instead of silently introducing a bug that will haunt us in the future. |
I think inherent associated types are unstable, so I'm curious about the reason to have these raw |
You're right :( I thought we had those for a while.
I was originally just thinking for convenience when calling the C methods with constant values, but indeed this doesn't gain much over casting the Rust type. |
So this is an issue that came up from #2908. If you have the following headers:
Runing
bindgen --rustified-enum=State
will produce this code:Sadly, using
takes_state
orreturns_state
can cause undefined behavior. This is documented behavior but it could easily be improved by adding appropriate conversion methods forState
(which is part of the purpose of #2908). Additionally, bindgen could expose the underlying type of the C enum and use this type instead ofState
.Essentially, I would expect bindgen to generate:
The main advantages of this approach is its flexibility as the user can explicitly opt-in for the conversion methods according to the safety guarantees. If your C library is kind enough to never produce invalid values for an enum, then you can codify that behavior
However, if you're unsure, you can deal with this accordingly and expose a Rust function that acknowledges this:
The additional improvement over the current behavior is when
takes_state
andreturns_state
are used in conjunction:With the current behavior
returns_state
can create an invalid value forState
, which is UB. Then this is passed totakes_state
and "hopefully" all works out. By using theState_ctype
all the unsafety would only happen on the C side.Cc @emilio @jbaublitz @ojeda
The text was updated successfully, but these errors were encountered: