macro_rules! dispatch_types {
(
ref type $name:ident: $interface:ident = $core_type:ident,$webgpu_type:ident,$custom_type:ident
) => { ... };
(
mut type $name:ident: $interface:ident = $core_type:ident,$webgpu_type:ident,$custom_type:ident
) => { ... };
}Expand description
Generates a dispatch type for some wgpu API type.
Invocations of this macro take one of the following forms:
dispatch_types! {mut type D: I = Core, Web, Dyn }
dispatch_types! {ref type D: I = Core, Web, Dyn }This defines D as a type that dereferences to a dyn I trait object. Most uses of
D in the rest of this crate just call the methods from the dyn I object, not from
D itself.
Internally, D is an enum with up to three variants holding values of type Core,
Web, and Dyn, all of which must implement I. Core, Web and Dyn are the
types from the wgpu_core, webgpu, and custom submodules of wgpu::backend that
correspond to D. The macro generates Deref and DerefMut implementations that
match on this enum and produce a dyn I reference for each variant.
The macro’s mut type form defines D as the unique owner of the backend type, with
a DerefMut implementation, and as_*_mut methods that return &mut references.
This D does not implement Clone.
The macro’s ref type form defines D to hold an Arc pointing to the backend type,
permitting Clone and Deref, but losing exclusive, mutable access.
For example:
dispatch_types! {ref type DispatchBuffer: BufferInterface =
CoreBuffer, WebBuffer, DynBuffer}This defines DispatchBuffer as a type that dereferences to &dyn BufferInterface,
which has methods like map_async and destroy. The enum would be:
pub enum DispatchBuffer {
#[cfg(wgpu_core)]
Core(Arc<CoreBuffer>),
#[cfg(webgpu)]
WebGPU(WebBuffer),
#[cfg(custom)]
Custom(DynBuffer),
}This macro also defines as_* methods so that the backend implementations can
dereference other arguments.
§Devirtualization
The dispatch types generated by this macro are carefully designed to allow the compiler to completely devirtualize calls in most circumstances.
Note that every variant of the enum generated by this macro is under a #[cfg].
Naturally, the match expressions in the Deref and DerefMut implementations have
matching #[cfg] attributes on each match arm.
In practice, when wgpu’s "custom" feature is not enabled, there is usually only
one variant in the enum, making it effectively a newtype around the sole variant’s
data: it has no discriminant to branch on, and the match expressions are removed
entirely by the compiler.
In this case, when we invoke a method from the interface trait I on a dispatch type,
the Deref and DerefMut implementations’ match statements build a &dyn I for
the data, on which we immediately invoke a method. The vtable is a constant, allowing
the Rust compiler to turn the dyn method call into an ordinary method call. This
creates opportunities for inlining.
Similarly, the as_* methods are free when there is only one backend.