* implement wasmtime::component::flags! per #4308 This is the last macro needed to complete #4308. It supports generating a Rust type that represents a `flags` component type, analogous to how the [bitflags crate](https://crates.io/crates/bitflags) operates. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * wrap `format_flags` output in parens This ensures we generate non-empty output even when no flags are set. Empty output for a `Debug` implementation would be confusing. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * unconditionally derive `Lift` and `Lower` in wasmtime::component::flags! Per feedback on #4414, we now derive impls for those traits unconditionally, which simplifies the syntax of the macro. Also, I happened to notice an alignment bug in `LowerExpander::expand_variant`, so I fixed that and cleaned up some related code. Finally, I used @jameysharp's trick to calculate bit masks without looping. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * fix shift overflow regression in previous commit Jamey pointed out my mistake: I didn't consider the case when the flag count was evenly divisible by the representation size. This fixes the problem and adds test cases to cover it. Signed-off-by: Joel Dice <joel.dice@fermyon.com>
This commit is contained in:
@@ -5,6 +5,7 @@ use crate::store::StoreOpaque;
|
||||
use crate::{AsContext, AsContextMut, StoreContext, StoreContextMut, ValRaw};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::marker;
|
||||
use std::mem::{self, MaybeUninit};
|
||||
use std::str;
|
||||
@@ -1581,6 +1582,55 @@ pub fn typecheck_union(
|
||||
}
|
||||
}
|
||||
|
||||
/// Verify that the given wasm type is a flags type with the expected flags in the right order and with the right
|
||||
/// names.
|
||||
pub fn typecheck_flags(
|
||||
ty: &InterfaceType,
|
||||
types: &ComponentTypes,
|
||||
expected: &[&str],
|
||||
) -> Result<()> {
|
||||
match ty {
|
||||
InterfaceType::Flags(index) => {
|
||||
let names = &types[*index].names;
|
||||
|
||||
if names.len() != expected.len() {
|
||||
bail!(
|
||||
"expected flags type with {} names, found {} names",
|
||||
expected.len(),
|
||||
names.len()
|
||||
);
|
||||
}
|
||||
|
||||
for (name, expected) in names.iter().zip(expected) {
|
||||
if name != expected {
|
||||
bail!("expected flag named {}, found {}", expected, name);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
other => bail!("expected `flags` found `{}`", desc(other)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Format the specified bitflags using the specified names for debugging
|
||||
pub fn format_flags(bits: &[u32], names: &[&str], f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str("(")?;
|
||||
let mut wrote = false;
|
||||
for (index, name) in names.iter().enumerate() {
|
||||
if ((bits[index / 32] >> (index % 32)) & 1) != 0 {
|
||||
if wrote {
|
||||
f.write_str("|")?;
|
||||
} else {
|
||||
wrote = true;
|
||||
}
|
||||
|
||||
f.write_str(name)?;
|
||||
}
|
||||
}
|
||||
f.write_str(")")
|
||||
}
|
||||
|
||||
unsafe impl<T> ComponentType for Option<T>
|
||||
where
|
||||
T: ComponentType,
|
||||
|
||||
@@ -16,7 +16,7 @@ pub use self::func::{
|
||||
};
|
||||
pub use self::instance::{ExportInstance, Exports, Instance, InstancePre};
|
||||
pub use self::linker::{Linker, LinkerInstance};
|
||||
pub use wasmtime_component_macro::{ComponentType, Lift, Lower};
|
||||
pub use wasmtime_component_macro::{flags, ComponentType, Lift, Lower};
|
||||
|
||||
// These items are expected to be used by an eventual
|
||||
// `#[derive(ComponentType)]`, they are not part of Wasmtime's API stability
|
||||
@@ -24,8 +24,8 @@ pub use wasmtime_component_macro::{ComponentType, Lift, Lower};
|
||||
#[doc(hidden)]
|
||||
pub mod __internal {
|
||||
pub use super::func::{
|
||||
align_to, next_field, typecheck_enum, typecheck_record, typecheck_union, typecheck_variant,
|
||||
MaybeUninitExt, Memory, MemoryMut, Options,
|
||||
align_to, format_flags, next_field, typecheck_enum, typecheck_flags, typecheck_record,
|
||||
typecheck_union, typecheck_variant, MaybeUninitExt, Memory, MemoryMut, Options,
|
||||
};
|
||||
pub use crate::map_maybe_uninit;
|
||||
pub use crate::store::StoreOpaque;
|
||||
|
||||
Reference in New Issue
Block a user