wasmtime_internal_wit_bindgen/
config.rs1use crate::{LookupItem, lookup_keys};
2use anyhow::Result;
3use wit_parser::{Function, FunctionKind, Resolve, WorldKey};
4
5bitflags::bitflags! {
6 #[derive(Default, Copy, Clone, Debug)]
7 pub struct FunctionFlags: u8 {
8 const ASYNC = 1 << 0;
9 const TRAPPABLE = 1 << 1;
10 const STORE = 1 << 2;
11 const TRACING = 1 << 3;
12 const VERBOSE_TRACING = 1 << 4;
13 const IGNORE_WIT = 1 << 5;
14 const EXACT = 1 << 6;
15 }
16}
17
18#[derive(Default, Debug, Clone)]
19pub struct FunctionConfig {
20 rules: Vec<FunctionRule>,
21 default: FunctionFlags,
22}
23
24#[derive(Debug, Clone)]
25struct FunctionRule {
26 filter: String,
27 flags: FunctionFlags,
28 used: bool,
29}
30
31#[derive(Debug, Clone)]
32pub enum FunctionFilter {
33 Name(String),
34 Default,
35}
36
37impl FunctionConfig {
38 pub fn new() -> FunctionConfig {
40 FunctionConfig::default()
41 }
42
43 pub fn push(&mut self, filter: FunctionFilter, flags: FunctionFlags) {
48 match filter {
49 FunctionFilter::Name(filter) => {
50 self.rules.push(FunctionRule {
51 filter,
52 flags,
53 used: false,
54 });
55 }
56 FunctionFilter::Default => {
57 self.default = flags;
58 }
59 }
60 }
61
62 pub(crate) fn flags(
68 &mut self,
69 resolve: &Resolve,
70 ns: Option<&WorldKey>,
71 func: &Function,
72 ) -> FunctionFlags {
73 let mut wit_flags = FunctionFlags::empty();
74
75 match &func.kind {
78 FunctionKind::Freestanding
79 | FunctionKind::Method(_)
80 | FunctionKind::Static(_)
81 | FunctionKind::Constructor(_) => {}
82
83 FunctionKind::AsyncFreestanding
84 | FunctionKind::AsyncMethod(_)
85 | FunctionKind::AsyncStatic(_) => {
86 wit_flags |= FunctionFlags::ASYNC | FunctionFlags::STORE;
87 }
88 }
89
90 let mut ret = FunctionFlags::empty();
91 self.add_function_flags(resolve, ns, &func.name, &mut ret);
92 if !ret.contains(FunctionFlags::IGNORE_WIT) {
93 ret |= wit_flags;
94 }
95 ret
96 }
97
98 pub(crate) fn resource_drop_flags(
99 &mut self,
100 resolve: &Resolve,
101 ns: Option<&WorldKey>,
102 resource_name: &str,
103 ) -> FunctionFlags {
104 let mut ret = FunctionFlags::empty();
105 self.add_function_flags(resolve, ns, &format!("[drop]{resource_name}"), &mut ret);
106 ret
107 }
108
109 fn add_function_flags(
110 &mut self,
111 resolve: &Resolve,
112 key: Option<&WorldKey>,
113 name: &str,
114 base: &mut FunctionFlags,
115 ) {
116 let mut apply_rules = |name: &str, is_exact: bool| {
117 for rule in self.rules.iter_mut() {
118 if name != rule.filter {
119 continue;
120 }
121 if !is_exact && rule.flags.contains(FunctionFlags::EXACT) {
122 continue;
123 }
124 rule.used = true;
125 *base |= rule.flags;
126
127 return true;
129 }
130
131 false
132 };
133 match key {
134 Some(key) => {
135 for (lookup, projection) in lookup_keys(resolve, key, LookupItem::Name(name)) {
136 if apply_rules(&lookup, projection.is_empty()) {
137 return;
138 }
139 }
140 }
141 None => {
142 if apply_rules(name, true) {
143 return;
144 }
145 }
146 }
147
148 *base |= self.default;
149 }
150
151 pub(crate) fn assert_all_rules_used(&self, kind: &str) -> Result<()> {
152 let mut unused = Vec::new();
153 for rule in self.rules.iter().filter(|r| !r.used) {
154 unused.push(format!("{:?}: {:?}", rule.filter, rule.flags));
155 }
156
157 if unused.is_empty() {
158 return Ok(());
159 }
160
161 anyhow::bail!("unused `{kind}` rules found: {unused:?}");
162 }
163}