Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions design/mvp/Binary.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ defvaltype ::= pvt:<primvaltype> => pvt
| 0x68 i:<typeidx> => (borrow i)
| 0x66 t?:<valtype>? => (stream t?) 🔀
| 0x65 t?:<valtype>? => (future t?) 🔀
| 0x63 k:<valtype> v:<valtype> => (map k v) (if k is in <keytype>) 🗺️
labelvaltype ::= l:<label'> t:<valtype> => l t
case ::= l:<label'> t?:<valtype>? 0x00 => (case l t?)
label' ::= len:<u32> l:<label> => l (if len = |l|)
Expand Down
1 change: 1 addition & 0 deletions design/mvp/CanonicalABI.md
Original file line number Diff line number Diff line change
Expand Up @@ -1961,6 +1961,7 @@ def despecialize(t):
case EnumType(labels) : return VariantType([ CaseType(l, None) for l in labels ])
case OptionType(t) : return VariantType([ CaseType("none", None), CaseType("some", t) ])
case ResultType(ok, err) : return VariantType([ CaseType("ok", ok), CaseType("error", err) ])
case MapType(k, v) : return ListType(despecialize(TupleType([k, v])))
case _ : return t
```
The specialized value types `string` and `flags` are missing from this list
Expand Down
15 changes: 15 additions & 0 deletions design/mvp/Explainer.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ implemented, considered stable and included in a future milestone:
* 📝: the `error-context` type
* 🔗: canonical interface names
* 🐘: [memory64]
* 🗺️: the `map` type

(Based on the previous [scoping and layering] proposal to the WebAssembly CG,
this repo merges and supersedes the [module-linking] and [interface-types]
Expand Down Expand Up @@ -563,12 +564,14 @@ defvaltype ::= bool
| (enum "<label>"+)
| (option <valtype>)
| (result <valtype>? (error <valtype>)?)
| (map <keytype> <valtype>) 🗺️
| (own <typeidx>)
| (borrow <typeidx>)
| (stream <valtype>?) 🔀
| (future <valtype>?) 🔀
valtype ::= <typeidx>
| <defvaltype>
keytype ::= bool | s8 | u8 | s16 | u16 | s32 | u32 | s64 | u64 | char | string 🗺️
resourcetype ::= (resource (rep i32) (dtor <funcidx>)?)
| (resource (rep i32) (dtor async <funcidx> (callback <funcidx>)?)?) 🚝
| (resource (rep i64) (dtor <funcidx>)?) 🐘
Expand Down Expand Up @@ -772,6 +775,7 @@ defined by the following mapping:
(option <valtype>) ↦ (variant (case "none") (case "some" <valtype>))
(result <valtype>? (error <valtype>)?) ↦ (variant (case "ok" <valtype>?) (case "error" <valtype>?))
string ↦ (list char)
(map <keytype> <valtype>) ↦ (list (tuple <keytype> <valtype>))
```

Specialized value types have the same set of semantic values as their
Expand All @@ -787,6 +791,16 @@ this can sometimes allow values to be represented differently. For example,
`flags` in the Canonical ABI uses a bit-vector while an equivalent record
of boolean fields uses a sequence of boolean-valued bytes.

Since a `map` is a specialization of a list of (key, value) pairs without any
additional semantic guarantee of key uniqueness or ordering, the Component Model
does not prevent duplicate keys from appearing in the list. Bindings generators
*may* deduplicate and reorder keys as long as the *last* (key, value) pair in the
original list defines the final value of the key. However, bindings generators
are not *required* to deduplicate keys and may instead simply present the
original list to guest code. To simplify bindings generation, `<keytype>` is a
conservative subset of `<valtype>`, but this subset could be expanded over time
based on use cases.

Note that, at least initially, variants must have a non-empty list of
cases. This could be relaxed in the future to allow an empty list of cases, with
the empty `(variant)` effectively serving as an [empty type] and indicating
Expand Down Expand Up @@ -3045,6 +3059,7 @@ At a high level, the additional coercions would be:
| `enum` | same as [`enum`] | same as [`enum`] |
| `option` | same as [`T?`] | same as [`T?`] |
| `result` | same as `variant`, but coerce a top-level `error` return value to a thrown exception | same as `variant`, but coerce uncaught exceptions to top-level `error` return values |
| `map` | `new Map(_)` | `Map`s directly or other objects via `Object.entries(_)` |
Comment thread
lukewagner marked this conversation as resolved.
| `own`, `borrow` | see below | see below |
| `future` | to a `Promise` | from a `Promise` |
| `stream` | to a `ReadableStream` | from a `ReadableStream` |
Expand Down
12 changes: 12 additions & 0 deletions design/mvp/WIT.md
Original file line number Diff line number Diff line change
Expand Up @@ -1021,6 +1021,7 @@ keyword ::= 'as'
| 'include'
| 'interface'
| 'list'
| 'map'
| 'option'
| 'own'
| 'package'
Expand Down Expand Up @@ -1715,6 +1716,7 @@ ty ::= 'u8' | 'u16' | 'u32' | 'u64'
| list
| option
| result
| map
| handle
| future
| stream
Expand All @@ -1736,6 +1738,11 @@ result ::= 'result' '<' ty ',' ty '>'
| 'result' '<' ty '>'
| 'result'

map ::= 'map' '<' kt ',' ty '>'
kt ::= 'u8' | 'u16' | 'u32' | 'u64'
| 's8' | 's16' | 's32' | 's64'
| 'char' | 'bool' | 'string'

future ::= 'future' '<' ty '>'
| 'future'

Expand Down Expand Up @@ -1775,6 +1782,11 @@ variant result {
These types are so frequently used and frequently have language-specific
meanings though so they're also provided as first-class types.

🗺️ The `map` type is semantically equivalent to a list of pairs of keys and
values but is meant to be represented by bindings generators in the source
language as a mapping from keys to values (e.g., as an associative array or or
hash table) where, in the case of duplicate keys, the last key's value is used.

The `future` and `stream` types are described as part of the [concurrency
explainer](Concurrency.md#streams-and-futures).

Expand Down
6 changes: 6 additions & 0 deletions design/mvp/canonical-abi/definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,11 @@ class ResultType(ValType):
ok: Optional[ValType]
error: Optional[ValType]

@dataclass
class MapType(ValType):
k: ValType # <keytype>
v: ValType

@dataclass
class FlagsType(ValType):
labels: list[str]
Expand Down Expand Up @@ -1082,6 +1087,7 @@ def despecialize(t):
case EnumType(labels) : return VariantType([ CaseType(l, None) for l in labels ])
case OptionType(t) : return VariantType([ CaseType("none", None), CaseType("some", t) ])
case ResultType(ok, err) : return VariantType([ CaseType("ok", ok), CaseType("error", err) ])
case MapType(k, v) : return ListType(despecialize(TupleType([k, v])))
case _ : return t

## Type Predicates
Expand Down
4 changes: 3 additions & 1 deletion design/mvp/canonical-abi/run_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,9 @@ def test_heap(t, expect, args, byte_array, addr_type='i32'):
v = [{ str(i):b for i in range(32) } for b in [True,False]]
test_heap(t, v, [0,2],
[0xff,0xff,0xff,0xff, 0,0,0,0])

t = MapType(U8Type(), U16Type())
test_heap(t, [{'0':42, '1':83}, {'0':43, '1':84}], [0, 2],
[42,0xff,83,0, 43,0xff,84,0])

def test_flatten(t, params, results, addr_type='i32'):
opts = mk_opts(MemInst(bytearray(), addr_type))
Expand Down
Loading