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