1 个不稳定版本
0.1.0 | 2022年7月6日 |
---|
#1028 in 数据结构
在 sidex-cli 中使用
6KB
Sidex
Sidex 是一种格式和语言无关的数据结构和API定义语言,注重简洁、可扩展性和开发者的人体工程学。Sidex旨在通过多种可能的序列化格式简化不同编程语言和平台之间的数据交换。
🚧 状态:尽管我们已经在生产中使用Sidex,但它仍然是 实验性的。请自行承担风险!
✨ 特性
- 基于模式 的数据结构和RPC-like API的定义。
- 专为 格式和语言无关 的定义设计。
- 现代 代数数据类型 和默认 非空。
- 通过用户定义的不透明类型进行 可扩展。
- 为 互操作性 设计,例如与JSON Schema。
- VS Code扩展以提高生产力。
- 默认支持Rust、TypeScript 和 JSON。
🚀 入门
Sidex目前通过Cargo 和 crates.io 分发。要安装Sidex,请运行
cargo install sidex-cli
然后,要创建一个名为 my_def
的新Sidex定义,请运行
sidex new my_def
每个Sidex定义都由位于 modules
目录中的平面集合的 模块 组成。以下是一个简单的模块示例,您可以将该模块放置在文件 person.sidex
中
opaque Uuid // This is an opaque user-defined type.
alias PersonId: Uuid // This is a type alias.
enum Role {
Admin,
User,
}
struct Person {
id: PersonId,
name: string,
email?: string, // This field is optional.
role: Role,
children: [PersonId], // A sequence of person ids.
}
enum GetPersonResult {
NotFound,
Found: Person,
}
fun get_person_by_id(id: PersonId) -> GetPersonResult
要检查定义的有效性,请运行
sidex check
请参阅食谱以获取如何使用Sidex的更多示例。
⚙️ Sidex语言
Sidex的核心是用于定义数据类型和函数类型的Sidex语言。
Sidex的核心仅关注此类类型,而不关注其他类型。
📦 数据类型
Sidex基于五种类型的 数据类型
-
不透明类型 对Sidex来说是透明的,即它们的内部结构是一个黑盒。
不透明类型使用
opaque
关键字定义。不透明类型是名义类型,即单独定义的不透明类型总是不同的,即使它们具有相同的名称。 -
枚举类型定义了具有不同类型标记变体的联合。
枚举类型使用
enum
关键字定义。枚举类型是名义类型,即单独定义的枚举类型总是不同的,即使它们的所有变体都相同。 -
结构类型定义了具有不同类型标记字段的记录。
结构类型使用
struct
关键字定义。结构类型是名义类型,即单独定义的结构类型总是不同的,即使它们的所有字段都相同。 -
序列类型定义了相同类型元素的序列。
序列类型通过
[T]
创建,其中T
表示元素类型。序列类型是结构类型,即具有相同元素类型的两个序列类型是相同的。 -
映射类型定义了从某些类型的键到某些类型的值的映射。
映射类型通过
[K: V]
创建,其中K
表示键类型,V
表示值类型。映射类型是结构类型,即具有相同键和值类型的两个映射类型是相同的。
Sidex提供了内置的字符串、整数和布尔值原始类型。技术上,这些原始类型与用户定义的不透明类型没有区别。这些原始类型包括
string
:用于Unicode码点的序列。i8
、i16
、i32
、i64
:用于不同位宽的有符号整数。u8
、u16
、u32
、u64
:用于不同位宽的无符号整数。bool
:用于布尔值。
此外,还有用于表示没有数据的void
类型。
使用不透明类型,您可以定义自己的原始类型,例如用于UUIDs
opaque Uuid
不透明类型的结构可以外部指定,例如使用JSON Schema。
📡 函数类型
受RPC和FFI的启发,Sidex允许使用fun
关键字定义函数类型。每个函数类型由一系列具有各自类型的命名参数和一个返回类型组成。在核心上,Sidex不预设任何调用此类函数的协议或其他机制。
🤝 数据交换
数据交换可能相当复杂,涉及多个关注点,而Sidex旨在将这些关注点分离。
📜 语言映射
为了有用,Sidex的定义需要映射到某些编程语言的类型或类定义,例如Rust或TypeScript。我们将此类映射称为语言映射。
┌──────────────────┐ Language Mapping ┌─────────────────┐
│ Sidex Definition │ ────────────────────► │ Target Language │
└──────────────────┘ └─────────────────┘
请注意,语言映射可能需要做出一些权衡。例如,在 TypeScript 的情况下,映射类型可以是 Object
或 Map
,而在 Rust 中,也有多种不同的映射类型可用,例如 HashMap
或 BTreeMap
。此外,根据语言的不同,某些数据类型可能由于语言特定的限制而无法映射。
因此,Sidex 项目的目标是提供工具和基础设施,以便将 Sidex 定义映射到不同的编程语言,而不强加任何特定的映射。使用 sidex
crate 作为基础,您可以定义自己的映射,甚至生成额外的样板代码,如构造函数和获取器。如果某些内容无法合理映射,工具可以生成错误作为最后的手段。
Sidex 旨在提供一些语言的默认映射。
请注意,语言映射本身完全独立于数据的序列化和函数的调用方式。它也可以在不交换任何数据的情况下有用。
📩 序列化格式
要在不同语言之间交换数据,需要将其 序列化 到某种通用格式。为此,需要一个从 Sidex 定义到序列化格式的 格式映射。
┌──────────────────┐ Format Mapping ┌──────────────────────┐
│ Sidex Definition │ ──────────────────► │ Serialization Format │
└──────────────────┘ └──────────────────────┘
请注意,格式映射应该是语言无关的。它仅描述了某些 Sidex 类型如何映射到序列化格式及其类型。
同样,Sidex 对序列化格式没有任何限制,但是它旨在提供一些常用格式的默认映射。
对于用户定义的不透明类型,必须提供特定的格式映射。
🔗 序列化绑定
一旦我们确定了一个语言映射和一个格式映射,我们需要使用 序列化绑定 将它们绑定在一起。序列化绑定是语言特定的,也是格式特定的。它根据格式映射接收序列化数据,并将其转换为根据语言映射的数据结构(称为 反序列化),反之亦然(称为 序列化)。
🤔 原因
为什么是模式优先?
模式优先方法相对于编程语言中的定义具有多个优势:(1) 它允许关注数据交换的重要方面。(2) 它允许开发与任何编程语言无关的工具。(3) 它使定义语言的独立演化和适应成为可能。(4) 它可以独立于特定的编程语言使用。
为什么还需要另一种语言?
现有的方法通常特定于某些序列化格式,不支持代数数据类型,不支持任意用户定义的不透明类型,默认有可空字段,或者过于复杂,支持比 Sidex 更多结构和类型。
⚖️ 许可
Sidex 在 MIT 许可下发布。除非您明确声明,否则,提交给此项目的任何有意贡献都应按 MIT 许可发布,不附加任何其他条款或条件。
由 Silitics 用 ❤️ 制作。
依赖关系
~1.3–2MB
~42K SLoC