11个重大版本发布

0.216.0 2024年8月22日
0.215.0 2024年7月31日
0.214.0 2024年7月16日
0.5.1 2024年2月24日
0.3.0 2023年10月2日

#84 in WebAssembly

Download history 206/week @ 2024-05-03 210/week @ 2024-05-10 113/week @ 2024-05-17 203/week @ 2024-05-24 256/week @ 2024-05-31 187/week @ 2024-06-07 377/week @ 2024-06-14 468/week @ 2024-06-21 372/week @ 2024-06-28 429/week @ 2024-07-05 591/week @ 2024-07-12 156/week @ 2024-07-19 500/week @ 2024-07-26 230/week @ 2024-08-02 467/week @ 2024-08-09 713/week @ 2024-08-16

1,970 每月下载量
用于 8 个库(直接使用5个)

Apache-2.0…

265KB
6K SLoC

WAVE:Web Assembly值编码

WAVE是WebAssembly组件模型值的面向人类文本编码。它旨在与WIT IDL格式保持一致。

类型 示例值
布尔值 truefalse
整数 123, -9
浮点数 3.146.022e+23nan-inf
字符 'x''☃︎''\'''\u{0}'
字符串 "abc\t123"
元组 ("abc", 123)
列表 [1, 2, 3]
记录 {字段-a: 1,字段-b: "two"}
变体 days(30)forever
枚举 southwest
选项 "flat some"some("explicit some")none
结果 "flat ok"ok("explicit ok")err("oops")
标志 {read, write}{}

用法

use wasmtime::component::{Type, Val};

let val: Val = wasm_wave::from_str(&Type::String, "\"👋 Hello, world! 👋\"").unwrap();
println!("{}", wasm_wave::to_string(&val).unwrap());

"👋 Hello, world! 👋"

编码

值以 Unicode 文本编码。在需要互操作二进制编码的地方应使用 UTF-8。

空白符

空白符在标记之间是无意义的,在标记内部是有意义的:关键字、标签、字符和字符串。

注释

注释从 // 开始,直到行尾。

关键字

一些标记是 WAVE 关键字:truefalseinfnansomenoneokerr。与这些关键字匹配的变体或枚举情况必须以 % 前缀。

标签

用于记录字段、变体情况、枚举情况和标志的标签使用破折号大小写。标签使用 ASCII 字母数字字符和破折号,遵循Wit 标识符语法

  • 标签由一个或多个破折号分隔的单词组成。
    • onetwo-words
  • 单词由一个 ASCII 字母后跟任意数量的 ASCII 字母数字字符组成。
    • qabc123
  • 每个单词可以包含小写或大写字母,但不能同时包含;标签中的每个单词可以使用不同的(单个)大小写。
    • HTTP3method-GET
  • 任何标签都可以用 % 前缀;这不是标签本身的一部分,但允许表示其他情况下会被解析为关键字的标签。
    • %err%non-keyword

布尔值

布尔值以关键字 falsetrue 之一编码。

整数

整数以十进制数字编码。

待定:十六进制/二进制表示?例如 0xab0b1011

浮点数

浮点数以 JSON 数字编码,或以关键字 nan(不是一个数字)、inf(无穷大)或 -inf(负无穷大)之一编码。

字符

字符编码为 '<char>',其中 <char> 是以下之一

  • 单个 Unicode 标量值
  • 以下转义序列之一
    • \''
    • \""
    • \\\
    • \t → U+9 (水平制表符)
    • \n → U+A (换行符)
    • \r → U+D (回车符)
    • \u{···} → U+··· (其中 ··· 是十六进制的 Unicode 标量值)

转义换行符 (\n)、\' 对字符是强制性的。

字符串

字符串编码为双引号分隔的 <char> 序列(与字符相同)。

转义换行符 (\n)、\" 对字符串是强制性的。

多行字符串

多行字符串以一个双引号 """ 开头,紧随其后的是一个换行符(\n\r\n),并以换行符、零个或多个空格以及 """ 结尾。紧随结尾双引号之前的空格数决定了整个多行字符串的缩进级别。字符串中的每个其他换行符都必须至少跟这么多空格,然后从解码字符串中省略这些空格(即“缩进”)。

