Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/tests/all/component_model/resources.rs
1692 views
1
#![cfg(not(miri))]
2
3
use anyhow::Result;
4
use wasmtime::component::*;
5
use wasmtime::{Store, Trap};
6
7
#[test]
8
fn host_resource_types() -> Result<()> {
9
let engine = super::engine();
10
let c = Component::new(
11
&engine,
12
r#"
13
(component
14
(import "t" (type $t (sub resource)))
15
(import "u" (type $u (sub resource)))
16
17
(export "t1" (type $t))
18
(export "t2" (type $t))
19
(export "u1" (type $u))
20
(export "u2" (type $u))
21
22
(component $c
23
(import "r" (type $r (sub resource)))
24
(export "r1" (type $r))
25
)
26
(instance $i1 (instantiate $c (with "r" (type $t))))
27
(instance $i2 (instantiate $c (with "r" (type $t))))
28
(export "t3" (type $i1 "r1"))
29
(export "t4" (type $i2 "r1"))
30
)
31
"#,
32
)?;
33
34
struct T;
35
struct U;
36
assert!(ResourceType::host::<T>() != ResourceType::host::<U>());
37
38
let mut store = Store::new(&engine, ());
39
let mut linker = Linker::new(&engine);
40
linker
41
.root()
42
.resource("t", ResourceType::host::<T>(), |_, _| Ok(()))?;
43
linker
44
.root()
45
.resource("u", ResourceType::host::<U>(), |_, _| Ok(()))?;
46
let i = linker.instantiate(&mut store, &c)?;
47
let t1 = i.get_resource(&mut store, "t1").unwrap();
48
let t2 = i.get_resource(&mut store, "t2").unwrap();
49
let t3 = i.get_resource(&mut store, "t3").unwrap();
50
let t4 = i.get_resource(&mut store, "t4").unwrap();
51
let u1 = i.get_resource(&mut store, "u1").unwrap();
52
let u2 = i.get_resource(&mut store, "u2").unwrap();
53
54
assert_eq!(t1, ResourceType::host::<T>());
55
assert_eq!(t2, ResourceType::host::<T>());
56
assert_eq!(t3, ResourceType::host::<T>());
57
assert_eq!(t4, ResourceType::host::<T>());
58
assert_eq!(u1, ResourceType::host::<U>());
59
assert_eq!(u2, ResourceType::host::<U>());
60
Ok(())
61
}
62
63
#[test]
64
fn guest_resource_types() -> Result<()> {
65
let engine = super::engine();
66
let c = Component::new(
67
&engine,
68
r#"
69
(component
70
(type $t (resource (rep i32)))
71
(type $u (resource (rep i32)))
72
73
(export "t1" (type $t))
74
(export "t2" (type $t))
75
(export "u1" (type $u))
76
(export "u2" (type $u))
77
78
(component $c
79
(import "r" (type $r (sub resource)))
80
(export "r1" (type $r))
81
)
82
(instance $i1 (instantiate $c (with "r" (type $t))))
83
(instance $i2 (instantiate $c (with "r" (type $t))))
84
(export "t3" (type $i1 "r1"))
85
(export "t4" (type $i2 "r1"))
86
)
87
"#,
88
)?;
89
90
let mut store = Store::new(&engine, ());
91
let linker = Linker::new(&engine);
92
let i = linker.instantiate(&mut store, &c)?;
93
let t1 = i.get_resource(&mut store, "t1").unwrap();
94
let t2 = i.get_resource(&mut store, "t2").unwrap();
95
let t3 = i.get_resource(&mut store, "t3").unwrap();
96
let t4 = i.get_resource(&mut store, "t4").unwrap();
97
let u1 = i.get_resource(&mut store, "u1").unwrap();
98
let u2 = i.get_resource(&mut store, "u2").unwrap();
99
100
assert_ne!(t1, u1);
101
assert_eq!(t1, t2);
102
assert_eq!(t1, t3);
103
assert_eq!(t1, t4);
104
assert_eq!(u1, u2);
105
Ok(())
106
}
107
108
#[test]
109
fn resource_any() -> Result<()> {
110
let engine = super::engine();
111
let c = Component::new(
112
&engine,
113
r#"
114
(component
115
(type $t' (resource (rep i32)))
116
(type $u' (resource (rep i32)))
117
118
(export $t "t" (type $t'))
119
(export $u "u" (type $u'))
120
121
(core func $t_ctor (canon resource.new $t))
122
(core func $u_ctor (canon resource.new $u))
123
124
(func (export "[constructor]t") (param "x" u32) (result (own $t))
125
(canon lift (core func $t_ctor)))
126
(func (export "[constructor]u") (param "x" u32) (result (own $u))
127
(canon lift (core func $u_ctor)))
128
129
(core func $t_drop (canon resource.drop $t))
130
(core func $u_drop (canon resource.drop $u))
131
132
(func (export "drop-t") (param "x" (own $t))
133
(canon lift (core func $t_drop)))
134
(func (export "drop-u") (param "x" (own $u))
135
(canon lift (core func $u_drop)))
136
)
137
"#,
138
)?;
139
140
let linker = Linker::new(&engine);
141
{
142
let mut store = Store::new(&engine, ());
143
let i = linker.instantiate(&mut store, &c)?;
144
let t = i.get_resource(&mut store, "t").unwrap();
145
let u = i.get_resource(&mut store, "u").unwrap();
146
147
assert_ne!(t, u);
148
149
let t_ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "[constructor]t")?;
150
let u_ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "[constructor]u")?;
151
let t_dtor = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "drop-t")?;
152
let u_dtor = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "drop-u")?;
153
154
let (t1,) = t_ctor.call(&mut store, (100,))?;
155
t_ctor.post_return(&mut store)?;
156
let (t2,) = t_ctor.call(&mut store, (200,))?;
157
t_ctor.post_return(&mut store)?;
158
let (u1,) = u_ctor.call(&mut store, (300,))?;
159
u_ctor.post_return(&mut store)?;
160
let (u2,) = u_ctor.call(&mut store, (400,))?;
161
u_ctor.post_return(&mut store)?;
162
163
assert_eq!(t1.ty(), t);
164
assert_eq!(t2.ty(), t);
165
assert_eq!(u1.ty(), u);
166
assert_eq!(u2.ty(), u);
167
168
u_dtor.call(&mut store, (u2,))?;
169
u_dtor.post_return(&mut store)?;
170
171
u_dtor.call(&mut store, (u1,))?;
172
u_dtor.post_return(&mut store)?;
173
174
t_dtor.call(&mut store, (t1,))?;
175
t_dtor.post_return(&mut store)?;
176
177
t_dtor.call(&mut store, (t2,))?;
178
t_dtor.post_return(&mut store)?;
179
}
180
181
{
182
let mut store = Store::new(&engine, ());
183
let i = linker.instantiate(&mut store, &c)?;
184
let t_ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "[constructor]t")?;
185
let u_ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "[constructor]u")?;
186
let t_dtor = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "drop-t")?;
187
188
// `t` is placed at host index 0
189
let (t,) = t_ctor.call(&mut store, (100,))?;
190
t_ctor.post_return(&mut store)?;
191
t_dtor.call(&mut store, (t,))?;
192
t_dtor.post_return(&mut store)?;
193
194
// `u` is also placed at host index 0 since `t` was deallocated
195
let (_u,) = u_ctor.call(&mut store, (100,))?;
196
u_ctor.post_return(&mut store)?;
197
198
// reuse of `t` should fail, despite it pointing to a valid resource
199
assert_eq!(
200
t_dtor.call(&mut store, (t,)).unwrap_err().to_string(),
201
"host-owned resource is being used with the wrong type"
202
);
203
}
204
205
Ok(())
206
}
207
208
#[test]
209
fn mismatch_intrinsics() -> Result<()> {
210
let engine = super::engine();
211
let c = Component::new(
212
&engine,
213
r#"
214
(component
215
(type $t' (resource (rep i32)))
216
(type $u' (resource (rep i32)))
217
218
(export $t "t" (type $t'))
219
(export $u "u" (type $u'))
220
221
;; note the mismatch where this is an intrinsic for `u` but
222
;; we're typing it as `t`
223
(core func $t_ctor (canon resource.new $u))
224
225
(func (export "ctor") (param "x" u32) (result (own $t))
226
(canon lift (core func $t_ctor)))
227
)
228
"#,
229
)?;
230
231
let mut store = Store::new(&engine, ());
232
let i = Linker::new(&engine).instantiate(&mut store, &c)?;
233
let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?;
234
assert_eq!(
235
ctor.call(&mut store, (100,)).unwrap_err().to_string(),
236
"handle index 1 used with the wrong type, expected guest-defined \
237
resource but found a different guest-defined resource",
238
);
239
240
Ok(())
241
}
242
243
#[test]
244
fn mismatch_resource_types() -> Result<()> {
245
let engine = super::engine();
246
let c = Component::new(
247
&engine,
248
r#"
249
(component
250
(type $t' (resource (rep i32)))
251
(type $u' (resource (rep i32)))
252
253
(export $t "t" (type $t'))
254
(export $u "u" (type $u'))
255
256
(core func $t_ctor (canon resource.new $t))
257
(func (export "ctor") (param "x" u32) (result (own $t))
258
(canon lift (core func $t_ctor)))
259
260
(core func $u_dtor (canon resource.drop $u))
261
(func (export "dtor") (param "x" (own $u))
262
(canon lift (core func $u_dtor)))
263
)
264
"#,
265
)?;
266
267
let mut store = Store::new(&engine, ());
268
let i = Linker::new(&engine).instantiate(&mut store, &c)?;
269
let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?;
270
let dtor = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "dtor")?;
271
272
let (t,) = ctor.call(&mut store, (100,))?;
273
ctor.post_return(&mut store)?;
274
assert_eq!(
275
dtor.call(&mut store, (t,)).unwrap_err().to_string(),
276
"mismatched resource types"
277
);
278
279
Ok(())
280
}
281
282
#[test]
283
fn drop_in_different_places() -> Result<()> {
284
let engine = super::engine();
285
let c = Component::new(
286
&engine,
287
r#"
288
(component
289
(type $t' (resource (rep i32)))
290
291
(export $t "t" (type $t'))
292
293
(core func $ctor (canon resource.new $t))
294
(func (export "ctor") (param "x" u32) (result (own $t))
295
(canon lift (core func $ctor)))
296
297
(core func $dtor (canon resource.drop $t))
298
(func (export "dtor1") (param "x" (own $t))
299
(canon lift (core func $dtor)))
300
301
(component $c
302
(import "t" (type $t (sub resource)))
303
(core func $dtor (canon resource.drop $t))
304
(func (export "dtor") (param "x" (own $t))
305
(canon lift (core func $dtor)))
306
)
307
(instance $i1 (instantiate $c (with "t" (type $t))))
308
(instance $i2 (instantiate $c (with "t" (type $t))))
309
310
(export "dtor2" (func $i1 "dtor"))
311
(export "dtor3" (func $i2 "dtor"))
312
)
313
"#,
314
)?;
315
316
let mut store = Store::new(&engine, ());
317
let i = Linker::new(&engine).instantiate(&mut store, &c)?;
318
let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?;
319
let dtor1 = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "dtor1")?;
320
let dtor2 = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "dtor2")?;
321
let dtor3 = i.get_typed_func::<(ResourceAny,), ()>(&mut store, "dtor3")?;
322
323
let (t,) = ctor.call(&mut store, (100,))?;
324
ctor.post_return(&mut store)?;
325
dtor1.call(&mut store, (t,))?;
326
dtor1.post_return(&mut store)?;
327
328
let (t,) = ctor.call(&mut store, (200,))?;
329
ctor.post_return(&mut store)?;
330
dtor2.call(&mut store, (t,))?;
331
dtor2.post_return(&mut store)?;
332
333
let (t,) = ctor.call(&mut store, (300,))?;
334
ctor.post_return(&mut store)?;
335
dtor3.call(&mut store, (t,))?;
336
dtor3.post_return(&mut store)?;
337
338
Ok(())
339
}
340
341
#[test]
342
fn drop_guest_twice() -> Result<()> {
343
let engine = super::engine();
344
let c = Component::new(
345
&engine,
346
r#"
347
(component
348
(type $t' (resource (rep i32)))
349
350
(export $t "t" (type $t'))
351
352
(core func $ctor (canon resource.new $t))
353
(func (export "ctor") (param "x" u32) (result (own $t))
354
(canon lift (core func $ctor)))
355
356
(core func $dtor (canon resource.drop $t))
357
(func (export "dtor") (param "x" (own $t))
358
(canon lift (core func $dtor)))
359
)
360
"#,
361
)?;
362
363
let mut store = Store::new(&engine, ());
364
let i = Linker::new(&engine).instantiate(&mut store, &c)?;
365
let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?;
366
let dtor = i.get_typed_func::<(&ResourceAny,), ()>(&mut store, "dtor")?;
367
368
let (t,) = ctor.call(&mut store, (100,))?;
369
ctor.post_return(&mut store)?;
370
dtor.call(&mut store, (&t,))?;
371
dtor.post_return(&mut store)?;
372
373
assert_eq!(
374
dtor.call(&mut store, (&t,)).unwrap_err().to_string(),
375
"unknown handle index 1"
376
);
377
378
Ok(())
379
}
380
381
#[test]
382
fn drop_host_twice() -> Result<()> {
383
let engine = super::engine();
384
let c = Component::new(
385
&engine,
386
r#"
387
(component
388
(import "t" (type $t (sub resource)))
389
390
(core func $dtor (canon resource.drop $t))
391
(func (export "dtor") (param "x" (own $t))
392
(canon lift (core func $dtor)))
393
)
394
"#,
395
)?;
396
397
struct MyType;
398
399
let mut store = Store::new(&engine, ());
400
let mut linker = Linker::new(&engine);
401
linker
402
.root()
403
.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
404
let i = linker.instantiate(&mut store, &c)?;
405
let dtor = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "dtor")?;
406
407
let t = Resource::new_own(100);
408
dtor.call(&mut store, (&t,))?;
409
dtor.post_return(&mut store)?;
410
411
assert_eq!(
412
dtor.call(&mut store, (&t,)).unwrap_err().to_string(),
413
"host resource already consumed"
414
);
415
416
Ok(())
417
}
418
419
#[test]
420
fn manually_destroy() -> Result<()> {
421
let engine = super::engine();
422
let c = Component::new(
423
&engine,
424
r#"
425
(component
426
(import "t1" (type $t1 (sub resource)))
427
428
(core module $m
429
(global $drops (mut i32) i32.const 0)
430
(global $last-drop (mut i32) i32.const 0)
431
432
(func (export "dtor") (param i32)
433
(global.set $drops (i32.add (global.get $drops) (i32.const 1)))
434
(global.set $last-drop (local.get 0))
435
)
436
(func (export "drops") (result i32) global.get $drops)
437
(func (export "last-drop") (result i32) global.get $last-drop)
438
(func (export "pass") (param i32) (result i32) local.get 0)
439
)
440
(core instance $i (instantiate $m))
441
(type $t2' (resource (rep i32) (dtor (func $i "dtor"))))
442
(export $t2 "t2" (type $t2'))
443
(core func $ctor (canon resource.new $t2))
444
(func (export "[constructor]t2") (param "rep" u32) (result (own $t2))
445
(canon lift (core func $ctor)))
446
(func (export "[static]t2.drops") (result u32)
447
(canon lift (core func $i "drops")))
448
(func (export "[static]t2.last-drop") (result u32)
449
(canon lift (core func $i "last-drop")))
450
451
(func (export "t1-pass") (param "t" (own $t1)) (result (own $t1))
452
(canon lift (core func $i "pass")))
453
)
454
"#,
455
)?;
456
457
struct MyType;
458
459
#[derive(Default)]
460
struct Data {
461
drops: u32,
462
last_drop: Option<u32>,
463
}
464
465
let mut store = Store::new(&engine, Data::default());
466
let mut linker = Linker::new(&engine);
467
linker
468
.root()
469
.resource("t1", ResourceType::host::<MyType>(), |mut cx, rep| {
470
let data: &mut Data = cx.data_mut();
471
data.drops += 1;
472
data.last_drop = Some(rep);
473
Ok(())
474
})?;
475
let i = linker.instantiate(&mut store, &c)?;
476
let t2_ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "[constructor]t2")?;
477
let t2_drops = i.get_typed_func::<(), (u32,)>(&mut store, "[static]t2.drops")?;
478
let t2_last_drop = i.get_typed_func::<(), (u32,)>(&mut store, "[static]t2.last-drop")?;
479
let t1_pass = i.get_typed_func::<(Resource<MyType>,), (ResourceAny,)>(&mut store, "t1-pass")?;
480
481
// Host resources can be destroyed through `resource_drop`
482
let t1 = Resource::new_own(100);
483
let (t1,) = t1_pass.call(&mut store, (t1,))?;
484
t1_pass.post_return(&mut store)?;
485
assert_eq!(store.data().drops, 0);
486
assert_eq!(store.data().last_drop, None);
487
t1.resource_drop(&mut store)?;
488
assert_eq!(store.data().drops, 1);
489
assert_eq!(store.data().last_drop, Some(100));
490
491
// Guest resources can be destroyed through `resource_drop`
492
let (t2,) = t2_ctor.call(&mut store, (200,))?;
493
t2_ctor.post_return(&mut store)?;
494
assert_eq!(t2_drops.call(&mut store, ())?, (0,));
495
t2_drops.post_return(&mut store)?;
496
assert_eq!(t2_last_drop.call(&mut store, ())?, (0,));
497
t2_last_drop.post_return(&mut store)?;
498
t2.resource_drop(&mut store)?;
499
assert_eq!(t2_drops.call(&mut store, ())?, (1,));
500
t2_drops.post_return(&mut store)?;
501
assert_eq!(t2_last_drop.call(&mut store, ())?, (200,));
502
t2_last_drop.post_return(&mut store)?;
503
504
// Wires weren't crossed to drop more resources
505
assert_eq!(store.data().drops, 1);
506
assert_eq!(store.data().last_drop, Some(100));
507
508
Ok(())
509
}
510
511
#[test]
512
fn dynamic_type() -> Result<()> {
513
let engine = super::engine();
514
let c = Component::new(
515
&engine,
516
r#"
517
(component
518
(import "t1" (type $t1 (sub resource)))
519
(type $t2' (resource (rep i32)))
520
(export $t2 "t2" (type $t2'))
521
(core func $f (canon resource.drop $t2))
522
523
(func (export "a") (param "x" (own $t1))
524
(canon lift (core func $f)))
525
(func (export "b") (param "x" (tuple (own $t2)))
526
(canon lift (core func $f)))
527
)
528
"#,
529
)?;
530
531
struct MyType;
532
533
let mut store = Store::new(&engine, ());
534
let mut linker = Linker::new(&engine);
535
linker
536
.root()
537
.resource("t1", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
538
let i = linker.instantiate(&mut store, &c)?;
539
540
let a = i.get_func(&mut store, "a").unwrap();
541
let b = i.get_func(&mut store, "b").unwrap();
542
let t2 = i.get_resource(&mut store, "t2").unwrap();
543
544
let a_params = a.params(&store);
545
assert_eq!(
546
a_params[0],
547
("x".to_string(), Type::Own(ResourceType::host::<MyType>()))
548
);
549
let b_params = b.params(&store);
550
match &b_params[0] {
551
(name, Type::Tuple(t)) => {
552
assert_eq!(name, "x");
553
assert_eq!(t.types().len(), 1);
554
let t0 = t.types().next().unwrap();
555
assert_eq!(t0, Type::Own(t2));
556
}
557
_ => unreachable!(),
558
}
559
560
Ok(())
561
}
562
563
#[test]
564
fn dynamic_val() -> Result<()> {
565
let engine = super::engine();
566
let c = Component::new(
567
&engine,
568
r#"
569
(component
570
(import "t1" (type $t1 (sub resource)))
571
(type $t2' (resource (rep i32)))
572
(export $t2 "t2" (type $t2'))
573
(core func $f (canon resource.new $t2))
574
575
(core module $m
576
(func (export "pass") (param i32) (result i32)
577
(local.get 0)))
578
(core instance $i (instantiate $m))
579
580
(func (export "a") (param "x" (own $t1)) (result (own $t1))
581
(canon lift (core func $i "pass")))
582
(func (export "b") (param "x" u32) (result (own $t2))
583
(canon lift (core func $f)))
584
)
585
"#,
586
)?;
587
588
struct MyType;
589
590
let mut store = Store::new(&engine, ());
591
let mut linker = Linker::new(&engine);
592
linker
593
.root()
594
.resource("t1", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
595
let i_pre = linker.instantiate_pre(&c)?;
596
let i = i_pre.instantiate(&mut store)?;
597
598
let a = i.get_func(&mut store, "a").unwrap();
599
let a_typed = i.get_typed_func::<(Resource<MyType>,), (ResourceAny,)>(&mut store, "a")?;
600
let a_typed_result =
601
i.get_typed_func::<(Resource<MyType>,), (Resource<MyType>,)>(&mut store, "a")?;
602
let b = i.get_func(&mut store, "b").unwrap();
603
let t2 = i.get_resource(&mut store, "t2").unwrap();
604
605
let t1 = Resource::new_own(100);
606
let (t1,) = a_typed.call(&mut store, (t1,))?;
607
a_typed.post_return(&mut store)?;
608
assert_eq!(t1.ty(), ResourceType::host::<MyType>());
609
610
let mut results = [Val::Bool(false)];
611
a.call(&mut store, &[Val::Resource(t1)], &mut results)?;
612
a.post_return(&mut store)?;
613
match &results[0] {
614
Val::Resource(resource) => {
615
assert_eq!(resource.ty(), ResourceType::host::<MyType>());
616
assert!(resource.owned());
617
618
let resource = resource.try_into_resource::<MyType>(&mut store)?;
619
assert_eq!(resource.rep(), 100);
620
assert!(resource.owned());
621
622
let resource = resource.try_into_resource_any(&mut store)?;
623
assert_eq!(resource.ty(), ResourceType::host::<MyType>());
624
assert!(resource.owned());
625
}
626
_ => unreachable!(),
627
}
628
629
let t1_any = Resource::<MyType>::new_own(100).try_into_resource_any(&mut store)?;
630
let mut results = [Val::Bool(false)];
631
a.call(&mut store, &[Val::Resource(t1_any)], &mut results)?;
632
a.post_return(&mut store)?;
633
match &results[0] {
634
Val::Resource(resource) => {
635
assert_eq!(resource.ty(), ResourceType::host::<MyType>());
636
assert!(resource.owned());
637
638
let resource = resource.try_into_resource::<MyType>(&mut store)?;
639
assert_eq!(resource.rep(), 100);
640
assert!(resource.owned());
641
642
let resource = resource.try_into_resource_any(&mut store)?;
643
assert_eq!(resource.ty(), ResourceType::host::<MyType>());
644
assert!(resource.owned());
645
}
646
_ => unreachable!(),
647
}
648
649
let t1 = Resource::<MyType>::new_own(100)
650
.try_into_resource_any(&mut store)?
651
.try_into_resource(&mut store)?;
652
let (t1,) = a_typed_result.call(&mut store, (t1,))?;
653
a_typed_result.post_return(&mut store)?;
654
assert_eq!(t1.rep(), 100);
655
assert!(t1.owned());
656
657
let t1_any = t1
658
.try_into_resource_any(&mut store)?
659
.try_into_resource::<MyType>(&mut store)?
660
.try_into_resource_any(&mut store)?;
661
let mut results = [Val::Bool(false)];
662
a.call(&mut store, &[Val::Resource(t1_any)], &mut results)?;
663
a.post_return(&mut store)?;
664
match &results[0] {
665
Val::Resource(resource) => {
666
assert_eq!(resource.ty(), ResourceType::host::<MyType>());
667
assert!(resource.owned());
668
669
let resource = resource.try_into_resource::<MyType>(&mut store)?;
670
assert_eq!(resource.rep(), 100);
671
assert!(resource.owned());
672
673
let resource = resource.try_into_resource_any(&mut store)?;
674
assert_eq!(resource.ty(), ResourceType::host::<MyType>());
675
assert!(resource.owned());
676
}
677
_ => unreachable!(),
678
}
679
680
b.call(&mut store, &[Val::U32(200)], &mut results)?;
681
match &results[0] {
682
Val::Resource(resource) => {
683
assert_eq!(resource.ty(), t2);
684
}
685
_ => unreachable!(),
686
}
687
688
Ok(())
689
}
690
691
#[test]
692
fn cannot_reenter_during_import() -> Result<()> {
693
let engine = super::engine();
694
let c = Component::new(
695
&engine,
696
r#"
697
(component
698
(import "f" (func $f))
699
700
(core func $f (canon lower (func $f)))
701
702
(core module $m
703
(import "" "f" (func $f))
704
(func (export "call") call $f)
705
(func (export "dtor") (param i32) unreachable)
706
)
707
708
(core instance $i (instantiate $m
709
(with "" (instance
710
(export "f" (func $f))
711
))
712
))
713
714
(type $t2' (resource (rep i32) (dtor (func $i "dtor"))))
715
(export $t2 "t" (type $t2'))
716
(core func $ctor (canon resource.new $t2))
717
(func (export "ctor") (param "x" u32) (result (own $t2))
718
(canon lift (core func $ctor)))
719
720
(func (export "call") (canon lift (core func $i "call")))
721
)
722
"#,
723
)?;
724
725
let mut store = Store::new(&engine, None);
726
let mut linker = Linker::new(&engine);
727
linker.root().func_wrap("f", |mut cx, ()| {
728
let data: &mut Option<ResourceAny> = cx.data_mut();
729
let err = data.take().unwrap().resource_drop(cx).unwrap_err();
730
assert_eq!(
731
err.downcast_ref(),
732
Some(&Trap::CannotEnterComponent),
733
"bad error: {err:?}"
734
);
735
Ok(())
736
})?;
737
let i = linker.instantiate(&mut store, &c)?;
738
739
let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?;
740
let call = i.get_typed_func::<(), ()>(&mut store, "call")?;
741
742
let (resource,) = ctor.call(&mut store, (100,))?;
743
ctor.post_return(&mut store)?;
744
*store.data_mut() = Some(resource);
745
call.call(&mut store, ())?;
746
747
Ok(())
748
}
749
750
#[test]
751
fn active_borrows_at_end_of_call() -> Result<()> {
752
let engine = super::engine();
753
let c = Component::new(
754
&engine,
755
r#"
756
(component
757
(import "t" (type $t (sub resource)))
758
759
(core module $m
760
(func (export "f") (param i32))
761
)
762
(core instance $i (instantiate $m))
763
764
(func (export "f") (param "x" (borrow $t))
765
(canon lift (core func $i "f")))
766
)
767
"#,
768
)?;
769
770
struct MyType;
771
772
let mut store = Store::new(&engine, ());
773
let mut linker = Linker::new(&engine);
774
linker
775
.root()
776
.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
777
let i = linker.instantiate(&mut store, &c)?;
778
779
let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f")?;
780
781
let resource = Resource::new_own(1);
782
f.call(&mut store, (&resource,))?;
783
let err = f.post_return(&mut store).unwrap_err();
784
assert_eq!(
785
err.to_string(),
786
"borrow handles still remain at the end of the call",
787
);
788
789
Ok(())
790
}
791
792
#[test]
793
fn thread_through_borrow() -> Result<()> {
794
let engine = super::engine();
795
let c = Component::new(
796
&engine,
797
r#"
798
(component
799
(import "t" (type $t (sub resource)))
800
(import "f" (func $f (param "x" (borrow $t))))
801
802
(core func $f (canon lower (func $f)))
803
(core func $drop (canon resource.drop $t))
804
805
(core module $m
806
(import "" "f" (func $f (param i32)))
807
(import "" "drop" (func $drop (param i32)))
808
(func (export "f2") (param i32)
809
(call $f (local.get 0))
810
(call $f (local.get 0))
811
(call $drop (local.get 0))
812
)
813
)
814
(core instance $i (instantiate $m
815
(with "" (instance
816
(export "f" (func $f))
817
(export "drop" (func $drop))
818
))
819
))
820
821
(func (export "f2") (param "x" (borrow $t))
822
(canon lift (core func $i "f2")))
823
)
824
"#,
825
)?;
826
827
struct MyType;
828
829
let mut store = Store::new(&engine, ());
830
let mut linker = Linker::new(&engine);
831
linker
832
.root()
833
.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
834
linker
835
.root()
836
.func_wrap("f", |_cx, (r,): (Resource<MyType>,)| {
837
assert!(!r.owned());
838
assert_eq!(r.rep(), 100);
839
Ok(())
840
})?;
841
let i = linker.instantiate(&mut store, &c)?;
842
843
let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f2")?;
844
845
let resource = Resource::new_own(100);
846
f.call(&mut store, (&resource,))?;
847
f.post_return(&mut store)?;
848
Ok(())
849
}
850
851
#[test]
852
fn cannot_use_borrow_for_own() -> Result<()> {
853
let engine = super::engine();
854
let c = Component::new(
855
&engine,
856
r#"
857
(component
858
(import "t" (type $t (sub resource)))
859
860
(core module $m
861
(func (export "f") (param i32) (result i32)
862
local.get 0
863
)
864
)
865
(core instance $i (instantiate $m))
866
867
(func (export "f") (param "x" (borrow $t)) (result (own $t))
868
(canon lift (core func $i "f")))
869
)
870
"#,
871
)?;
872
873
struct MyType;
874
875
let mut store = Store::new(&engine, ());
876
let mut linker = Linker::new(&engine);
877
linker
878
.root()
879
.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
880
let i = linker.instantiate(&mut store, &c)?;
881
882
let f = i.get_typed_func::<(&Resource<MyType>,), (Resource<MyType>,)>(&mut store, "f")?;
883
884
let resource = Resource::new_own(100);
885
let err = f.call(&mut store, (&resource,)).unwrap_err();
886
assert_eq!(err.to_string(), "cannot lift own resource from a borrow");
887
Ok(())
888
}
889
890
#[test]
891
fn can_use_own_for_borrow() -> Result<()> {
892
let engine = super::engine();
893
let c = Component::new(
894
&engine,
895
r#"
896
(component
897
(import "t" (type $t (sub resource)))
898
899
(core func $drop (canon resource.drop $t))
900
901
(core module $m
902
(import "" "drop" (func $drop (param i32)))
903
(func (export "f") (param i32)
904
(call $drop (local.get 0))
905
)
906
)
907
(core instance $i (instantiate $m
908
(with "" (instance
909
(export "drop" (func $drop))
910
))
911
))
912
913
(func (export "f") (param "x" (borrow $t))
914
(canon lift (core func $i "f")))
915
)
916
"#,
917
)?;
918
919
struct MyType;
920
921
let mut store = Store::new(&engine, ());
922
let mut linker = Linker::new(&engine);
923
linker
924
.root()
925
.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
926
let i_pre = linker.instantiate_pre(&c)?;
927
let i = i_pre.instantiate(&mut store)?;
928
929
let f = i.get_func(&mut store, "f").unwrap();
930
let f_typed = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f")?;
931
932
let resource = Resource::new_own(100);
933
f_typed.call(&mut store, (&resource,))?;
934
f_typed.post_return(&mut store)?;
935
936
let resource = Resource::new_borrow(200);
937
f_typed.call(&mut store, (&resource,))?;
938
f_typed.post_return(&mut store)?;
939
940
let resource = Resource::<MyType>::new_own(300).try_into_resource_any(&mut store)?;
941
f.call(&mut store, &[Val::Resource(resource)], &mut [])?;
942
f.post_return(&mut store)?;
943
resource.resource_drop(&mut store)?;
944
945
// TODO: Enable once https://github.com/bytecodealliance/wasmtime/issues/7793 is fixed
946
//let resource =
947
// Resource::<MyType>::new_borrow(400).try_into_resource_any(&mut store, &i_pre, ty_idx)?;
948
//f.call(&mut store, &[Val::Resource(resource)], &mut [])?;
949
//f.post_return(&mut store)?;
950
//resource.resource_drop(&mut store)?;
951
952
Ok(())
953
}
954
955
#[test]
956
fn passthrough_wrong_type() -> Result<()> {
957
let engine = super::engine();
958
let c = Component::new(
959
&engine,
960
r#"
961
(component
962
(import "t" (type $t (sub resource)))
963
(import "f" (func $f (param "a" (borrow $t)) (result (own $t))))
964
965
(core func $f (canon lower (func $f)))
966
967
(core module $m
968
(import "" "f" (func $f (param i32) (result i32)))
969
(func (export "f2") (param i32)
970
(drop (call $f (local.get 0)))
971
)
972
)
973
(core instance $i (instantiate $m
974
(with "" (instance
975
(export "f" (func $f))
976
))
977
))
978
979
(func (export "f2") (param "x" (borrow $t))
980
(canon lift (core func $i "f2")))
981
)
982
"#,
983
)?;
984
985
struct MyType;
986
987
let mut store = Store::new(&engine, ());
988
let mut linker = Linker::new(&engine);
989
linker
990
.root()
991
.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
992
linker
993
.root()
994
.func_wrap("f", |_cx, (r,): (Resource<MyType>,)| Ok((r,)))?;
995
let i = linker.instantiate(&mut store, &c)?;
996
997
let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f2")?;
998
999
let resource = Resource::new_own(100);
1000
let err = f.call(&mut store, (&resource,)).unwrap_err();
1001
assert!(
1002
format!("{err:?}").contains("cannot lower a `borrow` resource into an `own`"),
1003
"bad error: {err:?}"
1004
);
1005
Ok(())
1006
}
1007
1008
#[test]
1009
fn pass_moved_resource() -> Result<()> {
1010
let engine = super::engine();
1011
let c = Component::new(
1012
&engine,
1013
r#"
1014
(component
1015
(import "t" (type $t (sub resource)))
1016
(core module $m
1017
(func (export "f") (param i32 i32))
1018
)
1019
(core instance $i (instantiate $m))
1020
1021
(func (export "f") (param "x" (own $t)) (param "y" (borrow $t))
1022
(canon lift (core func $i "f")))
1023
)
1024
"#,
1025
)?;
1026
1027
struct MyType;
1028
1029
let mut store = Store::new(&engine, ());
1030
let mut linker = Linker::new(&engine);
1031
linker
1032
.root()
1033
.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
1034
let i = linker.instantiate(&mut store, &c)?;
1035
1036
let f = i.get_typed_func::<(&Resource<MyType>, &Resource<MyType>), ()>(&mut store, "f")?;
1037
1038
let resource = Resource::new_own(100);
1039
let err = f.call(&mut store, (&resource, &resource)).unwrap_err();
1040
assert!(
1041
format!("{err:?}").contains("host resource already consumed"),
1042
"bad error: {err:?}"
1043
);
1044
Ok(())
1045
}
1046
1047
#[test]
1048
fn type_mismatch() -> Result<()> {
1049
let engine = super::engine();
1050
let c = Component::new(
1051
&engine,
1052
r#"
1053
(component
1054
(type $t' (resource (rep i32)))
1055
(export $t "t" (type $t'))
1056
1057
(core func $drop (canon resource.drop $t))
1058
1059
(func (export "f1") (param "x" (own $t))
1060
(canon lift (core func $drop)))
1061
(func (export "f2") (param "x" (borrow $t))
1062
(canon lift (core func $drop)))
1063
(func (export "f3") (param "x" u32)
1064
(canon lift (core func $drop)))
1065
)
1066
"#,
1067
)?;
1068
1069
struct MyType;
1070
1071
let mut store = Store::new(&engine, ());
1072
let i = Linker::new(&engine).instantiate(&mut store, &c)?;
1073
1074
assert!(
1075
i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f1")
1076
.is_err()
1077
);
1078
assert!(
1079
i.get_typed_func::<(&ResourceAny,), ()>(&mut store, "f1")
1080
.is_ok()
1081
);
1082
1083
assert!(
1084
i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f2")
1085
.is_err()
1086
);
1087
assert!(
1088
i.get_typed_func::<(&ResourceAny,), ()>(&mut store, "f2")
1089
.is_ok()
1090
);
1091
1092
assert!(
1093
i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f3")
1094
.is_err()
1095
);
1096
assert!(
1097
i.get_typed_func::<(&ResourceAny,), ()>(&mut store, "f3")
1098
.is_err()
1099
);
1100
assert!(i.get_typed_func::<(u32,), ()>(&mut store, "f3").is_ok());
1101
1102
Ok(())
1103
}
1104
1105
#[test]
1106
fn drop_no_dtor() -> Result<()> {
1107
let engine = super::engine();
1108
let c = Component::new(
1109
&engine,
1110
r#"
1111
(component
1112
(type $t' (resource (rep i32)))
1113
(export $t "t" (type $t'))
1114
1115
(core func $ctor (canon resource.new $t))
1116
1117
(func (export "ctor") (param "x" u32) (result (own $t))
1118
(canon lift (core func $ctor)))
1119
)
1120
"#,
1121
)?;
1122
1123
let mut store = Store::new(&engine, ());
1124
let i = Linker::new(&engine).instantiate(&mut store, &c)?;
1125
let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?;
1126
let (resource,) = ctor.call(&mut store, (100,))?;
1127
ctor.post_return(&mut store)?;
1128
resource.resource_drop(&mut store)?;
1129
1130
Ok(())
1131
}
1132
1133
#[test]
1134
fn host_borrow_as_resource_any() -> Result<()> {
1135
let engine = super::engine();
1136
let c = Component::new(
1137
&engine,
1138
r#"
1139
(component
1140
(import "t" (type $t (sub resource)))
1141
(import "f" (func $f (param "f" (borrow $t))))
1142
1143
(core func $f (canon lower (func $f)))
1144
1145
(core module $m
1146
(import "" "f" (func $f (param i32)))
1147
(func (export "f2") (param i32)
1148
(call $f (local.get 0))
1149
)
1150
)
1151
(core instance $i (instantiate $m
1152
(with "" (instance
1153
(export "f" (func $f))
1154
))
1155
))
1156
1157
(func (export "f2") (param "x" (borrow $t))
1158
(canon lift (core func $i "f2")))
1159
)
1160
"#,
1161
)?;
1162
1163
struct MyType;
1164
1165
let mut store = Store::new(&engine, ());
1166
1167
// First test the above component where the host properly drops the argument
1168
{
1169
let mut linker = Linker::new(&engine);
1170
linker
1171
.root()
1172
.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
1173
linker
1174
.root()
1175
.func_wrap("f", |mut cx, (r,): (ResourceAny,)| {
1176
r.resource_drop(&mut cx)?;
1177
Ok(())
1178
})?;
1179
let i = linker.instantiate(&mut store, &c)?;
1180
1181
let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f2")?;
1182
1183
let resource = Resource::new_own(100);
1184
f.call(&mut store, (&resource,))?;
1185
}
1186
1187
// Then also test the case where the host forgets a drop
1188
{
1189
let mut linker = Linker::new(&engine);
1190
linker
1191
.root()
1192
.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
1193
linker.root().func_wrap("f", |_cx, (_r,): (ResourceAny,)| {
1194
// ... no drop here
1195
Ok(())
1196
})?;
1197
let i = linker.instantiate(&mut store, &c)?;
1198
1199
let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f2")?;
1200
1201
let resource = Resource::new_own(100);
1202
let err = f.call(&mut store, (&resource,)).unwrap_err();
1203
assert!(
1204
format!("{err:?}").contains("borrow handles still remain at the end of the call"),
1205
"bad error: {err:?}"
1206
);
1207
}
1208
Ok(())
1209
}
1210
1211
#[test]
1212
fn pass_guest_back_as_borrow() -> Result<()> {
1213
let engine = super::engine();
1214
let c = Component::new(
1215
&engine,
1216
r#"
1217
(component
1218
(type $t' (resource (rep i32)))
1219
1220
(export $t "t" (type $t'))
1221
1222
(core func $new (canon resource.new $t))
1223
1224
(core module $m
1225
(import "" "new" (func $new (param i32) (result i32)))
1226
1227
(func (export "mk") (result i32)
1228
(call $new (i32.const 100))
1229
)
1230
1231
(func (export "take") (param i32)
1232
(if (i32.ne (local.get 0) (i32.const 100)) (then (unreachable)))
1233
)
1234
)
1235
(core instance $i (instantiate $m
1236
(with "" (instance
1237
(export "new" (func $new))
1238
))
1239
))
1240
1241
(func (export "mk") (result (own $t))
1242
(canon lift (core func $i "mk")))
1243
(func (export "take") (param "x" (borrow $t))
1244
(canon lift (core func $i "take")))
1245
)
1246
"#,
1247
)?;
1248
1249
let mut store = Store::new(&engine, ());
1250
let i = Linker::new(&engine).instantiate(&mut store, &c)?;
1251
let mk = i.get_typed_func::<(), (ResourceAny,)>(&mut store, "mk")?;
1252
let take = i.get_typed_func::<(&ResourceAny,), ()>(&mut store, "take")?;
1253
1254
let (resource,) = mk.call(&mut store, ())?;
1255
mk.post_return(&mut store)?;
1256
take.call(&mut store, (&resource,))?;
1257
take.post_return(&mut store)?;
1258
1259
resource.resource_drop(&mut store)?;
1260
1261
// Should not be valid to use `resource` again
1262
let err = take.call(&mut store, (&resource,)).unwrap_err();
1263
assert_eq!(err.to_string(), "unknown handle index 1");
1264
1265
Ok(())
1266
}
1267
1268
#[test]
1269
fn pass_host_borrow_to_guest() -> Result<()> {
1270
let engine = super::engine();
1271
let c = Component::new(
1272
&engine,
1273
r#"
1274
(component
1275
(import "t" (type $t (sub resource)))
1276
1277
(core func $drop (canon resource.drop $t))
1278
1279
(core module $m
1280
(import "" "drop" (func $drop (param i32)))
1281
(func (export "take") (param i32)
1282
(call $drop (local.get 0))
1283
)
1284
)
1285
(core instance $i (instantiate $m
1286
(with "" (instance
1287
(export "drop" (func $drop))
1288
))
1289
))
1290
1291
(func (export "take") (param "x" (borrow $t))
1292
(canon lift (core func $i "take")))
1293
)
1294
"#,
1295
)?;
1296
1297
struct MyType;
1298
1299
let mut store = Store::new(&engine, ());
1300
let mut linker = Linker::new(&engine);
1301
linker
1302
.root()
1303
.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
1304
let i = linker.instantiate(&mut store, &c)?;
1305
let take = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "take")?;
1306
1307
let resource = Resource::new_borrow(100);
1308
take.call(&mut store, (&resource,))?;
1309
take.post_return(&mut store)?;
1310
1311
Ok(())
1312
}
1313
1314
#[test]
1315
fn drop_on_owned_resource() -> Result<()> {
1316
let engine = super::engine();
1317
let c = Component::new(
1318
&engine,
1319
r#"
1320
(component
1321
(import "t" (type $t (sub resource)))
1322
(import "[constructor]t" (func $ctor (result (own $t))))
1323
(import "[method]t.foo" (func $foo (param "self" (borrow $t)) (result (list u8))))
1324
1325
(core func $ctor (canon lower (func $ctor)))
1326
(core func $drop (canon resource.drop $t))
1327
1328
(core module $m1
1329
(import "" "drop" (func $drop (param i32)))
1330
(memory (export "memory") 1)
1331
(global $to-drop (export "to-drop") (mut i32) (i32.const 0))
1332
(func (export "realloc") (param i32 i32 i32 i32) (result i32)
1333
(call $drop (global.get $to-drop))
1334
unreachable)
1335
)
1336
(core instance $i1 (instantiate $m1
1337
(with "" (instance
1338
(export "drop" (func $drop))
1339
))
1340
))
1341
1342
(core func $foo (canon lower (func $foo)
1343
(memory $i1 "memory")
1344
(realloc (func $i1 "realloc"))))
1345
1346
(core module $m2
1347
(import "" "ctor" (func $ctor (result i32)))
1348
(import "" "foo" (func $foo (param i32 i32)))
1349
(import "i1" "to-drop" (global $to-drop (mut i32)))
1350
1351
(func (export "f")
1352
(local $r i32)
1353
(local.set $r (call $ctor))
1354
(global.set $to-drop (local.get $r))
1355
(call $foo
1356
(local.get $r)
1357
(i32.const 200))
1358
)
1359
)
1360
(core instance $i2 (instantiate $m2
1361
(with "" (instance
1362
(export "ctor" (func $ctor))
1363
(export "foo" (func $foo))
1364
))
1365
(with "i1" (instance $i1))
1366
))
1367
(func (export "f") (canon lift (core func $i2 "f")))
1368
)
1369
"#,
1370
)?;
1371
1372
struct MyType;
1373
1374
let mut store = Store::new(&engine, ());
1375
let mut linker = Linker::new(&engine);
1376
linker
1377
.root()
1378
.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
1379
linker.root().func_wrap("[constructor]t", |_cx, ()| {
1380
Ok((Resource::<MyType>::new_own(300),))
1381
})?;
1382
linker
1383
.root()
1384
.func_wrap("[method]t.foo", |_cx, (r,): (Resource<MyType>,)| {
1385
assert!(!r.owned());
1386
Ok((vec![2u8],))
1387
})?;
1388
let i = linker.instantiate(&mut store, &c)?;
1389
let f = i.get_typed_func::<(), ()>(&mut store, "f")?;
1390
1391
let err = f.call(&mut store, ()).unwrap_err();
1392
assert!(
1393
format!("{err:?}").contains("cannot remove owned resource while borrowed"),
1394
"bad error: {err:?}"
1395
);
1396
1397
Ok(())
1398
}
1399
1400
#[test]
1401
fn guest_different_host_same() -> Result<()> {
1402
let engine = super::engine();
1403
let c = Component::new(
1404
&engine,
1405
r#"
1406
(component
1407
(import "t1" (type $t1 (sub resource)))
1408
(import "t2" (type $t2 (sub resource)))
1409
1410
(import "f" (func $f (param "a" (borrow $t1)) (param "b" (borrow $t2))))
1411
1412
(export $g1 "g1" (type $t1))
1413
(export $g2 "g2" (type $t2))
1414
1415
(core func $f (canon lower (func $f)))
1416
(core func $drop1 (canon resource.drop $t1))
1417
(core func $drop2 (canon resource.drop $t2))
1418
1419
(core module $m
1420
(import "" "f" (func $f (param i32 i32)))
1421
(import "" "drop1" (func $drop1 (param i32)))
1422
(import "" "drop2" (func $drop2 (param i32)))
1423
1424
(func (export "f") (param i32 i32)
1425
;; different types, but everything goes into the same
1426
;; handle index namespace
1427
(if (i32.ne (local.get 0) (i32.const 1)) (then (unreachable)))
1428
(if (i32.ne (local.get 1) (i32.const 2)) (then (unreachable)))
1429
1430
;; host should end up getting the same resource
1431
(call $f (local.get 0) (local.get 1))
1432
1433
;; drop our borrows
1434
(call $drop1 (local.get 0))
1435
(call $drop2 (local.get 1))
1436
)
1437
)
1438
(core instance $i (instantiate $m
1439
(with "" (instance
1440
(export "f" (func $f))
1441
(export "drop1" (func $drop1))
1442
(export "drop2" (func $drop2))
1443
))
1444
))
1445
1446
(func (export "f2") (param "a" (borrow $g1)) (param "b" (borrow $g2))
1447
(canon lift (core func $i "f")))
1448
)
1449
"#,
1450
)?;
1451
1452
struct MyType;
1453
1454
let mut store = Store::new(&engine, ());
1455
let mut linker = Linker::new(&engine);
1456
linker
1457
.root()
1458
.resource("t1", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
1459
linker
1460
.root()
1461
.resource("t2", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
1462
linker.root().func_wrap(
1463
"f",
1464
|_cx, (r1, r2): (Resource<MyType>, Resource<MyType>)| {
1465
assert!(!r1.owned());
1466
assert!(!r2.owned());
1467
assert_eq!(r1.rep(), 100);
1468
assert_eq!(r2.rep(), 100);
1469
Ok(())
1470
},
1471
)?;
1472
let i = linker.instantiate(&mut store, &c)?;
1473
let f = i.get_typed_func::<(&Resource<MyType>, &Resource<MyType>), ()>(&mut store, "f2")?;
1474
1475
let t1 = i.get_resource(&mut store, "g1").unwrap();
1476
let t2 = i.get_resource(&mut store, "g2").unwrap();
1477
assert_eq!(t1, t2);
1478
assert_eq!(t1, ResourceType::host::<MyType>());
1479
1480
let resource = Resource::new_own(100);
1481
f.call(&mut store, (&resource, &resource))?;
1482
f.post_return(&mut store)?;
1483
1484
Ok(())
1485
}
1486
1487
#[test]
1488
fn resource_any_to_typed_handles_borrow() -> Result<()> {
1489
let engine = super::engine();
1490
let c = Component::new(
1491
&engine,
1492
r#"
1493
(component
1494
(import "t" (type $t (sub resource)))
1495
1496
(import "f" (func $f (param "a" (borrow $t))))
1497
1498
(core func $f (canon lower (func $f)))
1499
1500
(core module $m
1501
(import "" "f" (func $f (param i32)))
1502
1503
(func (export "f") (param i32)
1504
(call $f (local.get 0))
1505
)
1506
)
1507
(core instance $i (instantiate $m
1508
(with "" (instance
1509
(export "f" (func $f))
1510
))
1511
))
1512
1513
(func (export "f") (param "a" (own $t))
1514
(canon lift (core func $i "f")))
1515
)
1516
"#,
1517
)?;
1518
1519
struct MyType;
1520
1521
let mut store = Store::new(&engine, ());
1522
let mut linker = Linker::new(&engine);
1523
linker
1524
.root()
1525
.resource("t", ResourceType::host::<MyType>(), |_, _| Ok(()))?;
1526
linker
1527
.root()
1528
.func_wrap("f", |mut cx, (r,): (ResourceAny,)| {
1529
let r = r.try_into_resource::<MyType>(&mut cx).unwrap();
1530
assert_eq!(r.rep(), 100);
1531
assert!(!r.owned());
1532
Ok(())
1533
})?;
1534
let i = linker.instantiate(&mut store, &c)?;
1535
let f = i.get_typed_func::<(&Resource<MyType>,), ()>(&mut store, "f")?;
1536
1537
let resource = Resource::new_own(100);
1538
f.call(&mut store, (&resource,))?;
1539
f.post_return(&mut store)?;
1540
1541
Ok(())
1542
}
1543
1544