Skip to content

Commit 2fd0d78

Browse files
De-dup filter implementations
1 parent 46a570d commit 2fd0d78

9 files changed

Lines changed: 293 additions & 219 deletions

File tree

crates/c/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use wit_bindgen_core::abi::{
1010
self, AbiVariant, Bindgen, Bitcast, Instruction, LiftLower, WasmSignature, WasmType,
1111
};
1212
use wit_bindgen_core::{
13-
AnonymousTypeGenerator, AsyncFilterSet, Direction, Files, InterfaceGenerator as _, Ns,
14-
WorldGenerator, dealias, uwrite, uwriteln, wit_parser::*,
13+
AnonymousTypeGenerator, AsyncFilterSet, Direction, Files, FilterSet, InterfaceGenerator as _,
14+
Ns, WorldGenerator, dealias, uwrite, uwriteln, wit_parser::*,
1515
};
1616
use wit_component::StringEncoding;
1717

@@ -2077,7 +2077,7 @@ impl InterfaceGenerator<'_> {
20772077
.r#gen
20782078
.opts
20792079
.async_
2080-
.is_async(self.resolve, interface_name, func, true);
2080+
.apply_rules(self.resolve, interface_name, func, true);
20812081
if async_ {
20822082
self.r#gen.needs_async = true;
20832083
}
@@ -2246,7 +2246,7 @@ impl InterfaceGenerator<'_> {
22462246
.r#gen
22472247
.opts
22482248
.async_
2249-
.is_async(self.resolve, interface_name, func, false);
2249+
.apply_rules(self.resolve, interface_name, func, false);
22502250

22512251
let (variant, prefix) = if async_ {
22522252
self.r#gen.needs_async = true;

crates/core/src/async_.rs

Lines changed: 76 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
use anyhow::{Result, bail};
2-
use std::collections::HashSet;
31
use std::fmt;
2+
use std::{collections::HashSet, fmt::Write};
43
use wit_parser::{Function, FunctionKind, Resolve, WorldKey};
54

5+
use crate::filter::{FilterMode, FilterRule, FilterSet, FilterTarget};
6+
67
/// Structure used to parse the command line argument `--async` consistently
78
/// across guest generators.
89
#[cfg_attr(feature = "clap", derive(clap::Parser))]
@@ -33,9 +34,9 @@ pub struct AsyncFilterSet {
3334
arg(
3435
long = "async",
3536
value_parser = parse_async,
36-
value_delimiter =',',
37+
value_delimiter = ',',
3738
value_name = "FILTER",
38-
),
39+
)
3940
)]
4041
#[cfg_attr(feature = "serde", serde(rename = "async"))]
4142
async_: Vec<Async>,
@@ -45,26 +46,35 @@ pub struct AsyncFilterSet {
4546
used_options: HashSet<usize>,
4647
}
4748

