Revision control

Copy as Markdown

Other Tools

macro_rules! define_wasm_features {
(
$(#[$outer:meta])*
pub struct WasmFeatures: $repr:ty {
$(
$(#[$inner:ident $($args:tt)*])*
pub $field:ident: $const:ident($flag:expr) = $default:expr;
)*
}
) => {
#[cfg(feature = "features")]
bitflags::bitflags! {
$(#[$outer])*
pub struct WasmFeatures: $repr {
$(
$(#[$inner $($args)*])*
#[doc = "\nDefaults to `"]
#[doc = stringify!($default)]
#[doc = "`.\n"]
const $const = $flag;
)*
}
}
/// Enabled WebAssembly proposals and features.
///
/// This is the disabled zero-size version of this structure because the
/// `features` feature was disabled at compile time of this crate.
#[cfg(not(feature = "features"))]
#[derive(Clone, Debug, Default, Hash, Copy)]
pub struct WasmFeatures {
_priv: (),
}
#[cfg(feature = "features")]
impl Default for WasmFeatures {
#[inline]
fn default() -> Self {
let mut features = WasmFeatures::empty();
$(
features.set(WasmFeatures::$const, $default);
)*
features
}
}
impl WasmFeatures {
/// Construct a bit-packed `WasmFeatures` from the inflated struct version.
#[inline]
#[cfg(feature = "features")]
pub fn from_inflated(inflated: WasmFeaturesInflated) -> Self {
let mut features = WasmFeatures::empty();
$(
features.set(WasmFeatures::$const, inflated.$field);
)*
features
}
/// Inflate these bit-packed features into a struct with a field per
/// feature.
///
/// Although the inflated struct takes up much more memory than the
/// bit-packed version, its fields can be exhaustively matched
/// upon. This makes it useful for temporarily checking against,
/// while keeping the bit-packed version as the method of storing
/// the features for longer periods of time.
#[inline]
#[cfg(feature = "features")]
pub fn inflate(&self) -> WasmFeaturesInflated {
WasmFeaturesInflated {
$(
$field: self.$field(),
)*
}
}
$(
/// Returns whether this feature is enabled in this feature set.
#[inline]
pub fn $field(&self) -> bool {
#[cfg(feature = "features")]
{ self.contains(WasmFeatures::$const) }
#[cfg(not(feature = "features"))]
{ $default }
}
)*
}
/// Inflated version of [`WasmFeatures`][crate::WasmFeatures] that
/// allows for exhaustive matching on fields.
#[cfg(feature = "features")]
pub struct WasmFeaturesInflated {
$(
$(#[$inner $($args)*])*
#[doc = "\nDefaults to `"]
#[doc = stringify!($default)]
#[doc = "`.\n"]
pub $field: bool,
)*
}
macro_rules! foreach_wasm_feature {
($f:ident) => {
$($f!($field = $default);)*
}
}
pub(crate) use foreach_wasm_feature;
};
}
define_wasm_features! {
/// Flags for features that are enabled for validation.
///
/// This type controls the set of WebAssembly proposals and features that
/// are active during validation and parsing of WebAssembly binaries. This
/// is used in conjunction with
/// [`Validator::new_with_features`](crate::Validator::new_with_features)
/// for example.
///
/// The [`Default`] implementation for this structure returns the set of
/// supported WebAssembly proposals this crate implements. All features are
/// required to be in Phase 4 or above in the WebAssembly standardization
/// process.
///
/// Enabled/disabled features can affect both parsing and validation at this
/// time. When decoding a WebAssembly binary it's generally recommended if
/// possible to enable all features, as is the default with
/// [`BinaryReader::new`](crate::BinaryReader::new). If strict conformance
/// with historical versions of the specification are required then
/// [`BinaryReader::new_features`](crate::BinaryReader::new_features) or
/// [`BinaryReader::set_features`](crate::BinaryReader::set_features) can be
/// used.
///
/// This crate additionally has a compile-time Cargo feature called
/// `features` which can be used to enable/disable most of this type at
/// compile time. This crate feature is turned on by default and enables
/// this bitflags-representation of this structure. When the `features`
/// feature is disabled then this is a zero-sized structure and no longer
/// has any associated constants. When `features` are disabled all values
/// for proposals are fixed at compile time to their defaults.
#[derive(Hash, Debug, Copy, Clone, Eq, PartialEq)]
pub struct WasmFeatures: u32 {
/// The WebAssembly `mutable-global` proposal.
pub mutable_global: MUTABLE_GLOBAL(1) = true;
/// The WebAssembly `saturating-float-to-int` proposal.
pub saturating_float_to_int: SATURATING_FLOAT_TO_INT(1 << 1) = true;
/// The WebAssembly `sign-extension-ops` proposal.
pub sign_extension: SIGN_EXTENSION(1 << 2) = true;
/// The WebAssembly reference types proposal.
pub reference_types: REFERENCE_TYPES(1 << 3) = true;
/// The WebAssembly multi-value proposal.
pub multi_value: MULTI_VALUE(1 << 4) = true;
/// The WebAssembly bulk memory operations proposal.
pub bulk_memory: BULK_MEMORY(1 << 5) = true;
/// The WebAssembly SIMD proposal.
pub simd: SIMD(1 << 6) = true;
/// The WebAssembly Relaxed SIMD proposal.
pub relaxed_simd: RELAXED_SIMD(1 << 7) = true;
/// The WebAssembly threads proposal.
pub threads: THREADS(1 << 8) = true;
/// The WebAssembly shared-everything-threads proposal; includes new
/// component model built-ins.
pub shared_everything_threads: SHARED_EVERYTHING_THREADS(1 << 9) = false;
/// The WebAssembly tail-call proposal.
pub tail_call: TAIL_CALL(1 << 10) = true;
/// Whether or not floating-point instructions are enabled.
///
/// This is enabled by default can be used to disallow floating-point
/// operators and types.
///
/// This does not correspond to a WebAssembly proposal but is instead
/// intended for embeddings which have stricter-than-usual requirements
/// about execution. Floats in WebAssembly can have different NaN patterns
/// across hosts which can lead to host-dependent execution which some
/// runtimes may not desire.
pub floats: FLOATS(1 << 11) = true;
/// The WebAssembly multi memory proposal.
pub multi_memory: MULTI_MEMORY(1 << 12) = true;
/// The WebAssembly exception handling proposal.
pub exceptions: EXCEPTIONS(1 << 13) = true;
/// The WebAssembly memory64 proposal.
pub memory64: MEMORY64(1 << 14) = false;
/// The WebAssembly extended_const proposal.
pub extended_const: EXTENDED_CONST(1 << 15) = true;
/// The WebAssembly component model proposal.
pub component_model: COMPONENT_MODEL(1 << 16) = true;
/// The WebAssembly typed function references proposal.
pub function_references: FUNCTION_REFERENCES(1 << 17) = true;
/// The WebAssembly memory control proposal.
pub memory_control: MEMORY_CONTROL(1 << 18) = false;
/// The WebAssembly gc proposal.
pub gc: GC(1 << 19) = true;
/// The WebAssembly [custom-page-sizes
pub custom_page_sizes: CUSTOM_PAGE_SIZES(1 << 20) = false;
/// Support for the `value` type in the component model proposal.
pub component_model_values: COMPONENT_MODEL_VALUES(1 << 21) = false;
/// Support for the nested namespaces and projects in component model names.
pub component_model_nested_names: COMPONENT_MODEL_NESTED_NAMES(1 << 22) = false;
/// Support for more than 32 flags per-type in the component model.
pub component_model_more_flags: COMPONENT_MODEL_MORE_FLAGS(1 << 23) = false;
/// Support for multiple return values in a component model function.
pub component_model_multiple_returns: COMPONENT_MODEL_MULTIPLE_RETURNS(1 << 24) = false;
/// The WebAssembly legacy exception handling proposal (phase 1)
///
/// # Note
///
/// Support this feature as long as all leading browsers also support it
pub legacy_exceptions: LEGACY_EXCEPTIONS(1 << 25) = false;
/// Whether or not gc types are enabled.
///
/// This feature does not correspond to any WebAssembly proposal nor
/// concept in the specification itself. This is intended to assist
/// embedders in disabling support for GC types at validation time. For
/// example if an engine wants to support all of WebAssembly except
/// a runtime garbage collector it could disable this feature.
///
/// This features is enabled by default and is used to gate types such
/// as `externref` or `anyref`. Note that the requisite WebAssembly
/// proposal must also be enabled for types like `externref`, meaning
/// that it requires both `REFERENCE_TYPES` and `GC_TYPE` to be enabled.
///
/// Note that the `funcref` and `exnref` types are not gated by this
/// feature. Those are expected to not require a full garbage collector
/// so are not gated by this.
pub gc_types: GC_TYPES(1 << 26) = true;
/// The WebAssembly [stack-switching proposal](https://github.com/WebAssembly/stack-switching).
pub stack_switching: STACK_SWITCHING(1 << 27) = false;
/// The WebAssembly [wide-arithmetic proposal](https://github.com/WebAssembly/wide-arithmetic).
pub wide_arithmetic: WIDE_ARITHMETIC(1 << 28) = false;
}
}
impl WasmFeatures {
/// The feature set associated with the 1.0 version of the
/// WebAssembly specification or the "MVP" feature set.
#[cfg(feature = "features")]
pub const WASM1: WasmFeatures = WasmFeatures::FLOATS.union(WasmFeatures::GC_TYPES);
/// The feature set associated with the 2.0 version of the
/// WebAssembly specification.
#[cfg(feature = "features")]
pub const WASM2: WasmFeatures = WasmFeatures::WASM1
.union(WasmFeatures::BULK_MEMORY)
.union(WasmFeatures::REFERENCE_TYPES)
.union(WasmFeatures::SIGN_EXTENSION)
.union(WasmFeatures::MUTABLE_GLOBAL)
.union(WasmFeatures::SATURATING_FLOAT_TO_INT)
.union(WasmFeatures::MULTI_VALUE)
.union(WasmFeatures::SIMD);
/// The feature set associated with the 3.0 version of the
/// WebAssembly specification.
///
/// Note that as of the time of this writing the 3.0 version of the
/// specification is not yet published. The precise set of features set
/// here may change as that continues to evolve.
#[cfg(feature = "features")]
pub const WASM3: WasmFeatures = WasmFeatures::WASM2
.union(WasmFeatures::GC)
.union(WasmFeatures::TAIL_CALL)
.union(WasmFeatures::EXTENDED_CONST)
.union(WasmFeatures::FUNCTION_REFERENCES)
.union(WasmFeatures::MULTI_MEMORY)
.union(WasmFeatures::RELAXED_SIMD)
.union(WasmFeatures::THREADS)
.union(WasmFeatures::EXCEPTIONS);
}
#[cfg(feature = "features")]
impl From<WasmFeaturesInflated> for WasmFeatures {
#[inline]
fn from(inflated: WasmFeaturesInflated) -> Self {
Self::from_inflated(inflated)
}
}
#[cfg(feature = "features")]
impl From<WasmFeatures> for WasmFeaturesInflated {
#[inline]
fn from(features: WasmFeatures) -> Self {
features.inflate()
}
}