-
Notifications
You must be signed in to change notification settings - Fork 13.3k
book/ffi: nullable pointer cleanup #34258
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
Conversation
(rust_highfive has picked a reviewer for you, use r? to override) |
where `None` corresponds to `null`. So `Option<extern "C" fn(c_int) -> c_int>` is a correct way | ||
to represent a nullable function pointer using the C ABI (corresponding to the C type | ||
`int (*)(int)`). (However, generics are not required to get the optimization. A simple | ||
`enum NullableIntRef { Int(Box<i32>), NotInt }` is also represented as a single pointer.) |
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 think this can be removed if the "instantiated" wording above is replaced with a generics-agnostic description (i.e. one of the variants has no data, the other variant contains a non-nullable pointer - which also works if it's a nested struct).
@eddyb check out the expanded (very contrived) example |
@durka Amazing! I love it, although I'm not sure how usable it is for someone just getting into Rust. |
as a single pointer, and the non-data variant is represented as the null pointer. This is | ||
called an "optimization", but unlike other optimizations it is guaranteed to apply to | ||
eligible types. | ||
a single field of one of the non-nullable types listed above (or a struct containing such a type). |
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.
Don't think it's limited to a single field either. Just there's a non-nullable field somewhere in there, even nested.
I changed the wording that was pointed out on IRC. It was also suggested that I choose a simpler example, maybe from within snappy, but snappy doesn't have any callbacks or function pointers in its API. It does have functions that take pointers as parameters (but when the snappy API is introduced in the chapter, before this section, nullable-pointer-optimized Options are not used), so I could write an example like the following, but someone else on IRC said it's questionable to use extern "C" {
fn snappy_uncompressed_length(compressed: *const u8,
compressed_length: size_t,
result: Option<&mut size_t>) -> c_int;
}
let compressed: Vec<u8> = get_compressed_data();
let mut uncompressed_length = 0;
snappy_uncompressed_length(compressed.as_ptr(),
compressed.len(),
Some(&mut uncompressed_length)); |
@durka We've guaranteed that
http://doc.rust-lang.org/stable/book/ffi.html#the-nullable-pointer-optimization |
@ubsan note that you're quoting from the very paragraph being edited in
|
@durka I realize. That means that we can't change it :) |
OK. We should also make sure my edits don't introduce any new undesirable
|
@durka I don't think you should add that part; I think the only guarantee should be for exactly |
Well, @eddyb was encouraging me (I think) to document how it actually
|
@durka We shouldn't specify that, however. Guarantees are hard to take back. We shouldn't specify anything about enum representation without a very good reason: back compatibility is one of those reasons. |
You may be right. On the other hand I suspect we'll only make enum layout optimization more aggressive, not less, in the future. Anyone else have an opinion on what should be documented? Maybe I could change it to say "Furthermore, the current compiler searches through nested structs to find a non-nullable field in which to stash the discriminant, but this level of enum layout optimization should not yet be relied upon." |
@durka it should never be relied upon. We should guarantee as little as is reasonable, imo. edit: got it |
I've heard your opinion. I partially agree. I'd also like to get a sense of what the compiler folks think, but we're drowning them out :) |
It is always really unclear to me when we should be using these and when we should be using |
I like this PR, just the question about libc vs std::os::raw. |
I have always used libc for those kinds of definitions. |
☔ The latest upstream changes (presumably #34294) made this pull request unmergeable. Please resolve the merge conflicts. |
@durka any chance you can update this PR? |
Sure thing. I'm getting the sense I should roll back the libc commit and explain the nullable pointer thing in less detail so as to make fewer guarantees. |
👍 |
Expand the "nullable pointer optimization" section with a code example. Change examples to use std::os::raw instead of libc, when applicable.
Not sure the example is going to stay, but I can try to pass Travis for the bragging rights.
…ype, even though that is how it works
Done. There's still the question of whether my example is too contrived/complicated. |
I am okay with it. Thanks! @bors: r+ rollup |
📌 Commit 29546dd has been approved by |
book/ffi: nullable pointer cleanup Expand the "nullable pointer optimization" section with a code example. Fixes rust-lang#34250. I also noticed that many of the examples use the libc crate just for types such as `c_char` and `c_int`, which are now available through `std::os::raw`. I changed the ones that don't need to rely on libc. I'm glad to revert that part of the commit if it's unwanted churn.
Expand the "nullable pointer optimization" section with a code example. Fixes #34250.
I also noticed that many of the examples use the libc crate just for types such as
c_char
andc_int
, which are now available throughstd::os::raw
. I changed the ones that don't need to rely on libc. I'm glad to revert that part of the commit if it's unwanted churn.