Refactor futures/streams support for Rust#1249
Refactor futures/streams support for Rust#1249alexcrichton merged 13 commits intobytecodealliance:mainfrom
Conversation
|
This is a bit of a work-in-progress, but opening this up for upstream PRs. Will flesh out more in the future |
Mostly remove the old implementations for futures/streams and replace them with new versions which address a number of preexisting issues and additionally adapt to upcoming ABI changes.
f213e81 to
4c89fc0
Compare
| EVENT_STREAM_READ | EVENT_STREAM_WRITE | EVENT_FUTURE_READ | EVENT_FUTURE_WRITE => { | ||
| (*state).remove_waitable(event1 as u32); | ||
| let (waker, code) = (*state).wakers.remove(&(event1 as u32)).unwrap(); | ||
| *code = Some(event2 as u32); | ||
| waker.wake(); | ||
|
|
||
| let done = poll(state).is_ready(); | ||
| callback_code(state, done) | ||
| } |
There was a problem hiding this comment.
I'll note that in the future I want to fold EVENT_CALL_RETURNED into this exact same pattern as well, but that'll require some refactoring to achieve that.
|
|
||
| /// Cleanup helper used to deallocate blocks of canonical ABI data from | ||
| /// lowerings. | ||
| pub struct Cleanup { |
There was a problem hiding this comment.
I'll note that adding this is going to wreak havoc with cargo component. I don't know what to do about that.
There was a problem hiding this comment.
Ok I have now articulated a long-term goal: bytecodealliance/cargo-component#387
Now the question is what to do about this in the short term.
There was a problem hiding this comment.
Ok did some thinking (aka paused and did a think) -- I think we should go ahead and land this refactoring. This means that wit-bindgen basically can't get updated in cargo-component without breaking things, but it won't break anything itself. Not being able to update for a bit is I think probably the best tradeoff here for now.
| } | ||
| } | ||
|
|
||
| fn stream_direct(ty: &Type) -> bool { |
There was a problem hiding this comment.
I've replaced this with is_list_canonical which already existed but was somewhere else, so I refactored it to be available here.
tests/runtime-new-async-disabled/future-cancel-write-then-read/runner.rs
Outdated
Show resolved
Hide resolved
Require source edits for now though to enable it.
|
Ok @dicej I've thought through all the outstanding an open issues (sorry about the torrent of notifications here) and this should be good-to-go. |
| let len = vec.len(); | ||
| let cap = vec.capacity(); | ||
| mem::forget(vec); | ||
| Vec::<MaybeUninit<T>>::from_raw_parts(ptr.cast(), len, cap) |
There was a problem hiding this comment.
Out of curiosity, what's the advantage of doing it this way vs. using transmute? Are there soundness considerations?
There was a problem hiding this comment.
AFAIK this is a situation where it works and probably will work for a long time but everyone will still frown at you for doing it, so I've opted to be a bit safer here and sidestep the question of "is it ok?"
| /// | ||
| /// Panics if the operation has already been completed via `Future::poll`, | ||
| /// or if this method is called twice. | ||
| pub fn cancel(self: Pin<&mut Self>) -> Result<(), FutureWriteCancel<T>> { |
There was a problem hiding this comment.
What's the rationale for using Result here rather than adding a FutureWriteCancel::AlreadyDelivered variant and having this return FutureWriteCancel<T> instead? It's a little surprising to me that we'd consider FutureWriteCancel::Cancelled (or really any of the possible outcomes) to be an error.
There was a problem hiding this comment.
Originally I wanted to avoid making a new error type, but then when I ended up making a new error type anyway I didn't actually get back to fixing this. I'll update that. I think I'll probably just return an enum here instead of a result after all
| /// `Some(value)`, otherwise `None` is returned indicating the value was | ||
| /// sent. | ||
| pub async fn write_one(&mut self, value: T) -> Option<T> { | ||
| // TODO: can probably be a bit more efficient about this and avoid |
There was a problem hiding this comment.
FWIW, this is how I addressed it on the host side, i.e. by making the buffer type generic and implementing it for Vec, Bytes, and Single. That would require significant refactoring here, though, given the way AbiBuffer is currently tied to Vec.
There was a problem hiding this comment.
Good point yeah, I kind of want to avoid the complexity for now but I do still want to leave a note about a potential future optimization, so I'm probably going to leave this as is (and might advocate for the host to do the same in the near term...)
There was a problem hiding this comment.
To be clear, the host optimization was primarily motivated by being able to support bytes::Bytes (which is what Hyper uses out of the box, and thus wasmtime-wasi-http) natively without any conversions. The single-element optimization was just a nice side-effect of generic-izing the code.
Mostly remove the old implementations for futures/streams and replace them with new versions which address a number of preexisting issues and additionally adapt to upcoming ABI changes.
Closes #1152 - there's now a more custom interface for streams which doesn't use sink/stream traits
Closes #1174 - error-context has been removed from futures/streams
Closes #1177 - all "core" futures are now manual state machines, not
async fnCloses #1178 - lowering/lifting was adjusted to avoid leaking anything
Closes #1180 - this should now work
Closes #1181 - the "local" case will trap now in the component model ABI
Closes #1182 - dummy wakers haven't been used for awhile, doubly so here
Closes #1184 - futures/streams are reader/writer pairs with much simpler ownership
Closes #1188 - the intrinsic return value is now handled and accounts for the operation succeeding racily
Closes #1189 -
error-contextintegration with streams/futures is removedCloses #1190 -
Stream{Writer,Reader}take and give buffers, no allocations forstream<u8>Closes #1191 -
FutureWriter::write::cancelreturnsResult<(), FutureWriteCancel<T>>