#language #format #verilization #api-bindings #file-format #description #data

verilization-bindings-c-api-core

排除语言限制的 C API,允许添加额外的语言

1 个不稳定版本

0.1.0 2021年5月6日

#686 in WebAssembly

GPL-3.0-only

110KB
2.5K SLoC

Verilization

Verilization 是一种用于定义二进制文件格式的序列化描述语言。与 Protocol Buffers 等其他序列化工具不同,序列化的 Verilization 数据不具备向前或向后兼容性。相反,它使得从旧格式版本进行转换变得容易,从而允许数据更加紧凑,并能够更好地控制数据的底层形状。

目标

Verilization 具有以下主要目标。

  • 赋予用户对文件格式的最大控制权
  • 以语言无关的方式定义格式
  • 支持从旧版本格式轻松转换

其他更低层次的目标。

  • 支持大整型类型
  • 可以在其他语言中使用而不需要使用本地二进制文件

类型

以下类型得到支持。

类型 编码
struct 类型 按顺序编码每个字段
enum 类型 一个标签(使用与 nat 相同的格式编码)后跟由标签表示的字段的编码
extern 类型 由目标语言编写的代码定义

结构体

使用多个 版本 定义 struct 类型。每个版本定义一个字段列表。

struct Rectangle {
    version 1 {
        width: u32;
        height: u32;
    }
}

枚举

使用多个 版本 定义 enum 类型。每个版本定义一个用作情况的字段列表。枚举值恰好由这些字段中的一个组成。

struct StringOrInt {
    version 1 {
        str: string;
        num: int;
    }
}

外部

在用户代码中定义 extern 类型。类型定义、转换和编解码器必须在目标语言中实现。

extern 类型可以声明可用于该类型的文字。

extern MyString {
    literal {
        string;
    }
}

以下文字规范得到支持。

名称 示例 语法 注意
整数 integer [0, 256) 'integer'open_bracket integer_literal? ','integer_literal?close_bracket
其中 `open_bracket : '['
'('andclose_bracket : ']'
字符串 string 'string' 字符串的内容不能被限制。
序列 序列T '序列'类型表达式 定义特定类型的序列。
情况 情况 正数() '情况'标识符'(' [类型表达式{ ','类型表达式} ] ')' 定义一个情况。如果名称不同,可以指定多个情况字面量。
记录 记录{a:A;b:B; } '记录' '{' {标识符':'类型表达式';' } '}' 定义一个记录。

运行时库类型

运行时库提供了一些 extern 类型。

类型 字面量 编码
{i,u}{8,16,32,64} 类型范围内的整数 小端顺序的字节固定宽序列
int 整数 可变长格式
nat 非负整数 int 相似的格式,但没有符号位
string 字符串 长度为 nat,后跟指定长度的 UTF-8 字节序列
list T T 的序列 长度为 nat,后跟一个 T 序列
option T 两种情况 some(x)none() 一个字节 b。如果 b 非零,则其后跟一个 T

intnat 的编码定义了一个小端顺序的位序列。如果每个字节中还有更多的字节,则每个字节的最高位被设置。

此编码是字节序列 [B0, ..., Bn],其中当 i < n 时 Bi,7 = 1,且 Bn,7 = 0。这个字节序列等效于一个位序列 [B0,0, ... B0,6, ..., Bn-1,0, ..., Bn-1,6] = [b0, ..., bm-1],其中 m = 6n。本质上,位序列去除了用于确定序列何时结束的标志位,并将每个字节的剩余位从最低到最高排序。位序列映射如下

  • 对于 int 类型,如果 bm-1 = 0,则 k = b0 * 20 + ... + bm - 2 * 2m-2
  • 对于 int 类型,如果 bm-1 = 1,则 k = -(b0 * 20 + ... + bm - 2 * 2m-2) - 1
  • 对于 nat 类型,k = b0 * 20 + ... + bm - 1 * 2m-1

版本控制

在以下示例中,用户有一个用户名和出生日期。

struct Person {
    version 1 {
        name: Name;
        dob: Date;
    }
}

struct Name {
    version 1 {
        firstName: string;
        middleName: option string;
        lastName: string;
    }
}

但是,并非每个人都有 2 或 3 个名字。为了适应这种情况,我们可以创建一个新的版本,允许任意数量的名字。

struct Name {
    version 1 {
        ...
    }
    version 2 {
        names: list string;
    }
}

Name 的此更改意味着在格式的版本 2 中,Personname 字段将现在使用 Name 的版本 2。然而,由于 Person 没有直接更改,版本 2 是自动创建的。在生成的代码中,预期用户将提供可以将 Name 从版本 1 升级到版本 2 的代码。然而,没有必要为升级 Person 提供这样的代码。Person 可以使用其字段的升级代码自动升级。

最终

版本化类型可以被声明为final,以表示不再添加该类型的新版本。这限制了类型到最后一个明确声明的版本,防止自动生成新版本。最终类型可能只包括最终类型或非版本化类型的字段。

final struct FormatVersion {
    version 1 {
        major: nat;
    }
}

泛型

泛型类型允许类型进行参数化。

final struct Pair(A, B) {
    version 1 {
        left: A;
        right: B;
    }
}

常量

常量允许定义在生成的任何语言之间共享的值。

字面量 示例 用法
整数 88 extern类型与integer字面量
字符串 "Hello World" extern类型与string字面量
序列 [a,b,c] extern类型与sequence字面量
记录 {x= 1;y= 2; } struct类型和extern类型与record字面量
情况 名称(a) enum类型和extern类型与case Name字面量

命令行

Verilization具有命令行界面。以下选项受到支持。

语言生成器

以下语言受到支持。

编译器绑定

Verilization编译器是用Rust编写的。它可以编译成WebAssembly以在其他语言中使用。这具有优势,即工具可以分发(例如,作为NPM包、独立JAR等),而无需任何本地二进制文件。这些绑定公开了一个可以直接从运行时使用的接口,以及一个仅依赖于相关运行时的命令行界面。

目前,以下运行时存在绑定。

  • Node

lib.rs:

定义用于绑定的C API。最值得注意的是用于WebAssembly。

依赖关系

~2.5MB
~56K SLoC