Commit Graph

3147 Commits

Author SHA1 Message Date
e4b05d0b00 feat(interface-types) Remove the re-export of InterfaceType in values. 2020-04-09 10:54:09 +02:00
f955617d17 feat(interface-types) Extract InterfaceType and RecordType into its own types module. 2020-04-09 10:48:50 +02:00
ad6f939e85 Merge #1362
1362: feat(interface-types) Remove allocator index from `string.lower_memory` r=Hywan a=Hywan

This PR updates `string.lower_memory` to remove the allocator index. Indeed, the string pointer is assumed to be present on the stack.
Also, this PR updates `string.size` to pop, and not to peek, the string to compute the length from.

That way, it matches the WIT proposal.

Co-authored-by: Ivan Enderlin <ivan@mnt.io>
2020-04-09 08:05:50 +00:00
23bc0fd720 Fix kernel-net check, fix misc warnings
Split out nightly check step
2020-04-08 17:05:25 -07:00
b72000a2d6 Update emscripten in C API to use new API crate 2020-04-08 16:40:41 -07:00
4d58ae2d14 Fix issue with kernel-net; add it to CI 2020-04-08 15:18:04 -07:00
9e8d08a771 Merge branch 'master' into feature/dev-utils-in-tests 2020-04-08 12:15:22 -07:00
3d4ed92466 Move dev-utils crate into tests 2020-04-08 11:59:47 -07:00
45c412e8dd Merge #1363
1363: fix(interface-types) Don't duplicate code in the binary encoder. r=MarkMcCaskey a=Hywan

Use the `ToBytes` implementation of `RecordType` to encode the inner
record type of a type, so that it avoids code duplication.

Co-authored-by: Ivan Enderlin <ivan@mnt.io>
2020-04-08 18:48:49 +00:00
db76aea198 Remove more uses of wasmer_runtime_core from the C API 2020-04-07 17:28:23 -07:00
4eae19ccc7 fix(interface-types) Don't duplicate code in the binary encoder.
Use the `ToBytes` implementation of `RecordType` to encode the inner
record type of a type, so that it avoids code duplication.
2020-04-07 14:29:57 +02:00
1687744ec9 feat(interface-types) string.size pops the string.
Previously, `string.size` was just peeking the string.
2020-04-07 12:40:14 +02:00
bfa5821d98 test(interface-types) Update the test_executable_instruction macro.
It provides a better failure message.
2020-04-07 12:34:30 +02:00
2fffee32a5 fix(interface-types) Remove allocator index from string.lower_memory. 2020-04-07 12:34:07 +02:00
c0623b0f8c doc(interface-types) Add record instructions. 2020-04-07 11:58:13 +02:00
83f0a043e7 Update C API to use new API 2020-04-06 17:09:50 -07:00
4c29cd4af3 Merge branch 'master' into feature/reorganized-tests 2020-04-06 12:04:36 -07:00
52cbb60743 Fix up tests for CI 2020-04-06 11:42:44 -07:00
99f8c949d1 Merge #1354
1354: test(middleware-common) Remove an unused import r=MarkMcCaskey a=Hywan

This PR removes an unused import.

Co-authored-by: Ivan Enderlin <ivan.enderlin@hoa-project.net>
2020-04-06 17:40:35 +00:00
ac3288db1c test(middleware-common) Remove an unused import. 2020-04-06 08:34:55 +02:00
4d33020b35 Merge #1331
1331: feat(interface-types) Implement the `record` instructions r=Hywan a=Hywan

### Description

This PR implements the `record` WIT type, along with the `record.lift` and `record.lower` instructions.

With my current understanding of the draft/specification, here is how it works. Let's say we want to represent a Rust struct like the following:

```rust
struct S {
    x: String,
    y: i32
}
```

First declare a WIT type, such as:

```wat
(@interface type (record (field string) (field i32)))
```

The `record` type is supported by the binary encoder, the WAT encoder, the binary decoder, and the WAT decoder. A new `TypeKind` node has been introduced in the AST to differentiate a function type (`(@interface type (func (param …) (result …)))`) of a record type (see above).

