moonthrift

    Apache Thrift IDL tooling and binary protocol support for MoonBit

    thrift
    serialization
    idl
    code-generation
    rpc
    Download zip
    Author
    Version
    0.1.0
    License
    Apache-2.0
    Last updated
    21 hours ago
    Downloads
    19

    Dependencies

    #MoonThrift

    CI Mooncakes License

    MoonThrift 是一个用 MoonBit 编写的 Apache Thrift 基础工具库。它把 Thrift IDL 解析、语义检查、协议编解码、代码生成和接口兼容性检查放在同一套可复用 API 中,可用于构建 RPC 运行时、协议调试工具、Schema 仓库和数据迁移流程。

    项目当前聚焦与网络框架无关的核心能力,不绑定某一种 HTTP、Socket 或异步 运行时,因此库和测试可在 MoonBit 的 wasm、wasm-gc、JavaScript、native 四个 稳定后端运行;文件读写只放在 native CLI 中。

    #已实现功能

    • Thrift IDL lexer、带行列位置的 token 与错误信息;
    • 解析 includenamespaceconsttypedefenumstruct unionexceptionservicethrows、容器类型和 annotations;
    • 检查重复定义、未解析类型、字段 ID/名称冲突、union required 字段、 oneway 约束和 service 继承;
    • 动态 Thrift 值模型,无需先生成代码即可检查协议数据;
    • 标准 Binary Protocol 和 Compact Protocol 的值、容器、结构体编解码;
    • Binary/Compact RPC message envelope 编解码;
    • 深度、容器元素数、二进制长度限制,畸形输入以明确错误返回;
    • 从 Thrift Schema 生成 MoonBit typedef、enum、struct、union、exception 以及 service 的参数/结果模型;
    • 按稳定字段 ID、枚举数值、方法名比较两个版本,区分 compatible、warning、 breaking 变更;
    • checkinspectgeneratediff 四个 CLI 工作流。

    #快速开始

    安装依赖:

    moon add Xpeng/moonthrift

    解析和检查 IDL:

    let idl =
    #|struct User {
    #| 1: required i64 id,
    #| 2: optional string name
    #|}
    #|

    let (schema, diagnostics) = @moonthrift.compile_idl(idl)
    assert_eq(schema.definitions.length(), 1)
    assert_eq(diagnostics, [])

    动态值可以在不依赖生成代码的情况下经过两种协议往返:

    let value : @protocol.Value = StructValue([
    { id: 1, value: I64Value(7L) },
    { id: 2, value: BinaryValue(b"MoonBit") },
    ])

    let binary = @protocol.encode_binary(value)
    assert_eq(@protocol.decode_binary(binary, Struct), value)

    let compact = @protocol.encode_compact(value)
    assert_eq(@protocol.decode_compact(compact, Struct), value)

    对应的 moon.pkg

    import {
    "Xpeng/moonthrift",
    "Xpeng/moonthrift/protocol",
    }

    #CLI 示例

    仓库提供了可直接运行的 tutorial.thrift

    # 内置解析与 Compact Protocol 往返示例 moon run cmd/main --target native # 语法与语义检查 moon run cmd/main --target native -- check examples/tutorial.thrift # 查看 Schema 轮廓 moon run cmd/main --target native -- inspect examples/tutorial.thrift # 生成 MoonBit 数据模型 moon run cmd/main --target native -- generate examples/tutorial.thrift generated.mbt # 比较两个 Schema 版本;发现 breaking change 时退出码为 3 moon run cmd/main --target native -- diff \ examples/tutorial.thrift examples/tutorial-v2.thrift

    examples/generated/model.mbt 是由示例 IDL 生成并 纳入四后端编译测试的结果,防止生成器只“输出文本”却无法被 MoonBit 使用。

    #包结构

    用途
    Xpeng/moonthriftIDL AST、解析、语义检查、兼容性比较
    Xpeng/moonthrift/protocol动态值、Binary/Compact codec、RPC message
    Xpeng/moonthrift/codegenMoonBit 源码生成器
    cmd/mainnative 文件与命令行适配层

    详细数据流、功能边界和维护方向见 docs/architecture.md,协议实现与安全限制见 docs/protocols.md,复现测试的方法见 docs/verification.md

    #当前边界

    0.1.0 不包含 socket transport、服务端调度、TLS、连接池以及其他语言生成器。 这些能力依赖具体运行时策略,后续可以作为独立包建立在当前 AST、生成器和 codec 之上。跨文件 include 的磁盘定位也留给调用者;带命名空间的引用会保留在 AST 中,单文件检查不会把它误报成未定义类型。

    #质量与开源说明

    CI 会检查格式、公开接口漂移、四后端 check/build/test、CLI 示例、生成结果、 package artifact 和工作区洁净度。项目为原创 MoonBit 实现,兼容行为参考 Apache Thrift 公开规范,没有复制上游源码;来源和许可证说明见 THIRD_PARTY.md

    参与方式见 CONTRIBUTING.md,安全问题请按 SECURITY.md 私下报告。本项目采用 Apache-2.0 许可证。

    IdlError

    pub(all) suberror IdlError {
    UnexpectedCharacter(Char, Span)
    UnterminatedString(Span)
    UnterminatedComment(Span)
    InvalidEscape(Char, Span)
    InvalidInteger(String, Span)
    UnexpectedToken(String, Span)
    UnexpectedEnd(Span)
    } derive(Eq,
    Debug
    )

    A fatal lexical or syntactic error.

    Annotation

    pub(all) struct Annotation {
    key : String
    value : String?
    } derive(Eq,
    Debug
    )

    One key/value annotation attached to an IDL item.

    BaseType

    pub(all) enum BaseType {
    Bool
    Byte
    I16
    I32
    I64
    Double
    String
    Binary
    Void
    } derive(Eq,
    Debug
    )

    Primitive types defined by the Thrift IDL.

    ChangeKind

    pub(all) enum ChangeKind {
    Compatible
    Warning
    Breaking
    } derive(Eq, ToJson,
    Debug
    )

    Compatibility classification for schema evolution.

    ConstValue

    pub(all) enum ConstValue {
    BoolValue(Bool)
    IntegerValue(Int64)
    DoubleValue(Double)
    StringValue(String)
    IdentifierValue(String)
    ListValue(Array[ConstValue])
    MapValue(Array[(ConstValue, ConstValue)])
    } derive(Eq,
    Debug
    )

    A constant expression accepted by Thrift IDL.

    Definition

    pub(all) enum Definition {
    Const(name~ : String, ty~ : TypeRef, value~ : ConstValue, span~ : Span)
    Typedef(name~ : String, target~ : TypeRef, annotations~ : Array[Annotation], span~ : Span)
    Enum(name~ : String, members~ : Array[EnumMember], annotations~ : Array[Annotation], span~ : Span)
    Struct(name~ : String, fields~ : Array[Field], annotations~ : Array[Annotation], span~ : Span)
    Union(name~ : String, fields~ : Array[Field], annotations~ : Array[Annotation], span~ : Span)
    Exception(name~ : String, fields~ : Array[Field], annotations~ : Array[Annotation], span~ : Span)
    Service(name~ : String, extends~ : String?, functions~ : Array[FunctionDef], annotations~ : Array[Annotation], span~ : Span)
    } derive(Eq,
    Debug
    )

    Definition::kind

    fn Definition::kind(self : Definition) -> String

    Definition::name

    fn Definition::name(self : Definition) -> String

    Diagnostic

    pub(all) struct Diagnostic {
    code : String
    severity : Severity
    message : String
    span : Span
    } derive(Eq, ToJson,
    Debug
    )

    A stable, source-aware diagnostic produced by parsing or validation.

    Diagnostic::to_text

    fn Diagnostic::to_text(self : Diagnostic) -> String

    EnumMember

    pub(all) struct EnumMember {
    name : String
    value : Int
    annotations : Array[Annotation]
    span : Span
    } derive(Eq,
    Debug
    )

    Field

    pub(all) struct Field {
    id : Int
    requiredness : Requiredness
    ty : TypeRef
    name : String
    default_value : ConstValue?
    annotations : Array[Annotation]
    span : Span
    } derive(Eq,
    Debug
    )

    A field in a struct, union, exception, function, or throws clause.

    FunctionDef

    pub(all) struct FunctionDef {
    name : String
    return_type : TypeRef
    arguments : Array[Field]
    throws : Array[Field]
    oneway : Bool
    annotations : Array[Annotation]
    span : Span
    } derive(Eq,
    Debug
    )

    pub(all) enum Header {
    Include(path~ : String, span~ : Span)
    Namespace(language~ : String, name~ : String, span~ : Span)
    CppInclude(path~ : String, span~ : Span)
    } derive(Eq,
    Debug
    )

    Requiredness

    pub(all) enum Requiredness {
    Default
    Required
    Optional
    } derive(Eq,
    Debug
    )

    Schema

    pub(all) struct Schema {
    source : String
    headers : Array[Header]
    definitions : Array[Definition]
    } derive(Eq,
    Debug
    )

    A parsed Thrift file. Semantic diagnostics are produced separately by check_schema so tools can still inspect a syntactically valid AST.

    Schema::to_outline

    fn Schema::to_outline(self : Schema) -> String

    Produces a compact human-readable schema outline for CLIs and build logs.

    SchemaChange

    pub(all) struct SchemaChange {
    code : String
    kind : ChangeKind
    path : String
    message : String
    } derive(Eq, ToJson,
    Debug
    )

    One stable schema-evolution finding.

    SchemaChange::to_text

    fn SchemaChange::to_text(self : SchemaChange) -> String

    Severity

    pub(all) enum Severity {
    Error
    Warning
    } derive(Eq, ToJson,
    Debug
    )

    Severity of a schema diagnostic.

    Span

    pub(all) struct Span {
    source : String
    start : Int
    end : Int
    line : Int
    column : Int
    } derive(Eq, ToJson,
    Debug
    )

    A half-open source range in a Thrift document.

    Span::synthetic

    fn Span::synthetic(source? : String) -> Span

    Creates a synthetic span for programmatically constructed declarations.

    Token

    pub(all) struct Token {
    kind : TokenKind
    span : Span
    } derive(Eq,
    Debug
    )

    One lexical token and its source location.

    Token::describe

    fn Token::describe(self : Token) -> String

    TokenKind

    pub(all) enum TokenKind {
    Identifier(String)
    StringLiteral(String)
    IntegerLiteral(Int64)
    FloatLiteral(Double)
    Symbol(Char)
    End
    } derive(Eq,
    Debug
    )

    Token kinds emitted by the Thrift IDL lexer.

    TypeRef

    pub(all) enum TypeRef {
    Base(BaseType)
    Named(String)
    List(TypeRef)
    Set(TypeRef)
    Map(TypeRef, TypeRef)
    } derive(Eq,
    Debug
    )

    A primitive, named, or container type reference.

    check_schema

    fn check_schema(schema : Schema) -> Array[Diagnostic]

    Performs deterministic semantic checks without file-system access.

    Qualified names are accepted as references into an included schema. The caller can resolve and check include graphs separately.

    compare_schemas

    fn compare_schemas(before : Schema, after : Schema) -> Array[SchemaChange]

    Compares two checked schemas by stable field IDs, enum values, and service method names. Results are ordered deterministically by the old schema first, followed by additions from the new schema.

    compile_idl

    fn compile_idl(input : String, source? : String) -> (Schema, Array[Diagnostic]) raise IdlError

    Parses and validates a document in one call.

    has_breaking_changes

    fn has_breaking_changes(changes : ArrayView[SchemaChange]) -> Bool

    has_errors

    fn has_errors(diagnostics : ArrayView[Diagnostic]) -> Bool

    lex

    fn lex(input : String, source? : String) -> Array[Token] raise IdlError

    Tokenizes one Thrift IDL document without accessing the file system.

    parse_idl

    fn parse_idl(input : String, source? : String) -> Schema raise IdlError

    Parses a complete Apache Thrift IDL document.