-
Notifications
You must be signed in to change notification settings - Fork 125
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
Improve code generation. #76
Conversation
b60df08
to
a3f3dae
Compare
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.
Two questions on the justification of those changes and not the changes themselves. :)
And one on the topic of if I merge this PR, what happens to esp-idf-hal
and esp-idf-svc
?
@@ -5,7 +5,10 @@ use std::env; | |||
use std::iter::once; | |||
use std::path::PathBuf; | |||
|
|||
use ::bindgen::callbacks::{IntKind, ParseCallbacks}; | |||
use ::bindgen::{ |
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.
How would that affect esp-idf-hal
and esp-idf-svc
? Would these continue to compile just fine after these changes, or do we need a PR for each of those to fix any compilation errors?
Also: why do we want Rust enums?
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.
How would that affect
esp-idf-hal
andesp-idf-svc
?
I guess there will need to be some changes to those crates. I can have a look at that of course.
Also: why do we want Rust enums?
They are more ergonomic to use and the compiler will check if all variants are handled.
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.
How would that affect
esp-idf-hal
andesp-idf-svc
?I guess there will need to be some changes to those crates. I can have a look at that of course.
Would appreciate that. :)
Also: why do we want Rust enums?
They are more ergonomic to use and the compiler will check if all variants are handled.
I think I tried this once, but then for some reason abandoned it. Perhaps once you try to adjust esp-idf-svc
and esp-idf-hal
to work with the new enum-based constants, the problem (if there was a real one) will resurface itself.
build/build.rs
Outdated
@@ -95,6 +98,10 @@ fn main() -> anyhow::Result<()> { | |||
.parse_callbacks(Box::new(BindgenCallbacks)) | |||
.ctypes_prefix("c_types") | |||
.header(header_file.try_to_str()?) | |||
.default_enum_style(EnumVariation::Rust { |
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.
Ditto.
@@ -0,0 +1,30 @@ | |||
use crate::bindings::*; |
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.
Why would we want to do this here and not in esp-idf-svc
?
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.
You cannot implement Default
in another crate, so it needs to be defined here.
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.
No I mean given that we have a type-safe wrapper for Wifi already, why would you need these defaults here? Or do you plan on implementing another set of type-safe wrappers besides esp-idf-svc
? I would be supper happy if you could help us improve esp-idf-svc
instead. :)
One more point: we have discussed with Espressif, that the best possible solution is to have ESP-IDF expose C functions that implement these defaults and that we can consume - in addition to their C macros available today that we cannot consume. Timelines unclear though.
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 have implemented a different wrapper in one of my projects which used my own bindgen
crate before these crates existed. This would enable me to switch to this crate. Also, this could still be used in esp-idf-svc
which currently does the same thing as in this Default
implementation.
I would be supper happy if you could help us improve
esp-idf-svc
instead. :)
I will try to have a more detailed look at the esp-idf-svc
crate. I think my approach is a more high level API so it could potentially depend on the esp-idf-svc
crate.
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.
Ok so I'm all for switching to Rust enums if you can make it work in esp idf svc and esp idf hal. As for the default method, in light of the above idea of having it centralized in ESP IDF and consumable via CAPI call, perhaps we should wait with it a bit?
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.
By the way, EspWifi
is pretty high level if you put aside the fact that it is mostly async (for which there are good reasons and you can workaround that). Not sure how much higher level you can get?
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.
perhaps we should wait with it a bit?
I don't think it makes a difference. default
can easily be changed to use the CAPI call once it is available.
Not sure how much higher level you can get?
I'm also not sure. As I said, I implemented my wrapper before these crates existed, so I have also not yet reviewed in detail how EspWifi
is implemented.
8e7d14f
to
238b1cb
Compare
The changes to |
e77e1c6
to
0ef5381
Compare
@reitermarkus ^^^ |
@ivmarkov, I changed the enums to use newtypes instead of Rust enums. This doesn't have the problem with UB. This of course get's rid of the benefit of having exhaustiveness checked by the compiler, but type-safety is still improved a bit, and we don't have to deal with ugly constant names and |
cdb233a
to
9b2dd2c
Compare
9b2dd2c
to
9c95788
Compare
9c95788
to
1fdd1e0
Compare
OK so here's my take on this (to be discussed on the upcoming esp-rs meeting this Tuesday): Constified "enums"
If we switch to these what do we win?
What do we lose?
|
Constified enums are what is currently in this crate. You are talking about constified enum modules. This PR switches to newtype enums, which uses associated constants on the type itself. As to why the newtype style is not the default: I guess simply because it was added after the current default.
Yes, as you said better syntax. But also type safety since you cannot pass just any integer as before, you have to pass a newtype containing that integer.
Regarding |
But then again: it is not us who did this? It is Bindgen (since recently I think) - and by default. Which brings again the topic: if this is the default, perhaps they had good reason to make it the default (as in its usefulness is bigger than its caveats). And In general, I trust Bindgen defaults better than my own judgement, as they have seen much more C bindings than us. |
I don't think having (For example, the C enum enum ip_event_t {
IP_EVENT_STA_GOT_IP,
IP_EVENT_STA_LOST_IP,
...
}; representation in rust would turn from pub type ip_event_t = c_types::c_uint;
pub const ip_event_t_IP_EVENT_STA_GOT_IP: ip_event_t = 0;
pub const ip_event_t_IP_EVENT_STA_LOST_IP: ip_event_t = 1; into #[repr(transparent)]
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct ip_event_t(pub c_types::c_uint);
impl ip_event_t {
pub const IP_EVENT_STA_GOT_IP: ip_event_t = ip_event_t(0);
pub const IP_EVENT_STA_LOST_IP: ip_event_t = ip_event_t(1);
} ). Now I think it's really tempting to have the newtype representation. It's more structured, each enum has its own type (not just a type alias) with associated constants for the variants, which is similar to normal C or Rust enums. But I don't think we gain enough from this syntax to make it worth it, especially because this is a low level bindings crate. The biggest downside though is that manipulating these constants at compile-time (in a const context) becomes a pain, which we do pretty often in embedded code, this is especially true for the bitfield-ified enums. |
I don't really have any strong opinions about this. My gut is saying to have faith with the defaults of bindgen, but some added type safey would be nice, but to be honest not a huge deal. All these bindings are unsafe and should be used and reviewed with care. |
I'm closing this as I don't see us switching to other type of enum representation anytime soon. |
Generate Rust enums and implement correct default value for
wifi_init_config_t
.