Skip to content

Commit

Permalink
[22.0.0] Change WASI trait impls back to being blanket impls (#8767)
Browse files Browse the repository at this point in the history
* Change WASI trait impls back to being blanket impls (#8766)

This commit is a partial revert of #8609 to return `wasmtime-wasi` and
`wasmtime-wasi-http` back to using blanket impls. The main change from
before is to change the blanket impls to be in terms of a local newtype
wrapper to avoid trait coherence issues. This is done because otherwise
using the traits before required `&mut dyn WasiView` to exist but
sometimes only a `Foo<'a>` is held which is not easy to get a `&mut dyn
...` view of. By changing to a blanket impl in terms of a newtype
wrapper, `WasiImpl`, it's possible to call `bindgen!`-generated
`add_to_linker_get_host` functions with a return value of
`WasiImpl<Foo<'a>>` which enables hooking into all the generated
bindings.

* Update release notes
  • Loading branch information
alexcrichton committed Jun 10, 2024
1 parent 0e93db7 commit 69a78fc
Show file tree
Hide file tree
Showing 25 changed files with 475 additions and 171 deletions.
3 changes: 2 additions & 1 deletion RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,9 @@ Unreleased.
[#8610](https://github.com/bytecodealliance/wasmtime/pull/8610)

* Implementations of `Host` traits in the `wasmtime-wasi` crate are now for
`dyn WasiView` instead of blanket impls for `T: WasiView`.
`WasiImpl<T>` instead of blanket impls for `T`.
[#8609](https://github.com/bytecodealliance/wasmtime/pull/8609)
[#8766](https://github.com/bytecodealliance/wasmtime/pull/8766)

* The concepts of "virtual sp offset" and "nominal sp" have been removed from all
Cranelift backends.
Expand Down
7 changes: 5 additions & 2 deletions crates/wasi-http/src/http_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@ use crate::{
error::internal_error,
http_request_error,
types::{HostFutureIncomingResponse, HostOutgoingRequest, OutgoingRequestConfig},
WasiHttpView,
WasiHttpImpl, WasiHttpView,
};
use bytes::Bytes;
use http_body_util::{BodyExt, Empty};
use hyper::Method;
use wasmtime::component::Resource;

impl outgoing_handler::Host for dyn WasiHttpView + '_ {
impl<T> outgoing_handler::Host for WasiHttpImpl<T>
where
T: WasiHttpView,
{
fn handle(
&mut self,
request_id: Resource<HostOutgoingRequest>,
Expand Down
2 changes: 1 addition & 1 deletion crates/wasi-http/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,4 @@ pub use crate::error::{
http_request_error, hyper_request_error, hyper_response_error, HttpError, HttpResult,
};
#[doc(inline)]
pub use crate::types::{WasiHttpCtx, WasiHttpView};
pub use crate::types::{WasiHttpCtx, WasiHttpImpl, WasiHttpView};
16 changes: 8 additions & 8 deletions crates/wasi-http/src/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! The implementation at the top of the module for use in async contexts,
//! while the `sync` module provides implementation for use in sync contexts.

use crate::WasiHttpView;
use crate::{WasiHttpImpl, WasiHttpView};

mod bindings {
#![allow(missing_docs)]
Expand Down Expand Up @@ -83,7 +83,7 @@ pub fn add_to_linker<T>(l: &mut wasmtime::component::Linker<T>) -> anyhow::Resul
where
T: WasiHttpView + wasmtime_wasi::WasiView,
{
let closure = type_annotate_wasi::<T, _>(|t| t);
let closure = type_annotate_wasi::<T, _>(|t| wasmtime_wasi::WasiImpl(t));
wasmtime_wasi::bindings::clocks::wall_clock::add_to_linker_get_host(l, closure)?;
wasmtime_wasi::bindings::clocks::monotonic_clock::add_to_linker_get_host(l, closure)?;
wasmtime_wasi::bindings::io::poll::add_to_linker_get_host(l, closure)?;
Expand All @@ -101,13 +101,13 @@ where
// obsolete.
fn type_annotate_http<T, F>(val: F) -> F
where
F: Fn(&mut T) -> &mut dyn WasiHttpView,
F: Fn(&mut T) -> WasiHttpImpl<&mut T>,
{
val
}
fn type_annotate_wasi<T, F>(val: F) -> F
where
F: Fn(&mut T) -> &mut dyn wasmtime_wasi::WasiView,
F: Fn(&mut T) -> wasmtime_wasi::WasiImpl<&mut T>,
{
val
}
Expand All @@ -117,7 +117,7 @@ pub fn add_only_http_to_linker<T>(l: &mut wasmtime::component::Linker<T>) -> any
where
T: WasiHttpView,
{
let closure = type_annotate_http::<T, _>(|t| t);
let closure = type_annotate_http::<T, _>(|t| WasiHttpImpl(t));
crate::bindings::http::outgoing_handler::add_to_linker_get_host(l, closure)?;
crate::bindings::http::types::add_to_linker_get_host(l, closure)?;

Expand All @@ -126,7 +126,7 @@ where

/// Sync implementation of the `wasi:http/proxy` world.
pub mod sync {
use crate::WasiHttpView;
use crate::{WasiHttpImpl, WasiHttpView};

mod bindings {
#![allow(missing_docs)]
Expand Down Expand Up @@ -203,7 +203,7 @@ pub mod sync {
where
T: WasiHttpView + wasmtime_wasi::WasiView,
{
let closure = super::type_annotate_wasi::<T, _>(|t| t);
let closure = super::type_annotate_wasi::<T, _>(|t| wasmtime_wasi::WasiImpl(t));

wasmtime_wasi::bindings::clocks::wall_clock::add_to_linker_get_host(l, closure)?;
wasmtime_wasi::bindings::clocks::monotonic_clock::add_to_linker_get_host(l, closure)?;
Expand All @@ -226,7 +226,7 @@ pub mod sync {
where
T: WasiHttpView,
{
let closure = super::type_annotate_http::<T, _>(|t| t);
let closure = super::type_annotate_http::<T, _>(|t| WasiHttpImpl(t));

crate::bindings::http::outgoing_handler::add_to_linker_get_host(l, closure)?;
crate::bindings::http::types::add_to_linker_get_host(l, closure)?;
Expand Down
77 changes: 77 additions & 0 deletions crates/wasi-http/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,83 @@ impl<T: ?Sized + WasiHttpView> WasiHttpView for &mut T {
}
}

impl<T: ?Sized + WasiHttpView> WasiHttpView for Box<T> {
fn ctx(&mut self) -> &mut WasiHttpCtx {
T::ctx(self)
}

fn table(&mut self) -> &mut ResourceTable {
T::table(self)
}

fn new_response_outparam(
&mut self,
result: tokio::sync::oneshot::Sender<
Result<hyper::Response<HyperOutgoingBody>, types::ErrorCode>,
>,
) -> wasmtime::Result<Resource<HostResponseOutparam>> {
T::new_response_outparam(self, result)
}

fn send_request(
&mut self,
request: hyper::Request<HyperOutgoingBody>,
config: OutgoingRequestConfig,
) -> crate::HttpResult<HostFutureIncomingResponse> {
T::send_request(self, request, config)
}

fn is_forbidden_header(&mut self, name: &HeaderName) -> bool {
T::is_forbidden_header(self, name)
}
}

/// A concrete structure that all generated `Host` traits are implemented for.
///
/// This type serves as a small newtype wrapper to implement all of the `Host`
/// traits for `wasi:http`. This type is internally used and is only needed if
/// you're interacting with `add_to_linker` functions generated by bindings
/// themselves (or `add_to_linker_get_host`).
///
/// This type is automatically used when using
/// [`wasmtime_wasi_http::proxy::add_to_linker`](crate::proxy::add_to_linker)
/// or
/// [`wasmtime_wasi_http::proxy::sync::add_to_linker`](crate::proxy::sync::add_to_linker)
/// and doesn't need to be manually configured.
#[repr(transparent)]
pub struct WasiHttpImpl<T>(pub T);

impl<T: WasiHttpView> WasiHttpView for WasiHttpImpl<T> {
fn ctx(&mut self) -> &mut WasiHttpCtx {
self.0.ctx()
}

fn table(&mut self) -> &mut ResourceTable {
self.0.table()
}

fn new_response_outparam(
&mut self,
result: tokio::sync::oneshot::Sender<
Result<hyper::Response<HyperOutgoingBody>, types::ErrorCode>,
>,
) -> wasmtime::Result<Resource<HostResponseOutparam>> {
self.0.new_response_outparam(result)
}

fn send_request(
&mut self,
request: hyper::Request<HyperOutgoingBody>,
config: OutgoingRequestConfig,
) -> crate::HttpResult<HostFutureIncomingResponse> {
self.0.send_request(request, config)
}

fn is_forbidden_header(&mut self, name: &HeaderName) -> bool {
self.0.is_forbidden_header(name)
}
}

/// Returns `true` when the header is forbidden according to this [`WasiHttpView`] implementation.
pub(crate) fn is_forbidden_header(view: &mut dyn WasiHttpView, name: &HeaderName) -> bool {
static FORBIDDEN_HEADERS: [HeaderName; 10] = [
Expand Down
62 changes: 49 additions & 13 deletions crates/wasi-http/src/types_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
HostFutureIncomingResponse, HostIncomingRequest, HostIncomingResponse, HostOutgoingRequest,
HostOutgoingResponse, HostResponseOutparam,
},
WasiHttpView,
WasiHttpImpl, WasiHttpView,
};
use anyhow::Context;
use std::any::Any;
Expand All @@ -19,7 +19,10 @@ use wasmtime_wasi::{
Pollable, ResourceTableError,
};

impl crate::bindings::http::types::Host for dyn WasiHttpView + '_ {
impl<T> crate::bindings::http::types::Host for WasiHttpImpl<T>
where
T: WasiHttpView,
{
fn convert_error_code(&mut self, err: crate::HttpError) -> wasmtime::Result<types::ErrorCode> {
err.downcast()
}
Expand Down Expand Up @@ -98,7 +101,10 @@ fn get_fields_mut<'a>(
}
}

impl crate::bindings::http::types::HostFields for dyn WasiHttpView + '_ {
impl<T> crate::bindings::http::types::HostFields for WasiHttpImpl<T>
where
T: WasiHttpView,
{
fn new(&mut self) -> wasmtime::Result<Resource<HostFields>> {
let id = self
.table()
Expand Down Expand Up @@ -285,7 +291,10 @@ impl crate::bindings::http::types::HostFields for dyn WasiHttpView + '_ {
}
}

impl crate::bindings::http::types::HostIncomingRequest for dyn WasiHttpView + '_ {
impl<T> crate::bindings::http::types::HostIncomingRequest for WasiHttpImpl<T>
where
T: WasiHttpView,
{
fn method(&mut self, id: Resource<HostIncomingRequest>) -> wasmtime::Result<Method> {
let method = self.table().get(&id)?.parts.method.clone();
Ok(method.into())
Expand Down Expand Up @@ -370,7 +379,10 @@ impl crate::bindings::http::types::HostIncomingRequest for dyn WasiHttpView + '_
}
}

impl crate::bindings::http::types::HostOutgoingRequest for dyn WasiHttpView + '_ {
impl<T> crate::bindings::http::types::HostOutgoingRequest for WasiHttpImpl<T>
where
T: WasiHttpView,
{
fn new(
&mut self,
headers: Resource<Headers>,
Expand Down Expand Up @@ -556,7 +568,10 @@ impl crate::bindings::http::types::HostOutgoingRequest for dyn WasiHttpView + '_
}
}

impl crate::bindings::http::types::HostResponseOutparam for dyn WasiHttpView + '_ {
impl<T> crate::bindings::http::types::HostResponseOutparam for WasiHttpImpl<T>
where
T: WasiHttpView,
{
fn drop(&mut self, id: Resource<HostResponseOutparam>) -> wasmtime::Result<()> {
let _ = self.table().delete(id)?;
Ok(())
Expand All @@ -579,7 +594,10 @@ impl crate::bindings::http::types::HostResponseOutparam for dyn WasiHttpView + '
}
}

impl crate::bindings::http::types::HostIncomingResponse for dyn WasiHttpView + '_ {
impl<T> crate::bindings::http::types::HostIncomingResponse for WasiHttpImpl<T>
where
T: WasiHttpView,
{
fn drop(&mut self, response: Resource<HostIncomingResponse>) -> wasmtime::Result<()> {
let _ = self
.table()
Expand Down Expand Up @@ -640,7 +658,10 @@ impl crate::bindings::http::types::HostIncomingResponse for dyn WasiHttpView + '
}
}

impl crate::bindings::http::types::HostFutureTrailers for dyn WasiHttpView + '_ {
impl<T> crate::bindings::http::types::HostFutureTrailers for WasiHttpImpl<T>
where
T: WasiHttpView,
{
fn drop(&mut self, id: Resource<HostFutureTrailers>) -> wasmtime::Result<()> {
let _ = self
.table()
Expand Down Expand Up @@ -687,7 +708,10 @@ impl crate::bindings::http::types::HostFutureTrailers for dyn WasiHttpView + '_
}
}

impl crate::bindings::http::types::HostIncomingBody for dyn WasiHttpView + '_ {
impl<T> crate::bindings::http::types::HostIncomingBody for WasiHttpImpl<T>
where
T: WasiHttpView,
{
fn stream(
&mut self,
id: Resource<HostIncomingBody>,
Expand Down Expand Up @@ -718,7 +742,10 @@ impl crate::bindings::http::types::HostIncomingBody for dyn WasiHttpView + '_ {
}
}

impl crate::bindings::http::types::HostOutgoingResponse for dyn WasiHttpView + '_ {
impl<T> crate::bindings::http::types::HostOutgoingResponse for WasiHttpImpl<T>
where
T: WasiHttpView,
{
fn new(
&mut self,
headers: Resource<Headers>,
Expand Down Expand Up @@ -807,7 +834,10 @@ impl crate::bindings::http::types::HostOutgoingResponse for dyn WasiHttpView + '
}
}

impl crate::bindings::http::types::HostFutureIncomingResponse for dyn WasiHttpView + '_ {
impl<T> crate::bindings::http::types::HostFutureIncomingResponse for WasiHttpImpl<T>
where
T: WasiHttpView,
{
fn drop(&mut self, id: Resource<HostFutureIncomingResponse>) -> wasmtime::Result<()> {
let _ = self.table().delete(id)?;
Ok(())
Expand Down Expand Up @@ -866,7 +896,10 @@ impl crate::bindings::http::types::HostFutureIncomingResponse for dyn WasiHttpVi
}
}

impl crate::bindings::http::types::HostOutgoingBody for dyn WasiHttpView + '_ {
impl<T> crate::bindings::http::types::HostOutgoingBody for WasiHttpImpl<T>
where
T: WasiHttpView,
{
fn write(
&mut self,
id: Resource<HostOutgoingBody>,
Expand Down Expand Up @@ -903,7 +936,10 @@ impl crate::bindings::http::types::HostOutgoingBody for dyn WasiHttpView + '_ {
}
}

impl crate::bindings::http::types::HostRequestOptions for dyn WasiHttpView + '_ {
impl<T> crate::bindings::http::types::HostRequestOptions for WasiHttpImpl<T>
where
T: WasiHttpView,
{
fn new(&mut self) -> wasmtime::Result<Resource<types::RequestOptions>> {
let id = self.table().push(types::RequestOptions::default())?;
Ok(id)
Expand Down
33 changes: 33 additions & 0 deletions crates/wasi/src/ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,39 @@ impl<T: ?Sized + WasiView> WasiView for &mut T {
}
}

impl<T: ?Sized + WasiView> WasiView for Box<T> {
fn table(&mut self) -> &mut ResourceTable {
T::table(self)
}
fn ctx(&mut self) -> &mut WasiCtx {
T::ctx(self)
}
}

/// A small newtype wrapper which serves as the basis for implementations of
/// `Host` WASI traits in this crate.
///
/// This type is used as the basis for the implementation of all `Host` traits
/// generated by `bindgen!` for WASI interfaces. This is used automatically with
/// [`add_to_linker_sync`](crate::add_to_linker_sync) and
/// [`add_to_linker_async`](crate::add_to_linker_async).
///
/// This type is otherwise provided if you're calling the `add_to_linker`
/// functions generated by `bindgen!` from the [`bindings`
/// module](crate::bindings). In this situation you'll want to create a value of
/// this type in the closures added to a `Linker`.
#[repr(transparent)]
pub struct WasiImpl<T>(pub T);

impl<T: WasiView> WasiView for WasiImpl<T> {
fn table(&mut self) -> &mut ResourceTable {
T::table(&mut self.0)
}
fn ctx(&mut self) -> &mut WasiCtx {
T::ctx(&mut self.0)
}
}

/// Per-[`Store`] state which holds state necessary to implement WASI from this
/// crate.
///
Expand Down
Loading

0 comments on commit 69a78fc

Please sign in to comment.