waclay 0.2.2

Runtime-agnostic WebAssembly Component Model implementation
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
# Usage Guide


`wasm_component_layer` is a runtime-agnostic implementation of the WebAssembly component model. This guide provides comprehensive instructions for using the library to load, instantiate, and interact with WebAssembly components.

## Prerequisites


Before using `wasm_component_layer`, you need to add it to your `Cargo.toml` along with a WebAssembly runtime backend:

```toml
[dependencies]
wasm_component_layer = {git = "https://github.com/HemantKArya/wcomp_layer.git"}
# OR

wasm_component_layer = "0.1.18"
wasmi_runtime_layer = { version = "0.51" }
```

## Basic Usage


### Loading and Instantiating a Component


The fundamental workflow involves:
1. Creating an engine with your chosen WebAssembly backend
2. Loading component bytes into a `Component`
3. Creating a `Store` to manage WebAssembly state
4. Using a `Linker` to resolve imports (if any)
5. Instantiating the component to get an `Instance`
6. Accessing exported functions and calling them

```rust
use wasm_component_layer::*;

// The bytes of the component (usually from include_bytes!)
const WASM: &[u8] = include_bytes!("path/to/component.wasm");

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. Create an engine with your chosen backend
    let engine = Engine::new(wasmi::Engine::default());

    // 2. Create a store for managing WebAssembly data and state
    let mut store = Store::new(&engine, ());

    // 3. Parse the component bytes
    let component = Component::new(&engine, WASM)?;

    // 4. Create a linker (empty if no imports needed)
    let linker = Linker::default();

    // 5. Instantiate the component
    let instance = linker.instantiate(&mut store, &component)?;

    // 6. Use the instance...
    Ok(())
}
```

### Calling Functions


Components export functions that you can call. The library provides both untyped and strongly-typed APIs:

#### Untyped API


```rust
// Get an interface from the instance
let interface = instance.exports().instance(&"test:guest/foo".try_into()?)?;

// Get a function from the interface
let func = interface.func("select_nth")?;

// Call with untyped values
let args = vec![
    Value::List(List::from(&["a", "b", "c"].map(|s| s.to_string()))),
    Value::U32(1)
];
let mut results = vec![Value::String("".into())];
func.call(&mut store, &args, &mut results)?;
println!("Result: {:?}", results[0]);
```

#### Strongly-Typed API


```rust
// Get and type the function
let select_nth = interface.func("select_nth")?
    .typed::<(Vec<String>, u32), String>()?;

// Call with strongly-typed parameters
let result = select_nth.call(&mut store, (vec!["a".to_string(), "b".to_string(), "c".to_string()], 1))?;
println!("Result: {}", result);
```

## Working with Types


The component model supports rich type system. Here's how to work with different types:

### Primitive Types


```rust
use wasm_component_layer::Value;

// Boolean
let bool_val = Value::Bool(true);

// Integers (signed and unsigned, 8-64 bits)
let s32_val = Value::S32(-42);
let u64_val = Value::U64(18446744073709551615);

// Floats
let f32_val = Value::F32(3.14159);
let f64_val = Value::F64(2.718281828459045);

// Characters and strings
let char_val = Value::Char('🚀');
let string_val = Value::String("Hello, WebAssembly!".into());
```

### Complex Types


#### Lists


```rust
use wasm_component_layer::{List, ListType, Value};

// Create a list type for strings
let list_ty = ListType::new(ValueType::String);

// Create a list value
let string_list = List::new(list_ty, vec![
    Value::String("first".into()),
    Value::String("second".into()),
    Value::String("third".into()),
])?;

// Access elements
for item in &string_list {
    println!("Item: {:?}", item);
}

// For primitive types, use specialized access
let numbers: List = vec![1i32, 2, 3].as_slice().into();
let typed_numbers = numbers.typed::<i32>()?;
assert_eq!(typed_numbers, &[1, 2, 3]);
```

#### Records


```rust
use wasm_component_layer::{Record, RecordType, Value};

// Define a record type
let person_ty = RecordType::new(None, vec![
    ("name", ValueType::String),
    ("age", ValueType::U32),
    ("active", ValueType::Bool),
])?;

// Create a record value
let person = Record::new(person_ty, vec![
    ("name", Value::String("Alice".into())),
    ("age", Value::U32(30)),
    ("active", Value::Bool(true)),
])?;

// Access fields
let name = person.field("name")?;
let age = person.field("age")?;
```

#### Tuples


```rust
use wasm_component_layer::{Tuple, TupleType, Value};

// Define a tuple type
let point_ty = TupleType::new(None, vec![
    ValueType::F32,  // x
    ValueType::F32,  // y
    ValueType::F32,  // z
]);

// Create a tuple value
let point = Tuple::new(point_ty, vec![
    Value::F32(1.0),
    Value::F32(2.5),
    Value::F64(3.0),
])?;

// Access by index
let x = &point[0];
let y = &point[1];
```

#### Variants and Enums


```rust
use wasm_component_layer::{Variant, VariantType, Enum, EnumType, Value};

// Define an enum type
let status_ty = EnumType::new(None, vec!["pending", "active", "inactive"])?;

// Create an enum value
let status = Enum::new(status_ty, 1)?; // "active"

// Define a variant type
let result_ty = VariantType::new(None, vec![
    VariantCase::new("ok", Some(ValueType::String)),
    VariantCase::new("error", Some(ValueType::String)),
    VariantCase::new("none", None),
])?;

// Create variant values
let ok_result = Variant::new(result_ty.clone(), 0, Some(Value::String("Success!".into())))?;
let none_result = Variant::new(result_ty, 2, None)?;
```