Second, the `record.lower` transforms a host value (here Rust value, `S`) into a WIT value. In our implementation, a record value is defined as:

```rust
InterfaceValue::Record(Vec<InterfaceValue>)
```

Multiple mechanisms are used to type check a record value based on a record type. The code of the `record.lower` is pretty straightforward.

Because transforming a host value into a WIT value isn't obvious, a `Serializer` has been implemented, based on [`serde`](https://serde.rs/). This feature is behind the `serde` flag, which is turned on by default.

Serde is only used to cross the host/Wasm boundary, but it's not used to represent the value in memory or anything. It's only a shortcut to transform a host value into a WIT value, and vice versa.

Use the following code to transform `S` into a WIT value:

```rust
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct S {
    x: String,
    y: i32,
}

let host_value = S { x: "hello".to_string(), y: 42 };
let wit_value = to_interface_value(&host_value).unwrap();

assert_eq!(
    wit_value,
    InterfaceValue::Record(vec![
        InterfaceValue::String("hello".to_string()),
        InterfaceValue::I32(42),
    ])
);
```

Third, the `record.lift`  instruction does the opposite of `record.lower`: It transforms WIT values into a host value. To also facilitate the user experience, this PR contains a `Deserializer` implementation, still based on `serde`, with the `from_interface_values` function. It looks like this:

```rust
let wit_values = vec![
    InterfaceValue::Record(vec![
        InterfaceValue::String("hello".to_string()),
        InterfaceValue::I32(42),
    ])
];
let host_value = from_interface_values::<S>(&wit_values).unwrap();

assert_eq!(
    host_value,
    S { x: "hello".to_string(), y: 42 },
);
```

With the `Serializer` and `Deserializer`, it's super easy for the user to send or receive values from WIT.

The `record.lift` and `record.lower` instructions are kind of basic. The `record.lift` instruction has a little trick to reduce vector allocations, but there is a documentation for that.

#### Opened questions

Records of dimension 1 do not raise any issue. With `record.lift`, all values on the stack (the WIT interpreter stack) are popped, and are used as record field values. Something like:

```
[stack]
i32(1)
i64(2),
string("hello")
record.lift <record_type>
```

generates

```
[stack]
record { i32(1), i64(2), string("hello") }
```

But it's not clear what happens with record of dimension > 1, for instance for a type like `record (field i32) (record (field i32) (field i32)) (field string)`, it is assumed (in this PR) that the stack must be like this:

```
[stack]
i32(1)
i32(2)
i32(3)
string("hello")
record.lift <record_type>
```

to generate:

```
[stack]
record { i32(1), record { i32(2), i32(3) }, string("hello") }
```

If we want the stack to contain an intermediate record, we should have something like this:

```
[stack]
i32(1)
i32(2)
i32(3)
record.lift <record_type_2>
string("hello")
record.lift <record_type_1>
```

But it would imply that `record_type_1` is defined as `record (field i32) (record (type record_type_2)) (field i32)`.

A sub-record defined by another record type isn't support, as it is not specified in the draft. I believe my assumption is fine enough for a first implementation of records in WIT.

### To do

- [x] Encode and decode record type (`(@interface type (record string i32))`):
  - [x] Binary encoder/decoder
  - [x] WAT encoder/decoder
- [x] Implement the `record.lift` instruction
- [x] Implement the `record.lower` instruction
- [x] Test
- [x] Documentation
- [x] Surprise!
  - [x] Serialize a Rust value to WIT values (useful for `record`s)
  - [x] Deserialize WIT values to a Rust value (useful for `record`s)