编码字符串中除了第一行和最后一行之外的每行换行符都被解码为换行符(\n)。

对多行字符串转义 \ 是强制性的。转义回车符(\r)在保留时必须立即在字面换行符(\n)之前进行。必要时转义 " 是强制性的,即使在字符串的第一个双引号被转义的情况下(即不允许 \""")。

"""
A single line
"""

"A single line"

"""
    Indentation determined
      by ending delimiter
  """

"  Indentation determined\n    by ending delimiter"
"""
  Must escape carriage return at end of line: \r
  Must break up double quote triplets: ""\""
  """

"Must escape carriage return at end of line: \r\nMust break up double quote triplets: \"\"\"\""

元组

元组编码为逗号分隔的值序列,允许尾随逗号。

tuple<u8, string>(123, "abc")

列表

列表以逗号分隔的方括号序列进行编码。允许尾部有逗号。

list<char>[]['a', 'b', 'c']

记录

记录以逗号分隔的记录条目集合进行编码,允许尾部有逗号。每个记录条目由字段标签、冒号和值组成。字段可以按任意顺序出现。具有 option 类型的值 none 的记录条目可以省略;如果记录的所有字段都以此方式省略,则“空”记录必须编码为 {:}(以区分空 flags 值)。

record example {
  must-have: u8,
  optional: option<u8>,
}

{must-have: 123} = {must-have: 123, optional: none,}

record all-optional {
  optional: option<u8>,
}

{:} = {optional: none}

注意:字段标签 可能% 为前缀,但这不是必需的。

变体

变体以情况标签进行编码。如果情况有有效负载,标签后跟括号中的情况有效负载值。

如果变体情况匹配 WAVE 关键字,它必须以 % 为前缀。

variant response {
  empty,
  body(list<u8>),
  err(string),
}

emptybody([79, 75])%err("oops")

枚举

枚举以情况标签进行编码。

如果枚举情况匹配 WAVE 关键字,它必须以 % 为前缀。

enum status { ok, not-found }%oknot-found

选项

选项可能以变体形式编码(例如 some(...)none)。一个 some 值也可以编码为“扁平”有效载荷值本身,但仅当有效载荷不是选项或结果类型时。

  • option<u8>123 = some(123)

结果

结果可以以它们的变体形式编码(例如 ok(...)err("oops"))。一个 ok 值也可以编码为“扁平”有效载荷值本身,但仅当它具有不是选项或结果类型的有效载荷时。

  • result<u8>123 = ok(123)
  • result<_, string>okerr("oops")
  • resultokerr

标志

标志可以编码为任何顺序的逗号分隔的标志标签的括号集合。允许尾部逗号。

flags perms { read, write, exec }{write, read,}

注意:标志 可能 可以用 % 前缀,但这不是必需的。

TBD:允许记录形式? {read: true, write: true, exec: false}

资源

TBD (<named-type>(<idx>)?)

附录:函数调用

某些应用程序可能受益于一种标准方式来编码函数调用和/或结果,如下所述。

函数调用可以编码为某些应用程序相关的函数标识符(如短横线命名标签)后跟括号中的函数参数。

如果需要将函数结果与调用一起编码,可以使用 -> 将其与调用分开。

my-func("param")
    
with-result() -> ok("result")

函数参数

参数编码为逗号分隔值的序列。

序列末尾可以有任意数量的 option none 值,可以省略。

// f: func(a: option<u8>, b: option<u8>, c: option<u8>)
// all equivalent:
f(some(1))
f(some(1), none)
f(some(1), none, none)

待定:命名参数编码?例如:my-func(named-param: 1) 可能允许省略 "中间" none 参数。

函数结果

结果以多种方式之一进行编码,具体取决于结果值的数量

  • 任意数量的结果值都可以编码为逗号分隔的结果条目括号序列。每个结果条目由一个标签(用于命名结果)或基于零的索引号、一个冒号和结果值组成。结果条目顺序必须与函数定义匹配。
  • 零个结果值可以编码为 () 或完全省略。
  • 单个结果值可以编码为 "扁平" 的结果值本身。
-> ()

-> some("single result")
// or
-> (0: some("single result"))
    
-> (result-a: "abc", result-b: 123)

🌊

依赖

~3MB
~34K SLoC