#### Options and Results


```rust
use wasm_component_layer::{OptionValue, OptionType, ResultValue, ResultType, Value};

// Option type
let opt_string_ty = OptionType::new(ValueType::String);
let some_value = OptionValue::new(opt_string_ty.clone(), Some(Value::String("Hello".into())))?;
let none_value = OptionValue::new(opt_string_ty, None)?;

// Result type
let result_ty = ResultType::new(Some(ValueType::String), Some(ValueType::String));
let ok_result = ResultValue::new(result_ty.clone(), Ok(Some(Value::String("Success".into()))))?;
let err_result = ResultValue::new(result_ty, Err(Some(Value::String("Error occurred".into()))))?;
```

### Flags


```rust
use wasm_component_layer::{Flags, FlagsType};

// Define flags type
let permissions_ty = FlagsType::new(None, vec!["read", "write", "execute"])?;

// Create flags value
let mut permissions = Flags::new(permissions_ty);

// Set flags
permissions.set("read", true);
permissions.set("write", true);
permissions.set("execute", false);

// Check flags
assert!(permissions.get("read"));
assert!(!permissions.get("execute"));
```

## Working with Resources


Resources represent opaque handles to data that can be passed between host and guest:

### Host Resources


```rust
use wasm_component_layer::{ResourceType, ResourceOwn};

// Create a host resource type for a custom struct
#[derive(Debug)]

struct MyData {
    value: i32,
}

let resource_ty = ResourceType::new::<MyData>(None);

// Create a resource instance
let resource = ResourceOwn::new(&mut store, MyData { value: 42 }, resource_ty)?;

// Borrow the resource
let borrow = resource.borrow(&mut store)?;

// Access the underlying data
{
    let data = resource.rep::<MyData, _, _>(&store)?;
    println!("Value: {}", data.value);
}

// Mutably access the data
{
    let data = resource.rep_mut::<MyData, _, _>(&mut store)?;
    data.value = 100;
}
```

### Guest Resources


Guest resources are created by WebAssembly components and can be received by the host:

```rust
// Assume a component exports a function that creates resources
let create_resource = instance.exports().root().func("create_resource")?
    .typed::<(), ResourceType>()?;

// Call the function to get a guest resource
let guest_resource: ResourceOwn = create_resource.call(&mut store, ())?;
```

## Advanced Usage


### Defining Host Functions


You can define functions in Rust that can be called from WebAssembly:

```rust
use wasm_component_layer::{Func, FuncType, Value};

// Define a function type
let func_ty = FuncType::new(
    vec![ValueType::String, ValueType::U32],
    vec![ValueType::String]
);

// Create a host function
let host_func = Func::new(&mut store, func_ty, |ctx, args, results| {
    let input_string = &args[0];
    let count = &args[1];

    if let (Value::String(s), Value::U32(n)) = (input_string, count) {
        let repeated = s.repeat(*n as usize);
        results[0] = Value::String(repeated.into());
    }
    Ok(())
});

// Add to linker
let mut linker = Linker::default();
linker.root_mut().define_func("repeat_string", host_func)?;
```

### Linking Multiple Interfaces


Components can import multiple interfaces:

```rust
// Define interfaces
let mut linker = Linker::default();

// Root interface
linker.root_mut().define_func("log", logging_func)?;

// Named interface
let math_interface = linker.define_instance("math:1.0".try_into()?)?;
math_interface.define_func("add", add_func)?;
math_interface.define_func("multiply", multiply_func)?;
```

### Error Handling


The library uses `anyhow::Result` for error handling:

```rust
match component_operation() {
    Ok(result) => println!("Success: {:?}", result),
    Err(e) => {
        eprintln!("Error: {}", e);
        // Check for specific error types
        if let Some(func_error) = e.downcast_ref::<FuncError>() {
            eprintln!("Function error in {}: {}", func_error.name(), func_error.error());
        }
    }
}
```

## Examples


The repository includes several examples demonstrating different features:

- `single_component`: Basic function calling
- `resource`: Working with resources
- `multilevel_resource`: Complex resource hierarchies
- `option_result`: Using option and result types
- `record_response`: Working with records
- `string_host_guest`: String passing between host and guest
- `variant_return`: Using variant types
- `func_param`: Function parameters

Each example includes:
- A WebAssembly component (`*.wasm`)
- Rust source code showing usage
- Build scripts for different platforms

To run an example:

```bash
cd examples/single_component
cargo run --example single_component
```

## Performance Considerations


- Use strongly-typed APIs (`TypedFunc`) when possible for better performance
- For large lists of primitive types, the library automatically uses optimized storage
- Resource operations involve reference counting - be mindful of borrow lifetimes
- Memory allocation in WebAssembly can be expensive; reuse buffers when possible

## Troubleshooting


### Common Issues


1. **"Incorrect parameter types"**: Ensure function signatures match exactly
2. **"Resource was already destroyed"**: Check resource lifetimes and borrowing rules
3. **"Could not find import"**: Verify all required imports are defined in the linker
4. **"Store mismatch"**: Use the same store instance for all operations

### Debugging


Enable debug logging to see detailed information about component operations:

```rust
env_logger::init();
```

Check component exports and imports:

```rust
println!("Exports: {:?}", component.exports());
println!("Imports: {:?}", component.imports());
```

---

> **⚠️ Warning: Documentation**
>
> This documentation was completely refined by AI and may contain inaccuracies, errors, or incomplete information. Please use it as a reference but verify critical details against the actual codebase. If you find any useful corrections, improvements, or additional content that would benefit other users, please submit a pull request to help improve this documentation for the community.