-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Add the Close trait #2677
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
Add the Close trait #2677
Conversation
For some prior-art in the Rust ecosystem Tokio has |
I think this could also be generalized to a general |
@CryZe As it stands, |
As an aside, I was unsure of whether |
A language solution could take |
When we call `self.into_inner()`, it internally calls `self.flush_buf()`. If flushing causes an error, then the stream shouldn't be flushed again. Thus we must turn off the `self.flush_buf()` call in the destructor. Either `self.panicked = true` or `self.inner.take()` works. I choose the second because it more explicitly shows we are ignoring errors in dropping the inner writer.
What is the benefit of adding a new trait rather than just adding as an inherent method? |
@WiSaGaN The RFC gives the examples of close() methods on I do think the RFC would benefit from calling that out early in the motivation; I had the same question until I got to those examples. |
This is at the end of the first paragraph of motivation. Do you have any other concerns @WiSaGaN ?
|
Does it need to be |
@vi if you want to statically ensure no one can use the resource after it’s closed, then you need to take |
If I understand, there are many designs suitable for different settings, but this one fits with We'd manually propagate errors with this by calling
Actual drop glue would call I'd think transactional data structures require multiple
I think this RFC's design makes sense, but the documentation should explain that |
This won't work for the following reasons:
|
``` | ||
|
||
Although this checks if there were errors in writing the data to the file, there | ||
sometimes are spurious failures that aren't caught here. Our program is |
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.
For someone like myself who might not be familiar with them, can you give some examples of what these failures might be? Are there any that File::sync_all
wouldn’t surface?
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.
For specifically File
, that is correct. sync_all
allows us to handle these errors. Maybe a better example is something like a TCPStream
where you have to send a finish packet to signal to the other side to close the connection. (At least that is my understanding from googling tcp for a few minutes)
About alternatives, I'm wondering about adding a fn close(mut self) -> io::Result<()> {
self.flush() // Or `Ok(())` I suppose, this is arguable
} The RFC argues this is a bad idea as "it would remove backwards compatibility", but I don't see it myself being a case. A default implementation would mean that the already existing structures would work, sure, maybe they wouldn't close the file, but it would be good enough in many cases. One interpretation I could think of is that code explicitly implementing It also argues that "It also prevents us from closing reading resources", which frankly seems like non-issue, what does As for other traits where closing can error, I think it makes sense for those traits to provide their own Keep in mind that having One issue with |
@xfix Thanks for the feedback! I was arguing that it would be backwards incompatible if we didn't have a default implementation. That is what Tokio and futures-preview does (see the comment by Nemo above). That is, they require an implementation of I think it makes sense just to flush and auto drop. I'll add this in.
To be perfectly honest, it's unclear to me what we should do about this case. Because when we close a resource we should take it by value and dispose of it. But at the same time, dynamic types can't work with this. The approach taken by both Tokio and futures-preview is to take |
Actually, Other dynamic dispatch types are non-issue, because they cannot pass the ownership, |
Question, let's say |
IMO if |
@Nemo157 In my opinion, doing nothing (returning |
@xfix it doesn't have to take
That depends a lot on the specific API, if it's just a helper API then it shouldn't be calling |
@czipperz Please note that both Tokio's This is actually a known problem that completion-based IO operations may have no way to cancel them synchronously and thus |
Closing asynchronous I/O is out of scope for this RFC in my opinion. It's so different to regular closing that even if we somehow made I also feel similarly about When having a
As mentioned, |
That's not what the OS |
Following the design of a session-ending trait thrown in by @burdges, impl<W: Write + Close> Close for BufWriter<W> {
type CloseError = buf_writer::CloseError<W>;
fn close(self) -> Result<(), Self::CloseError> {
let flush_res = self.flush();
if let Err(e) = flush_res {
return buf_writer::CloseError::incomplete_flush(e, self);
}
self.inner.close()?; // The error variant returned here features W::CloseError
}
} |
I recently hit the need of some kind of |
I'm not using Rust anymore so if someone else wants this PR to go through feel free to fork my PR. |
I came across this PR while working on BurntSushi/ripgrep#1766. Just want to add that during my research I found https://crates.io/crates/io-close, which implements a Close trait. It works by taking ownership, flushing, using unsafe {} to close the underlying fd/handle/socket, and returning any error. |
Hey, we discussed this RFC in last week's libs team meeting. There are some additional notes in the agenda but the gist of the discussion is that we're unsure about the specific motivating use cases, and we're unsure if this should be a trait. As an alternative we were wondering if an inherent Could you update the RFC to include some example use cases that motivate / justify this being a Trait? Assuming, of course, that you feel it needs to be a trait. If you're happy with the |
I can point out to the IRLO discussion where the example, which led to the discussion, was mentioned. Briefly, I wanted to implement a bitwise compression algorithm that is supposed to terminate the output, so it has to emit the termination when the output is going to finish. I wanted to implement it as a I mentioned in the discussion that a more generic trait, let's call it |
I no longer use Rust so am going to close this issue. If anyone is interested in moving forward with this proposal feel free to fork it. |
Rendered