Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/wast/src/component.rs
1691 views
1
use crate::core;
2
use anyhow::{Context, Result, bail};
3
use json_from_wast::{ComponentConst, FloatConst};
4
use std::collections::BTreeSet;
5
use std::fmt::Debug;
6
7
pub use wasmtime::component::*;
8
9
pub fn val(v: &ComponentConst<'_>) -> Result<Val> {
10
Ok(match v {
11
ComponentConst::Bool(b) => Val::Bool(*b),
12
ComponentConst::U8(b) => Val::U8(b.0),
13
ComponentConst::S8(b) => Val::S8(b.0),
14
ComponentConst::U16(b) => Val::U16(b.0),
15
ComponentConst::S16(b) => Val::S16(b.0),
16
ComponentConst::U32(b) => Val::U32(b.0),
17
ComponentConst::S32(b) => Val::S32(b.0),
18
ComponentConst::U64(b) => Val::U64(b.0),
19
ComponentConst::S64(b) => Val::S64(b.0),
20
ComponentConst::F32(b) => Val::Float32(f32::from_bits(b.0)),
21
ComponentConst::F64(b) => Val::Float64(f64::from_bits(b.0)),
22
ComponentConst::Char(b) => Val::Char(*b),
23
ComponentConst::String(s) => Val::String(s.to_string()),
24
ComponentConst::List(vals) => {
25
let vals = vals.iter().map(|v| val(v)).collect::<Result<Vec<_>>>()?;
26
Val::List(vals)
27
}
28
ComponentConst::Record(vals) => {
29
let mut fields = Vec::new();
30
for (name, v) in vals {
31
fields.push((name.to_string(), val(v)?));
32
}
33
Val::Record(fields)
34
}
35
ComponentConst::Tuple(vals) => {
36
Val::Tuple(vals.iter().map(|v| val(v)).collect::<Result<Vec<_>>>()?)
37
}
38
ComponentConst::Enum(name) => Val::Enum(name.to_string()),
39
ComponentConst::Variant { case, payload } => {
40
let payload = payload_val(payload.as_deref())?;
41
Val::Variant(case.to_string(), payload)
42
}
43
ComponentConst::Option(v) => Val::Option(match v {
44
Some(v) => Some(Box::new(val(v)?)),
45
None => None,
46
}),
47
ComponentConst::Result(v) => Val::Result(match v {
48
Ok(v) => Ok(payload_val(v.as_deref())?),
49
Err(v) => Err(payload_val(v.as_deref())?),
50
}),
51
ComponentConst::Flags(v) => Val::Flags(v.iter().map(|s| s.to_string()).collect()),
52
})
53
}
54
55
fn payload_val(v: Option<&ComponentConst<'_>>) -> Result<Option<Box<Val>>> {
56
match v {
57
Some(v) => Ok(Some(Box::new(val(v)?))),
58
None => Ok(None),
59
}
60
}
61
62
pub fn match_val(expected: &ComponentConst<'_>, actual: &Val) -> Result<()> {
63
match expected {
64
ComponentConst::Bool(e) => match actual {
65
Val::Bool(a) => match_debug(a, e),
66
_ => mismatch(expected, actual),
67
},
68
ComponentConst::U8(e) => match actual {
69
Val::U8(a) => core::match_int(a, &e.0),
70
_ => mismatch(expected, actual),
71
},
72
ComponentConst::S8(e) => match actual {
73
Val::S8(a) => core::match_int(a, &e.0),
74
_ => mismatch(expected, actual),
75
},
76
ComponentConst::U16(e) => match actual {
77
Val::U16(a) => core::match_int(a, &e.0),
78
_ => mismatch(expected, actual),
79
},
80
ComponentConst::S16(e) => match actual {
81
Val::S16(a) => core::match_int(a, &e.0),
82
_ => mismatch(expected, actual),
83
},
84
ComponentConst::U32(e) => match actual {
85
Val::U32(a) => core::match_int(a, &e.0),
86
_ => mismatch(expected, actual),
87
},
88
ComponentConst::S32(e) => match actual {
89
Val::S32(a) => core::match_int(a, &e.0),
90
_ => mismatch(expected, actual),
91
},
92
ComponentConst::U64(e) => match actual {
93
Val::U64(a) => core::match_int(a, &e.0),
94
_ => mismatch(expected, actual),
95
},
96
ComponentConst::S64(e) => match actual {
97
Val::S64(a) => core::match_int(a, &e.0),
98
_ => mismatch(expected, actual),
99
},
100
ComponentConst::F32(e) => match actual {
101
Val::Float32(a) => {
102
core::match_f32(a.to_bits(), &FloatConst::Value(f32::from_bits(e.0)))
103
}
104
_ => mismatch(expected, actual),
105
},
106
ComponentConst::F64(e) => match actual {
107
Val::Float64(a) => {
108
core::match_f64(a.to_bits(), &FloatConst::Value(f64::from_bits(e.0)))
109
}
110
_ => mismatch(expected, actual),
111
},
112
ComponentConst::Char(e) => match actual {
113
Val::Char(a) => match_debug(a, e),
114
_ => mismatch(expected, actual),
115
},
116
ComponentConst::String(e) => match actual {
117
Val::String(a) => match_debug(&a[..], e),
118
_ => mismatch(expected, actual),
119
},
120
ComponentConst::List(e) => match actual {
121
Val::List(a) => {
122
if e.len() != a.len() {
123
bail!("expected {} values got {}", e.len(), a.len());
124
}
125
for (i, (expected, actual)) in e.iter().zip(a.iter()).enumerate() {
126
match_val(expected, actual)
127
.with_context(|| format!("failed to match list element {i}"))?;
128
}
129
Ok(())
130
}
131
_ => mismatch(expected, actual),
132
},
133
ComponentConst::Record(e) => match actual {
134
Val::Record(a) => {
135
if e.len() != e.len() {
136
bail!("mismatched number of record fields");
137
}
138
for ((e_name, e_val), (a_name, a_val)) in e.iter().zip(a.iter()) {
139
if e_name != a_name {
140
bail!("expected field `{e_name}` got `{a_name}`");
141
}
142
match_val(e_val, a_val)
143
.with_context(|| format!("failed to match field `{e_name}`"))?;
144
}
145
Ok(())
146
}
147
_ => mismatch(expected, actual),
148
},
149
ComponentConst::Tuple(e) => match actual {
150
Val::Tuple(a) => {
151
if e.len() != a.len() {
152
bail!("expected {}-tuple, found {}-tuple", e.len(), a.len());
153
}
154
for (i, (expected, actual)) in e.iter().zip(a.iter()).enumerate() {
155
match_val(expected, actual)
156
.with_context(|| format!("failed to match tuple element {i}"))?;
157
}
158
Ok(())
159
}
160
_ => mismatch(expected, actual),
161
},
162
ComponentConst::Variant {
163
case: name,
164
payload: e,
165
} => match actual {
166
Val::Variant(discr, payload) => {
167
if *discr != *name {
168
bail!("expected discriminant `{name}` got `{discr}`");
169
}
170
match_payload_val(name, e.as_deref(), payload.as_deref())
171
}
172
_ => mismatch(expected, actual),
173
},
174
ComponentConst::Enum(name) => match actual {
175
Val::Enum(a) => {
176
if *a != *name {
177
bail!("expected discriminant `{name}` got `{a}`");
178
} else {
179
Ok(())
180
}
181
}
182
_ => mismatch(expected, actual),
183
},
184
ComponentConst::Option(e) => match actual {
185
Val::Option(a) => match (e, a) {
186
(None, None) => Ok(()),
187
(Some(expected), Some(actual)) => match_val(expected, actual),
188
(None, Some(_)) => bail!("expected `none`, found `some`"),
189
(Some(_), None) => bail!("expected `some`, found `none`"),
190
},
191
_ => mismatch(expected, actual),
192
},
193
ComponentConst::Result(e) => match actual {
194
Val::Result(a) => match (e, a) {
195
(Ok(_), Err(_)) => bail!("expected `ok`, found `err`"),
196
(Err(_), Ok(_)) => bail!("expected `err`, found `ok`"),
197
(Err(e), Err(a)) => match_payload_val("err", e.as_deref(), a.as_deref()),
198
(Ok(e), Ok(a)) => match_payload_val("ok", e.as_deref(), a.as_deref()),
199
},
200
_ => mismatch(expected, actual),
201
},
202
ComponentConst::Flags(e) => match actual {
203
Val::Flags(a) => {
204
let expected = e.iter().map(|s| &s[..]).collect::<BTreeSet<_>>();
205
let actual = a.iter().map(|s| s.as_str()).collect::<BTreeSet<_>>();
206
match_debug(&actual, &expected)
207
}
208
_ => mismatch(expected, actual),
209
},
210
}
211
}
212
213
fn match_payload_val(
214
name: &str,
215
expected: Option<&ComponentConst<'_>>,
216
actual: Option<&Val>,
217
) -> Result<()> {
218
match (expected, actual) {
219
(Some(e), Some(a)) => {
220
match_val(e, a).with_context(|| format!("failed to match case `{name}`"))
221
}
222
(None, None) => Ok(()),
223
(Some(_), None) => bail!("expected payload for case `{name}`"),
224
(None, Some(_)) => bail!("unexpected payload for case `{name}`"),
225
}
226
}
227
228
fn match_debug<T>(actual: &T, expected: &T) -> Result<()>
229
where
230
T: Eq + Debug + ?Sized,
231
{
232
if actual == expected {
233
Ok(())
234
} else {
235
bail!(
236
"
237
expected {expected:?}
238
actual {actual:?}"
239
)
240
}
241
}
242
243
fn mismatch(expected: &ComponentConst<'_>, actual: &Val) -> Result<()> {
244
let expected = match expected {
245
ComponentConst::Bool(..) => "bool",
246
ComponentConst::U8(..) => "u8",
247
ComponentConst::S8(..) => "s8",
248
ComponentConst::U16(..) => "u16",
249
ComponentConst::S16(..) => "s16",
250
ComponentConst::U32(..) => "u32",
251
ComponentConst::S32(..) => "s32",
252
ComponentConst::U64(..) => "u64",
253
ComponentConst::S64(..) => "s64",
254
ComponentConst::F32(..) => "f32",
255
ComponentConst::F64(..) => "f64",
256
ComponentConst::Char(..) => "char",
257
ComponentConst::String(..) => "string",
258
ComponentConst::List(..) => "list",
259
ComponentConst::Record(..) => "record",
260
ComponentConst::Tuple(..) => "tuple",
261
ComponentConst::Enum(..) => "enum",
262
ComponentConst::Variant { .. } => "variant",
263
ComponentConst::Option(..) => "option",
264
ComponentConst::Result(..) => "result",
265
ComponentConst::Flags(..) => "flags",
266
};
267
let actual = match actual {
268
Val::Bool(..) => "bool",
269
Val::U8(..) => "u8",
270
Val::S8(..) => "s8",
271
Val::U16(..) => "u16",
272
Val::S16(..) => "s16",
273
Val::U32(..) => "u32",
274
Val::S32(..) => "s32",
275
Val::U64(..) => "u64",
276
Val::S64(..) => "s64",
277
Val::Float32(..) => "f32",
278
Val::Float64(..) => "f64",
279
Val::Char(..) => "char",
280
Val::String(..) => "string",
281
Val::List(..) => "list",
282
Val::Record(..) => "record",
283
Val::Tuple(..) => "tuple",
284
Val::Enum(..) => "enum",
285
Val::Variant(..) => "variant",
286
Val::Option(..) => "option",
287
Val::Result(..) => "result",
288
Val::Flags(..) => "flags",
289
Val::Resource(..) => "resource",
290
Val::Future(..) => "future",
291
Val::Stream(..) => "stream",
292
Val::ErrorContext(..) => "error-context",
293
};
294
bail!("expected `{expected}` got `{actual}`")
295
}
296
297