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