-
Notifications
You must be signed in to change notification settings - Fork 50
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
Finish 0.4 update #70
Conversation
I will have a close look at this the next time i have some time for 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.
This looks nice, but I think you should keep the commit history from #67 - maybe merge that first, and rebase this on top
Open to doing this if desired. |
I normally don't place a strong value on git history stuff, as long as the code that's published is correct that's good enough for me. However, if you know how to merge the history (or whatever you call it) and it's easy enough to do, then it seems like a good idea, since it was asked for. |
or, if you need me to actually merge #67 to make it work then i can do that. |
Yes, i think we should do that and i'll rebase this as suggested. |
alright, you're set. |
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.
Have a few minor nits, but doesn't matter much, approved from my side
I also pushed a commit which moves the "Safety guarantees" documentation to the crate root, making it more prominent. In the previous location, it was easy to miss it. |
Hmm, but when viewing in rustdoc you usually look at the page for the item itself. In this case the page for the trait. Myself, I rarely look at module level documentation to find out info on a specific item. Also, the rust-analyzer tooltip shows the item's docs not the docs of the module the item goes in. We could have a message in both places, but i think the trait should have the full safety message and the module should have a note to please see the docs of the trait for the rules. |
This is the best solution, thanks! |
I'm guessing |
Yeah, because there's unsafe stuff going on we didn't want to just use a standard conversion trait. You should have to pay just a little more attention about what's happening. |
If everyone is happy I'll merge this in a few hours. |
I just have a minor issue with naming consistency. There are a couple of types/enum variants which derive their names from some other underlying technology/library whose name contains an acronym and is typically written in a stylized way:
Out of these, I see three options here, and I'm not entirely happy with any of them.
|
I am in favor of option 1. While none of these are perfect, option 1 is the only correct one. |
I agree with @Friz64. So it would be |
I have no strong opinion here, (1) seems reasonable enough. |
Yes exactly. And regarding the changelog: Is it complete now? |
Yes, I believe we're all set. I'll merge later if no one speaks up. |
So a lifetime question regarding the trusted handle. Per the documentation the The idea of The trusted handle is not Cloneable, so we can rely on that living as long as the scope it was initialized for. However I don't think this garuntees the backing resources of the handle will live longer than the handle itself. I may consider what vulkano does with their surface object, which also takes a window object, be it a winit window or an Arc to act as a sort of anchor for making the trusted handle live long enough. |
Yeah, you do have a point - Maybe the API should be completely changed to something like: pub trait HasTrustedWindowHandle {
fn trusted_window_handle<'a>(&'a self) -> TrustedWindowHandle<'a>;
}
#[derive(...)]
pub struct TrustedWindowHandle<'a> {
raw: RawWindowHandle,
_phantom: PhantomData<&'a ()>,
}
impl<'a> TrustedWindowHandle<'a> {
pub const unsafe fn from_raw(raw: RawWindowHandle) -> Self { ... }
pub fn as_raw(&self) -> RawWindowHandle { ... }
}
impl From<TrustedWindowHandle<'a>> for RawWindowHandle { ... }
(Actually, we could rename But this still leaves open what |
The trusted part is supposed to be indicating that the pointers contained, if non-null, are valid (at least when you make the value). |
But I don't think that is a strong enough guarantee to help e.g. |
they just say the handle has to be valid i their safety rules. if there are other undocumented requirements then that should be documented. |
Well, I don't know much about So the following example would cause undefined behaviour, because things created from the let window: winit::Window = ...;
let handle = TrustedWindowHandle::from_has_raw_window_handle(&window);
// Changed to take the current TrustedWindowHandle, which would make it "safe"
let surface = backend::Instance::create_surface(handle)?;
drop(window);
// Use `surface` later on, causes undefined behaviour because the window was deallocated. |
So my position on this sort of thing has usually been that you can have an unsafe constructor and then part of the unsafe promise is that you won't use the value (or things based on it in this case) for "too long". So if Because the alternative is that we can never ever claim safe surface creation, when we know that the creation step itself isn't causing issues. probably the surface and window should be bundled together by some code that knows how to make the surface bot outlive the window. |
I've been meaning to bring this up, but the gfx-rs folks have been thinking about this as well in gfx-rs/wgpu#1463. As I understand it, the thing that's most interesting to guarantee is that the handles you get stay valid after you've got a hold of them. In gfx-rs/wgpu#1463, it was suggested that things (in this case: impl<'a, T: HasRawWindowHandle> HasRawWindowHandle for &'a T { /* .. */ }
impl<T: HasRawWindowHandle> HasRawWindowHandle for Rc<T> { /* .. */ }
impl<T: HasRawWindowHandle> HasRawWindowHandle for Arc<T> { /* .. */ } With this in mind, I don't see where |
It would, but that defeats the bigger purpose of
This would be possible on MacOS at least (by let window: winit::Window = ...;
let handle = TrustedWindowHandle::from_has_raw_window_handle(&window);
drop(window);
// Later on when the window has been deallocated:
let surface = backend::Instance::create_surface(handle)?; |
Thanks for the reference! This is definitely a path forward, though I think it's pretty unergonomic that the user would no longer have full control over the window. But then again, it might be unsafe if they did, or if the surface didn't somehow take mutable ownership (e.g. attempting to create two surfaces on the same window would need to be guarded against, since it would very likely cause undefined behaviour). |
Kinda, you'd have to not have a surface and window separate, they'd have to be combined so that you can't drop them in the wrong order. Then the end user code would only handle the bundle and not interact with the inner fields directly. to tell you the truth I don't remember why TrustedWindowHandle was developed, because it's not really needed for end users to have all safe code. |
Would it be an option to keep the |
@msiglreith I'm not sure I fully understand the problem. The And we took out all the |
yeah.. well I guess I'm fine with it as I can workaround that part |
We could maybe make the docs more clear about the expectations, and then you could use that as the basis for a PR to winit to just return the darn null pointer, if that would help you. |
I want In this case, it would be the job of If the conversation here is correct, it seems that completely decoupling these is going to be difficult, and need some more thinking. I think the most viable choice is |
In any case, I think the decision on the safety around |
Ah, yes, right. I'll merge as is and we can discuss further if needed before a release. |
To that end, I've opened a separate issue (#71). |
FWIW, if the I'm not sure why you feel you need an unsafe constructor here, though. If you need the actual window elsewhere, the way you construct the |
It is not a issue because |
From what I have heard, this isn't necessarily something that can be relied on going forward to prevent moves, while |
Can someone explain the Arc::make_mut concern in more detail? Is the idea that someone could run a mem::swap using the &mut RawWindowHandle to change the value out from under you? |
This PR picks up where #67 left off, cleans up the documentation and implements all remaining TODOs and concerns. #68 was also backported.
cfg
guards. #63