The domain itself isn't fundamentally unsafe, only the way the C API has been designed. You're right that meaningfully different abstractions (instead of a one-to-one translation) may be required to make a safe API, which is why I suggested that could be a possibility.
This ought to be doable automatically, at least a lot better than the current code:
let event = CreateEventW(
std::ptr::null_mut(),
true.into(),
false.into(),
std::ptr::null(),
);
The .into() is silly but tolerable. But the first parameter is a pointer to a struct, and it’s clear enough from the signature that a reference would work. It could be mut to be on the safe side. (Yes, this involves someone making sure that the API doesn’t retain the pointer.). The last argument is, per the prototype, is a string. Admittedly, the Windows API has a truly horrible idea of what a string is, but surely they could do better than using a pointer.
Both of these parameters can be null, and references cannot be null, so it is not possible to use references directly without losing some functionality.
(They could remove the intos if they wanted to, I agree it feels kind of weird but I'm not actually sure if doing it is better or worse, I am conflicted.)
It could very well be Option<&mut T>, though. Personally I think having a 1:1 mapping to the C API is reasonable enough as a first target. It should make porting code easy and referencing the official documentation is probably easiest this way.
No matter how many heuristics they apply to make a somewhat more idiomatic mapping, it'll never feel right until it's manually designed to fit with Rust conventions. So I'm okay with it as it is now and can hope for a much thicker abstraction in the future.
There are a few different possibilities, and some of them involve Option, yes. But doing this would still possibly create an annotation burden that the parent is complaining about.
My comment was trying to be pretty narrowly scoped to "why not use a reference here." You and your sibling are both right in ways!
But that wouldn't eliminate the need for unsafe code at the border. All ffi calls are inherently unsafe to Rust. You can design the cleanest nicest safest C api in the world but it's still unsafe as far as Rust is concerned.
It's very much possible (essential, even) to be able to present a safe API to external callers of your code, despite using unsafe code under the hood. In this case you're making a human-checked assertion of safety, which is not guaranteed to be without bugs, but the important thing is that you're minimizing the surface area of un-safety and declaring a contract with your users. You're "stopping the buck" of unsafety rather than passing it on. The parts that really have to be unsafe can enjoy extra scrutiny, and everything else (including the caller's code) can be checked by the compiler. This is not uncommon in the standard library and other low-level libraries.
Sure. So this library exposes all of Microsoft’s DLL surface area in an API-native way. That’s important.
Now that it’s released, library authors can wrap this with another library, which abstracts over win32, reexposing it in safe rust. Wrapper libraries like that almost certainly won’t cover 100% of the api surface area - there are so many functions in the windows APIs.
Anyway, give it time. People will wrap this with safe rust.
Yes, but those unsafe blocks can be wrapped into the library. "Unsafe" doesn't inherently mean "bad", it just means that the programmer is explicitly taking the burden of making sure that the normal invariants still hold. So long as the library authors ensure that, then the "unsafe" blocks remain within the library and don't need to be worried about by the users of the library. On the other hand, if a library pushes that additional responsibility to me, it makes me more worried.
Yes, but if the library abstracts away the unsafe code, then users of the library don't need to write any themselves. This has the advantage of a single point of unsafeness, which can be fixed by the library author/maintainer for all clients.
This makes no sense to me, what you’re saying here. You pass raw pointers to the Windows API for one, for which it makes no safety guarantees. Short of rewriting Windows from scratch I don’t see how this isn’t a fundamentally unsafe domain. Sure you could put more and more wrappers up on top (it’s not an even an issue of one-to-one translation, but how resources such as memory are wrapped), but whatever binding there is pretty much must be unsafe.
That it’s possible to write a safe wrapper is kind of obvious.