Co-authored-by: Ivan Enderlin <ivan.enderlin@hoa-project.net>
2020-04-06 06:17:45 +00:00
9f10b7ae50 doc(interface-types) Update from_interface_values's doc.
Using `InterfaceValue::Record` explicitely doesn't change anything
since values are flatten, but it's better for a usual reading to avoid
confusion.
2020-04-06 08:13:10 +02:00
27053d5ca6 doc(interface-types) Rewrite record_lift_ documentation. 2020-04-06 08:09:10 +02:00
c2b1b87f9a feat(interface-types) Use VecDeque to remove unsafe code. 2020-04-06 07:55:56 +02:00
4faf827dc9 feat(interface-types) Avoid clones by using owned items in an iterator.
`into_iter` owned the item, so no need to clone when moving them in
the stack.
2020-04-06 07:54:51 +02:00
4ad3d7f123 doc(interface-types) Explain a part of an algorithm. 2020-04-04 08:10:38 +02:00
dfa6247075 Move spectests, wrap up test restructure 2020-04-03 14:24:40 -07:00
5119b6a58f feat(interface-types) Simplify FlattenInterfaceValueIterator with last_mut. 2020-04-03 16:22:26 +02:00
e4921bd496 feat(interface-types) Use Vec::last_mut to simplify code. 2020-04-03 16:20:22 +02:00
398d791c9f fix(interface-types) Also apply another lazy evaluation in the deserializer. 2020-04-03 16:19:07 +02:00
e160feb99a fix(interface-types) Use lazy evaluation in the deserializer. 2020-04-03 16:18:24 +02:00
d186142507 doc(interface-types) Fix a typo. 2020-04-03 16:16:53 +02:00
3159da5bfe feat(interface-types) Add the Vec1 type to represent a non-empty vector.
`Vec1` is used by `RecordType` to ensure that a record have at least 1
field. Then an `InterfaceValue::Record` is ensured to get at least one
value with the type-checking pass.
2020-04-03 16:13:44 +02:00
6cef1c244a doc(interface-types) Fix typos. 2020-04-03 14:46:59 +02:00
513e6acbc1 Move emscripten-tests to tests dir + misc fixes 2020-04-02 16:51:58 -07:00
1833af7eba Merge #1350
1350: update blake3 to 0.3.1 r=syrusakbary a=oconnor663

Version 0.3.0 caused problems because it required a C compiler with
AVX-512 support, which broke Android x86 cross-compilation. Version
0.3.1 automatically falls back to a pure Rust build when the C compiler
either doesn't exist or doesn't support the flags we need.

Co-authored-by: Jack O'Connor <oconnor663@gmail.com>
2020-04-02 15:11:41 +00:00
aca0bd11c0 update blake3 to 0.3.1
Version 0.3.0 caused problems because it required a C compiler with
AVX-512 support, which broke Android x86 cross-compilation. Version
0.3.1 automatically falls back to a pure Rust build when the C compiler
either doesn't exist or doesn't support the flags we need.
2020-04-02 11:02:49 -04:00
2011fda31d chore(interface-types) Split the serde module…
… into `serde/ser.rs` and `serde/de.rs`. I like smaller files.
2020-04-02 16:46:23 +02:00
be66ac8aa4 doc(interface-types) Improve serde module documentation. 2020-04-02 16:41:03 +02:00
e385bf66c7 feat(interface-types) Make unwraps safe by introducing more errors. 2020-04-02 16:38:40 +02:00
b0af014339 doc(interface-types) Update an example. 2020-04-02 16:29:52 +02:00
ee0596d2c3 feat(interface-types) Restrict supported type in the Deserializer.
`seq`, `map` and `tuple` for instance are not supported officially. It
was fun to play with it at the beginning, but it is time to remove it
to match the `Serializer` implementation.
2020-04-02 16:26:24 +02:00
d6f7e3ff02 doc(interface-types) Describe to_interface_value. 2020-04-02 15:59:07 +02:00
f9832fecaf feat(interface-types) Implement a serializer for WIT values. 2020-04-02 15:54:39 +02:00
8868d640fa feat(interface-types) Rename from_values to from_interface_values. 2020-04-02 13:56:20 +02:00
7b182416df feat(interface-types) Make serde optional behind a feature flag. 2020-04-02 13:53:10 +02:00
f8507533fb fix(interface-types) Fix a git-merge issue. 2020-04-02 12:16:30 +02:00
bac56a6e0b Merge branch 'master' into feat-interface-types-record-instructions 2020-04-02 12:10:01 +02:00
8f8c5f1bc8 chore(interface-types) Improve code readabilit of the record.lift instruction. 2020-04-02 12:06:54 +02:00
0023eea275 feat(interface-types) Implement the record.lower instruction. 2020-04-02 12:06:27 +02:00