Path: blob/main/crates/wit-bindgen/src/config.rs
3073 views
use crate::{LookupItem, lookup_keys};1use anyhow::Result;2use wit_parser::{Function, FunctionKind, Resolve, WorldKey};34bitflags::bitflags! {5#[derive(Default, Copy, Clone, Debug)]6pub struct FunctionFlags: u8 {7const ASYNC = 1 << 0;8const TRAPPABLE = 1 << 1;9const STORE = 1 << 2;10const TRACING = 1 << 3;11const VERBOSE_TRACING = 1 << 4;12const IGNORE_WIT = 1 << 5;13const EXACT = 1 << 6;14const TASK_EXIT = 1 << 7;15}16}1718#[derive(Default, Debug, Clone)]19pub struct FunctionConfig {20rules: Vec<FunctionRule>,21pub(crate) default: FunctionFlags,22}2324#[derive(Debug, Clone)]25struct FunctionRule {26filter: String,27flags: FunctionFlags,28used: bool,29}3031#[derive(Debug, Clone)]32pub enum FunctionFilter {33Name(String),34Default,35}3637impl FunctionConfig {38/// Creates a blank set of configuration.39pub fn new() -> FunctionConfig {40FunctionConfig::default()41}4243/// Adds a new rule to this configuration.44///45/// Note that the order rules are added is significant as only the first46/// matching rule is used for a function.47pub fn push(&mut self, filter: FunctionFilter, flags: FunctionFlags) {48match filter {49FunctionFilter::Name(filter) => {50self.rules.push(FunctionRule {51filter,52flags,53used: false,54});55}56FunctionFilter::Default => {57self.default = flags;58}59}60}6162/// Returns the set of configuration flags associated with `func`.63///64/// The `name` provided should include the full name of the function65/// including its interface. The `kind` is the classification of the66/// function in WIT which affects the default set of flags.67pub(crate) fn flags(68&mut self,69resolve: &Resolve,70ns: Option<&WorldKey>,71func: &Function,72) -> FunctionFlags {73let mut wit_flags = FunctionFlags::empty();7475// If the kind is async, then set the async/store flags as that's a76// concurrent function which requires access to both.77match &func.kind {78FunctionKind::Freestanding79| FunctionKind::Method(_)80| FunctionKind::Static(_)81| FunctionKind::Constructor(_) => {}8283FunctionKind::AsyncFreestanding84| FunctionKind::AsyncMethod(_)85| FunctionKind::AsyncStatic(_) => {86wit_flags |= FunctionFlags::ASYNC | FunctionFlags::STORE;87}88}8990let mut ret = FunctionFlags::empty();91self.add_function_flags(resolve, ns, &func.name, &mut ret);92if !ret.contains(FunctionFlags::IGNORE_WIT) {93ret |= wit_flags;94}95ret96}9798pub(crate) fn resource_drop_flags(99&mut self,100resolve: &Resolve,101ns: Option<&WorldKey>,102resource_name: &str,103) -> FunctionFlags {104let mut ret = FunctionFlags::empty();105self.add_function_flags(resolve, ns, &format!("[drop]{resource_name}"), &mut ret);106ret107}108109fn add_function_flags(110&mut self,111resolve: &Resolve,112key: Option<&WorldKey>,113name: &str,114base: &mut FunctionFlags,115) {116let mut apply_rules = |name: &str, is_exact: bool| {117for rule in self.rules.iter_mut() {118if name != rule.filter {119continue;120}121if !is_exact && rule.flags.contains(FunctionFlags::EXACT) {122continue;123}124rule.used = true;125*base |= rule.flags;126127// only the first rule is used.128return true;129}130131false132};133match key {134Some(key) => {135for (lookup, projection) in lookup_keys(resolve, key, LookupItem::Name(name)) {136if apply_rules(&lookup, projection.is_empty()) {137return;138}139}140}141None => {142if apply_rules(name, true) {143return;144}145}146}147148*base |= self.default;149}150151pub(crate) fn assert_all_rules_used(&self, kind: &str) -> Result<()> {152let mut unused = Vec::new();153for rule in self.rules.iter().filter(|r| !r.used) {154unused.push(format!("{:?}: {:?}", rule.filter, rule.flags));155}156157if unused.is_empty() {158return Ok(());159}160161anyhow::bail!("unused `{kind}` rules found: {unused:?}");162}163}164165166