48-
#[cfg(feature = "clap")]
49-
fn parse_async(s: &str) -> Result<Async, String> {
50-
Ok(Async::parse(s))
51-
}
49+
impl FilterSet for AsyncFilterSet {
50+
type Mode = bool;
51+
type Filter = AsyncFilter;
5252

53-
impl AsyncFilterSet {
54-
/// Returns a set where all functions should be async or not depending on
55-
/// `async_` provided.
56-
pub fn all(async_: bool) -> AsyncFilterSet {
57-
AsyncFilterSet {
58-
async_: vec![Async {
59-
enabled: async_,
60-
filter: AsyncFilter::All,
61-
}],
53+
fn new(rules: Vec<Async>) -> Self {
54+
Self {
55+
async_: rules,
6256
used_options: HashSet::new(),
6357
}
6458
}
6559

66-
/// Returns whether the `func` provided is to be bound `async` or not.
67-
pub fn is_async(
60+
fn rules(&self) -> &[Async] {
61+
&self.async_
62+
}
63+
fn rules_mut(&mut self) -> &mut Vec<Async> {
64+
&mut self.async_
65+
}
66+
fn used_options(&self) -> &HashSet<usize> {
67+
&self.used_options
68+
}
69+
fn used_options_mut(&mut self) -> &mut HashSet<usize> {
70+
&mut self.used_options
71+
}
72+
73+
fn option_name() -> &'static str {
74+
"async"
75+
}
76+
77+
fn apply_rules(
6878
&mut self,
6979
resolve: &Resolve,
7080
interface: Option<&WorldKey>,
@@ -75,11 +85,12 @@ impl AsyncFilterSet {
7585
Some(key) => format!("{}#{}", resolve.name_world_key(key), func.name),
7686
None => func.name.clone(),
7787
};
88+
7889
for (i, opt) in self.async_.iter().enumerate() {
7990
let name = match &opt.filter {
8091
AsyncFilter::All => {
8192
self.used_options.insert(i);
82-
return opt.enabled;
93+
return opt.mode;
8394
}
8495
AsyncFilter::Function(s) => s,
8596
AsyncFilter::Import(s) => {
@@ -97,95 +108,77 @@ impl AsyncFilterSet {
97108
};
98109
if *name == name_to_test {
99110
self.used_options.insert(i);
100-
return opt.enabled;
111+
return opt.mode;
101112
}
102113
}
103114

104-
match &func.kind {
105-
FunctionKind::Freestanding
106-
| FunctionKind::Method(_)
107-
| FunctionKind::Static(_)
108-
| FunctionKind::Constructor(_) => false,
115+
matches!(
116+
func.kind,
109117
FunctionKind::AsyncFreestanding
110-
| FunctionKind::AsyncMethod(_)
111-
| FunctionKind::AsyncStatic(_) => true,
112-
}
113-
}
114-
115-
/// Intended to be used in the header comment of generated code to help
116-
/// indicate what options were specified.
117-
pub fn debug_opts(&self) -> impl Iterator<Item = String> + '_ {
118-
self.async_.iter().map(|opt| opt.to_string())
118+
| FunctionKind::AsyncMethod(_)
119+
| FunctionKind::AsyncStatic(_)
120+
)
119121
}
122+
}
120123

121-
/// Tests whether all `--async` options were used throughout bindings
122-
/// generation, returning an error if any were unused.
123-
pub fn ensure_all_used(&self) -> Result<()> {
124-
for (i, opt) in self.async_.iter().enumerate() {
125-
if self.used_options.contains(&i) {
126-
continue;
127-
}
128-
if !matches!(opt.filter, AsyncFilter::All) {
129-
bail!("unused async option: {opt}");
130-
}
131-
}
132-
Ok(())
133-
}
124+
#[cfg(feature = "clap")]
125+
fn parse_async(s: &str) -> Result<Async, String> {
126+
Ok(Async::parse(s))
127+
}
134128

135-
/// Returns whether any option explicitly requests that async is enabled.
129+
impl AsyncFilterSet {
136130
pub fn any_enabled(&self) -> bool {
137-
self.async_.iter().any(|o| o.enabled)
131+
self.async_.iter().any(|o| o.mode)
138132
}
133+
}
134+
135+
type Async = FilterRule<bool, AsyncFilter>;
139136

140-
/// Pushes a new option into this set.
141-
pub fn push(&mut self, directive: &str) {
142-
self.async_.push(Async::parse(directive));
137+
impl FilterMode for bool {
138+
fn parse(s: &str) -> (Self, &str) {
139+
match s.strip_prefix('-') {
140+
Some(rest) => (false, rest),
141+
None => (true, s),
142+
}
143+
}
144+
fn fmt_prefix(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145+
if *self {
146+
f.write_char('-')?;
147+
}
148+
Ok(())
143149
}
144150
}
145151

146152
#[derive(Debug, Clone)]
147153
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
148-
struct Async {
149-
enabled: bool,
150-
filter: AsyncFilter,
154+
pub enum AsyncFilter {
155+
All,
156+
Function(String),
157+
Import(String),
158+
Export(String),
151159
}
152160

153-
impl Async {
154-
fn parse(s: &str) -> Async {
155-
let (s, enabled) = match s.strip_prefix('-') {
156-
Some(s) => (s, false),
157-
None => (s, true),
158-
};
159-
let filter = match s {
161+
impl FilterTarget for AsyncFilter {
162+
fn parse(s: &str) -> Self {
163+
match s {
160164
"all" => AsyncFilter::All,
161165
other => match other.strip_prefix("import:") {
162-
Some(s) => AsyncFilter::Import(s.to_string()),
166+
Some(sub) => AsyncFilter::Import(sub.to_string()),
163167
None => match other.strip_prefix("export:") {
164-
Some(s) => AsyncFilter::Export(s.to_string()),
165-
None => AsyncFilter::Function(s.to_string()),
168+
Some(sub) => AsyncFilter::Export(sub.to_string()),
169+
None => AsyncFilter::Function(other.to_string()),
166170
},
167171
},
168-
};
169-
Async { enabled, filter }
172+
}
170173
}
171-
}
172174

173-
impl fmt::Display for Async {
174-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
175-
if !self.enabled {
176-
write!(f, "-")?;
177-
}
178-
self.filter.fmt(f)
175+
fn all() -> AsyncFilter {
176+
AsyncFilter::All
179177
}
180-
}
181178

182-
#[derive(Debug, Clone)]
183-
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
184-
enum AsyncFilter {
185-
All,
186-
Function(String),
187-
Import(String),
188-
Export(String),
179+
fn is_all(&self) -> bool {
180+
matches!(self, AsyncFilter::All)
181+
}
189182
}
190183

191184
impl fmt::Display for AsyncFilter {

0 commit comments

Comments
 (0)