Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/wit-bindgen/src/config.rs
3073 views
1
use crate::{LookupItem, lookup_keys};
2
use anyhow::Result;
3
use wit_parser::{Function, FunctionKind, Resolve, WorldKey};
4
5
bitflags::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)]
20
pub struct FunctionConfig {
21
rules: Vec<FunctionRule>,
22
pub(crate) default: FunctionFlags,
23
}
24
25
#[derive(Debug, Clone)]
26
struct FunctionRule {
27
filter: String,
28
flags: FunctionFlags,
29
used: bool,
30
}
31
32
#[derive(Debug, Clone)]
33
pub enum FunctionFilter {
34
Name(String),
35
Default,
36
}
37
38
impl FunctionConfig {
39
/// Creates a blank set of configuration.
40
pub fn new() -> FunctionConfig {
41
FunctionConfig::default()
42
}
43
44
/// Adds a new rule to this configuration.
45
///
46
/// Note that the order rules are added is significant as only the first
47
/// matching rule is used for a function.
48
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
/// Returns the set of configuration flags associated with `func`.
64
///
65
/// The `name` provided should include the full name of the function
66
/// including its interface. The `kind` is the classification of the
67
/// function in WIT which affects the default set of flags.
68
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
// If the kind is async, then set the async/store flags as that's a
77
// concurrent function which requires access to both.
78
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
// only the first rule is used.
129
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
}
165
166