Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

仓颉编程语言扩展库概述

仓颉编程语言扩展库(stdx)包含若干包,提供相关功能。

标准库为开发者提供了最通用的 API,而扩展库则专注于某一领域。如 compress 包提供压缩与解压缩能力,crypto 包提供加解密相关能力,net 包则专注于提供高效的网络协议解析和网络通信能力。

说明:

目前,官方提供的扩展库不随仓颉编译器、工具链一起发布,需要用户单独下载。

平台支持说明

扩展库提供的 API 支持在如下操作系统上运行:

注意:

部分 API 不支持在特定的操作系统运行,详情请参见对应 API 描述。

操作系统CPU 架构环境及其版本要求
Linuxx86_64glibc 2.22;Linux Kernel 4.12 或更高版本;系统安装 libstdc++ 6.0.24 或更高版本
Linuxaarch64glibc 2.27;Linux Kernel 4.15 或更高版本;系统安装 libstdc++ 6.0.24 或更高版本
Windowsx86_64Windows 10 或更高版本
macOSaarch64macOS 12.0 或更高版本
OpenHarmonyaarch64OpenHarmony 5.1 或更高版本
OpenHarmonyarm32OpenHarmony 5.1 或更高版本
HarmonyOSaarch64HarmonyOS 5.1 或更高版本
iOSaarch64iOS 11 或更高版本(ast 库需要 iOS 12 或更高版本)
Androidaarch64Android API 26 或更高版本

使用指导

仓颉编程语言扩展库 stdx 二进制包包含静态(static)和 动态 (dynamic) 两部分,请按需引用。

二进制产物结构

二进制包解压出来的目录包含 dynamic 和 static 两个目录:

dynamic/stdx 是动态产物,包含动态文件、cjo、bc 文件。

static/stdx 是静态产物,包含静态文件、cjo、bc 文件。

使用 Openssl 静态库链接

假设存放 Openssl 静态库的目录为 STATIC_OPENSSL_DIR,则命令如下。

# GNU ld64
cjc -L $STATIC_OPENSSL_DIR --link-option "-Bstatic" --link-option "--whole-archive" -lssl -lcrypto --link-option "--no-whole-archive" --link-option "-Bdynamic" main.cj

# Apple ld64
cjc -L $STATIC_OPENSSL_DIR --link-option "-force_load" --link-option "$STATIC_OPENSSL_DIR/libssl.a" --link-option "-force_load" --link-option "$STATIC_OPENSSL_DIR/libcrypto.a" main.cj

包依赖

导入库名依赖包
import stdx.actors.*stdx.actors
import stdx.actors.macros.*stdx.actors.macros
import stdx.aspectCJ.*stdx.aspectCJ
import stdx.compress.zlib.*stdx.compress.zlib
import stdx.crypto.common.*stdx.crypto.common、stdx.encoding.base64
import stdx.crypto.crypto.*stdx.crypto.crypto、stdx.crypto.digest、stdx.crypto.common、stdx.encoding.base64
import stdx.crypto.digest.*stdx.crypto.digest、stdx.crypto.common、stdx.encoding.base64
import stdx.crypto.keys.*stdx.crypto.keys、stdx.crypto.x509、stdx.encoding.hex、stdx.crypto.crypto、stdx.crypto.digest、stdx.crypto.common、stdx.encoding.base64
import stdx.crypto.kit.*stdx.crypto.keys、stdx.crypto.x509、stdx.encoding.hex、stdx.crypto.crypto、stdx.crypto.digest、stdx.crypto.common、stdx.encoding.base64
import stdx.crypto.x509.*stdx.crypto.x509、stdx.encoding.hex、stdx.crypto.crypto、stdx.crypto.digest、stdx.crypto.common、stdx.encoding.base64
import stdx.effect.*stdx.effect
import stdx.encoding.hex.*stdx.encoding.hex
import stdx.encoding.base64.*stdx.encoding.base64
import stdx.encoding.json.*stdx.encoding.json、stdx.serialization.serialization
import stdx.encoding.json.stream.*stdx.encoding.json.stream
import stdx.encoding.url.*stdx.encoding.url
import stdx.log.*stdx.log
import stdx.logger.*stdx.logger
import stdx.serialization.serialization.*stdx.serialization.serialization
import stdx.syntax.*stdx.syntax
import stdx.fuzz.fuzz.*stdx.fuzz.fuzz
import stdx.net.http .*stdx.net.http、stdx.net.tls.common、stdx.logger、stdx.log、stdx.encoding.url、stdx.encoding.json.stream、stdx.crypto.x509、stdx.encoding.hex、stdx.crypto.crypto、stdx.crypto.digest、stdx.crypto.common、stdx.encoding.base64
import stdx.net.tls.*stdx.net.tls、stdx.net.tls.common、stdx.crypto.x509、stdx.encoding.hex、stdx.crypto.crypto、stdx.crypto.digest、stdx.crypto.common、stdx.encoding.base64
import stdx.net.tls.common.*stdx.net.tls.common、stdx.crypto.x509、stdx.encoding.hex、stdx.crypto.crypto、stdx.crypto.digest、stdx.crypto.common、stdx.encoding.base64
import stdx.unittest.data.*stdx.encoding.json、stdx.serialization.serialization

代码中导入上述包,用 cjc 命令去编译代码,需要严格按照上述包的依赖的顺序去链接。 如果是用 cjpm 则无需关注。

如果使用静态库,在导入 crypto 和 net 库时,由于需要依赖系统符号,所以 Windows 操作系统 需要额外添加 -lcrypt32Linux 操作系统 需要额外添加 -ldl

cjc 使用命令示例

cjc 的介绍和编译请查看 cangjie 用户手册

import stdx.actors.*
import stdx.actors.macros.*
import stdx.aspectCJ.*
import stdx.compress.zlib.*
import stdx.crypto.crypto.*
import stdx.crypto.digest.*
import stdx.crypto.keys.*
import stdx.crypto.x509.*
import stdx.effect.*
import stdx.encoding.hex.*
import stdx.encoding.base64.*
import stdx.encoding.json.*
import stdx.encoding.url.*
import stdx.encoding.json.stream.*
import stdx.net.tls.*
import stdx.net.http.*
import stdx.log.*
import stdx.logger.*
import stdx.syntax.*
import stdx.serialization.serialization.*
main() {
    0
}

Linux 和 mac 的编译命令:

cjc main.cj -L $CANGJIE_STDX_PATH -lstdx.actors -lstdx.aspectCJ -lstdx.effect -lstdx.encoding.json -lstdx.serialization.serialization -lstdx.net.http -lstdx.net.tls -lstdx.net.tls.common -lstdx.logger -lstdx.log -lstdx.encoding.url -lstdx.encoding.json.stream -lstdx.crypto.kit -lstdx.crypto.keys -lstdx.crypto.x509 -lstdx.encoding.hex -lstdx.crypto.crypto -lstdx.crypto.digest -lstdx.crypto.common -lstdx.encoding.base64 -lstdx.compress.zlib -lstdx.compress -lstdx.syntax -lstdx.syntaxFFI -ldl --import-path $CANGJIE_STDX_PATH -o main.out

windows 编译命令:

cjc main.cj -L $CANGJIE_STDX_PATH -lstdx.actors -lstdx.aspectCJ -lstdx.effect -lstdx.encoding.json -lstdx.serialization.serialization -lstdx.net.http -lstdx.net.tls -lstdx.net.tls.common -lstdx.logger -lstdx.log -lstdx.encoding.url -lstdx.encoding.json.stream -lstdx.crypto.kit -lstdx.crypto.keys -lstdx.crypto.x509 -lstdx.encoding.hex -lstdx.crypto.crypto -lstdx.crypto.digest -lstdx.crypto.common -lstdx.encoding.base64 -lstdx.compress.zlib -lstdx.compress -lstdx.syntax -lstdx.syntaxFFI -lcrypt32 --import-path $CANGJIE_STDX_PATH -o main.out

CANGJIE_STDX_PATH 是设置的 stdx 路径。

例如在 linux 系统中设置:

export CANGJIE_STDX_PATH=/target/linux_x86_64_cjnative/dynamic/stdx

运行前 Linux 操作系统需要在 LD_LIBRARY_PATH 中设置扩展库的路径,Windows 操作系统需要在 PATH 中设置扩展库的路径,macOS 操作系统需要在 DYLD_LIBRARY_PATH 中设置扩展库的路径。

例如在 linux 系统中设置:

export LD_LIBRARY_PATH=/target/linux_x86_64_cjnative/dynamic/stdx:$LD_LIBRARY_PATH

cjpm 使用示例

cjpm 的介绍和使用请查看 cjpm 手册。

cjpm.toml 增加如下配置:

[target.x86_64-unknown-linux-gnu]
  [target.x86_64-unknown-linux-gnu.bin-dependencies]
    path-option = ["${CANGJIE_STDX_PATH}"]

上面配置中 x86_64-unknown-linux-gnu 表示的是系统架构信息,需要通过 cjc -v 获取,并替换成自己获取的系统架构信息。 CANGJIE_STDX_PATH 是设置的 stdx 路径。

包列表

stdx 含若干包,提供了丰富的扩展功能:

包名功能
actorsactors 包提供 actor 编程模型的基础能力。
actors.macrosactors.macros 包提供把 class 变成 active object 的能力。
aspectCJaspectCJ 包提供 Cangjie 中面向切面编程(Aspect Oriented Programming, AOP)相关的能力。
compress.zlibcompress 包提供压缩解压功能。
crypto.commoncrypto.common 包提供了加解密相关接口。
crypto.cryptocrypto 包提供安全加密能力。
crypto.digestdigest 包提供常用的消息摘要算法。
crypto.keyskeys 包提供非对称加密和签名算法。
crypto.kitcrypto.kit 包提供了一套 CryptoKit 的默认实现,提供随机数生成器及解码 DER、PEM 的能力。
crypto.x509x509 包提供处理数字证书功能。
effectstdx.effect 包是 Cangjie 中用于使用 Effect Handler 的用户级 API。这是一项实验性功能,需要配合支持该机制的 Cangjie 编译器使用。
encoding.base64base 包提供字符串的 Base64 编码及解码。
encoding.hexhex 包提供字符串的 Hex 编码及解码。
encoding.jsonjson 包用于对 json 数据的处理,实现 String, JsonValue, DataModel 之间的相互转换。
encoding.json.streamjson.stream 包主要用于仓颉对象和 JSON 数据流之间的互相转换。
encoding.urlurl 包提供了 URL 相关的能力,包括解析 URL 的各个组件,对 URL 进行编解码,合并 URL 或路径等。 。
fuzzfuzz 包为开发者提供基于覆盖率反馈的仓颉 fuzz 引擎及对应的接口,开发者可以编写代码对 API 进行测试。
loglog 包提供了日志记录相关的能力。
loggerlogger 包提供文本格式和 JSON 格式日志打印功能。
net.httphttp 包提供 HTTP/1.1,HTTP/2,WebSocket 协议的 server、client 端实现。
net.tlstls 包用于进行安全加密的网络通信,提供创建 TLS 服务器、基于协议进行 TLS 握手、收发加密数据、恢复 TLS 会话等能力。
net.tls.commontls.common 包提供了 TLS 相关的抽象接口,用于适配多种 TLS 实现。
serializationserialization 包提供了序列化和反序列化能力。
syntaxsyntax 包主要包含了仓颉源码的语法解析器和仓颉语法树节点,提供语法解析函数。
unittest.dataunittest 模块提供了单元测试扩展能力。
string_internstring_intern 模块提供字符串内联缓存能力。

扩展库源码集成指南

两种集成方式

stdx 有两种源码集成方式:git 源码依赖和本地源码依赖。

git 源码依赖

在工程的 cjpm.toml 文件中,新增如下源码依赖配置:

[dependencies]
  stdx = { git = "https://gitcode.com/Cangjie/cangjie_stdx.git", branch = "dev", output-type = "dynamic" }

在工程的 cjpm.toml 文件所在目录,执行 cjpm update 命令即可同步更新本仓源码。

本地源码依赖

如果不希望通过 git 依赖本仓,开发者可以直接下载本仓库分支的全量源码(包括本仓库的 cjpm.toml 配置文件),然后在工程的 cjpm.toml 文件中添加本地模块依赖。

[dependencies]
  stdx = { path = "/path/to/cangjie_stdx", output-type="dynamic"}

完成本地模块依赖添加之后,即可在项目中使用 stdx。

包范围

目前源码依赖集成的 stdx 不包含 aspectCJ 和 syntax,并且在 Windows 平台上没有 fuzz 包。

支持平台

  • Linux
  • macOs
  • Windows
  • 交叉编译 OpenHarmony

交叉编译 OpenHarmony

Linux 和 macOS 平台交叉编译 OpenHarmony 需要配置交叉编译工具链的环境变量(非 DevEco Studio 项目),请参考编译 ohos-x86_64、ohos-aarch64 工具链

  1. OHOS_TOOLCHAIN_PATH (编译工具链中 Clang/LLVM 编译器的二进制目录, 如 /opt/buildtools/ohos_root/prebuilts/clang/ohos/linux-x86_64/llvm/bin)

  2. OHOS_SYSROOT_PATH (OpenHarmony 系统头文件目录,如 /opt/buildtools/ohos_root/out/sdk/obj/third_party/musl/sysroot)

DevEco Studio 自带 OpenHarmony 交叉编译工具链,无需设置上面的环境变量。

交叉编译命令:cjpm build --target aarch64-linux-ohos 或者 cjpm build --target x86_64-linux-ohos

注意

部分版本 DevEco Studio 可能缺少 openssl 头文件, 构建过程中报错找不到 openssl 头文件,需要准备 openssl 头文件放入 DevEco Studio 的 sysroot 下。

  • Windows 常见路径如 C:\Program Files\Huawei\DevEco Studio\sdk\default\openharmony\native\sysroot\usr\include\openssl

  • macOS 常见路径如 /Applications/DevEco-Studio.app/Contents/sdk/default/openharmony/native/sysroot/usr/include/openssl

依赖

由于 stdx 需要拉取并编译外部开源 C 库,也有涉及 C 互操作的包,目前构建有一些额外依赖(使用 DevEco Studio 除外,DevEco Studio 自带了下面的工具),提前准备好下面的依赖,同时配置好环境变量。

  • python: > 3.7
  • cmake: >= 3.16.5 且 < 4
  • ninja: >1.10
  • openssl: >= 3 (需要配置环境变量 OPENSSL_ROOT_DIR,指向 OpenSSL 安装的根目录)
  • clang: >= 15.0.4 且 < 16 (Linux or macOS)
  • mingw-w64 (Windows) 下载地址

stdx.actors

功能介绍

Actor 模型概述

Actor 模型是一种并发编程模型,旨在简化并发任务的处理。

在这个模型中,actor 是基本的并发单元,具备以下特征:

  • 每个 actor 都拥有独立的仓颉线程。
  • 每个 actor 都拥有自己的成员变量。
  • 这些变量只能由该 actor 的线程进行访问和修改。
  • Actor 包含一种特殊的成员函数,称为 "接收函数"。当接收函数被调用时,调用请求会被加入到一个队列中,并在该 actor 的线程上按顺序执行。
  • 一旦没有任何引用指向该 actor,且所有的接收函数都已执行完毕,它就可以被系统回收。

注意:

Actor 模型的第三项特性还没有被语言强制实施,所以 actor 的成员变量还不具备完全的并发安全性。未来,类型系统可以解决这个问题,确保成员变量的并发安全。

Actor 的主要应用场景是在多线程环境下对同一个对象进行访问和修改。例如,一个银行账户的对象能会被多个线程同时访问,如执行存款或取款。在缺乏任何同步机制的情况下,可能会导致数据竞争:

public class Account {
    public Account(
        private let name: String,
        private var balance: Float64
    ) {}

    public func deposit(amount: Float64): Unit {
        balance += amount
    }

    public func withdraw(amount: Float64): Unit {
        if (balance < amount) {
            throw BalanceNotEnoughException(name)
        }
        balance -= amount
    }

    public func getBalance(): Float64 {
        balance
    }
}

在多线程环境下同时访问和修改该对象,可能会导致数据竞争:

let account = Account("Steven", 0.0)
spawn {
    account.deposit(1000.0)
}
spawn {
    account.withdraw(2000.0)
}

正确使用 Actor 模型可以使并发编程变得更加简洁和高效。

Actor 的声明

引用上述银行账户的例子,为了避免线程安全问题,我们可以使用 Actor 模型来设计一个专门处理账户操作的 actor。

首先,我们可以使用 @Actor 注解将 Account 类标记为一个 actor。然后,使用 @Receiver 注解来标记 deposit , withdraw 和 getBalance 函数:

@Actor
public class Account {
    public Account(
        private let name: String,
        private var balance: Float64
    ) {}

    @Receiver
    public func deposit(amount: Float64): Unit {
        balance += amount
    }

    @Receiver
    public func withdraw(amount: Float64): Unit {
        if (balance < amount) {
            throw BalanceNotEnoughException(name)
        }
        balance -= amount
    }

    @Receiver
    public func getBalance(): Float64 {
        balance
    }
}

对于 @Actor@Receiver 的使用规则跟限制,请参考对应的文档。

我们可以通过调用该类的构造函数来创建一个 Account 实例,例如:

let stevenAccount: Account = Account("Steven", 0.0)

在创建 Account 实例的同时,系统会自动创建一个与该实例关联的仓颉线程。

调用接收函数

与普通函数不同,接收函数的调用是异步的,并返回一个 ActorFuture<T> 对象。通过该对象,可以等待接收函数执行完成并获取结果,其中 T 是该接收函数的返回类型。例如,调用 getBalance 时,将返回一个 ActorFuture<Float64> 的对象:

let fut: ActorFuture<Float64> = stevenAccount.getBalance()

当接收函数被调用时,调用请求会被加入到一个队列中,并在该 actor 的附属线程上按顺序执行。

随后,我们可以通过调用 ActorFuture<T> 的 get 函数来阻塞当前线程,直到 steven.getBalance() 函数执行完成,并返回一个 T 类型的值。

let stevenBalance: Float64 = fut.get()

stevenBalance 的值将取决于 steven.getBalance() 执行时成员变量 balance 的值。

在多线程环境下,虽然接收函数可能同时被调用,但由于同一个 actor 实例的接收函数是顺序执行的,不会发生交叉执行。因此,我们可以将它们视为原子操作(atomic function),从而避免数据竞争。

let account = Account("Steven", 0.0)
spawn {
    account.deposit(1000.0)
}
spawn {
    account.withdraw(2000.0)
}

注意:

目前 actor 的成员变量还不具备完全的并发安全性。例如在以下的例子当中,public 的成员变量还是可以被直接在外部访问与修改:

@Actor
public class MyActor {
    public var x: Int64 = 0
}

let myActor = MyActor()
spawn {
    myActor.x = 2
}
spawn {
    myActor.x = 3
}

未来,一个新的类型系统可以解决这个问题,确保成员变量的并发安全。

接收函数的执行顺序

在同一线程对同一个 actor 调用接收函数时,这些函数将按调用的顺序执行。例如:

func foo() {
    let account = Account("Federico", 0.0)
    account.deposit(1000.0)
    account.withdraw(500.0)
    let fut = account.getBalance()
    println(fut.get())
}

在没有其他线程的情况下,这段代码必然会输出以下内容,并不会出现 account.withdraw(500.0) 先于 account.deposit(1000.0) 执行的情况:

500.0

不同线程对同一 actor 的调用将不保证执行顺序,比如:

let account = Account("Steven", 0.0)
spawn {
    account.deposit(1000.0)
}
spawn {
    account.withdraw(500.0)
}

以下都是可能出现的执行顺序:

account.deposit(1000.0)
account.withdraw(500.0)
account.withdraw(500.0)
account.deposit(1000.0)

接收函数抛出的异常

接收函数抛出的任何未捕获的异常或错误都将传播到对应的 ActorFuture<T> 对象,类似于 spawn 的处理。

继续应用 Account 的例子,在 withdraw(amount) 函数里面,如果户口里面的 balance 不够会抛出 BalanceNotEnoughException 异常:

@Receiver
public func withdraw(amount: Float64): Unit {
    if (balance < amount) {
        throw BalanceNotEnoughException(name)
    }
    balance -= amount
}

抛出的异常会被传递到对应的 ActorFuture 对象,调用它的 get 函数时会抛出同一个异常:

let account = Account("Hamid", 0.0)
let fut: ActorFuture<Unit> = account.withdraw(500.0)
try {
    let res = fut.get()
} catch (e: BalanceNotEnoughException) {
    println("fut.get() throws BalanceNotEnoughException")
    println()
    e.printStackTrace()
}

由于 account.withdraw(500.0) 抛出了 BalanceNotEnoughException,因此 fut.get() 也会抛出相同的异常。以下是输出内容:

fut.get() throws BalanceNotEnoughException

An exception has occurred:
Exception: Balance for account Hamid is not enough.
         at default.BalanceNotEnoughException::init(std.core::String)(/home/.../main.cj:6)
         at default.Account::withdraw::lambda.0()(/home/.../main.cj:25)
         at stdx.actors.ActorFuture<...>::execute()(stdx/actors/actor_future.cj:90)
         at stdx.actors.SequentialDispatcher::startActorLoop::lambda.0()(stdx/actors/actors.cj:46)

当一个接收函数抛出异常后, 该 actor 的附属线程会继续执行下一个在队列里面的接收函数调用:

let account = Account("Hamid", 0.0)
let fut: ActorFuture<Unit> = account.withdraw(500.0)
let fut2: ActorFuture<Float64> = account.getBalance()
try {
    let res = fut.get()
} catch (e: BalanceNotEnoughException) {
    println("fut.get() throws BalanceNotEnoughException")
    println()
    e.printStackTrace()
    println()
}
let res = fut2.get()
println("Balance = ${res}")

在该 actor 的线程里面, account.withdraw(500.0) 执行并抛出异常后,线程会继续执行 account.getBalance()。以下是输出内容:

fut.get() throws BalanceNotEnoughException

An exception has occurred:
Exception: Balance for account Hamid is not enough.
         at default.BalanceNotEnoughException::init(std.core::String)(/home/.../main.cj:6)
         at default.Account::withdraw::lambda.0()(/home/.../main.cj:25)
         at stdx.actors.ActorFuture<...>::execute()(stdx/actors/actor_future.cj:90)
         at stdx.actors.SequentialDispatcher::startActorLoop::lambda.0()(stdx/actors/actors.cj:46)

Balance = 0.0

Actor 的生命周期

当没有任何引用指向该 actor,并且没有待执行的接收函数调用时,该 actor 就可以被运行时回收:

func test(): Unit {
    let account = Account("Ziming", 0.0)
    let fut = account.deposit(5.0)
    println(fut.get())
}

func bar() {
    test()
    // account 有可能被回收
}

在 test() 返回后,由于已经没有对 account 的引用,且没有待执行的接收函数调用(因为我们在 test() 内部已经等待了 account.deposit(5.0) 的结果),因此 account 所指向的 actor 及其附属仓颉线程将会被系统回收。

接收函数的优先值

用户可以为接收函数指定优先级,从而使高优先级的接收函数有可能在低优先级的接收函数之前执行。

首先,用户需要通过在 @Actor 宏上加上 enableReceiverPriority: true 选项,用于启用 actor 接收函数之间的优先级。例如:

@Actor[enableReceiverPriority: true]
public class Account {
    public Account(
        private let name: String,
        private var balance: Float64
    ) {}
}

如果 enableReceiverPriority 设置为 false 或者 @Actor 宏没有这个选项,那么意味着接收函数的优先级未启用。

接下来我们可以为每个接收函数指定默认的优先级级别,目前我们提供了 10 个优先级级别,用 1 到 10 的整数表示;数字越大,优先级越高,如果未设置 priority 选项,则默认值为 5:

@Actor[enableReceiverPriority: true]
public class Account {
    ...

    @Receiver[priority: 10]
    public func deposit(amount: Float64): Unit {
        balance += amount
    }

    @Receiver[priority: 1]
    public func withdraw(amount: Float64): Unit {
        if (balance < amount) {
            throw BalanceNotEnoughException(name)
        }
        balance -= amount
    }

    @Receiver
    public func getBalance(): Float64 {
        balance
    }
}

通过提高 deposit 的优先级并降低 withdraw 的优先级,当同时有大量 deposit 和 withdraw 调用时,deposit 将优先执行,从而减少 withdraw 抛出 BalanceNotEnoughException 的机会。

此外,在调用接收函数时,可以通过在参数列表末尾传递一个额外的命名参数 priority 来重载该函数的优先级:

func foo(account: Account) {
    account.getBalance()
    account.withdraw(100.0, priority: 10)
}

account.withdraw(100.0, priority: 10) 的调用将有可能被优先执行。

死锁

最后请注意,在 actor 的接收函数中调用 fut.get() 可能会导致死锁,例如:

@Actor
class MyActor {
    @Receiver
    func foo(): Int64 {
        let fut = this.bar()
        // this will deadlock
        fut.get()
    }

    @Receiver
    func bar(): Int64 {
        42
    }
}

调用 this.bar() 会将该接收函数添加到队列末尾。然而在一个接收函数里面阻塞会导致 actor 的线程阻塞,所以 bar() 永远不会被执行。所以在 foo() 里面执行 fut.get() 会永远阻塞。

完整例子

package actorDemo

import std.collection.ArrayList

import stdx.actors.*
import stdx.actors.macros.*

@Actor[enableReceiverPriority: true]
public class Account {
    public Account(
        private let name: String,
        private var balance: Float64
    ) {}

    @Receiver[priority: 10]
    public func deposit(amount: Float64): Unit {
        balance += amount
    }

    @Receiver[priority: 1]
    public func withdraw(amount: Float64): Unit {
        if (balance < amount) {
            throw BalanceNotEnoughException(name)
        }
        balance -= amount
    }

    @Receiver
    public func getBalance(): Float64 {
        balance
    }
}

public class BalanceNotEnoughException <: Exception {
    public init(name: String) {
        super("Balance for account ${name} is not enough.")
    }
}

main() {
    let account = Account("Steven", 0.0)
    let futs = ArrayList<Future<Unit>>()
    for (_ in 0..100) {
        let fut1 = spawn {
            for (_ in 0..10) {
                account.deposit(1000.0)
            }
        }
        let fut2 = spawn {
            for (_ in 0..10) {
                account.withdraw(1000.0)
            }
        }
        futs.add(fut1)
        futs.add(fut2)
    }
    for (f in futs) {
        f.get()
    }
    println("Balance: ${account.getBalance().get()}")
}

API 列表

类名功能
ActorFuture<T>调用接收函数获得,可用于获取其结果。
SequentialDispatcher提供把多个闭包在同一个线程排队执行的功能,通常用户不需要自己使用这个类型。

class ActorFuture

public class ActorFuture<T> {}

功能:提交给一个 Actor 的闭包的待定结果。

func get()

public func get(): T

功能:阻塞当前线程,直到闭包完成。如果闭包抛出异常或错误,此方法将抛出相同的异常或错误。

返回值:

  • T - 对应的闭包的计算结果。

示例:

import stdx.actors.*
import stdx.actors.macros.*

@Actor
public class Counter {
    private var cnt: Int64 = 42

    @Receiver
    public func getCnt(): Int64 {
        cnt
    }
}

main() {
    let counter: Counter = Counter()
    let fut: ActorFuture<Int64> = counter.getCnt()
    let res: Int64 = fut.get()
    println(res)
}

运行结果:

42

func get(Duration)

public func get(timeout: Duration): Option<T>

功能:阻塞当前线程,直到指定的时间段结束或结果准备好。如果结果已经准备好,它将返回结果,否则它将返回 None。如果结果是异常或错误,此方法将抛出相同的异常或错误。如果指定的超时时间为零,则表示没有时间限制。

参数:

  • timeout: Duration - 它应该等待的最大时间。

返回值:

  • Option<T> - 如果结果在指定超时时间内未准备好,则返回 None,否则返回结果值。

示例:

import stdx.actors.*
import stdx.actors.macros.*

@Actor
public class Counter {
    private var cnt: Int64 = 42

    @Receiver
    public func getCnt(): Int64 {
        cnt
    }
}

main() {
    let counter: Counter = Counter()
    let fut: ActorFuture<Int64> = counter.getCnt()
    let res: Option<Int64> = fut.get(Duration.second)
    println(res)
}

运行结果:

Some(42)

func tryGet()

public func tryGet(): Option<T>

功能:如果结果已经准备好,则立即返回结果;否则返回 None。如果结果是异常或错误,此方法将抛出相同的异常或错误。

返回值:

  • Option<T> - 如果结果尚未准备好,则返回 None,否则返回结果值。

示例:

import stdx.actors.*
import stdx.actors.macros.*

@Actor
public class Counter {
    private var cnt: Int64 = 42

    @Receiver
    public func getCnt(): Int64 {
        cnt
    }
}

main() {
    let counter: Counter = Counter()
    let fut: ActorFuture<Int64> = counter.getCnt()
    fut.get()
    let res: Option<Int64> = fut.tryGet()
    println(res)
}

运行结果:

Some(42)

class SequentialDispatcher

public class SequentialDispatcher {
  public init(enableReceiverPriorty!: Bool)
}

功能:一个 SequentialDispatcher 实例代表了一个仓颉的线程,用户可以向一个 SequentialDispatcher 实例提交闭包,这些闭包会在一个仓颉线程上排队执行。

通常用户不需要直接使用这个类,而是应该使用 @Actor 宏。

init(Bool)

public init(enableReceiverPriorty!: Bool)

功能:创建一个 SequentialDispatcher 实例并启动 SequentialDispatcher 的线程来处理用户提交的闭包。

参数:

  • enableReceiverPriorty!: Bool - 设置为 true 时提供提供优先值功能,让优先值高的闭包优先执行。

func post<T>(() -> T, Int64)

public func post<T>(task: () -> T, priority!: Int64 = 5): ActorFuture<T>

功能:将一个闭包提交给 dispatcher,该闭包将在 dispatcher 线程上排队并执行。此方法返回一个 ActorFuture<T>,表示闭包的待定结果。如果这个 dispatcher 在构建时如果设置 enableReceiverPriorty 为 true,优先值高的闭包会优先执行;如果设置 enableReceiverPriorty 为 false 时,priority 值将不起作用。

参数:

  • task: () -> T - 提交到 actor 的闭包。
  • priority!: Int64 - 提交任务的优先级,1 <= priority <= 10,默认为 5。

返回值:

异常:

  • IllegalArgumentException - 如果优先级参数 priority 小于 1 或大于 10,则会抛出此异常。

示例:

import stdx.actors.*

main() {
  let seqDispatcher = SequentialDispatcher()
  let fut: ActorFuture<Int64> = seqDispatcher.post<Int64>({ => 40 + 2 })
  let res: Int64 = fut.get()
  println(res)
}

运行结果:

42

示例:

import stdx.actors.*

main() {
  let seqDispatcher = SequentialDispatcher(enableReceiverPriority: true)
  let fut: ActorFuture<Int64> = seqDispatcher.post<Int64>({ => 40 + 2 }, priority: 5)
  let res: Int64 = fut.get()
  println(res)
}

运行结果:

42

stdx.actors.macros

功能介绍

该包为用户提供了一个 @Actor 宏,用于声明一个 actor;以及一个 @Receiver 宏,用于声明一个接收函数。

API 列表

功能
Actor声明一个 actor。
Receiver声明一个接收函数。

@Actor 宏

public macro Actor(input: Tokens): Tokens

public macro Actor(options: Tokens, input: Tokens): Tokens

功能:把一个 class 类变成一个 actor。

说明:

@Actor 宏的使用有以下限制:

  • 它只能用于类;
  • 被标注的类不能是 abstract/open/sealed。

违反这些限制会导致宏展开时出现编译错误。

选项:Actor 宏接受以 opt1: value1, opt2: value2 形式的选项列表。例如,

@Actor[option1: value1, option2: value2]

目前可用的选项只有 enableReceiverPriority: value - 指定是否启用接收函数之间的优先级。提供的值必须是 boolean 的字面量,即 true 或 false。如果没有指定此选项,默认为 false。

所有选项只能出现一次,否则在宏展开期间将抛出错误。

示例:

import stdx.actors.*
import stdx.actors.macros.*

@Actor
public class Counter <: ToString {
    private var cnt: Int64 = 0

    public func toString(): String {
        "This is a counter."
    }
}

main() {
    let counter: Counter = Counter()
    println(counter)
}

运行结果:

This is a counter.

@Receiver 宏

public macro Receiver(input: Tokens): Tokens

public macro Receiver(options: Tokens, input: Tokens): Tokens

功能:把一个成员函数变成接收函数。

说明:

@Receiver 宏的使用有以下限制:

  • 只能在 @Actor 宏内部使用;
  • 被注解的方法必须是非 static 的;
  • 被注解的方法必须具有明确声明的返回类型;
  • 被注解的方法不能覆盖接口方法,即不能被 override 修饰;
  • 如果被注解方法没有显式的 override 修饰符但实际上覆盖了接口方法,则会在宏展开后会导致编译错误;
  • 被注解的方法不能是 open 的;
  • 当在 @Actor 宏内部使用且 enableReceiverPriority 设置为 true 时,被注解的方法不能具有名为 priority 的参数。

违反这些限制会导致宏展开时出现编译错误。

选项:Receiver 宏接受以 opt1: value1, opt2: value2 形式的选项列表。例如,

@Receiver[option1: value1, option2: value2]

目前可用的选项只有 priority: value - 指定接收函数的默认优先级级别。提供的值必须是介于 1 到 10 之间的整数字面量;否则,在宏展开期间将抛出错误。此选项仅在外层 @Actor 宏具有 enableReceiverPriority: true 选项时才可用。

所有选项只能出现一次,否则在宏展开期间将抛出错误。

示例:

import stdx.actors.*
import stdx.actors.macros.*

@Actor
public class Counter <: ToString {
    private var cnt: Int64 = 0

    @Receiver
    public func inc(): Unit {
        cnt++
    }

    @Receiver
    public func getCnt(): Int64 {
        cnt
    }

    public func toString(): String {
        "This is a counter: cnt = ${getCnt().get()}."
    }
}

main() {
    let counter: Counter = Counter()
    counter.inc()
    counter.inc()
    println(counter)
}

运行结果:

This is a counter: cnt = 2.

stdx.aspectCJ

功能介绍

stdx.aspectCJ 包提供了仓颉中面向切面编程(Aspect Oriented Programming, AOP)的相关注解,配合 libcollect-aspects 和 libwave-aspects 两个编译插件使用,可以对函数进行前后插桩以及替换实现。

API 列表

类名功能
InsertAtEntry一个注解类,提供一种切面能力。在注解所指定方法的入口,织入对被注解标注的函数的调用。
InsertAtExit一个注解类,提供一种切面能力。在注解所指定方法的退出点,织入对被注解标注的函数的调用。
ReplaceFuncBody一个注解类,提供一种切面能力。将注解所指定方法的方法体,替换为对被注解标注的函数的调用。

规格和使用

规格

标注范围:

  • 注解暂不支持标注在泛型函数上,也不支持织入泛型函数;
  • 注解只允许标注在 public 函数上;
  • 注解可以标注在全局函数上,支持:
    • 织入另一个全局函数,
    • 织入另一个实例成员函数,
    • 织入另一个静态成员函数;
  • 注解可以标注在静态成员函数上,支持:
    • 织入另一个全局函数,
    • 织入另一个实例成员函数,
    • 织入另一个静态成员函数;
  • 注解可以标注在实例成员函数上,支持:
    • 织入同类型的其它实例成员函数。

全局变量定义约束:

  • 定义了切面的包中,只允许定义基本类型(整型、浮点、Rune、Bool)字面值的全局变量,否则编译报错;若需要使用超规格的全局变量,需要将其定义在另外的包再导入使用,以避免在编译后可能产生的循环依赖;

形参约束:

  • 被标注 @InsertAtEntry/@InsertAtExit 的函数,其返回类型只能是 Unit;
  • 被标注 @ReplaceFuncBody 的函数,其返回类型应和被织入的函数的返回类型相同;
  • 被标注 @InsertAtEntry/@InsertAtExit/@ReplaceFuncBody 的函数如果没有形参,那么其织入后总是被无参调用 ;
  • 被标注 @InsertAtEntry/@InsertAtExit/@ReplaceFuncBody 的函数如果有形参,其形参列表应和被织入函数的源码形参列表相同,此外:
    • 特别地,如果被织入的函数是实例成员函数,那么需要将 this 参数显式地写在形参中;
    • 对于被标注 @ReplaceFuncBody 的函数,需要额外添加一个形参,形参的类型和被织入的函数相同,该形参表示被织入函数原始版本的闭包。

使用

要实现 AOP 的完整功能,除了使用上述的注解类来定义切面,还需要两个编译插件:

  • libcollect-aspects.so(.dll/.dylib)
  • libwave-aspects.so(.dll/.dylib)

这两个编译插件以动态库的形式在 stdx.aspectCJ 中提供,不同平台提供不同版本。

应先使用 libcollect-aspects,在编译时收集所有切面、连接点信息;再使用 libwave-aspects 进行二次编译,把之前收集的切面织入到连接点。

class InsertAtEntry

public class InsertAtEntry {
    public const init(packageName!: String, className!: String, methodName!: String, isStatic!: Bool, funcTypeStr!: String, recursive!: Bool)
}

功能:在注解所指定方法的入口,织入对被注解标注的函数的调用。注解所指定的方法和被注解标注的函数,需满足规格限制

示例:

参考InsertAtEntry 示例教程了解具体调用流程。

const init(String, String, String, Bool, String, Bool)

public const init(packageName!: String, className!: String, methodName!: String, isStatic!: Bool, funcTypeStr!: String, recursive!: Bool)

功能:创建 InsertAtEntry 对象。

示例:

参考InsertAtEntry 示例教程了解具体调用流程。

参数:

  • packageName!: String - 被织入的函数的所属包名,如 "default", "std.core";
  • className!: String - 如果被织入的函数是成员函数,则为函数所属类名;如果被织入的函数是全局函数,则为空;
  • methodName!: String - 被织入的函数名称,如 "foo";
  • isStatic!: Bool - 被织入的函数是否为静态成员函数;
  • funcTypeStr!: String - 被织入的函数的类型字符串,不包括空格。对于自定义类型,类型定义所在的包名不可省略,且和类型名之间使用 . 分隔。不需要包括隐式的 this 形参的类型。如 "(Int64,std.core.Object)->Unit";
  • recursive!: Bool - 当被织入的函数是成员函数时,表示是否对子类里的函数 override 版本也做织入;否则该字段应填 false。

class InsertAtExit

public class InsertAtExit {
    public const init(packageName!: String, className!: String, methodName!: String, isStatic!: Bool, funcTypeStr!: String, recursive!: Bool)
}

功能:在注解所指定方法的退出点,织入对被注解标注的函数的调用。注解所指定的方法和被注解标注的函数,需满足规格限制

示例:

参考InsertAtExit 示例教程了解具体调用流程。

const init(String, String, String, Bool, String, Bool)

public const init(packageName!: String, className!: String, methodName!: String, isStatic!: Bool, funcTypeStr!: String, recursive!: Bool)

功能:创建 InsertAtExit 对象。

示例:

参考InsertAtExit 示例教程了解具体调用流程。

参数:

  • packageName!: String - 被织入的函数的所属包名,如 "default", "std.core";
  • className!: String - 如果被织入的函数是成员函数,则为函数所属类名;如果被织入的函数是全局函数,则为空;
  • methodName!: String - 被织入的函数名称,如 "foo";
  • isStatic!: Bool - 被织入的函数是否为静态成员函数;
  • funcTypeStr!: String - 被织入的函数的类型字符串,不包括空格。对于自定义类型,类型定义所在的包名不可省略,且和类型名之间使用 . 分隔。不需要包括隐式的 this 形参的类型。如 "(Int64,std.core.Object)->Unit";
  • recursive: Bool - 当被织入的函数是成员函数时,表示是否对子类里的函数 override 版本也做织入;否则该字段应填 false。

class ReplaceFuncBody

public class ReplaceFuncBody {
    public const init(packageName!: String, className!: String, methodName!: String, isStatic!: Bool, recursive!: Bool)
}

功能:将注解所指定方法的方法体,替换为对被注解标注的函数的调用。注解所指定的方法和被注解标注的函数,需满足规格限制

示例:

参考ReplaceFuncBody 示例教程了解具体调用流程。

const init(String, String, String, Bool, Bool)

public const init(packageName!: String, className!: String, methodName!: String, isStatic!: Bool, recursive!: Bool)

功能:创建 ReplaceFuncBody 对象。

示例:

参考ReplaceFuncBody 示例教程了解具体调用流程。

参数:

  • packageName!: String - 被织入的函数的所属包名,如 "default", "std.core";
  • className!: String - 如果被织入的函数是成员函数,则为函数所属类名;如果被织入的函数是全局函数,则为空;
  • methodName!: String - 被织入的函数名称,如 "foo";
  • isStatic!: Bool - 被织入的函数是否为静态成员函数;
  • recursive!: Bool - 当被织入的函数是成员函数时,表示是否对子类里的函数 override 版本也做织入;否则该字段应填 false。

AOP 开发示例

InsertAtEntry 入口插桩示例

下面是使用 @InsertAtEntry 完成在指定函数入口插桩的示例代码:

package AOP_demo1

import stdx.aspectCJ.*
import std.time.DateTime

@InsertAtEntry[packageName: "AOP_demo1", className: "", methodName: "printCurrentTime", isStatic: false, funcTypeStr: "()->Unit", recursive: false]
public func printCurrentTimeImpl() {
    println("----- ${DateTime.now()} -----")
}

public func printCurrentTime() {
    println("hi")
    println("bye")
}

main() {
    printCurrentTime()
    0
}

linux 平台编译命令:

cjc aop_demo1.cj -L $CANGJIE_STDX_PATH --import-path $CANGJIE_STDX_PATH -lstdx.aspectCJ --plugin=$CANGJIE_STDX_PATH/libcollect-aspects.so -o main # 第一次编译,收集切面
cjc aop_demo1.cj -L $CANGJIE_STDX_PATH --import-path $CANGJIE_STDX_PATH -lstdx.aspectCJ --plugin=$CANGJIE_STDX_PATH/libwave-aspects.so -o main # 第二次编译,织入切面

运行结果可能如下:

----- 2025-06-03T00:00:18.994507-07:00 -----
hi
bye

InsertAtExit 退出插桩示例

下面是使用 @InsertAtExit 完成在指定函数退出前插桩的示例代码:

package AOP_demo2

import stdx.aspectCJ.*
import std.time.DateTime

@InsertAtExit[packageName: "AOP_demo2", className: "", methodName: "printCurrentTime", isStatic: false, funcTypeStr: "()->std.core:String", recursive: false]
public func printCurrentTimeImpl() {
    println("----- ${DateTime.now()} -----")
}

public func printCurrentTime() {
    println("hi")
    println("bye")
    "done"
}

main() {
    println(printCurrentTime())
    0
}

linux 平台编译命令:

cjc aop_demo2.cj -L $CANGJIE_STDX_PATH --import-path $CANGJIE_STDX_PATH -lstdx.aspectCJ --plugin=$CANGJIE_STDX_PATH/libcollect-aspects.so -o main # 第一次编译,收集切面
cjc aop_demo2.cj -L $CANGJIE_STDX_PATH --import-path $CANGJIE_STDX_PATH -lstdx.aspectCJ --plugin=$CANGJIE_STDX_PATH/libwave-aspects.so -o main # 第二次编译,织入切面

运行结果可能如下:

hi
bye
----- 2025-06-03T00:04:59.996469-07:00 -----
done

ReplaceFuncBody 替换函数体示例

下面是使用 @ReplaceFuncBody 完成替换指定函数函数体的示例代码:

package AOP_demo3

import stdx.aspectCJ.*
import std.time.DateTime

@ReplaceFuncBody[packageName: "AOP_demo3", className: "", methodName: "printCurrentTime", isStatic: false, recursive: false]
public func printCurrentTimeImpl(original: (String)->String) {
    println("----- ${DateTime.now()} -----")
    println(original("abc"))
    println("----- end -----")
    "def"
}

public func printCurrentTime(x: String): String {
    println(x)
    "456"
}

main() {
    println(printCurrentTime("123"))
    0
}

linux 平台编译命令:

cjc aop_demo3.cj -L $CANGJIE_STDX_PATH --import-path $CANGJIE_STDX_PATH -lstdx.aspectCJ --plugin=$CANGJIE_STDX_PATH/libcollect-aspects.so -o main # 第一次编译,收集切面
cjc aop_demo3.cj -L $CANGJIE_STDX_PATH --import-path $CANGJIE_STDX_PATH -lstdx.aspectCJ --plugin=$CANGJIE_STDX_PATH/libwave-aspects.so -o main # 第二次编译,织入切面

运行结果可能如下:

----- 2025-06-03T00:04:59.996469-07:00 -----
abc
456
----- end -----
def

stdx.chir

说明:

当前处于开发阶段,尚不具备完整功能。

功能介绍

chir 包提供类型系统的基础类型定义,包括抽象类型基类、内置类型(整数、浮点数、布尔、字符等)以及引用类型等。该包为仓颉语言的类型系统提供核心支持。

API 列表

类名功能
BoolType表示布尔类型。
CPointerType表示 C 指针类型,用于与 C 代码互操作。
CStringType表示 C 字符串类型,用于与 C 代码互操作。
FloatType表示浮点类型(Float16、Float32、Float64)。
IntType表示整数类型(有符号和无符号)。
NothingType表示 Nothing 类型(底部类型)。
NumericType数值类型的抽象基类。
RefType表示引用类型。
RuneType表示字符类型。
Type类型系统中所有类型的抽象基类。
UnitType表示 Unit 类型(类似 C 语言中的 void)。

class BoolType

public class BoolType <: BuiltinType & Equatable<BoolType>

功能:表示类型系统中的布尔类型。这是一个单例类型,表示 Bool 类型。

父类型:

  • BuiltinType
  • Equatable<BoolType>

static func get()

public static func get(): BoolType

功能:获取 BoolType 的单例实例。

返回值:

  • BoolType - BoolType 实例。

示例:

import stdx.chir.*

main() {
    let boolType = BoolType.get()
    println("布尔类型: ${boolType.toString()}")
}

运行结果:

布尔类型: Bool

operator func==(BoolType)

public operator func==(_: BoolType): Bool

功能:检查该 BoolType 是否与另一个 BoolType 相等。

参数:

  • _: BoolType - 要比较的另一个 BoolType(未使用,始终返回 true)。

返回值:

  • Bool - 始终返回 true,因为所有 BoolType 实例都相等。

示例:

import stdx.chir.*

main() {
    let boolType1 = BoolType.get()
    let boolType2 = BoolType.get()
    println("两个 BoolType 相等: ${boolType1 == boolType2}")
}

运行结果:

两个 BoolType 相等: true

class CPointerType

public class CPointerType <: BuiltinType & Equatable<CPointerType>

功能:表示类型系统中的 C 指针类型。该类型表示指向 C 类型的指针,用于与 C 代码互操作。该类维护所有 C 指针类型的缓存以确保唯一性。

父类型:

  • BuiltinType
  • Equatable<CPointerType>

prop elementType

public prop elementType: Type

功能:获取该 C 指针类型所指向的元素类型。

返回值:

  • Type - 元素类型。

示例:

import stdx.chir.*

main() {
    let intType = IntType.getInt32()
    let cPointerType = CPointerType.get(intType)
    let elementType = cPointerType.elementType
    println("C 指针类型: ${cPointerType.toString()}")
    println("元素类型: ${elementType.toString()}")
}

运行结果:

C 指针类型: CPointer<Int32>
元素类型: Int32

operator func==(CPointerType)

public operator func==(other: CPointerType): Bool

功能:检查该 CPointerType 是否与另一个 CPointerType 相等。

参数:

  • other: CPointerType - 要比较的 CPointerType。

返回值:

  • Bool - 如果类型相等则返回 true,否则返回 false。

示例:

import stdx.chir.*

main() {
    let intType = IntType.getInt32()
    let cPointerType1 = CPointerType.get(intType)
    let cPointerType2 = CPointerType.get(intType)
    println("两个 C 指针类型相等: ${cPointerType1 == cPointerType2}")
}

运行结果:

两个 C 指针类型相等: true

static func get(Type)

public static func get(elementType: Type): CPointerType

功能:获取或创建给定元素类型的 CPointerType。

此方法确保每个元素类型只存在一个 CPointerType 实例。

参数:

  • elementType: Type - 指针所指向的类型。

返回值:

  • CPointerType - 给定元素类型的 CPointerType 实例。

示例:

import stdx.chir.*

main() {
    let intType = IntType.getInt32()
    let cPointerType = CPointerType.get(intType)
    println("C 指针类型: ${cPointerType.toString()}")
}

运行结果:

C 指针类型: CPointer<Int32>

func toString()

public func toString(): String

功能:将该 CPointerType 转换为字符串表示。

返回值:

  • String - C 指针类型的字符串表示(CPointer<elementType>)。

示例:

import stdx.chir.*

main() {
    let intType = IntType.getInt32()
    let cPointerType = CPointerType.get(intType)
    println("C 指针类型字符串: ${cPointerType.toString()}")
}

运行结果:

C 指针类型字符串: CPointer<Int32>

class CStringType

public class CStringType <: BuiltinType & Equatable<CStringType>

功能:表示类型系统中的 C 字符串类型。该类型表示 C 风格的空终止字符串,用于与 C 代码互操作。这是一个单例类型,表示内置的 C 字符串类型。

父类型:

  • BuiltinType
  • Equatable<CStringType>

operator func==(CStringType)

public operator func==(_: CStringType): Bool

功能:检查该 CStringType 是否与另一个 CStringType 相等。

参数:

  • _: CStringType - 要比较的另一个 CStringType(未使用,始终返回 true)。

返回值:

  • Bool - 始终返回 true,因为所有 CStringType 实例都相等。

示例:

import stdx.chir.*

main() {
    let cStringType1 = CStringType.get()
    let cStringType2 = CStringType.get()
    println("两个 CStringType 相等: ${cStringType1 == cStringType2}")
}

运行结果:

两个 CStringType 相等: true

static func get()

public static func get(): CStringType

功能:获取 CStringType 的单例实例。

返回值:

  • CStringType - CStringType 实例。

示例:

import stdx.chir.*

main() {
    let cStringType = CStringType.get()
    println("C 字符串类型: ${cStringType.toString()}")
}

运行结果:

C 字符串类型: CString
public operator func==(_: CStringType): Bool

功能:检查该 CStringType 是否与另一个 CStringType 相等。

参数:

  • _: CStringType - 要比较的另一个 CStringType(未使用,始终返回 true)。

返回值:

  • Bool - 始终返回 true,因为所有 CStringType 实例都相等。

示例:

import stdx.chir.*

main() {
    let cStringType1 = CStringType.get()
    let cStringType2 = CStringType.get()
    println("两个 CStringType 相等: ${cStringType1 == cStringType2}")
}

运行结果:

两个 CStringType 相等: true

class FloatType

public class FloatType <: NumericType & Equatable<FloatType>

功能:表示类型系统中的浮点类型。该类表示三种浮点类型:Float16、Float32 和 Float64。

父类型:

static func getFloat16()

public static func getFloat16(): FloatType

功能:获取 Float16 类型实例。

返回值:

  • FloatType - Float16 类型。

示例:

import stdx.chir.*

main() {
    let float16Type = FloatType.getFloat16()
    println("Float16 类型: ${float16Type.toString()}")
}

运行结果:

Float16 类型: Float16

static func getFloat32()

public static func getFloat32(): FloatType

功能:获取 Float32 类型实例。

返回值:

  • FloatType - Float32 类型。

示例:

import stdx.chir.*

main() {
    let float32Type = FloatType.getFloat32()
    println("Float32 类型: ${float32Type.toString()}")
}

运行结果:

Float32 类型: Float32

static func getFloat64()

public static func getFloat64(): FloatType

功能:获取 Float64 类型实例。

返回值:

  • FloatType - Float64 类型。

示例:

import stdx.chir.*

main() {
    let float64Type = FloatType.getFloat64()
    println("Float64 类型: ${float64Type.toString()}")
}

运行结果:

Float64 类型: Float64

operator func==(FloatType)

public operator func==(other: FloatType): Bool

功能:检查该 FloatType 是否与另一个 FloatType 相等。

参数:

  • other: FloatType - 要比较的 FloatType。

返回值:

  • Bool - 如果类型相等则返回 true,否则返回 false。

示例:

import stdx.chir.*

main() {
    let float32Type1 = FloatType.getFloat32()
    let float32Type2 = FloatType.getFloat32()
    let float64Type = FloatType.getFloat64()
    println("两个 Float32 相等: ${float32Type1 == float32Type2}")
    println("Float32 和 Float64 相等: ${float32Type1 == float64Type}")
}

运行结果:

两个 Float32 相等: true
Float32 和 Float64 相等: false

class IntType

public class IntType <: NumericType & Equatable<IntType>

功能:表示类型系统中的整数类型。该类表示各种大小的有符号和无符号整数类型。

父类型:

static func getInt16()

public static func getInt16(): IntType

功能:获取 Int16 类型实例。

返回值:

  • IntType - Int16 类型。

示例:

import stdx.chir.*

main() {
    let int16Type = IntType.getInt16()
    println("Int16 类型: ${int16Type.toString()}")
}

运行结果:

Int16 类型: Int16

static func getInt32()

public static func getInt32(): IntType

功能:获取 Int32 类型实例。

返回值:

  • IntType - Int32 类型。

示例:

import stdx.chir.*

main() {
    let int32Type = IntType.getInt32()
    println("Int32 类型: ${int32Type.toString()}")
}

运行结果:

Int32 类型: Int32

static func getInt64()

public static func getInt64(): IntType

功能:获取 Int64 类型实例。

返回值:

  • IntType - Int64 类型。

示例:

import stdx.chir.*

main() {
    let int64Type = IntType.getInt64()
    println("Int64 类型: ${int64Type.toString()}")
}

运行结果:

Int64 类型: Int64

static func getInt8()

public static func getInt8(): IntType

功能:获取 Int8 类型实例。

返回值:

  • IntType - Int8 类型。

示例:

import stdx.chir.*

main() {
    let int8Type = IntType.getInt8()
    println("Int8 类型: ${int8Type.toString()}")
}

运行结果:

Int8 类型: Int8

static func getIntNative()

public static func getIntNative(): IntType

功能:获取 IntNative 类型实例。

返回值:

  • IntType - IntNative 类型。

示例:

import stdx.chir.*

main() {
    let intNativeType = IntType.getIntNative()
    println("IntNative 类型: ${intNativeType.toString()}")
}

运行结果:

IntNative 类型: IntNative

static func getUInt16()

public static func getUInt16(): IntType

功能:获取 UInt16 类型实例。

返回值:

  • IntType - UInt16 类型。

示例:

import stdx.chir.*

main() {
    let uint16Type = IntType.getUInt16()
    println("UInt16 类型: ${uint16Type.toString()}")
}

运行结果:

UInt16 类型: UInt16

static func getUInt32()

public static func getUInt32(): IntType

功能:获取 UInt32 类型实例。

返回值:

  • IntType - UInt32 类型。

示例:

import stdx.chir.*

main() {
    let uint32Type = IntType.getUInt32()
    println("UInt32 类型: ${uint32Type.toString()}")
}

运行结果:

UInt32 类型: UInt32

static func getUInt64()

public static func getUInt64(): IntType

功能:获取 UInt64 类型实例。

返回值:

  • IntType - UInt64 类型。

示例:

import stdx.chir.*

main() {
    let uint64Type = IntType.getUInt64()
    println("UInt64 类型: ${uint64Type.toString()}")
}

运行结果:

UInt64 类型: UInt64

static func getUInt8()

public static func getUInt8(): IntType

功能:获取 UInt8 类型实例。

返回值:

  • IntType - UInt8 类型。

示例:

import stdx.chir.*

main() {
    let uint8Type = IntType.getUInt8()
    println("UInt8 类型: ${uint8Type.toString()}")
}

运行结果:

UInt8 类型: UInt8

static func getUIntNative()

public static func getUIntNative(): IntType

功能:获取 UIntNative 类型实例。

返回值:

  • IntType - UIntNative 类型。

示例:

import stdx.chir.*

main() {
    let uintNativeType = IntType.getUIntNative()
    println("UIntNative 类型: ${uintNativeType.toString()}")
}

运行结果:

UIntNative 类型: UIntNative

operator func==(IntType)

public operator func==(other: IntType): Bool

功能:检查该 IntType 是否与另一个 IntType 相等。

参数:

  • other: IntType - 要比较的 IntType。

返回值:

  • Bool - 如果类型相等则返回 true,否则返回 false。

示例:

import stdx.chir.*

main() {
    let int32Type1 = IntType.getInt32()
    let int32Type2 = IntType.getInt32()
    let int64Type = IntType.getInt64()
    println("两个 Int32 相等: ${int32Type1 == int32Type2}")
    println("Int32 和 Int64 相等: ${int32Type1 == int64Type}")
}

运行结果:

两个 Int32 相等: true
Int32 和 Int64 相等: false

func isSigned()

public func isSigned(): Bool

功能:检查该整数类型是否为有符号类型。

返回值:

  • Bool - 如果类型是有符号的则返回 true,如果是无符号的则返回 false。

示例:

import stdx.chir.*

main() {
    let int32Type = IntType.getInt32()
    let uint32Type = IntType.getUInt32()
    println("Int32 是有符号的: ${int32Type.isSigned()}")
    println("UInt32 是有符号的: ${uint32Type.isSigned()}")
}

运行结果:

Int32 是有符号的: true
UInt32 是有符号的: false

class NothingType

public class NothingType <: BuiltinType & Equatable<NothingType>

功能:表示类型系统中的 Nothing 类型(底部类型)。该类型用于表示永远不会返回的表达式。

父类型:

  • BuiltinType
  • Equatable<NothingType>

static func get()

public static func get(): NothingType

功能:获取 NothingType 的单例实例。

返回值:

  • NothingType - NothingType 实例。

示例:

import stdx.chir.*

main() {
    let nothingType = NothingType.get()
    println("Nothing 类型: ${nothingType.toString()}")
}

运行结果:

Nothing 类型: Nothing

operator func==(NothingType)

public operator func==(_: NothingType): Bool

功能:检查该 NothingType 是否与另一个 NothingType 相等。

参数:

  • _: NothingType - 要比较的另一个 NothingType(未使用,始终返回 true)。

返回值:

  • Bool - 始终返回 true,因为所有 NothingType 实例都相等。

示例:

import stdx.chir.*

main() {
    let nothingType1 = NothingType.get()
    let nothingType2 = NothingType.get()
    println("两个 NothingType 相等: ${nothingType1 == nothingType2}")
}

运行结果:

两个 NothingType 相等: true

class NumericType

sealed abstract class NumericType <: BuiltinType & Equatable<NumericType>

功能:数值类型的抽象基类。该类表示数值类型,包括整数类型和浮点类型。

父类型:

  • BuiltinType
  • Equatable<NumericType>

operator func==(NumericType)

public operator func==(other: NumericType): Bool

功能:检查该数值类型是否与另一个数值类型相等。

参数:

  • other: NumericType - 要比较的数值类型。

返回值:

  • Bool - 如果类型相等则返回 true,否则返回 false。

示例:

import stdx.chir.*

main() {
    let intType1 = IntType.getInt32()
    let intType2 = IntType.getInt32()
    let floatType = FloatType.getFloat32()
    println("两个 Int32 相等: ${intType1 == intType2}")
    println("Int32 和 Float32 相等: ${intType1 == floatType}")
}

运行结果:

两个 Int32 相等: true
Int32 和 Float32 相等: false

class RefType

public class RefType <: Type & Equatable<RefType>

功能:表示类型系统中的引用类型。该类型包装另一个类型以表示对该类型的引用。该类维护所有引用类型的缓存以确保唯一性。

父类型:

  • Type
  • Equatable<RefType>

prop baseType

public prop baseType: Type

功能:获取该引用类型所引用的基类型。

返回值:

  • Type - 基类型。

示例:

import stdx.chir.*

main() {
    let intType = IntType.getInt32()
    let refType = RefType.get(intType)
    let baseType = refType.baseType
    println("引用类型: ${refType.toString()}")
    println("基类型: ${baseType.toString()}")
}

运行结果:

引用类型: Int32&
基类型: Int32

operator func==(RefType)

public operator func==(other: RefType): Bool

功能:检查该 RefType 是否与另一个 RefType 相等。

参数:

  • other: RefType - 要比较的 RefType。

返回值:

  • Bool - 如果类型相等则返回 true,否则返回 false。

示例:

import stdx.chir.*

main() {
    let intType = IntType.getInt32()
    let refType1 = RefType.get(intType)
    let refType2 = RefType.get(intType)
    println("两个引用类型相等: ${refType1 == refType2}")
}

运行结果:

两个引用类型相等: true

static func get(Type)

public static func get(baseType: Type): RefType

功能:获取或创建给定基类型的 RefType。

此方法确保每个基类型只存在一个 RefType 实例。

参数:

  • baseType: Type - 要创建引用的基类型。

返回值:

  • RefType - 给定基类型的 RefType 实例。

示例:

import stdx.chir.*

main() {
    let intType = IntType.getInt32()
    let refType = RefType.get(intType)
    println("引用类型: ${refType.toString()}")
}

运行结果:

引用类型: Int32&

func toString()

public func toString(): String

功能:将该 RefType 转换为字符串表示。

返回值:

  • String - 引用类型的字符串表示(基类型后跟 '&')。

示例:

import stdx.chir.*

main() {
    let intType = IntType.getInt32()
    let refType = RefType.get(intType)
    println("引用类型字符串: ${refType.toString()}")
}

运行结果:

引用类型字符串: Int32&

class RuneType

public class RuneType <: BuiltinType & Equatable<RuneType>

功能:表示类型系统中的 Rune 类型。该类型表示字符类型。

父类型:

  • BuiltinType
  • Equatable<RuneType>

static func get()

public static func get(): RuneType

功能:获取 RuneType 的单例实例。

返回值:

  • RuneType - RuneType 实例。

示例:

import stdx.chir.*

main() {
    let runeType = RuneType.get()
    println("Rune 类型: ${runeType.toString()}")
}

运行结果:

Rune 类型: Rune

operator func==(RuneType)

public operator func==(_: RuneType): Bool

功能:检查该 RuneType 是否与另一个 RuneType 相等。

参数:

  • _: RuneType - 要比较的另一个 RuneType(未使用,始终返回 true)。

返回值:

  • Bool - 始终返回 true,因为所有 RuneType 实例都相等。

示例:

import stdx.chir.*

main() {
    let runeType1 = RuneType.get()
    let runeType2 = RuneType.get()
    println("两个 RuneType 相等: ${runeType1 == runeType2}")
}

运行结果:

两个 RuneType 相等: true

class Type

sealed abstract class Type <: ToString & Hashable & Equatable<Type>

功能:类型系统中所有类型的抽象基类。该类提供了类型的基础功能,包括相等性比较、哈希计算和字符串转换。

父类型:

  • ToString
  • Hashable
  • Equatable<Type>

prop typeArgs

public prop typeArgs: Array<Type>

功能:获取该类型的类型参数。

返回值:

  • Array<Type> - 类型参数数组。

示例:

import stdx.chir.*

main() {
    let intType = IntType.getInt32()
    println("类型参数数量: ${intType.typeArgs.size}")
}

运行结果:

类型参数数量: 0

func dump()

public func dump(): Unit

功能:将类型的字符串表示打印到标准输出。

示例:

import stdx.chir.*

main() {
    let intType = IntType.getInt32()
    intType.dump()
}

运行结果:

Int32

func hashCode()

public func hashCode(): Int64

功能:获取该类型的哈希码。

返回值:

  • Int64 - 类型的哈希码。

示例:

import stdx.chir.*

main() {
    let intType = IntType.getInt32()
    println("哈希码: ${intType.hashCode()}")
}

运行结果:

哈希码: -7959616418923165251

func isBoolType()

public func isBoolType(): Bool

功能:检查该类型是否为布尔类型。

返回值:

  • Bool - 如果类型是 Bool 则返回 true,否则返回 false。

示例:

import stdx.chir.*

main() {
    let boolType = BoolType.get()
    let intType = IntType.getInt32()
    println("BoolType 是布尔类型: ${boolType.isBoolType()}")
    println("Int32 是布尔类型: ${intType.isBoolType()}")
}

运行结果:

BoolType 是布尔类型: true
Int32 是布尔类型: false

func isFloatType()

public func isFloatType(): Bool

功能:检查该类型是否为浮点类型。

返回值:

  • Bool - 如果类型是 Float16、Float32 或 Float64 则返回 true,否则返回 false。

示例:

import stdx.chir.*

main() {
    let floatType = FloatType.getFloat32()
    let intType = IntType.getInt32()
    println("Float32 是浮点类型: ${floatType.isFloatType()}")
    println("Int32 是浮点类型: ${intType.isFloatType()}")
}

运行结果:

Float32 是浮点类型: true
Int32 是浮点类型: false

func isIntType()

public func isIntType(): Bool

功能:检查该类型是否为整数类型(有符号或无符号)。

返回值:

  • Bool - 如果类型是任何整数类型则返回 true,否则返回 false。

示例:

import stdx.chir.*

main() {
    let intType = IntType.getInt32()
    let floatType = FloatType.getFloat32()
    println("Int32 是整数类型: ${intType.isIntType()}")
    println("Float32 是整数类型: ${floatType.isIntType()}")
}

运行结果:

Int32 是整数类型: true
Float32 是整数类型: false

func isNothingType()

public func isNothingType(): Bool

功能:检查该类型是否为 Nothing 类型。

返回值:

  • Bool - 如果类型是 Nothing 则返回 true,否则返回 false。

示例:

import stdx.chir.*

main() {
    let nothingType = NothingType.get()
    let intType = IntType.getInt32()
    println("NothingType 是 Nothing 类型: ${nothingType.isNothingType()}")
    println("Int32 是 Nothing 类型: ${intType.isNothingType()}")
}

运行结果:

NothingType 是 Nothing 类型: true
Int32 是 Nothing 类型: false

func isNumericType()

public func isNumericType(): Bool

功能:检查该类型是否为数值类型(整数或浮点数)。

返回值:

  • Bool - 如果类型是数值类型则返回 true,否则返回 false。

示例:

import stdx.chir.*

main() {
    let intType = IntType.getInt32()
    let floatType = FloatType.getFloat32()
    let boolType = BoolType.get()
    println("Int32 是数值类型: ${intType.isNumericType()}")
    println("Float32 是数值类型: ${floatType.isNumericType()}")
    println("Bool 是数值类型: ${boolType.isNumericType()}")
}

运行结果:

Int32 是数值类型: true
Float32 是数值类型: true
Bool 是数值类型: false

func isPrimitiveType()

public func isPrimitiveType(): Bool

功能:检查该类型是否为原始类型。

返回值:

  • Bool - 如果类型是原始类型(int、float、bool、rune、unit 或 nothing)则返回 true,否则返回 false。

示例:

import stdx.chir.*

main() {
    let intType = IntType.getInt32()
    let boolType = BoolType.get()
    println("Int32 是原始类型: ${intType.isPrimitiveType()}")
    println("Bool 是原始类型: ${boolType.isPrimitiveType()}")
}

运行结果:

Int32 是原始类型: true
Bool 是原始类型: true

func isRefType()

public func isRefType(): Bool

功能:检查该类型是否为引用类型。

返回值:

  • Bool - 如果类型是引用类型则返回 true,否则返回 false。

示例:

import stdx.chir.*

main() {
    let intType = IntType.getInt32()
    let refType = RefType.get(intType)
    println("Int32 是引用类型: ${intType.isRefType()}")
    println("Int32& 是引用类型: ${refType.isRefType()}")
}

运行结果:

Int32 是引用类型: false
Int32& 是引用类型: true

func isRuneType()

public func isRuneType(): Bool

功能:检查该类型是否为 Rune 类型。

返回值:

  • Bool - 如果类型是 Rune 则返回 true,否则返回 false。

示例:

import stdx.chir.*

main() {
    let runeType = RuneType.get()
    let intType = IntType.getInt32()
    println("RuneType 是 Rune 类型: ${runeType.isRuneType()}")
    println("Int32 是 Rune 类型: ${intType.isRuneType()}")
}

运行结果:

RuneType 是 Rune 类型: true
Int32 是 Rune 类型: false

func isSignedIntType()

public func isSignedIntType(): Bool

功能:检查该类型是否为有符号整数类型。

返回值:

  • Bool - 如果类型是有符号整数类型则返回 true,否则返回 false。

示例:

import stdx.chir.*

main() {
    let intType = IntType.getInt32()
    let uintType = IntType.getUInt32()
    println("Int32 是有符号整数: ${intType.isSignedIntType()}")
    println("UInt32 是有符号整数: ${uintType.isSignedIntType()}")
}

运行结果:

Int32 是有符号整数: true
UInt32 是有符号整数: false

func isUnitType()

public func isUnitType(): Bool

功能:检查该类型是否为 Unit 类型。

返回值:

  • Bool - 如果类型是 Unit 则返回 true,否则返回 false。

示例:

import stdx.chir.*

main() {
    let unitType = UnitType.get()
    let intType = IntType.getInt32()
    println("UnitType 是 Unit 类型: ${unitType.isUnitType()}")
    println("Int32 是 Unit 类型: ${intType.isUnitType()}")
}

运行结果:

UnitType 是 Unit 类型: true
Int32 是 Unit 类型: false

func isUnsignedIntType()

public func isUnsignedIntType(): Bool

功能:检查该类型是否为无符号整数类型。

返回值:

  • Bool - 如果类型是无符号整数类型则返回 true,否则返回 false。

示例:

import stdx.chir.*

main() {
    let intType = IntType.getInt32()
    let uintType = IntType.getUInt32()
    println("Int32 是无符号整数: ${intType.isUnsignedIntType()}")
    println("UInt32 是无符号整数: ${uintType.isUnsignedIntType()}")
}

运行结果:

Int32 是无符号整数: false
UInt32 是无符号整数: true

operator func==(Type)

public open operator func==(other: Type): Bool

功能:检查该类型是否与另一个类型相等。

参数:

  • other: Type - 要比较的类型。

返回值:

  • Bool - 如果类型具有相同的种类和类型参数则返回 true,否则返回 false。

示例:

import stdx.chir.*

main() {
    let type1 = IntType.getInt32()
    let type2 = IntType.getInt32()
    let type3 = IntType.getInt64()
    println("type1 == type2: ${type1 == type2}")
    println("type1 == type3: ${type1 == type3}")
}

运行结果:

type1 == type2: true
type1 == type3: false

func stripAllRefs()

public func stripAllRefs(): Type

功能:去除该类型的所有引用包装。

递归地移除所有 Ref 类型包装,直到到达非引用类型。

返回值:

  • Type - 去除所有引用包装后的基类型。

示例:

import stdx.chir.*

main() {
    let intType = IntType.getInt32()
    let refType = RefType.get(intType)
    let baseType = refType.stripAllRefs()
    println("引用类型: ${refType.toString()}")
    println("去除引用后: ${baseType.toString()}")
}

运行结果:

引用类型: Int32&
去除引用后: Int32

func toString()

public open func toString(): String

功能:将类型转换为字符串表示。

返回值:

  • String - 类型的字符串表示。

示例:

import stdx.chir.*

main() {
    let intType = IntType.getInt32()
    println("类型: ${intType.toString()}")
}

运行结果:

类型: Int32

class UnitType

public class UnitType <: BuiltinType & Equatable<UnitType>

功能:表示类型系统中的 Unit 类型。该类型表示没有有意义的值,类似于 C 语言中的 void。

父类型:

  • BuiltinType
  • Equatable<UnitType>

static func get()

public static func get(): UnitType

功能:获取 UnitType 的单例实例。

返回值:

  • UnitType - UnitType 实例。

示例:

import stdx.chir.*

main() {
    let unitType = UnitType.get()
    println("Unit 类型: ${unitType.toString()}")
}

运行结果:

Unit 类型: Unit

operator func==(UnitType)

public operator func==(_: UnitType): Bool

功能:检查该 UnitType 是否与另一个 UnitType 相等。

参数:

  • _: UnitType - 要比较的另一个 UnitType(未使用,始终返回 true)。

返回值:

  • Bool - 始终返回 true,因为所有 UnitType 实例都相等。

示例:

import stdx.chir.*

main() {
    let unitType1 = UnitType.get()
    let unitType2 = UnitType.get()
    println("两个 UnitType 相等: ${unitType1 == unitType2}")
}

运行结果:

两个 UnitType 相等: true

stdx.compress

功能介绍

compress 是一个压缩与归档能力的集合模块,旨在提供流式、高效且易用的压缩与归档工具集,支持单文件压缩、数据流压缩、以及归档(打包)功能的组合使用。

压缩是指用更少的比特表示数据,以便更高效地存储和传输数据。此能力由子模块 stdx.compress.zlib 提供。

归档是将多个文件/目录的元数据与内容打包为一个连续的归档流(不隐含压缩)。此能力由子模块 stdx.compress.tar 提供,支持 V7/USTAR/PAX/GNU 格式。

压缩和归档通常组合使用,常见用法是先归档再压缩(例如 tar.gz)。本包在顶层提供便捷的组合工具(例如 TarGzip),将打包与压缩组合为单步读写接口,方便常见场景使用。

API 列表

类名功能
TarGzip一键式 tar.gz 压缩解压组合工具

class TarGzip

public class TarGzip {}

功能:压缩和解压目录或流。

static func archive(Path, (Path) -> Bool, Path, Bool)

public static func archive(fromDir!: Path, filter!: (Path) -> Bool, destFile!: Path, includeBaseDirectory!: Bool): Unit

功能:配合过滤函数选择性地将指定目录压缩为 .tar.gz 文件。内部先以 tar 格式归档目录,再以 gzip 压缩归档结果。

参数:

  • fromDir!: Path - 待压缩目录。

  • filter!: (Path) -> Bool - 过滤函数,会传入遍历到的目录、文件和软链接路径,返回 true 表示保留,否则丢弃。

  • destFile!: Path - 输出的 .tar.gz 文件路径。

  • includeBaseDirectory!: Bool - 是否包含根目录。

异常:

  • TarException - 如果 tar 归档时发生错误,抛出异常。

  • ZlibException - 如果 zlib 压缩时发生错误,抛出异常。

示例:

import stdx.compress.*
import std.fs.*

main(): Unit {
    // 测试路径
    let testDir = Path("./test_dir")
    let testFile = Path("./test_dir/test.txt")
    let destFile = Path("./test.tar.gz")

    // 创建目录和文件(创建前清理)
    removeIfExists(testDir, recursive: true)
    Directory.create(testDir)
    File.writeTo(testFile, "Hello, TarGzip!".toArray())

    // 使用TarGzip压缩目录,使用过滤函数
    TarGzip.archive(
        fromDir: testDir,
        filter: {path: Path => return path.toString().endsWith(".txt")},
        destFile: destFile,
        includeBaseDirectory: true
    )

    println("Did the TarGzip archive with filter complete successfully? ${exists(destFile)}")

    // 清理测试文件
    removeIfExists(testDir, recursive: true)
    removeIfExists(destFile)
}

运行结果:

Did the TarGzip archive with filter complete successfully? true

static func archive(Path, Path, Bool)

public static func archive(fromDir!: Path, destFile!: Path, includeBaseDirectory!: Bool): Unit

功能:将指定目录压缩为 .tar.gz 文件。内部先以 tar 格式归档目录,再以 gzip 压缩归档结果。

参数:

  • fromDir!: Path - 待压缩的目录路径。

  • destFile!: Path - 生成的 .tar.gz 文件路径。

  • includeBaseDirectory!: Bool - 是否包含目录本身作为顶级目录。若为 true,归档包内包含该目录;若为 false,仅包含其内容。

异常:

  • TarException - 如果 tar 归档时发生错误,抛出异常。

  • ZlibException - 如果 zlib 压缩时发生错误,抛出异常。

示例:

import stdx.compress.*
import std.fs.*

main(): Unit {
    // 测试路径
    let testDir = Path("./test_dir_simple")
    let testFile = Path("./test_dir_simple/test.txt")
    let destFile = Path("./test_simple.tar.gz")

    // 创建目录和文件(创建前清理)
    removeIfExists(testDir, recursive: true)
    Directory.create(testDir)
    File.writeTo(testFile, "Hello, TarGzip Simple Archive!".toArray())

    // 使用TarGzip压缩目录,不使用过滤函数
    TarGzip.archive(
        fromDir: testDir,
        destFile: destFile,
        includeBaseDirectory: true
    )

    println("Did the TarGzip simple archive complete successfully? ${exists(destFile)}")

    // 清理测试文件
    removeIfExists(testDir, recursive: true)
    removeIfExists(destFile)
}

运行结果:

Did the TarGzip simple archive complete successfully? true

static func archive(String, (String) -> Bool, String, Bool)

public static func archive(fromDir!: String, filter!: (String) -> Bool, destFile!: String, includeBaseDirectory!: Bool): Unit

功能:配合过滤函数选择性地将指定目录压缩为 .tar.gz 文件。内部先以 tar 格式归档目录,再以 gzip 压缩归档结果。

参数:

  • fromDir!: String - 待压缩目录。

  • filter!: (String) -> Bool - 过滤函数,会传入遍历到的目录、文件和软链接路径,返回 true 表示保留,否则丢弃。

  • destFile!: String - 输出的 .tar.gz 文件路径。

  • includeBaseDirectory!: Bool - 是否包含根目录。

异常:

  • TarException - 如果 tar 归档时发生错误,抛出异常。

  • ZlibException - 如果 zlib 压缩时发生错误,抛出异常。

示例:

import stdx.compress.*
import std.fs.*

main(): Unit {
    // 测试路径
    let testDir = "./test_dir_str_filter"
    let testFile = "./test_dir_str_filter/test.txt"
    let testLogFile = "./test_dir_str_filter/test.log"
    let destFile = "./test_str_filter.tar.gz"

    // 创建目录和文件(创建前清理)
    removeIfExists(testDir, recursive: true)
    Directory.create(testDir)
    File.writeTo(testFile, "Hello, TarGzip String Filter Archive!".toArray())
    File.writeTo(testLogFile, "This is a log file that should be filtered out".toArray())

    // 使用TarGzip压缩目录,使用字符串过滤函数
    TarGzip.archive(
        fromDir: testDir,
        filter: {path: String => return path.endsWith(".txt")},
        destFile: destFile,
        includeBaseDirectory: true
    )

    println("Did the TarGzip archive with string filter complete successfully? ${exists(Path(destFile))}")

    // 清理测试文件
    removeIfExists(testDir, recursive: true)
    removeIfExists(destFile)
}

运行结果:

Did the TarGzip archive with string filter complete successfully? true

static func archive(String, String, Bool)

public static func archive(fromDir!: String, destFile!: String, includeBaseDirectory!: Bool): Unit

功能:将指定目录压缩为 .tar.gz 文件。内部先以 tar 格式归档目录,再以 gzip 压缩归档结果。

参数:

  • fromDir!: String - 待压缩的目录路径。

  • destFile!: String - 生成的 .tar.gz 文件路径。

  • includeBaseDirectory!: Bool - 是否包含目录本身作为顶级目录。若为 true,归档包内包含该目录;若为 false,仅包含其内容。

异常:

  • TarException - 如果 tar 归档时发生错误,抛出异常。

  • ZlibException - 如果 zlib 压缩时发生错误,抛出异常。

示例:

import stdx.compress.*
import std.fs.*

main(): Unit {
    // 测试路径
    let testDir = "./test_dir_str_simple"
    let testFile = "./test_dir_str_simple/test.txt"
    let destFile = "./test_str_simple.tar.gz"

    // 创建目录和文件(创建前清理)
    removeIfExists(testDir, recursive: true)
    Directory.create(testDir)
    File.writeTo(testFile, "Hello, TarGzip String Simple Archive!".toArray())

    // 使用TarGzip压缩目录,使用字符串参数
    TarGzip.archive(
        fromDir: testDir,
        destFile: destFile,
        includeBaseDirectory: true
    )

    println("Did the TarGzip string simple archive complete successfully? ${exists(destFile)}")

    // 清理测试文件
    removeIfExists(testDir, recursive: true)
    removeIfExists(destFile)
}

运行结果:

Did the TarGzip string simple archive complete successfully? true

static func archive<T>(Path, T, Bool) where T <: OutputStream

public static func archive<T>(fromDir!: Path, destStream!: T, includeBaseDirectory!: Bool): Unit where T <: OutputStream

功能:将目录压缩为 .tar.gz 数据并写入指定输出流。

注意:

函数不负责 destStream 资源的释放,调用方需自行管理该输出流的生命周期。

参数:

  • fromDir!: Path - 待压缩的目录路径。

  • destStream!: T - 压缩后数据的输出流。

  • includeBaseDirectory!: Bool - 是否包含根目录。

异常:

  • TarException - 如果 tar 归档时发生错误,抛出异常。

  • ZlibException - 如果 zlib 压缩时发生错误,抛出异常。

示例:

import stdx.compress.*
import std.fs.*
import std.io.*

main(): Unit {
    // 测试路径
    let testDir = Path("./test_dir_stream")
    let testFile = Path("./test_dir_stream/test.txt")
    let destFile = Path("./test_stream.tar.gz")

    // 创建目录和文件(创建前清理)
    removeIfExists(testDir, recursive: true)
    Directory.create(testDir)
    File.writeTo(testFile, "Hello, TarGzip Stream Archive!".toArray())

    // 创建文件输出流
    let fileStream = File(destFile, Write)

    // 使用TarGzip压缩目录到输出流
    TarGzip.archive(
        fromDir: testDir,
        destStream: fileStream,
        includeBaseDirectory: true
    )

    // 关闭流
    fileStream.close()

    println("Did the TarGzip archive to stream complete successfully? ${exists(destFile)}")

    // 清理测试文件
    removeIfExists(testDir, recursive: true)
    removeIfExists(destFile)
}

运行结果:

Did the TarGzip archive to stream complete successfully? true

static func archive<T>(String, T, Bool) where T <: OutputStream

public static func archive<T>(fromDir!: String, destStream!: T, includeBaseDirectory!: Bool): Unit where T <: OutputStream

功能:将目录压缩为 .tar.gz 数据并写入指定输出流。

注意:

函数不负责 destStream 资源的释放,调用方需自行管理该输出流的生命周期。

参数:

  • fromDir!: String - 待压缩的目录路径。

  • destStream!: T - 压缩后数据的输出流。

  • includeBaseDirectory!: Bool - 是否包含根目录。

异常:

  • TarException - 如果 tar 归档时发生错误,抛出异常。

  • ZlibException - 如果 zlib 压缩时发生错误,抛出异常。

示例:

import stdx.compress.*
import std.fs.*
import std.io.*

main(): Unit {
    // 测试路径
    let testDir = "./test_dir_stream_str"
    let testFile = "./test_dir_stream_str/test.txt"
    let destFile = "./test_stream_str.tar.gz"

    // 创建目录和文件(创建前清理)
    removeIfExists(testDir, recursive: true)
    Directory.create(testDir)
    File.writeTo(testFile, "Hello, TarGzip Stream Archive with String Path!".toArray())

    // 创建文件输出流
    let fileStream = File(destFile, Write)

    // 使用TarGzip压缩目录到输出流(使用字符串路径)
    TarGzip.archive(
        fromDir: testDir,
        destStream: fileStream,
        includeBaseDirectory: true
    )

    // 关闭流
    fileStream.close()

    println("Did the TarGzip archive to stream with string path complete successfully? ${exists(destFile)}")

    // 清理测试文件
    removeIfExists(testDir, recursive: true)
    removeIfExists(destFile)
}

运行结果:

Did the TarGzip archive to stream with string path complete successfully? true

static func extract(Path, Path, Bool)

public static func extract(fromTarGzip!: Path, destDir!: Path, overwrite!: Bool): Unit

功能:将 .tar.gz 文件解压至指定目录。内部先以 gzip 解压缩,再以 tar 解包。

参数:

  • fromTarGzip!: Path - 待解压的 .tar.gz 文件路径。

  • destDir!: Path - 解压目标目录。

  • overwrite!: Bool - 若为 true,允许覆盖已存在文件、目录;否则遇到重名文件、目录将抛出异常。

异常:

  • TarException - 如果 tar 提取时发生错误,抛出异常。

  • ZlibException - 如果 zlib 解压时发生错误,抛出异常。

示例:

import stdx.compress.*
import std.fs.*

main(): Unit {
    // 测试路径
    let testDir = Path("./test_extract_dir")
    let testFile = Path("./test_extract_dir/test.txt")
    let archiveFile = Path("./test_extract.tar.gz")
    let extractDir = Path("./extracted_dir")

    // 创建目录和文件(创建前清理)
    removeIfExists(testDir, recursive: true)
    Directory.create(testDir)
    File.writeTo(testFile, "Hello, TarGzip Extract!".toArray())

    // 首先创建一个压缩文件
    TarGzip.archive(
        fromDir: testDir,
        destFile: archiveFile,
        includeBaseDirectory: true
    )

    // 清理测试目录,保留压缩文件
    removeIfExists(testDir, recursive: true)

    // 创建解压目标目录
    removeIfExists(extractDir, recursive: true)
    Directory.create(extractDir)

    // 解压文件
    TarGzip.extract(
        fromTarGzip: archiveFile,
        destDir: extractDir,
        overwrite: true
    )

    println("Did the TarGzip extract complete successfully? ${exists(extractDir)}")

    // 清理测试文件
    removeIfExists(archiveFile)
    removeIfExists(extractDir, recursive: true)
}

运行结果:

Did the TarGzip extract complete successfully? true

static func extract(String, String, Bool)

public static func extract(fromTarGzip!: String, destDir!: String, overwrite!: Bool): Unit

功能:将 .tar.gz 文件解压至指定目录。内部先以 gzip 解压缩,再以 tar 解包。

参数:

  • fromTarGzip!: String - 待解压的 .tar.gz 文件路径。

  • destDir!: String - 解压目标目录。

  • overwrite!: Bool - 若为 true,允许覆盖已存在文件、目录;否则遇到重名文件、目录将抛出异常。

异常:

  • TarException - 如果 tar 提取时发生错误,抛出异常。

  • ZlibException - 如果 zlib 解压时发生错误,抛出异常。

示例:

import stdx.compress.*
import std.fs.*

main(): Unit {
    // 测试路径
    let testDir = "./test_extract_dir_str"
    let testFile = "./test_extract_dir_str/test.txt"
    let archiveFile = "./test_extract_str.tar.gz"
    let extractDir = "./extracted_dir_str"

    // 创建目录和文件(创建前清理)
    removeIfExists(testDir, recursive: true)
    Directory.create(testDir)
    File.writeTo(testFile, "Hello, TarGzip Extract with String Paths!".toArray())

    // 首先创建一个压缩文件
    TarGzip.archive(
        fromDir: testDir,
        destFile: archiveFile,
        includeBaseDirectory: true
    )

    // 清理测试目录,保留压缩文件
    removeIfExists(testDir, recursive: true)

    // 创建解压目标目录
    removeIfExists(extractDir, recursive: true)
    Directory.create(extractDir)

    // 解压文件(使用字符串路径)
    TarGzip.extract(
        fromTarGzip: archiveFile,
        destDir: extractDir,
        overwrite: true
    )

    println("Did the TarGzip extract with string paths complete successfully? ${exists(extractDir)}")

    // 清理测试文件
    removeIfExists(archiveFile)
    removeIfExists(extractDir, recursive: true)
}

运行结果:

Did the TarGzip extract with string paths complete successfully? true

static func extract<T>(T, Path, Bool) where T <: InputStream

public static func extract<T>(fromStream!: T, destDir!: Path, overwrite!: Bool): Unit where T <: InputStream

功能:将 .tar.gz 数据从输入流中读取并解压至指定目录。

参数:

  • fromStream!: T - 待解压的 .tar.gz 数据输入流。

  • destDir!: Path - 解压目标目录。

  • overwrite!: Bool - 若为 true,允许覆盖已存在文件、目录;否则遇到重名文件、目录将抛出异常。

异常:

  • TarException - 如果 tar 提取时发生错误,抛出异常。

  • ZlibException - 如果 zlib 解压时发生错误,抛出异常。

示例:

import stdx.compress.*
import std.fs.*
import std.io.*

main(): Unit {
    // 测试路径
    let testDir = Path("./test_extract_stream_dir")
    let testFile = Path("./test_extract_stream_dir/test.txt")
    let archiveFile = Path("./test_extract_stream.tar.gz")
    let extractDir = Path("./extracted_stream_dir")

    // 创建目录和文件(创建前清理)
    removeIfExists(testDir, recursive: true)
    Directory.create(testDir)
    File.writeTo(testFile, "Hello, TarGzip Extract with Stream!".toArray())

    // 首先创建一个压缩文件
    TarGzip.archive(
        fromDir: testDir,
        destFile: archiveFile,
        includeBaseDirectory: true
    )

    // 清理测试目录,保留压缩文件
    removeIfExists(testDir, recursive: true)

    // 创建解压目标目录
    removeIfExists(extractDir, recursive: true)
    Directory.create(extractDir)

    // 创建输入流并从文件读取
    let inputStream = File(archiveFile, Read)

    // 从输入流解压文件
    TarGzip.extract(
        fromStream: inputStream,
        destDir: extractDir,
        overwrite: true
    )

    // 关闭输入流
    inputStream.close()

    println("Did the TarGzip extract from stream complete successfully? ${exists(extractDir)}")

    // 清理测试文件
    removeIfExists(archiveFile)
    removeIfExists(extractDir, recursive: true)
}

运行结果:

Did the TarGzip extract from stream complete successfully? true

static func extract<T>(T, String, Bool) where T <: InputStream

public static func extract<T>(fromStream!: T, destDir!: String, overwrite!: Bool): Unit where T <: InputStream

功能:将 .tar.gz 数据从输入流中读取并解压至指定目录。

参数:

  • fromStream!: T - 待解压的 .tar.gz 数据输入流。

  • destDir!: String - 解压目标目录。

  • overwrite!: Bool - 若为 true,允许覆盖已存在文件、目录;否则遇到重名文件、目录将抛出异常。

异常:

  • TarException - 如果 tar 提取时发生错误,抛出异常。

  • ZlibException - 如果 zlib 解压时发生错误,抛出异常。

示例:

import stdx.compress.*
import std.fs.*
import std.io.*

main(): Unit {
    // 测试路径
    let testDir = Path("./test_extract_stream_str_dir")
    let testFile = Path("./test_extract_stream_str_dir/test.txt")
    let archiveFile = Path("./test_extract_stream_str.tar.gz")
    let extractDir = "./extracted_stream_str_dir"

    // 创建目录和文件(创建前清理)
    removeIfExists(testDir, recursive: true)
    Directory.create(testDir)
    File.writeTo(testFile, "Hello, TarGzip Extract with Stream and String Path!".toArray())

    // 首先创建一个压缩文件
    TarGzip.archive(
        fromDir: testDir,
        destFile: archiveFile,
        includeBaseDirectory: true
    )

    // 清理测试目录,保留压缩文件
    removeIfExists(testDir, recursive: true)

    // 创建解压目标目录
    removeIfExists(extractDir, recursive: true)
    Directory.create(extractDir)

    // 创建输入流并从文件读取
    let inputStream = File(archiveFile, Read)

    // 从输入流解压文件(目标目录使用字符串路径)
    TarGzip.extract(
        fromStream: inputStream,
        destDir: extractDir,
        overwrite: true
    )

    // 关闭输入流
    inputStream.close()

    println("Did the TarGzip extract from stream with string path complete successfully? ${exists(extractDir)}")

    // 清理测试文件
    removeIfExists(archiveFile)
    removeIfExists(extractDir, recursive: true)
}

运行结果:

Did the TarGzip extract from stream with string path complete successfully? true

stdx.compress.tar

功能介绍

compress.tar 提供了归档和读取功能。

归档是一种将多个文件或目录组织成单个文件的方法,通常用于将多个文件或目录压缩成单个文件,并保存在磁盘上。归档文件通常包含文件的元数据(如文件名、权限、时间戳等)以及文件的内容。常见的归档格式有 tar、zip、rar 等。

本包实现了 tar 归档格式,支持 V7、USTAR、PAX 和 GNU 四种格式。tar 格式广泛用于备份和分发文件的场景中。

说明:

要进行文件压缩请使用 stdx.compress.zlib 进行压缩或使用 stdx.compress 的组合工具 TarGzip 进行归档压缩操作。

规格说明

功能限制

本包当前版本存在以下功能限制:

  • 不支持 ACL(访问控制列表):归档和解归档操作不会处理文件的 ACL 信息。
  • 不支持 xattr(扩展属性):归档和解归档操作不会处理文件的扩展属性。
  • 暂不支持特殊文件类型:块设备文件、字符设备文件和管道文件(FIFO)暂不支持归档和解归档。

setuid/setgid 权限位处理

解归档时,setuid/setgid 权限位会原样恢复到文件上。但实际是否恢复成功,取决于以下因素:

  • 执行解归档操作的用户/进程权限
  • 操作系统的安全限制

在大多数 Unix/Linux 系统中,普通用户无法设置 setgid 位,只有 root 用户或具有相应能力的进程才能成功恢复这些权限位。

uid/gid 恢复行为

解归档时,对于文件 uid/gid 的恢复行为如下:

  • tar 归档文件中记录的 uid/gid 会被读取并尝试恢复到解压后的文件上
  • 实际恢复是否成功,取决于执行进程的权限和操作系统限制
  • 普通用户通常只能将文件的所有者设置为自己的 uid/gid,无法设置为其他用户

一键解压的条目数量限制

Tar 的一键解压方法未对解压的条目总数做限制。如果归档文件包含大量条目,可能导致资源耗尽或处理时间过长。

如需对解压条目数量进行限制,建议使用 TarReader,在迭代过程中添加自定义的限制。

API 列表

类名功能
Tartar 文件操作类。
TarEntry表示 tar 文件条目。
V7TarEntry表示 V7 tar 文件条目。
PosixTarEntry表示 Posix tar 文件条目。
UstarTarEntry表示 USTAR tar 文件条目。
GnuTarEntry表示 GNU tar 文件条目。
PaxTarEntry表示 Pax tar 文件条目。
TarReader用于读取 tar 文件的读取器。
TarWriter用于写入 tar 文件的写入器。

枚举

枚举名功能
TarEntryFormattar 条目格式。
TarEntryTypetar 条目类型。

异常类

异常类名功能
TarExceptiontar 包的异常类。

class GnuTarEntry

public class GnuTarEntry <: PosixTarEntry {
    public init(path: String)
    public init(path: Path)
}

功能:表示 Gnu tar 文件条目。

父类型:

prop accessTime

public prop accessTime: DateTime

功能:获取当前条目的访问时间。

类型:DateTime

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建一个 GnuTarEntry
    var entry = GnuTarEntry(testFile)

    println("访问时间: ${entry.accessTime}")

    // 清理测试文件
    removeIfExists(testFile)
}

可能的运行结果:

访问时间: 2025-12-19T03:42:59Z

prop changeTime

public prop changeTime: DateTime

功能:获取当前条目的修改时间。

类型:DateTime

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建一个 GnuTarEntry
    var entry = GnuTarEntry(testFile)

    println("修改时间: ${entry.changeTime}")

    // 清理测试文件
    removeIfExists(testFile)
}

可能的运行结果:

修改时间: 2025-12-19T03:45:31Z

init(Path)

public init(path: Path)

功能:从文件、目录、软链接构造一个 Gnu tar 文件条目。

参数:

  • path: Path - 文件、目录、软链接的路径。

异常:

  • TarException - 如果 path 参数指定的目标不存在或不是文件、目录、软链接,则抛出异常。

  • FSException - 如果读取目标信息或创建目标文件流失败,则抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建 GnuTarEntry
    var gnuEntry = GnuTarEntry(testFile)

    println("GnuTarEntry created successfully")
    println("Entry name: ${gnuEntry.name}")
    println("Entry size: ${gnuEntry.size}")

    // 清理测试文件
    removeIfExists(testFile)
}

运行结果:

GnuTarEntry created successfully
Entry name: test.txt
Entry size: 11

init(String)

public init(path: String)

功能:从文件、目录、软链接构造一个 Gnu tar 文件条目。

参数:

  • path: String - 文件、目录、软链接的路径。

异常:

  • TarException - 如果 path 参数指定的目标不存在或不是文件、目录、软链接,则抛出异常。

  • FSException - 如果读取目标信息或创建目标文件流失败,则抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = "./test.txt"
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建 GnuTarEntry
    var gnuEntry = GnuTarEntry(testFile)

    println("GnuTarEntry created successfully from string path")
    println("Entry name: ${gnuEntry.name}")
    println("Entry size: ${gnuEntry.size}")

    // 清理测试文件
    removeIfExists(testFile)
}

运行结果:

GnuTarEntry created successfully from string path
Entry name: test.txt
Entry size: 11

func writeTo(OutputStream)

public override func writeTo(target: OutputStream): Unit

功能:将当前条目写入到指定的输出流中。

参数:

  • target: OutputStream - 指定输出流。

异常:

  • TarException - 如果字段超出格式要求或写入失败,则抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建 GnuTarEntry
    var entry = GnuTarEntry(testFile)

    // 创建输出流
    let outFile = File("./output.tar", Write)

    // 将条目写入输出流
    entry.writeTo(outFile)

    println("GnuTarEntry written to stream successfully")

    // 清理文件
    outFile.close()
    removeIfExists(testFile)
    removeIfExists("./output.tar")
}

运行结果:

GnuTarEntry written to stream successfully

class PaxTarEntry

public class PaxTarEntry <: PosixTarEntry {
    public init(path: String)
    public init(path: Path)
}

功能:表示 Pax tar 文件条目。

父类型:

init(Path)

public init(path: Path)

功能:从文件、目录、软链接构造一个 Pax tar 文件条目。

参数:

  • path: Path - 文件、目录、软链接的路径。

异常:

  • TarException - 如果 path 参数指定的目标不存在或不是文件、目录、软链接,则抛出异常。

  • FSException - 如果读取目标信息或创建目标文件流失败,则抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建 PaxTarEntry
    var entry = PaxTarEntry(testFile)

    println("PaxTarEntry 创建成功")
    println("条目名称: ${entry.name}")
    println("条目大小: ${entry.size}")

    // 清理测试文件
    removeIfExists(testFile)
}

运行结果:

PaxTarEntry 创建成功
条目名称: test.txt
条目大小: 11

init(String)

public init(path: String)

功能:从文件、目录、软链接构造一个 Pax tar 文件条目。

参数:

  • path: String - 文件、目录、软链接的路径。

异常:

  • TarException - 如果 path 参数指定的目标不存在或不是文件、目录、软链接,则抛出异常。

  • FSException - 如果读取目标信息或创建目标文件流失败,则抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = "./test.txt"
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 使用字符串路径创建 PaxTarEntry
    var entry = PaxTarEntry(testFile)

    println("PaxTarEntry 通过字符串路径创建成功")
    println("条目名称: ${entry.name}")
    println("条目大小: ${entry.size}")

    // 清理测试文件
    removeIfExists(testFile)
}

运行结果:

PaxTarEntry 通过字符串路径创建成功
条目名称: test.txt
条目大小: 11

func getPaxData(String)

public func getPaxData(key: String): ?String

功能:获取当前条目的 Pax 数据。

参数:

  • key: String - Pax 数据的键。

返回值:

  • Option<String> - 如果存在对应键的 Pax 数据,则返回其值,否则返回 None。

示例:

import std.process.*
import stdx.compress.tar.*
import std.fs.*

main(): Int64 {
    // 设定路径
    let testFile = "./testFile.txt"
    let testPax = "./test.pax"

    // 创建测试文件
    File.writeTo(testFile, "文件数据...".toArray())

    // 创建 pax 文件,执行命令 "tar --format=pax --pax-option=yourKey=yourValue -cf test.pax testFile.txt"
    executeWithOutput(
        "tar",
        ["--format=pax", "--pax-option=yourKey=yourValue", "-cf", testPax, testFile]
    )

    // 创建输入流
    let inFile = File(testPax, Read)

    // 创建 TarReader
    var reader = TarReader(inFile)

    for (entry in reader) {
        if (let Some(paxEntry) <- (entry as PaxTarEntry)) {
            // 获取 Pax 数据
            let paxData = paxEntry.getPaxData("yourKey")
            println("Pax 数据: ${paxData}")
        }
    }
    // 清理测试文件
    removeIfExists(testFile)
    removeIfExists(testPax)

    return 0
}

运行结果:

Pax 数据: Some(yourValue)

func writeTo(OutputStream)

public override func writeTo(target: OutputStream): Unit

功能:将当前条目写入到指定的输出流中。

参数:

  • target: OutputStream - 指定输出流。

异常:

  • TarException - 如果字段超出格式要求或写入失败,则抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建 PaxTarEntry
    var entry = PaxTarEntry(testFile)

    // 创建输出流
    let outFile = File("./output.tar", Write)

    // 将条目写入输出流
    entry.writeTo(outFile)

    println("PaxTarEntry 成功写入流")

    // 清理文件
    outFile.close()
    removeIfExists(testFile)
    removeIfExists("./output.tar")
}

运行结果:

PaxTarEntry 成功写入流

class PosixTarEntry

public abstract class PosixTarEntry <: TarEntry {
    protected init(path: String)
    protected init(path: Path)
}

功能:表示含有 Ustar Gnu Pax 格式共有字段的 tar 文件条目。

父类型:

prop deviceMajor

public prop deviceMajor: Int32

功能:获取当前条目的设备主编号。

类型:Int32

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建一个 PosixTarEntry
    var entry: PosixTarEntry = PaxTarEntry(testFile)

    println("Entry device major: ${entry.deviceMajor}")

    // 清理测试文件
    removeIfExists(testFile)
}

运行结果:

Entry device major: 0

prop deviceMinor

public prop deviceMinor: Int32

功能:获取当前条目的设备次编号。

类型:Int32

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建一个 PosixTarEntry
    var entry: PosixTarEntry = PaxTarEntry(testFile)

    println("Entry device minor: ${entry.deviceMinor}")

    // 清理测试文件
    removeIfExists(testFile)
}

运行结果:

Entry device minor: 0

prop groupName

public prop groupName: String

功能:获取当前条目的组名。

类型:String

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建一个 PosixTarEntry
    var entry: PosixTarEntry = PaxTarEntry(testFile)

    println("Entry group name: ${entry.groupName}")

    // 清理测试文件
    removeIfExists(testFile)
}

可能的运行结果:

Entry group name: yourName

prop userName

public prop userName: String

功能:获取当前条目的用户名。

类型:String

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建一个 PosixTarEntry
    var entry: PosixTarEntry = PaxTarEntry(testFile)

    println("Entry user name: ${entry.userName}")

    // 清理测试文件
    removeIfExists(testFile)
}

可能的运行结果:

Entry user name: yourName

init(Path)

public init(path: Path)

功能:从文件、目录、软链接构造一个 tar 文件条目。

参数:

  • path: Path - 文件、目录、软链接的路径。

异常:

  • TarException - 如果 path 参数指定的目标不存在或不是文件、目录、软链接,则抛出异常。

  • FSException - 如果读取目标信息或创建目标文件流失败,则抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建一个 PosixTarEntry(PosixTarEntry本身是抽象类,不能直接实例化)
    var entry: PosixTarEntry = PaxTarEntry(testFile)

    // 清理测试文件
    removeIfExists(testFile)
}

init(String)

public init(path: String)

功能:从文件、目录、软链接构造一个 tar 文件条目。

参数:

  • path: String - 文件、目录、软链接的路径。

异常:

  • TarException - 如果 path 参数指定的目标不存在或不是文件、目录、软链接,则抛出异常。

  • FSException - 如果读取目标信息或创建目标文件流失败,则抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = "./test.txt"
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建一个 PosixTarEntry(PosixTarEntry本身是抽象类,不能直接实例化)
    var entry: PosixTarEntry = PaxTarEntry(testFile)

    // 清理测试文件
    removeIfExists(testFile)
}

class Tar

public class Tar {}

功能:归档和提取目录或流。

static func archive(Path, (Path) -> Bool, Path, Bool)

public static func archive(fromDir!: Path, filter!: (Path) -> Bool, destFile!: Path, includeBaseDirectory!: Bool): Unit

功能:配合过滤函数选择性地将指定目录归档为 .tar 文件。

参数:

  • fromDir!: Path - 待归档目录。

  • filter!: (Path) -> Bool - 过滤函数,会传入遍历到的目录、文件和软链接路径,返回 true 表示保留,否则丢弃。

  • destFile!: Path - 输出的 .tar 文件路径。

  • includeBaseDirectory!: Bool - 是否包含根目录。

异常:

  • TarException - 如果 tar 归档时发生错误,抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 设定测试路径
    let testDir = Path("./test_dir")
    let testFile = Path("./test_dir/test.txt")

    // 创建测试目录和文件
    removeIfExists(testDir, recursive: true)
    Directory.create(testDir)
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 归档目录
    let archiveFile = Path("./test_archive.tar")
    Tar.archive(fromDir: testDir, filter: {_: Path => true}, destFile: archiveFile, includeBaseDirectory: true)

    println("归档文件: ${archiveFile}")

    // 清理测试文件
    removeIfExists(testFile)
    removeIfExists(testDir, recursive: true)
    removeIfExists(archiveFile)
}

运行结果:

归档文件: ./test_archive.tar

static func archive(Path, Path, Bool)

public static func archive(fromDir!: Path, destFile!: Path, includeBaseDirectory!: Bool): Unit

功能:将指定目录归档为 .tar 文件。

参数:

  • fromDir!: Path - 待归档的目录路径。

  • destFile!: Path - 生成的 .tar 文件路径。

  • includeBaseDirectory!: Bool - 是否包含目录本身作为顶级目录。若为 true,归档包内包含该目录;若为 false,仅包含其内容。

异常:

  • TarException - 如果 tar 归档时发生错误,抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 设定测试路径
    let testDir = Path("./test_dir")
    let testFile = Path("./test_dir/test.txt")

    // 创建测试目录和文件
    removeIfExists(testDir, recursive: true)
    Directory.create(testDir)
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 归档目录
    let archiveFile = Path("./test_archive.tar")
    Tar.archive(fromDir: testDir, destFile: archiveFile, includeBaseDirectory: true)

    println("目录归档成功")
    println("归档文件: ${archiveFile}")

    // 清理测试文件
    removeIfExists(testFile)
    removeIfExists(testDir, recursive: true)
    removeIfExists(archiveFile)
}

运行结果:

目录归档成功
归档文件: ./test_archive.tar

static func archive(String, (String) -> Bool, String, Bool)

public static func archive(fromDir!: String, filter!: (String) -> Bool, destFile!: String, includeBaseDirectory!: Bool): Unit

功能:配合过滤函数选择性地将指定目录归档为 .tar 文件。

参数:

  • fromDir!: String - 待归档目录。

  • filter!: (String) -> Bool - 过滤函数,会传入遍历到的目录、文件和软链接路径,返回 true 表示保留,否则丢弃。

  • destFile!: String - 输出的 .tar 文件路径。

  • includeBaseDirectory!: Bool - 是否包含根目录。

异常:

  • TarException - 如果 tar 归档时发生错误,抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 设定测试路径
    let testDir = "./test_dir"
    let testFile = "./test_dir/test.txt"

    // 创建测试目录和文件
    removeIfExists(testDir, recursive: true)
    Directory.create(testDir)
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 使用字符串路径和过滤函数归档目录
    let archiveFile = "./test_archive_filtered.tar"
    Tar.archive(fromDir: testDir, filter: {_: String => true}, destFile: archiveFile, includeBaseDirectory: true)

    println("带过滤函数的目录归档成功")
    println("归档文件: ${archiveFile}")

    // 清理测试文件
    removeIfExists(testFile)
    removeIfExists(testDir, recursive: true)
    removeIfExists(archiveFile)
}

运行结果:

带过滤函数的目录归档成功
归档文件: ./test_archive_filtered.tar

static func archive(String, String, Bool)

public static func archive(fromDir!: String, destFile!: String, includeBaseDirectory!: Bool): Unit

功能:将指定目录归档为 .tar 文件。

参数:

  • fromDir!: String - 待归档的目录路径。

  • destFile!: String - 生成的 .tar 文件路径。

  • includeBaseDirectory!: Bool - 是否包含目录本身作为顶级目录。若为 true,归档包内包含该目录;若为 false,仅包含其内容。

异常:

  • TarException - 如果 tar 归档时发生错误,抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 设定测试路径
    let testDir = "./test_dir"
    let testFile = "./test_dir/test.txt"

    // 创建测试目录和文件
    removeIfExists(testDir, recursive: true)
    Directory.create(testDir)
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 使用字符串路径归档目录
    let archiveFile = "./test_archive_string.tar"
    Tar.archive(fromDir: testDir, destFile: archiveFile, includeBaseDirectory: true)

    println("使用字符串路径的目录归档成功")
    println("归档文件: ${archiveFile}")

    // 清理测试文件
    removeIfExists(testFile)
    removeIfExists(testDir, recursive: true)
    removeIfExists(archiveFile)
}

运行结果:

使用字符串路径的目录归档成功
归档文件: ./test_archive_string.tar

static func archive<T>(Path, T, Bool) where T <: OutputStream

public static func archive<T>(fromDir!: Path, destStream!: T, includeBaseDirectory!: Bool): Unit where T <: OutputStream

功能:将目录归档为 .tar 数据并写入指定输出流。

注意:

函数不负责 destStream 资源的释放,调用方需自行管理该输出流的生命周期。

参数:

  • fromDir!: Path - 待归档的目录路径。

  • destStream!: T - 归档后数据的输出流。

  • includeBaseDirectory!: Bool - 是否包含根目录。

异常:

  • TarException - 如果 tar 归档时发生错误,抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 设定测试路径
    let testDir = Path("./test_dir")
    let testFile = Path("./test_dir/test.txt")
    let testFileStream = Path("./test_archive_stream.tar")

    // 创建测试目录和文件
    removeIfExists(testDir, recursive: true)
    Directory.create(testDir)
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建输出流
    let outputStream = File(testFileStream, Write)

    // 将目录归档到输出流
    Tar.archive(fromDir: testDir, destStream: outputStream, includeBaseDirectory: true)

    println("目录归档到输出流成功")

    // 清理测试文件
    outputStream.close()
    removeIfExists(testFile)
    removeIfExists(testDir, recursive: true)
    removeIfExists(testFileStream)
}

运行结果:

目录归档到输出流成功

static func archive<T>(String, T, Bool) where T <: OutputStream

public static func archive<T>(fromDir!: String, destStream!: T, includeBaseDirectory!: Bool): Unit where T <: OutputStream

功能:将目录归档为 .tar 数据并写入指定输出流。

注意:

函数不负责 destStream 资源的释放,调用方需自行管理该输出流的生命周期。

参数:

  • fromDir!: String - 待归档的目录路径。

  • destStream!: T - 归档后数据的输出流。

  • includeBaseDirectory!: Bool - 是否包含根目录。

异常:

  • TarException - 如果 tar 归档时发生错误,抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 设定测试路径
    let testDir = "./test_dir"
    let testFile = Path("./test_dir/test.txt")
    let testFileStream = Path("./test_archive_string_stream.tar")

    // 创建测试目录和文件
    removeIfExists(testDir, recursive: true)
    Directory.create(testDir)
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建输出流
    let outputStream = File(testFileStream, Write)

    // 使用字符串路径将目录归档到输出流
    Tar.archive(fromDir: testDir, destStream: outputStream, includeBaseDirectory: true)

    println("使用字符串路径归档到输出流成功")

    // 清理测试文件
    outputStream.close()
    removeIfExists(testFile)
    removeIfExists(testDir, recursive: true)
    removeIfExists(testFileStream)
}

运行结果:

使用字符串路径归档到输出流成功

static func extract(Path, Path, Bool)

public static func extract(fromTar!: Path, destDir!: Path, overwrite!: Bool): Unit

功能:将 .tar 文件提取至指定目录。

参数:

  • fromTar!: Path - 待提取的 .tar 文件路径。

  • destDir!: Path - 提取目标目录。

  • overwrite!: Bool - 若为 true,允许覆盖已存在文件、目录;否则遇到重名文件、目录将抛出异常。

异常:

  • TarException - 如果 tar 提取时发生错误,抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 设定测试路径
    let testDir = Path("./test_dir")
    let testFile = Path("./test_dir/test.txt")

    // 创建测试目录和文件
    removeIfExists(testDir, recursive: true)
    Directory.create(testDir)
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 归档目录
    let archiveFile = Path("./test_archive.tar")
    Tar.archive(fromDir: testDir, destFile: archiveFile, includeBaseDirectory: false)

    println("tar 归档成功")
    println("归档文件: ${archiveFile}")

    // 删除源文件
    removeIfExists(testFile)
    removeIfExists(testDir, recursive: true)

    // 解压目录
    Tar.extract(fromTar: archiveFile, destDir: testDir, overwrite: true)
    println("tar 解压成功")
    println("解压目录: ${testDir}")

    // 清理测试文件和目录
    removeIfExists(testDir, recursive: true)
    removeIfExists(archiveFile)
}

运行结果:

tar 归档成功
归档文件: ./test_archive.tar
tar 解压成功
解压目录: ./test_dir

static func extract(String, String, Bool)

public static func extract(fromTar!: String, destDir!: String, overwrite!: Bool): Unit

功能:将 .tar 文件提取至指定目录。

参数:

  • fromTar!: String - 待提取的 .tar 文件路径。

  • destDir!: String - 提取目标目录。

  • overwrite!: Bool - 若为 true,允许覆盖已存在文件、目录;否则遇到重名文件、目录将抛出异常。

异常:

  • TarException - 如果 tar 提取时发生错误,抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 设定测试路径
    let testDir = "./test_dir"
    let testFile = Path("./test_dir/test.txt")

    // 创建测试目录和文件
    removeIfExists(testDir, recursive: true)
    Directory.create(testDir)
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 归档目录
    let archiveFile = "./test_archive.tar"
    Tar.archive(fromDir: testDir, destFile: archiveFile, includeBaseDirectory: false)

    println("tar 归档成功")
    println("归档文件: ${archiveFile}")

    // 删除源文件
    removeIfExists(testFile)
    removeIfExists(testDir, recursive: true)

    // 解压目录
    Tar.extract(fromTar: archiveFile, destDir: testDir, overwrite: true)
    println("tar 解压成功")
    println("解压目录: ${testDir}")

    // 清理测试文件和目录
    removeIfExists(testDir, recursive: true)
    removeIfExists(archiveFile)
}

运行结果:

tar 归档成功
归档文件: ./test_archive.tar
tar 解压成功
解压目录: ./test_dir

static func extract<T>(T, Path, Bool) where T <: InputStream

public static func extract<T>(fromStream!: T, destDir!: Path, overwrite!: Bool): Unit where T <: InputStream

功能:将 .tar 数据从输入流中读取并提取至指定目录。

参数:

  • fromStream!: T - 待提取的 .tar 数据输入流。

  • destDir!: Path - 提取目标目录。

  • overwrite!: Bool - 若为 true,允许覆盖已存在文件、目录;否则遇到重名文件、目录将抛出异常。

异常:

  • TarException - 如果 tar 提取时发生错误,抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 设定测试路径
    let testDir = Path("./test_dir")
    let testFile = Path("./test_dir/test.txt")
    let testFileStream = Path("./test_archive_string_stream.tar")

    // 创建测试目录和文件
    removeIfExists(testDir, recursive: true)
    Directory.create(testDir)
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建输出流
    let outputStream = File(testFileStream, Write)

    // 将目录归档到输出流
    Tar.archive(fromDir: testDir, destStream: outputStream, includeBaseDirectory: false)

    println("归档到输出流成功")

    // 清理测试文件
    outputStream.close()
    removeIfExists(testFile)
    removeIfExists(testDir, recursive: true)

    // 创建输入流
    let inputStream = File(testFileStream, Read)
    // 提取目录
    Tar.extract(fromStream: inputStream, destDir: testDir, overwrite: true)

    println("提取目录: ${testDir}")
    println("提取完成")

    // 清理测试文件和目录
    removeIfExists(testDir, recursive: true)
    removeIfExists(testFileStream)
}

运行结果:

归档到输出流成功
提取目录: ./test_dir
提取完成

static func extract<T>(T, String, Bool) where T <: InputStream

public static func extract<T>(fromStream!: T, destDir!: String, overwrite!: Bool): Unit where T <: InputStream

功能:将 .tar 数据从输入流中读取并提取至指定目录。

参数:

  • fromStream!: T - 待提取的 .tar 数据输入流。

  • destDir!: String - 提取目标目录。

  • overwrite!: Bool - 若为 true,允许覆盖已存在文件、目录;否则遇到重名文件、目录将抛出异常。

异常:

  • TarException - 如果 tar 提取时发生错误,抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 设定测试路径
    let testDir = "./test_dir"
    let testFile = Path("./test_dir/test.txt")
    let testFileStream = Path("./test_archive_string_stream.tar")

    // 创建测试目录和文件
    removeIfExists(testDir, recursive: true)
    Directory.create(testDir)
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建输出流
    let outputStream = File(testFileStream, Write)

    // 将目录归档到输出流
    Tar.archive(fromDir: testDir, destStream: outputStream, includeBaseDirectory: false)

    println("归档到输出流成功")

    // 清理测试文件
    outputStream.close()
    removeIfExists(testFile)
    removeIfExists(testDir, recursive: true)

    // 创建输入流
    let inputStream = File(testFileStream, Read)
    // 提取目录
    Tar.extract(fromStream: inputStream, destDir: testDir, overwrite: true)

    println("提取目录: ${testDir}")
    println("提取完成")

    // 清理测试文件和目录
    removeIfExists(testDir, recursive: true)
    removeIfExists(testFileStream)
}

运行结果:

归档到输出流成功
提取目录: ./test_dir
提取完成

class TarEntry

public abstract class TarEntry {
    protected init(path: String)
    protected init(path: Path)
}

功能:表示一个 tar 文件中的条目,用于和 TarReaderTarWriter 进行交互。可从 TarReader 中获取 TarEntry 实例,表示 tar 归档文件中的一个条目。也可通过 TarWriter 将其写入到 tar 归档文件中。

prop entryType

public prop entryType: TarEntryType

功能:获取当前条目的条目类型。

类型:TarEntryType

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建一个 TarEntry 实例 (使用 PaxTarEntry,因为 TarEntry 是抽象类)
    var entry: TarEntry = PaxTarEntry(testFile)

    // 获取 entryType 属性
    let entryType = entry.entryType
    println("条目类型: ${entryType}")

    // 清理测试文件
    removeIfExists(testFile)
}

运行结果:

条目类型: TarEntryType.RegularFile

prop gid

public mut prop gid: Int32

功能:获取当前条目的组 ID。

类型:Int32

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建一个 TarEntry 实例 (使用 PaxTarEntry,因为 TarEntry 是抽象类)
    var entry: TarEntry = PaxTarEntry(testFile)

    // 获取 gid 属性
    let gid = entry.gid
    println("组ID: ${gid}")

    // 清理测试文件
    removeIfExists(testFile)
}

可能的运行结果:

组ID: 1000

prop mode

public mut prop mode: Int32

功能:获取当前条目的权限模式。

类型:Int32

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建一个 TarEntry 实例 (使用 PaxTarEntry,因为 TarEntry 是抽象类)
    var entry: TarEntry = PaxTarEntry(testFile)

    // 获取 mode 属性
    let mode = entry.mode
    println("权限模式: ${mode}")

    // 清理测试文件
    removeIfExists(testFile)
}

可能的运行结果:

权限模式: 420

prop modificationTime

public prop modificationTime: DateTime

功能:获取当前条目的最后修改时间。

类型:DateTime

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建一个 TarEntry 实例 (使用 PaxTarEntry,因为 TarEntry 是抽象类)
    var entry: TarEntry = PaxTarEntry(testFile)

    // 获取 modificationTime 属性
    let modTime = entry.modificationTime
    println("最后修改时间: ${modTime}")

    // 清理测试文件
    removeIfExists(testFile)
}

可能的运行结果:

最后修改时间: 2025-12-23T03:20:02Z

prop name

public mut prop name: String

功能:获取当前条目的文件名。

类型:String

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建一个 TarEntry 实例 (使用 PaxTarEntry,因为 TarEntry 是抽象类)
    var entry: TarEntry = PaxTarEntry(testFile)

    // 获取 name 属性
    let name = entry.name
    println("文件名: ${name}")

    // 清理测试文件
    removeIfExists(testFile)
}

可能的运行结果:

文件名: test.txt

prop size

public prop size: Int64

功能:获取当前条目的大小。

类型:Int64

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建一个 TarEntry 实例 (使用 PaxTarEntry,因为 TarEntry 是抽象类)
    var entry: TarEntry = PaxTarEntry(testFile)

    // 获取 size 属性
    let size = entry.size
    println("大小: ${size}")

    // 清理测试文件
    removeIfExists(testFile)
}

运行结果:

大小: 11

prop stream

public prop stream: ?InputStream

功能:获取当前条目的输入流。如果实例由 TarReader 创建,则本属性返回流中为条目的数据,若条目没有数据则返回 None。如果实例由构造函数创建,则本属性返回的是创建的文件流,传入 TarWriter 时会调用该属性用于写入条目数据。

类型:Option<InputStream>

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建一个 TarEntry 实例 (使用 PaxTarEntry,因为 TarEntry 是抽象类)
    var entry: TarEntry = PaxTarEntry(testFile)

    // 获取 stream 属性
    let stream = entry.stream

    // 清理测试文件
    removeIfExists(testFile)
}

prop uid

public mut prop uid: Int32

功能:获取当前条目的用户 ID。

类型:Int32

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建一个 TarEntry 实例 (使用 PaxTarEntry,因为 TarEntry 是抽象类)
    var entry: TarEntry = PaxTarEntry(testFile)

    // 获取 uid 属性
    let uid = entry.uid
    println("用户ID: ${uid}")

    // 清理测试文件
    removeIfExists(testFile)
}

可能的运行结果:

用户ID: 1000

init(Path)

protected init(path: Path)

功能:从文件、目录、软链接构造一个 tar 文件条目。

参数:

  • path: Path - 文件、目录、软链接的路径。

异常:

  • TarException - 如果 path 参数指定的目标不存在或不是文件、目录、软链接,则抛出异常。

  • FSException - 如果读取目标信息或创建目标文件流失败,则抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 使用 Path 参数构造一个 TarEntry 实例 (使用 PaxTarEntry,因为 TarEntry 是抽象类)
    var entry: TarEntry = PaxTarEntry(testFile)

    println("TarEntry 使用 Path 构造成功")
    println("文件名: ${entry.name}")

    // 清理测试文件
    removeIfExists(testFile)
}

运行结果:

TarEntry 使用 Path 构造成功
文件名: test.txt

init(String)

protected init(path: String)

功能:从文件、目录、软链接构造一个 tar 文件条目。

参数:

  • path: String - 文件、目录、软链接的路径。

异常:

  • TarException - 如果 path 参数指定的目标不存在或不是文件、目录、软链接,则抛出异常。

  • FSException - 如果读取目标信息或创建目标文件流失败,则抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = "./test.txt"
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 使用 String 参数构造一个 TarEntry 实例 (使用 PaxTarEntry,因为 TarEntry 是抽象类)
    var entry: TarEntry = PaxTarEntry(testFile)

    println("TarEntry 使用 String 构造成功")
    println("文件名: ${entry.name}")

    // 清理测试文件
    removeIfExists(testFile)
}

运行结果:

TarEntry 使用 String 构造成功
文件名: test.txt

func writeTo(OutputStream)

public open func writeTo(target: OutputStream): Unit

功能:将当前条目写入到指定的输出流中。

参数:

  • target: OutputStream - 指定输出流。

异常:

  • TarException - 如果字段超出格式要求或写入失败,则抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建一个 TarEntry 实例 (使用 PaxTarEntry,因为 TarEntry 是抽象类)
    var entry: TarEntry = PaxTarEntry(testFile)

    // 创建输出流
    let outputFile = Path("./output.tar")
    let outputStream = File(outputFile, Write)

    // 调用 writeTo 方法
    entry.writeTo(outputStream)

    println("writeTo 方法调用成功")

    // 清理流和文件
    outputStream.close()

    // 清理测试文件
    removeIfExists(testFile)
    removeIfExists(outputFile)
}

运行结果:

writeTo 方法调用成功

class TarReader

public class TarReader<T> <: Iterable<TarEntry> where T <: InputStream {
    public init(stream: T)
}

功能:从流中按照 tar 格式读取条目。

init(T)

public init(stream: T)

功能:从指定的流中创建一个 tar 文件读取器。

参数:

  • stream: T - 指定的输入流。

示例:

import stdx.compress.tar.*
import std.fs.*
import std.process.*

main(): Unit {
    // 设定路径
    let testFile01 = "./testFile01.txt"
    let testFile02 = "./testFile02.txt"
    let testTar = "./test.tar"

    // 创建测试文件
    File.writeTo(testFile01, "文件数据...123".toArray())
    File.writeTo(testFile02, "文件数据...123456".toArray())

    // 创建 tar 文件,执行命令 "tar -cf test.tar testFile.txt"
    executeWithOutput("tar", ["-cf", testTar, testFile01, testFile02])

    // 创建一个 TarReader 实例
    let fileStream = File(testTar, Read)
    var reader = TarReader(fileStream)

    println("TarReader 创建成功")

    // 清理测试文件
    fileStream.close()
    removeIfExists(testFile01)
    removeIfExists(testFile02)
}

运行结果:

TarReader 创建成功

func iterator()

public func iterator(): Iterator<TarEntry>

功能:返回一个迭代器,迭代 tar 文件中的条目。

返回值:

  • Iterator<TarEntry> - 一个 TarEntry 的迭代器。

示例:

import stdx.compress.tar.*
import std.fs.*
import std.process.*

main(): Unit {
    // 设定路径
    let testFile01 = "./testFile01.txt"
    let testFile02 = "./testFile02.txt"
    let testTar = "./test.tar"

    // 创建测试文件
    File.writeTo(testFile01, "文件数据...123".toArray())
    File.writeTo(testFile02, "文件数据...123456".toArray())

    // 创建 tar 文件,执行命令 "tar -cf test.tar testFile.txt"
    executeWithOutput("tar", ["-cf", testTar, testFile01, testFile02])

    // 创建一个 TarReader 实例
    let fileStream = File(testTar, Read)
    var reader = TarReader(fileStream)

    // 获取迭代器
    var iterator = reader.iterator()

    for (entry in iterator) {
        println("条目名称: ${entry.name}")
        println("条目大小: ${entry.size}")
    }
    // 清理测试文件
    fileStream.close()
    removeIfExists(testFile01)
    removeIfExists(testFile02)
}

运行结果:

条目名称: testFile01.txt
条目大小: 18
条目名称: testFile02.txt
条目大小: 21

extend<T> TarReader<T> <: Resource where T <: Resource

extend<T> TarReader<T> <: Resource where T <: Resource

功能:为 TarReader 实现 Resource 接口,该类型对象可在 try-with-resource 语法上下文中实现自动资源释放。

父类型:

  • Resource

func close()

public func close(): Unit

功能:关闭内部流。

注意:

调用此方法后不可再调用 TarReader 的其他接口,否则会造成不可期现象。

示例:

import stdx.compress.tar.*
import std.fs.*
import std.io.InputStream
import std.process.*

main(): Unit {
    // 设定路径
    let testFile01 = "./testFile01.txt"
    let testFile02 = "./testFile02.txt"
    let testTar = "./test.tar"

    // 创建测试文件
    File.writeTo(testFile01, "文件数据...123".toArray())
    File.writeTo(testFile02, "文件数据...123456".toArray())

    // 创建 tar 文件,执行命令 "tar -cf test.tar testFile.txt"
    executeWithOutput("tar", ["-cf", testTar, testFile01, testFile02])

    // 创建一个 TarReader 实例
    let fileStream = File(testTar, Read)
    var reader = TarReader(fileStream)

    // 关闭 TarReader
    reader.close()

    println("TarReader 关闭成功")

    // 清理测试文件
    removeIfExists(testFile01)
    removeIfExists(testFile02)
}

运行结果:

TarReader 关闭成功

func isClosed()

public func isClosed(): Bool

功能:判断内部流是否关闭。

返回值:

  • Bool - 如果内部流已经被关闭,返回 true,否则返回 false。

示例:

import stdx.compress.tar.*
import std.fs.*
import std.io.InputStream
import std.process.*

main(): Unit {
    // 设定路径
    let testFile01 = "./testFile01.txt"
    let testFile02 = "./testFile02.txt"
    let testTar = "./test.tar"

    // 创建测试文件
    File.writeTo(testFile01, "文件数据...123".toArray())
    File.writeTo(testFile02, "文件数据...123456".toArray())

    // 创建 tar 文件,执行命令 "tar -cf test.tar testFile.txt"
    executeWithOutput("tar", ["-cf", testTar, testFile01, testFile02])

    // 创建一个 TarReader 实例
    let fileStream = File(testTar, Read)
    var reader = TarReader(fileStream)

    // 检查是否已关闭
    let isClosedBefore = reader.isClosed()
    println("关闭前状态: ${isClosedBefore}")

    // 关闭 TarReader
    reader.close()

    // 再次检查是否已关闭
    let isClosedAfter = reader.isClosed()
    println("关闭后状态: ${isClosedAfter}")

    // 清理测试文件
    removeIfExists(testFile01)
    removeIfExists(testFile02)
}

运行结果:

关闭前状态: false
关闭后状态: true

class TarWriter

public class TarWriter<T> where T <: OutputStream {
    public init(stream: T)
    public init(stream: T, format: TarEntryFormat)
}

功能:将条目写入到流中,并完成 tar 文件的写入。

prop format

public prop format: TarEntryFormat

功能:获取当前 tar 文件的条目格式。

类型:TarEntryFormat

示例:

import stdx.compress.tar.*
import std.fs.*
import std.io.*

main(): Unit {
    // 创建输出流
    let outputFile = Path("./test.tar")
    let outputStream = File(outputFile, Write)

    // 创建一个 TarWriter 实例
    var writer = TarWriter(outputStream)

    // 获取 format 属性
    let format = writer.format
    println("TarWriter 格式: ${format}")

    // 清理资源
    writer.close()

    // 清理测试文件
    removeIfExists(outputFile)
}

运行结果:

TarWriter 格式: TarEntryFormat.Pax

init(T)

public init(stream: T)

功能:从指定的流中创建一个 tar 文件写入器,默认为 Pax 格式。

参数:

  • stream: T - 指定的输出流。

示例:

import stdx.compress.tar.*
import std.fs.*
import std.io.*

main(): Unit {
    // 创建输出流
    let outputFile = Path("./test.tar")
    let outputStream = File(outputFile, Write)

    // 创建一个 TarWriter 实例(使用默认格式)
    var writer = TarWriter(outputStream)

    println("TarWriter 创建成功")

    // 清理资源
    writer.close()

    // 清理测试文件
    removeIfExists(outputFile)
}

运行结果:

TarWriter 创建成功

init(T, TarEntryFormat)

public init(stream: T, format: TarEntryFormat)

功能:从指定的流中创建一个 tar 文件写入器。

参数:

  • stream: T - 指定的输出流。

  • format: TarEntryFormat - tar 文件的条目格式。

示例:

import stdx.compress.tar.*
import std.fs.*
import std.io.*

main(): Unit {
    // 创建输出流
    let outputFile = Path("./test.tar")
    let outputStream = File(outputFile, Write)

    // 创建一个 TarWriter 实例(指定格式)
    var writer = TarWriter(outputStream, TarEntryFormat.Gnu)

    println("TarWriter 指定格式创建成功")
    println("格式: ${writer.format}")

    // 清理资源
    writer.close()

    // 清理测试文件
    removeIfExists(outputFile)
}

运行结果:

TarWriter 指定格式创建成功
格式: TarEntryFormat.Gnu

func finish()

public func finish(): Unit

功能:写入 tar 结尾标志,即 1024 个空字节,结束 tar 格式的写入。

异常:

  • TarException - 如果写入已结束,或者写入失败,则抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*
import std.io.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建 TarWriter
    let outFile = File("./test.tar", ReadWrite)
    var writer = TarWriter(outFile)

    // 写入文件
    writer.write(testFile, entryName: "test_entry.txt")
    println("File size before finish: ${outFile.info.size}")
    writer.finish()
    println("File size after finish: ${outFile.info.size}")

    // 清理测试文件
    writer.close()
    removeIfExists(testFile)
    removeIfExists("./test.tar")
}

运行结果:

File size before finish: 1024
File size after finish: 2048

func flush()

public func flush(): Unit

功能:刷新内部流。

异常:

示例:

import stdx.compress.tar.*
import std.fs.*
import std.io.*

main(): Unit {
    // 创建输出流
    let outputFile = Path("./test.tar")
    let outputStream = File(outputFile, Write)

    // 创建一个 TarWriter 实例
    var writer = TarWriter(outputStream)

    // 刷新内部流
    writer.flush()

    println("TarWriter flush() 调用成功")

    // 清理资源
    writer.close()

    // 清理测试文件
    removeIfExists(outputFile)
}

运行结果:

TarWriter flush() 调用成功

func write(FileInfo, String)

public func write(info: FileInfo, entryName!: String): Unit

功能:将指定文件、目录、软链接写入到内部流中。

参数:

  • info: FileInfo - 待写入的文件、目录、软链接信息。

  • entryName!: String - tar 文件中的条目名。

异常:

  • TarException - 如果写入已结束,或者创建或写入条目失败,则抛出异常。

  • FSException - 如果创建文件流失败,则抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*
import std.io.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())
    let file = File(testFile, Read)

    // 创建 TarWriter
    let outFile = File("./test.tar", ReadWrite)
    var writer = TarWriter(outFile)

    // 通过文件信息info写入文件
    writer.write(file.info, entryName: "test_entry.txt")
    writer.finish()

    // 清理测试文件
    writer.close()
    removeIfExists(testFile)
    removeIfExists("./test.tar")
}

func write(Iterable<TarEntry>)

public func write(it: Iterable<TarEntry>): Unit

功能:将指定 tar 文件条目列表写入到内部流中。

参数:

  • it: Iterable<TarEntry> - 待写入的 tar 文件条目列表。

异常:

  • TarException - 如果写入已结束,或者写入条目失败,则抛出异常。

示例:

import stdx.compress.tar.*
import std.collection.*
import std.fs.*
import std.io.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建输出流
    let outputFile = Path("./test.tar")
    let outputStream = File(outputFile, Write)

    // 创建一个 TarWriter 实例
    var writer = TarWriter(outputStream)

    // 创建 TarEntry 列表
    var entry = PaxTarEntry(testFile)
    var entries = ArrayList<TarEntry>()
    entries.add(entry)

    // 写入 TarEntry 列表
    writer.write(entries)

    println("write(Iterable<TarEntry>) 调用成功,写入了 ${outputFile}")

    // 清理资源
    writer.finish()
    writer.close()

    // 清理测试文件
    removeIfExists(testFile)
    removeIfExists(outputFile)
}

运行结果:

write(Iterable<TarEntry>) 调用成功,写入了 ./test.tar

func write(Path, String)

public func write(path: Path, entryName!: String): Unit

功能:将指定文件、目录、软链接写入到内部流中。

参数:

  • path: Path - 指定文件、目录、软链接路径。

  • entryName!: String - tar 文件中的条目名。

异常:

  • TarException - 如果写入已结束,或者创建或写入条目失败,则抛出异常。

  • FSException - 如果创建文件流失败,则抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*
import std.io.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建 TarWriter
    let outFile = File("./test.tar", ReadWrite)
    var writer = TarWriter(outFile)

    // 通过路径写入文件
    writer.write(testFile, entryName: "test_entry.txt")
    writer.finish()

    // 清理测试文件
    writer.close()
    removeIfExists(testFile)
    removeIfExists("./test.tar")
}

func write(String, String)

public func write(path!: String, entryName!: String): Unit

功能:将指定文件、目录、软链接写入到内部流中。

参数:

  • path!: String - 指定文件、目录、软链接的路径。

  • entryName!: String - tar 文件中的条目名。

异常:

  • TarException - 如果写入已结束,或者创建或写入条目失败,则抛出异常。

  • FSException - 如果创建文件流失败,则抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*
import std.io.*

main(): Unit {
    // 创建测试文件
    let testFile = "./test.txt"
    File.writeTo(Path(testFile), "Hello, Tar!".toArray())

    // 创建 TarWriter 并写入文件
    let outFile = File("./test.tar", Write)
    var writer = TarWriter(outFile)

    // 通过路径字符串写入
    writer.write(path: testFile, entryName: "test_entry.txt")
    writer.finish()

    // 清理测试文件
    writer.close()
    removeIfExists(testFile)
    removeIfExists("./test.tar")
}

func write(TarEntry)

public func write(entry: TarEntry): Unit

功能:将指定 tar 文件条目写入到内部流中。

参数:

  • entry: TarEntry - 待写入的 tar 文件条目。

异常:

  • TarException - 如果写入已结束,或者写入条目失败,则抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*
import std.io.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建输出流
    let outputFile = Path("./test.tar")
    let outputStream = File(outputFile, Write)

    // 创建一个 TarWriter 实例
    var writer = TarWriter(outputStream)

    // 创建一个 TarEntry
    var entry = PaxTarEntry(testFile)

    // 写入 TarEntry
    writer.write(entry)

    println("TarWriter write(TarEntry) 调用成功")

    // 清理资源
    writer.finish()
    writer.close()

    // 清理测试文件
    removeIfExists(testFile)
    removeIfExists(outputFile)
}

运行结果:

TarWriter write(TarEntry) 调用成功

extend<T> TarWriter<T> <: Resource where T <: Resource

extend<T> TarWriter<T> <: Resource where T <: Resource

功能:为 TarWriter 实现 Resource 接口,该类型对象可在 try-with-resource 语法上下文中实现自动资源释放。

父类型:

  • Resource

func close()

public func close(): Unit

功能:写入 tar 结尾标志,并关闭内部流。

注意:

调用此方法后不可再调用 TarWriter 的其他接口,否则会造成不可期现象。

示例:

import stdx.compress.tar.*
import std.fs.*
import std.io.*

main(): Unit {
    // 创建输出流
    let outputFile = Path("./test.tar")
    let outputStream = File(outputFile, Write)

    // 创建一个 TarWriter 实例
    var writer = TarWriter(outputStream)

    // 关闭 TarWriter
    writer.close()

    println("TarWriter close() 调用成功")

    // 清理测试文件
    removeIfExists(outputFile)
}

运行结果:

TarWriter close() 调用成功

func isClosed()

public func isClosed(): Bool

功能:判断内部流是否关闭。

返回值:

  • Bool - 如果内部流已经被关闭,返回 true,否则返回 false。

示例:

import stdx.compress.tar.*
import std.fs.*
import std.io.*

main(): Unit {
    // 创建输出流
    let outputFile = Path("./test.tar")
    let outputStream = File(outputFile, Write)

    // 创建一个 TarWriter 实例
    var writer = TarWriter(outputStream)

    // 检查是否已关闭
    let isClosedBefore = writer.isClosed()
    println("关闭前状态: ${isClosedBefore}")

    // 关闭 TarWriter
    writer.close()

    // 再次检查是否已关闭
    let isClosedAfter = writer.isClosed()
    println("关闭后状态: ${isClosedAfter}")

    // 清理测试文件
    removeIfExists(outputFile)
}

运行结果:

关闭前状态: false
关闭后状态: true

class UstarTarEntry

public class UstarTarEntry <: PosixTarEntry {
    public init(path: String)
    public init(path: Path)
}

功能:表示 Ustar tar 文件条目。

父类型:

init(Path)

public init(path: Path)

功能:从文件、目录、软链接构造一个 Ustar tar 文件条目。

参数:

  • path: Path - 文件、目录、软链接的路径。

异常:

  • TarException - 如果 path 参数指定的目标不存在或不是文件、目录、软链接,则抛出异常。

  • FSException - 如果读取目标信息或创建目标文件流失败,则抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建 UstarTarEntry
    var ustarEntry = UstarTarEntry(testFile)

    println("UstarTarEntry created successfully")
    println("Entry name: ${ustarEntry.name}")
    println("Entry size: ${ustarEntry.size}")

    // 清理测试文件
    remove(testFile)
}

运行结果:

UstarTarEntry created successfully
Entry name: test.txt
Entry size: 11

init(String)

public init(path: String)

功能:从文件、目录、软链接构造一个 Ustar tar 文件条目。

参数:

  • path: String - 文件、目录、软链接的路径。

异常:

  • TarException - 如果 path 参数指定的目标不存在或不是文件、目录、软链接,则抛出异常。

  • FSException - 如果读取目标信息或创建目标文件流失败,则抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = "./test.txt"
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建 UstarTarEntry
    var ustarEntry = UstarTarEntry(testFile)

    println("UstarTarEntry created successfully from string path")
    println("Entry name: ${ustarEntry.name}")
    println("Entry size: ${ustarEntry.size}")

    // 清理测试文件
    remove(testFile)
}

运行结果:

UstarTarEntry created successfully from string path
Entry name: test.txt
Entry size: 11

func writeTo(OutputStream)

public override func writeTo(target: OutputStream): Unit

功能:将当前条目写入到指定的输出流中。

参数:

  • target: OutputStream - 指定输出流。

异常:

  • TarException - 如果字段超出格式要求或写入失败,则抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*
import std.io.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建 UstarTarEntry
    var entry = UstarTarEntry(testFile)

    // 创建输出流
    let outFile = File("./output.tar", Write)

    // 将条目写入输出流
    entry.writeTo(outFile)

    println("UstarTarEntry written to stream successfully")

    // 清理文件
    outFile.close()
    remove(testFile)
    remove("./output.tar")
}

运行结果:

UstarTarEntry written to stream successfully

class V7TarEntry

public class V7TarEntry <: TarEntry {
    public init(filePath: String)
    public init(filePath: Path)
}

功能:表示 V7 tar 文件条目。

父类型:

init(Path)

public init(filePath: Path)

功能:从文件、目录、软链接构造一个 V7 tar 文件条目。

参数:

  • filePath: Path - 文件、目录、软链接的路径。

异常:

  • TarException - 如果 filePath 参数指定的目标不存在或不是文件、目录、软链接,则抛出异常。

  • FSException - 如果读取目标信息或创建目标文件流失败,则抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = Path("./test.txt")
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建 V7TarEntry
    var v7Entry = V7TarEntry(testFile)

    println("V7TarEntry created successfully")
    println("Entry name: ${v7Entry.name}")
    println("Entry size: ${v7Entry.size}")

    // 清理测试文件
    remove(testFile)
}

运行结果:

V7TarEntry created successfully
Entry name: test.txt
Entry size: 11

init(String)

public init(filePath: String)

功能:从文件、目录、软链接构造一个 V7 tar 文件条目。

参数:

  • filePath: String - 文件、目录、软链接的路径。

异常:

  • TarException - 如果 filePath 参数指定的目标不存在或不是文件、目录、软链接,则抛出异常。

  • FSException - 如果读取目标信息或创建目标文件流失败,则抛出异常。

示例:

import stdx.compress.tar.*
import std.fs.*

main(): Unit {
    // 创建测试文件
    let testFile = "./test.txt"
    File.writeTo(testFile, "Hello, Tar!".toArray())

    // 创建 V7TarEntry
    var v7Entry = V7TarEntry(testFile)

    println("V7TarEntry created successfully from string path")
    println("Entry name: ${v7Entry.name}")
    println("Entry size: ${v7Entry.size}")

    // 清理测试文件
    remove(testFile)
}

运行结果:

V7TarEntry created successfully from string path
Entry name: test.txt
Entry size: 11

枚举

enum TarEntryFormat

public enum TarEntryFormat {
    | V7
    | Ustar
    | Pax
    | Gnu
}

功能:tar 条目格式。

该枚举表示不同版本的 tar 文件头部格式,用于区分各格式在元数据与扩展字段上的支持程度。

Gnu

Gnu

功能:构造一个 GNU 扩展格式枚举实例。

Pax

Pax

功能:构造一个 PAX 格式枚举实例,表示 POSIX.1-2001 扩展格式,兼容 USTAR,并可通过扩展头记录额外元数据。

Ustar

Ustar

功能:构造一个 USTAR 格式枚举实例,表示 POSIX.1-1988 定义的标准格式。

V7

V7

功能:构造一个 V7 格式枚举实例,表示最初的 UNIX 第七版 tar 格式(1979)。

func toString(): String

public func toString(): String

功能:返回当前 tar 文件头部格式枚举实例的 字符串表示。

返回值:

  • String - 当前 tar 文件头部格式枚举实例的 字符串表示。

示例:

import stdx.compress.tar.*

main(): Unit {
    let format = TarEntryFormat.Pax
    println("Tar entry format: ${format}")
}

运行结果:

Tar entry format: TarEntryFormat.Pax

operator func !=(TarEntryFormat): Bool

operator func !=(rhs: TarEntryFormat): Bool

功能:判断当前 tar 文件头部格式枚举实例是否与传入的 tar 文件头部格式枚举实例不相等。

参数:

  • rhs: TarEntryFormat - 要比较的 tar 文件头部格式枚举实例。

返回值:

  • Bool - 如果两个 tar 文件头部格式枚举实例不相等,则返回 true;否则返回 false。

示例:

import stdx.compress.tar.*

main(): Unit {
    let format1 = TarEntryFormat.Pax
    let format2 = TarEntryFormat.Gnu

    if (format1 != format2) {
        println("${format1} is not equal to ${format2}")
    } else {
        println("${format1} is equal to ${format2}")
    }
}

运行结果:

TarEntryFormat.Pax is not equal to TarEntryFormat.Gnu

operator func ==(TarEntryFormat): Bool

operator func ==(rhs: TarEntryFormat): Bool

功能:判断当前 tar 文件头部格式枚举实例是否与传入的 tar 文件头部格式枚举实例相等。

参数:

  • rhs: TarEntryFormat - 要比较的 tar 文件头部格式枚举实例。

返回值:

  • Bool - 如果两个 tar 文件头部格式枚举实例相等,则返回 true;否则返回 false。

示例:

import stdx.compress.tar.*

main(): Unit {
    let format1 = TarEntryFormat.Pax
    let format2 = TarEntryFormat.Pax
    let format3 = TarEntryFormat.Gnu

    if (format1 == format2) {
        println("${format1} is equal to ${format2}")
    } else {
        println("${format1} is not equal to ${format2}")
    }

    if (format1 == format3) {
        println("${format1} is equal to ${format3}")
    } else {
        println("${format1} is not equal to ${format3}")
    }
}

运行结果:

TarEntryFormat.Pax is equal to TarEntryFormat.Pax
TarEntryFormat.Pax is not equal to TarEntryFormat.Gnu

enum TarEntryType

public enum TarEntryType {
    | V7RegularFile
    | RegularFile
    | ContiguousFile
    | HardLink
    | Symlink
    | CharDevice
    | BlockDevice
    | Directory
    | Fifo
    | ExtendedHeader
    | GlobalExtendedHeader
    | GnuLongName
    | GnuLongLink
    | GnuSparse
    | GnuDumpDir
    | GnuMultiVolume
    | GnuName
    | GnuVolumeHeader
    | Unknown(UInt8)
}

功能:tar 条目类型。

该枚举定义了所有 tar 文件条目的类型,对应 tar 头部中的 typeflag 字段。

BlockDevice

BlockDevice

功能:构造一个块设备文件类型枚举实例,对应 typeflag '4'

CharDevice

CharDevice

功能:构造一个字符设备文件类型枚举实例,对应 typeflag '3'

ContiguousFile

ContiguousFile

功能:构造一个连续文件类型枚举实例,用于表示数据在存储介质上连续排列的文件(typeflag '7')。

Directory

Directory

功能:构造一个目录类型枚举实例,对应 typeflag '5'

ExtendedHeader

ExtendedHeader

功能:构造一个 PAX 扩展头类型枚举实例,对应 typeflag 'x',用于存储附加元数据。

Fifo

Fifo

功能:构造一个命名管道(FIFO)类型枚举实例,对应 typeflag '6'

GlobalExtendedHeader

GlobalExtendedHeader

功能:构造一个 PAX 全局扩展头类型枚举实例,对应 typeflag 'g',适用于作用于整个归档的全局元信息。

GnuDumpDir

GnuDumpDir

功能:构造一个 GNU Dump 目录类型枚举实例,对应 typeflag 'D'

GnuLongLink

功能:构造一个 GNU 长链接名扩展类型枚举实例,对应 typeflag 'K'

GnuLongName

GnuLongName

功能:构造一个 GNU 长文件名扩展类型枚举实例,对应 typeflag 'L'

GnuMultiVolume

GnuMultiVolume

功能:构造一个 GNU 多卷归档条目类型枚举实例,对应 typeflag 'M'

GnuName

GnuName

功能:构造一个 GNU 文件名表条目类型枚举实例,对应 typeflag 'N'

GnuSparse

GnuSparse

功能:构造一个 GNU 稀疏文件类型枚举实例,对应 typeflag 'S'

GnuVolumeHeader

GnuVolumeHeader

功能:构造一个 GNU 卷头条目类型枚举实例,对应 typeflag 'V'

HardLink

功能:构造一个硬链接类型枚举实例,对应 typeflag '1'

RegularFile

RegularFile

功能:构造一个标准普通文件类型枚举实例,对应 POSIX/USTAR 格式中的普通文件(typeflag '0')。

Symlink

功能:构造一个符号链接类型枚举实例,对应 typeflag '2'

Unknown(UInt8)

Unknown(UInt8)

功能:构造一个未知类型条目枚举实例,用于保留无法识别或自定义的 typeflag 字节值。

V7RegularFile

V7RegularFile

功能:构造一个 V7 格式的普通文件类型枚举实例,对应早期 Unix V7 格式(typeflag \0)。

prop flag

public prop flag: UInt8

功能:获取当前条目的 typeflag 字节值。

类型:UInt8

示例:

import stdx.compress.tar.*

main(): Unit {
    let fileType = TarEntryType.RegularFile
    println("Tar entry type flag: ${fileType.flag}")
}

运行结果:

Tar entry type flag: 48

static func fromFlag(UInt8)

public static func fromFlag(flag: UInt8): TarEntryType

功能:根据传入的 typeflag 字节值构造对应的 TarEntryType 枚举实例。

参数:

  • flag: UInt8 - tar 头部中 typeflag 的字节值。

返回值:

  • TarEntryType - 对应的条目类型枚举实例。如果无法识别,将返回 Unknown(flag)

示例:

import stdx.compress.tar.*

main(): Unit {
    let fileType = TarEntryType.fromFlag(48) // 48 is the flag for RegularFile
    println("Tar entry type from flag 48: ${fileType}")

    let unknownType = TarEntryType.fromFlag(99) // 99 is an unknown flag
    println("Tar entry type from unknown flag 99: ${unknownType}")
}

运行结果:

Tar entry type from flag 48: TarEntryType.RegularFile
Tar entry type from unknown flag 99: TarEntryType.Unknown(99)

func toString(): String

public func toString(): String

功能:返回当前条目类型枚举实例的字符串表示。

返回值:

  • String - 当前条目类型枚举实例的字符串表示。

示例:

import stdx.compress.tar.*

main(): Unit {
    let fileType = TarEntryType.RegularFile
    println("Tar entry type: ${fileType.toString()}")

    let dirType = TarEntryType.Directory
    println("Tar entry type: ${dirType.toString()}")
}

运行结果:

Tar entry type: TarEntryType.RegularFile
Tar entry type: TarEntryType.Directory

operator func !=(TarEntryType): Bool

operator func !=(rhs: TarEntryType): Bool

功能:判断当前条目类型枚举实例是否与传入的条目类型枚举实例不相等。

参数:

  • rhs: TarEntryType - 要比较的条目类型枚举实例。

返回值:

  • Bool - 如果两个条目类型枚举实例不相等,则返回 true;否则返回 false。

示例:

import stdx.compress.tar.*

main(): Unit {
    let fileType = TarEntryType.RegularFile
    let dirType = TarEntryType.Directory

    if (fileType != dirType) {
        println("${fileType} is not equal to ${dirType}")
    } else {
        println("${fileType} is equal to ${dirType}")
    }
}

运行结果:

TarEntryType.RegularFile is not equal to TarEntryType.Directory

operator func ==(TarEntryType): Bool

operator func ==(rhs: TarEntryType): Bool

功能:判断当前条目类型枚举实例是否与传入的条目类型枚举实例相等。

参数:

  • rhs: TarEntryType - 要比较的条目类型枚举实例。

返回值:

  • Bool - 如果两个条目类型枚举实例相等,则返回 true;否则返回 false。

示例:

import stdx.compress.tar.*

main(): Unit {
    let fileType1 = TarEntryType.RegularFile
    let fileType2 = TarEntryType.RegularFile
    let dirType = TarEntryType.Directory

    if (fileType1 == fileType2) {
        println("${fileType1} is equal to ${fileType2}")
    } else {
        println("${fileType1} is not equal to ${fileType2}")
    }

    if (fileType1 == dirType) {
        println("${fileType1} is equal to ${dirType}")
    } else {
        println("${fileType1} is not equal to ${dirType}")
    }
}

运行结果:

TarEntryType.RegularFile is equal to TarEntryType.RegularFile
TarEntryType.RegularFile is not equal to TarEntryType.Directory

异常类

class TarException

public class TarException <: Exception {
    public init(message: String)
}

功能:tar 包的异常类。

父类型:

  • Exception

init(String)

public init(message: String)

功能:根据异常信息创建 TarException 实例。

参数:

  • message: String - 异常提示信息。

示例:

import stdx.compress.tar.*

main(): Unit {
    try {
        throw TarException("This is a test exception")
    } catch (e: TarException) {
        println("捕获到 TarException: ${e.message}")
    }
}

运行结果:

捕获到 TarException: This is a test exception

Tar 格式数据的归档与提取

示例:

import stdx.compress.tar.*
import std.fs.*
import std.io.*

main() {
    let originalFile = Path("./tgz_src.txt")
    let archiveFile = Path("./archive.tar")
    let extractedFile = Path("./tgz_dst.txt")
    let size = 1024 * 1024

    createFile(originalFile, size)

    let tgzSize = archive(originalFile, archiveFile)
    if (tgzSize > 0) {
        println("Pack(.tar) size: ${tgzSize}")
    } else {
        println("Failed to pack .tar!")
    }

    let extractedBytes = extract(archiveFile, extractedFile)
    if (extractedBytes > 0) {
        println("Unpacked bytes: ${extractedBytes}")
    } else {
        println("Failed to unpack .tar!")
    }

    if (compareFile(originalFile, extractedFile)) {
        println("success")
    } else {
        println("failed")
    }

    remove(originalFile)
    remove(archiveFile)
    remove(extractedFile)
    return 0
}

func archive(srcFileName: Path, tarFileName: Path): Int64 {
    try (outFile: File = File(tarFileName, Write)) {
        var tar = TarWriter(outFile)

        tar.write(srcFileName, entryName: srcFileName.fileName)
        tar.finish()

        return outFile.length
    }
    return 0
}

func extract(tarFileName: Path, destFileName: Path): Int64 {
    var written: Int64 = 0
    try (inFile: File = File(tarFileName, Read), outFile: File = File(destFileName, Write)) {
        var reader = TarReader(inFile)
        for (entry in reader) {
            if (entry.entryType == TarEntryType.RegularFile) {
                if (let Some(data) <- entry.stream) {
                    written = copy(data, to: outFile)
                    break
                }
            }
        }
    }
    return written
}

func createFile(file: Path, size: Int64) {
    File.writeTo(file, Array<Byte>(size, {i => UInt8(i % 256)}))
}

func compareFile(fileName1: Path, fileName2: Path): Bool {
    return File.readFrom(fileName1) == File.readFrom(fileName2)
}

运行结果:

Pack(.tar) size: 1050112
Unpacked bytes: 1048576
success

stdx.compress.zlib

功能介绍

compress.zlib 提供压缩解压功能。

压缩是指用更少的比特表示数据,以便更高效地存储和传输数据。在实际应用中,压缩广泛应用于文件压缩、网页压缩、数据库备份等。

压缩功能的实现依赖于压缩算法,主流的压缩算法有 deflate、lz77、lzw 等,这些算法可以将数据中的冗余信息去除或者替换成更紧凑的表示形式,从而实现数据压缩的目的。目前使用 deflate 算法。

基于 deflate 压缩算法,给压缩后数据加上首部和尾部,可封装成不同格式的压缩文件,如 deflate-raw(无封装)、gzip、zip、png 等。其中 zip 可用于多个文件的压缩和打包,gzip 仅包含一个压缩文件。目前支持的数据格式有 deflate-raw 和 gzip,暂不支持文件打包功能。

此外,支持设置压缩级别,更高的压缩级别对应着更高的压缩率和更慢的压缩速度,反之,更低的压缩级别对应着更低的压缩率和更快的压缩速度。

特别地,zlib 指的是压缩功能的一个实现库,zlib 包实现了 deflate 算法,并支持 deflate-raw 和 gzip 压缩格式。

本包基于开源库 zlib,使用 deflate 算法,支持 deflate-raw 和 gzip 数据格式,支持快速、默认、高压缩率三种压缩等级,压缩速度依次下降,压缩率依次提升。

本包提供流式压缩和解压功能,即支持从输入流读取数据,将其压缩或解压,并写入字节数组,或从字节数组中读取数据,将其压缩或解压,并写入输出流。

说明:

要进行文件打包请使用 stdx.compress.tar 进行归档或使用 stdx.compress 的组合工具 TarGzip 进行归档压缩操作。

API 列表

类名功能
CompressInputStream压缩输入流。
CompressOutputStream压缩输出流。
DecompressInputStream解压输入流。
DecompressOutputStream解压输出流。

枚举

枚举名功能
CompressLevel压缩等级。
WrapType压缩数据格式。

异常类

异常类名功能
ZlibExceptionzlib 包的异常类。

class CompressInputStream

public class CompressInputStream <: InputStream {
    public init(inputStream: InputStream, wrap!: WrapType = DeflateFormat, compressLevel!: CompressLevel = DefaultCompression, bufLen!: Int64 = 512)
}

功能:压缩输入流。

可将 CompressInputStream 实例通过构造函数绑定到任意 InputStream 类型输入流,通过循环调用 read(outBuf: Array<Byte>) 函数,将该输入流中的数据压缩,并将压缩后的数据输出到传入的字节数组。

父类型:

  • InputStream

init(InputStream, WrapType, CompressLevel, Int64)

public init(inputStream: InputStream, wrap!: WrapType = DeflateFormat, compressLevel!: CompressLevel = DefaultCompression, bufLen!: Int64 = 512)

功能:构造一个压缩输入流。

需绑定一个输入流,可设置压缩数据格式、压缩等级、内部缓冲区大小(每次从输入流中读取多少数据进行压缩)。

参数:

  • inputStream: InputStream - 待压缩的输入流。
  • wrap!: WrapType - 压缩数据格式,默认值为 DeflateFormat
  • compressLevel!: CompressLevel - 压缩等级,默认值为 DefaultCompression
  • bufLen!: Int64 - 输入流缓冲区的大小,取值范围为 (0, Int64.Max],默认 512 字节。

异常:

  • ZlibException - 当 bufLen 小于等于 0,输入流分配内存失败,或压缩资源初始化失败,抛出异常。

示例:

import stdx.compress.zlib.*
import std.io.*

main(): Unit {
    let arr1 = "Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!".toArray()
    let byteBuffer = ByteBuffer(arr1)
    let bufferedInputStream = BufferedInputStream(byteBuffer)
    var compressInputStream: CompressInputStream = CompressInputStream(bufferedInputStream)
    compressInputStream.close()
}

func close()

public func close(): Unit

功能:关闭压缩输入流。

当前 CompressInputStream 实例使用完毕后必须调用此函数来释放其所占内存资源,以免造成内存泄漏。调用该函数前需确保 read 函数已返回 0,否则可能导致绑定的 InputStream 并未被全部压缩。

异常:

  • ZlibException - 如果释放压缩资源失败,抛出异常。

示例:

import stdx.compress.zlib.*
import std.io.*

main(): Unit {
    let arr1 = "Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!".toArray()
    let byteBuffer = ByteBuffer(arr1)
    let bufferedInputStream = BufferedInputStream(byteBuffer)
    var compressInputStream: CompressInputStream = CompressInputStream(bufferedInputStream)
    // 使用压缩输入流进行一些操作
    var arr: Array<Byte> = Array<Byte>(1024, repeat: 0)
    var len = compressInputStream.read(arr)
    println("Read ${len} bytes.")
    // 关闭压缩输入流
    compressInputStream.close()
}

运行结果:

Read 18 bytes.

func read(Array<Byte>)

public func read(outBuf: Array<Byte>): Int64

功能:从绑定的输入流中读取数据并压缩,压缩后数据放入指定的字节数组中。

参数:

  • outBuf: Array<Byte> - 用来存放压缩后数据的缓冲区。

返回值:

  • Int64 - 如果压缩成功,返回压缩后字节数,如果绑定的输入流中数据已经全部压缩完成,或者该压缩输入流被关闭,返回 0。

异常:

  • ZlibException - 当 outBuf 为空,或压缩数据失败,抛出异常。

示例:

import stdx.compress.zlib.*
import std.io.*

main(): Unit {
    let arr1 = "Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!".toArray()
    let byteBuffer = ByteBuffer(arr1)
    let bufferedInputStream = BufferedInputStream(byteBuffer)
    var compressInputStream: CompressInputStream = CompressInputStream(bufferedInputStream)
    var arr: Array<Byte> = Array<Byte>(1024, repeat: 0)
    println("原始数据长度: ${arr1.size}")
    var len = compressInputStream.read(arr)
    println("压缩后的数据长度: ${len}")
    compressInputStream.close()
}

运行结果:

原始数据长度: 65
压缩后的数据长度: 18

class CompressOutputStream

public class CompressOutputStream <: OutputStream {
    public init(outputStream: OutputStream, wrap!: WrapType = DeflateFormat, compressLevel!: CompressLevel = DefaultCompression, bufLen!: Int64 = 512)
}

功能:压缩输出流。

可将 CompressOutputStream 实例通过构造函数绑定到任意 OutputStream 类型输出流,调用 write(inBuf: Array<Byte>) 函数读取、压缩指定字节数组中的数据,并将压缩后的数据输出到绑定的输出流。

父类型:

  • OutputStream

init(OutputStream, WrapType, CompressLevel, Int64)

public init(outputStream: OutputStream, wrap!: WrapType = DeflateFormat, compressLevel!: CompressLevel = DefaultCompression, bufLen!: Int64 = 512)

功能:构造一个压缩输出流,需绑定一个输出流,可设置压缩数据类型、压缩等级、内部缓冲区大小(每得到多少压缩后数据往输出流写出)。

参数:

  • outputStream: OutputStream - 绑定的输出流,压缩后数据将写入该输出流。
  • wrap!: WrapType - 压缩数据格式,默认值为 DeflateFormat
  • compressLevel!: CompressLevel - 压缩等级,默认值为 DefaultCompression
  • bufLen!: Int64 - 输出流缓冲区的大小,取值范围为 (0, Int64.Max],默认 512 字节。

异常:

  • ZlibException - 如果 bufLen 小于等于 0,输出流分配内存失败,或压缩资源初始化失败,抛出异常。

示例:

import stdx.compress.zlib.*
import std.io.*

main(): Unit {
    var byteBuffer = ByteBuffer()
    var compressOutputStream: CompressOutputStream = CompressOutputStream(byteBuffer, wrap: GzipFormat,
        compressLevel: BestCompression, bufLen: 1024)
    compressOutputStream.close()
}

func close()

public func close(): Unit

功能:关闭当前压缩输出流实例。

关闭时,将写入剩余压缩数据(包括缓冲区中数据,以及压缩尾部信息),并释放其所占内存资源。当前压缩输出流使用完毕后必须调用此函数来释放其所占内存资源,以免造成内存泄漏。在调用 close 函数前,绑定的输出流里已写入的数据并不是一段完整的压缩数据,调用 close 函数后,才会把剩余压缩数据写入绑定的输出流,使其完整。

异常:

  • ZlibException - 如果当前压缩输出流已经被关闭,或释放压缩资源失败,抛出异常。

示例:

import stdx.compress.zlib.*
import std.io.*

main(): Unit {
    var byteBuffer = ByteBuffer()
    var compressOutputStream: CompressOutputStream = CompressOutputStream(byteBuffer, bufLen: 39)

    var arr = "Hello, World!Hello, World!Hello, World!".toArray()

    /* 将字节数组压缩后写入压缩输出流的缓冲区 */
    compressOutputStream.write(arr)

    /* 将内部缓冲区里已压缩的数据刷出并写入绑定的输出流,然后刷新绑定的输出流 */
    compressOutputStream.flush()

    /* 关闭压缩输出流 */
    compressOutputStream.close()
}

func flush()

public func flush(): Unit

功能:刷新压缩输出流。将内部缓冲区里已压缩的数据刷出并写入绑定的输出流,然后刷新绑定的输出流。

异常:

  • ZlibException - 如果当前压缩输出流已经被关闭,抛出异常。

示例:

import stdx.compress.zlib.*
import std.io.*

main(): Unit {
    var byteBuffer = ByteBuffer()
    var compressOutputStream: CompressOutputStream = CompressOutputStream(byteBuffer, bufLen: 39)

    var arr = "Hello, World!Hello, World!Hello, World!".toArray()

    /* 将字节数组压缩后写入压缩输出流的缓冲区 */
    compressOutputStream.write(arr)

    /* 将内部缓冲区里已压缩的数据刷出并写入绑定的输出流,然后刷新绑定的输出流 */
    compressOutputStream.flush()

    /* 关闭压缩输出流 */
    compressOutputStream.close()
}

func write(Array<Byte>)

public func write(inBuf: Array<Byte>): Unit

功能:将指定字节数组中的数据进行压缩,并写入输出流,当数据全部压缩完成并写入输出流,函数返回。

参数:

  • inBuf: Array<Byte> - 待压缩的字节数组。

异常:

  • ZlibException - 如果当前压缩输出流已经被关闭,或压缩数据失败,抛出异常。

示例:

import stdx.compress.zlib.*
import std.io.*

main(): Unit {
    var byteBuffer = ByteBuffer()
    var compressOutputStream: CompressOutputStream = CompressOutputStream(byteBuffer, bufLen: 39)

    var arr = "Hello, World!Hello, World!Hello, World!".toArray()

    /* 将字节数组压缩后写入压缩输出流的缓冲区 */
    compressOutputStream.write(arr)

    /* 将内部缓冲区里已压缩的数据刷出并写入绑定的输出流,然后刷新绑定的输出流 */
    compressOutputStream.flush()

    /* 关闭压缩输出流 */
    compressOutputStream.close()
}

class DecompressInputStream

public class DecompressInputStream <: InputStream {
    public init(inputStream: InputStream, wrap!: WrapType = DeflateFormat, bufLen!: Int64 = 512)
}

功能:解压输入流。

可将 DecompressInputStream 实例通过构造函数绑定到任意 InputStream 输入流,通过循环调用 read(outBuf: Array<Byte>) 函数读取、解压输入流中的数据,并将解压后数据输出到指定字节数组。

父类型:

  • InputStream

init(InputStream, WrapType, Int64)

public init(inputStream: InputStream, wrap!: WrapType = DeflateFormat, bufLen!: Int64 = 512)

功能:构造一个解压输入流。

需绑定一个输入流,可设置待解压数据格式、内部缓冲区大小(每次从输入流中读取多少数据进行解压)。

参数:

  • inputStream: InputStream - 待压缩的输入流。
  • wrap!: WrapType - 待解压数据格式,默认值为 DeflateFormat
  • bufLen!: Int64 - 输入流缓冲区的大小,取值范围为 (0, Int64.Max],默认 512 字节。

异常:

  • ZlibException - 如果 bufLen 小于等于 0,输入流分配内存失败,或待解压资源初始化失败,抛出异常。

示例:

import stdx.compress.zlib.*
import std.io.*

main(): Unit {
    let arr1 = "Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!".toArray()

    /* 使用压缩输入流进行数据压缩 */
    let byteBuffer = ByteBuffer(arr1)
    var compressInputStream: CompressInputStream = CompressInputStream(byteBuffer)
    var arr2: Array<Byte> = Array<Byte>(1024, repeat: 0)
    var len1 = compressInputStream.read(arr2)

    /* 使用解压缩输入流进行数据解压 */
    var decompressInputStream: DecompressInputStream = DecompressInputStream(ByteBuffer(arr2[..len1]), wrap: GzipFormat,
        bufLen: 1024)

    /* 关闭输入流 */
    compressInputStream.close()
    decompressInputStream.close()
}

func close()

public func close(): Unit

功能:关闭解压输入流。

当前 DecompressInputStream 实例使用完毕后必须调用此函数来释放其所占内存资源,以免造成内存泄漏。调用该函数前需确保 read 函数已返回 0,否则可能导致绑定的 InputStream 并未被全部解压。

异常:

  • ZlibException - 如果释放解压资源失败,抛出异常。

示例:

import stdx.compress.zlib.*
import std.io.*

main(): Unit {
    let arr1 = "Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!".toArray()

    /* 使用压缩输入流进行数据压缩 */
    let byteBuffer = ByteBuffer(arr1)
    var compressInputStream: CompressInputStream = CompressInputStream(byteBuffer)
    var arr2: Array<Byte> = Array<Byte>(1024, repeat: 0)
    var len1 = compressInputStream.read(arr2)

    /* 使用解压缩输入流进行数据解压 */
    var decompressInputStream: DecompressInputStream = DecompressInputStream(ByteBuffer(arr2[..len1]))
    var arr3: Array<Byte> = Array<Byte>(1024, repeat: 0)
    var len2 = decompressInputStream.read(arr3)
    println(String.fromUtf8(arr3[..len2]))

    /* 关闭输入流 */
    compressInputStream.close()
    decompressInputStream.close()
    println("DecompressInputStream closed successfully.")
}

运行结果:

Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!
DecompressInputStream closed successfully.

func read(Array<Byte>)

public func read(outBuf: Array<Byte>): Int64

功能:从绑定的输入流中读取数据并解压,解压后数据放入指定的字节数组中。

参数:

  • outBuf: Array<Byte> - 用来存放解压后数据的缓冲区。

返回值:

  • Int64 - 如果解压成功,返回解压后字节数,如果绑定的输入流中数据已经全部解压完成,或者该解压输入流被关闭,返回 0。

异常:

  • ZlibException - 当 outBuf 为空,或解压数据失败,抛出异常。

示例:

import stdx.compress.zlib.*
import std.io.*

main(): Unit {
    let arr1 = "Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!".toArray()

    /* 使用压缩输入流进行数据压缩 */
    let byteBuffer = ByteBuffer(arr1)
    var compressInputStream: CompressInputStream = CompressInputStream(byteBuffer)
    var arr2: Array<Byte> = Array<Byte>(1024, repeat: 0)
    /* 原始数据长度 */
    println("原始数据长度: ${arr1.size}")
    var len1 = compressInputStream.read(arr2)
    /* 压缩后的数据长度 */
    println("压缩后的数据长度: ${len1}")

    /* 使用解压缩输入流进行数据解压 */
    var decompressInputStream: DecompressInputStream = DecompressInputStream(ByteBuffer(arr2[..len1]))
    var arr3: Array<Byte> = Array<Byte>(1024, repeat: 0)
    var len2 = decompressInputStream.read(arr3)
    println("解压后的数据长度: ${len2}")
    println("解压后数据: ${String.fromUtf8(arr3[..len2])}")

    /* 关闭输入流 */
    compressInputStream.close()
    decompressInputStream.close()
}

运行结果:

原始数据长度: 65
压缩后的数据长度: 18
解压后的数据长度: 65
解压后数据: Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!

class DecompressOutputStream

public class DecompressOutputStream <: OutputStream {
    public init(outputStream: OutputStream, wrap!: WrapType = DeflateFormat, bufLen!: Int64 = 512)
}

功能:解压输出流。

可将 DecompressOutputStream 实例通过构造函数绑定到指定的 OutputStream 类型输出流,通过调用 write(inBuf: Array<Byte>) 函数读取、解压指定字节数组中的数据,并将解压后数据输出到绑定的输出流中。

父类型:

  • OutputStream

init(OutputStream, WrapType, Int64)

public init(outputStream: OutputStream, wrap!: WrapType = DeflateFormat, bufLen!: Int64 = 512)

功能:构造一个解压输出流。

需绑定一个输出流,可设置压缩数据类型、压缩等级、内部缓冲区大小(解压后数据会存入内部缓冲区,缓冲区存满后再写到输出流)。

参数:

  • outputStream: OutputStream - 绑定的输出流,解压后数据将写入该输出流。
  • wrap!: WrapType - 待解压数据格式,默认值为 DeflateFormat
  • bufLen!: Int64 - 输出流缓冲区的大小,取值范围为 (0, Int64.Max],默认 512 字节。

异常:

  • ZlibException - 如果 bufLen 小于等于 0,输出流分配内存失败,或解压资源初始化失败,抛出异常。

示例:

import stdx.compress.zlib.*
import std.fs.*

main(): Unit {
    let arr1 = "Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!".toArray()

    // 创建一个临时文件用于压缩
    File.writeTo("./temp_input.txt", arr1)

    // 压缩文件
    compressFile("./temp_input.txt", "./temp_compressed.gz")

    // 读取压缩后的数据
    let compressedData = File.readFrom("./temp_compressed.gz")

    /* 使用解压缩输出流进行数据解压后,将数据写入文件,文件的内容为原始数据 */
    var file = File("./file.text", ReadWrite)
    var decompressOutputStream: DecompressOutputStream = DecompressOutputStream(file, wrap: GzipFormat, bufLen: 1024)

    decompressOutputStream.write(compressedData)
    decompressOutputStream.flush()

    /* 关闭输出流和文件 */
    decompressOutputStream.close()

    println("解压后文件数据字节数和压缩前数据字节数是否相等: ${file.length == arr1.size}")
    file.close()

    // 清理临时文件
    removeIfExists("./temp_input.txt")
    removeIfExists("./temp_compressed.gz")
    removeIfExists("./file.text")
}

func compressFile(srcFileName: String, destFileName: String): Int64 {
    var count: Int64 = 0
    var srcFile: File = File(srcFileName, Read)
    var destFile: File = File(destFileName, Write)

    var tempBuf: Array<UInt8> = Array<UInt8>(1024, repeat: 0)
    var compressOutputStream: CompressOutputStream = CompressOutputStream(destFile, wrap: GzipFormat, bufLen: 10000)
    while (true) {
        var readNum = srcFile.read(tempBuf)
        if (readNum > 0) {
            compressOutputStream.write(tempBuf.slice(0, readNum).toArray())
            count += readNum
        } else {
            break
        }
    }
    compressOutputStream.flush()
    compressOutputStream.close()

    srcFile.close()
    destFile.close()
    return count
}

运行结果:

解压后文件数据字节数和压缩前数据字节数是否相等: true

func close()

public func close(): Unit

功能:关闭当前解压输出流实例。

关闭时,将写入剩余解压后数据,并释放其所占内存资源。当前压缩输出流使用完毕后必须调用此函数来释放其所占内存资源,以免造成内存泄漏。如果之前 write 函数已处理的压缩数据不完整,调用 close 函数时会因为解压数据不全而抛出异常。

异常:

  • ZlibException - 如果当前压缩输出流已经被关闭,通过 write 函数传入的待解压数据不完整,或释放压缩资源失败,抛出异常。

示例:

import stdx.compress.zlib.*
import std.fs.*

main(): Unit {
    let arr1 = "Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!".toArray()

    // 创建一个临时文件用于压缩
    File.writeTo("./temp_input.txt", arr1)

    // 压缩文件
    compressFile("./temp_input.txt", "./temp_compressed.gz")

    // 读取压缩后的数据
    let compressedData = File.readFrom("./temp_compressed.gz")

    /* 使用解压缩输出流进行数据解压后,将数据写入文件,文件的内容为原始数据 */
    var file = File("./file.text", ReadWrite)
    var decompressOutputStream: DecompressOutputStream = DecompressOutputStream(file, wrap: GzipFormat, bufLen: 1024)

    decompressOutputStream.write(compressedData)
    decompressOutputStream.flush()

    /* 关闭输出流和文件 */
    decompressOutputStream.close()

    println("解压后文件数据字节数和压缩前数据字节数是否相等: ${file.length == arr1.size}")
    file.close()

    // 清理临时文件
    removeIfExists("./temp_input.txt")
    removeIfExists("./temp_compressed.gz")
    removeIfExists("./file.text")
}

func compressFile(srcFileName: String, destFileName: String): Int64 {
    var count: Int64 = 0
    var srcFile: File = File(srcFileName, Read)
    var destFile: File = File(destFileName, Write)

    var tempBuf: Array<UInt8> = Array<UInt8>(1024, repeat: 0)
    var compressOutputStream: CompressOutputStream = CompressOutputStream(destFile, wrap: GzipFormat, bufLen: 10000)
    while (true) {
        var readNum = srcFile.read(tempBuf)
        if (readNum > 0) {
            compressOutputStream.write(tempBuf.slice(0, readNum).toArray())
            count += readNum
        } else {
            break
        }
    }
    compressOutputStream.flush()
    compressOutputStream.close()

    srcFile.close()
    destFile.close()
    return count
}

运行结果:

解压后文件数据字节数和压缩前数据字节数是否相等: true

func flush()

public func flush(): Unit

功能:刷新解压输出流。将内部缓冲区里已解压的数据写入绑定的输出流,然后刷新绑定的输出流。

异常:

  • ZlibException - 如果当前解压输出流已经被关闭,抛出异常。

示例:

import stdx.compress.zlib.*
import std.fs.*

main(): Unit {
    let arr1 = "Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!".toArray()

    // 创建一个临时文件用于压缩
    File.writeTo("./temp_input.txt", arr1)

    // 压缩文件
    compressFile("./temp_input.txt", "./temp_compressed.gz")

    // 读取压缩后的数据
    let compressedData = File.readFrom("./temp_compressed.gz")

    /* 使用解压缩输出流进行数据解压后,将数据写入文件,文件的内容为原始数据 */
    var file = File("./file.text", ReadWrite)
    var decompressOutputStream: DecompressOutputStream = DecompressOutputStream(file, wrap: GzipFormat, bufLen: 1024)

    decompressOutputStream.write(compressedData)
    decompressOutputStream.flush()

    /* 关闭输出流和文件 */
    decompressOutputStream.close()

    println("解压后文件数据字节数和压缩前数据字节数是否相等: ${file.length == arr1.size}")
    file.close()

    // 清理临时文件
    removeIfExists("./temp_input.txt")
    removeIfExists("./temp_compressed.gz")
    removeIfExists("./file.text")
}

func compressFile(srcFileName: String, destFileName: String): Int64 {
    var count: Int64 = 0
    var srcFile: File = File(srcFileName, Read)
    var destFile: File = File(destFileName, Write)

    var tempBuf: Array<UInt8> = Array<UInt8>(1024, repeat: 0)
    var compressOutputStream: CompressOutputStream = CompressOutputStream(destFile, wrap: GzipFormat, bufLen: 10000)
    while (true) {
        var readNum = srcFile.read(tempBuf)
        if (readNum > 0) {
            compressOutputStream.write(tempBuf.slice(0, readNum).toArray())
            count += readNum
        } else {
            break
        }
    }
    compressOutputStream.flush()
    compressOutputStream.close()

    srcFile.close()
    destFile.close()
    return count
}

运行结果:

解压后文件数据字节数和压缩前数据字节数是否相等: true

func write(Array<Byte>)

public func write(inBuf: Array<Byte>): Unit

功能:将指定字节数组中的数据进行解压,并写入输出流,当数据全部解压完成并写入输出流,函数返回。

参数:

  • inBuf: Array<Byte> - 待解压的字节数组。

异常:

  • ZlibException - 如果当前解压输出流已经被关闭,或解压数据失败,抛出异常。

示例:

import stdx.compress.zlib.*
import std.io.*
import std.fs.*

main(): Unit {
    let arr1 = "Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!".toArray()

    /* 使用压缩输入流进行数据压缩 */
    let byteBuffer = ByteBuffer(arr1)
    var compressInputStream: CompressInputStream = CompressInputStream(byteBuffer)
    var arr2: Array<Byte> = Array<Byte>(1024, repeat: 0)
    /* 原始数据长度 */
    println("原始数据长度: ${arr1.size}")
    var len1 = compressInputStream.read(arr2)
    /* 压缩后的数据长度 */
    println("压缩后的数据长度: ${len1}")

    /* 使用解压缩输出流进行数据解压后,将数据写入文件,文件的内容为原始数据 */
    var file = File("./file.text", ReadWrite)
    var decompressOutputStream: DecompressOutputStream = DecompressOutputStream(file)
    decompressOutputStream.write(arr2[..len1])
    decompressOutputStream.flush()

    /* 关闭输入流和输出流 */
    compressInputStream.close()
    decompressOutputStream.close()
    println("解压后文件数据字节数和压缩前数据字节数是否相等: ${file.length == arr1.size}")
    file.close()
    removeIfExists("./file.text")
}

运行结果:

原始数据长度: 65
压缩后的数据长度: 18
解压后文件数据字节数和压缩前数据字节数是否相等: true

枚举

enum CompressLevel

public enum CompressLevel {
    | BestCompression
    | BestSpeed
    | DefaultCompression
}

功能:压缩等级。

压缩等级决定了压缩率和压缩速度,目前支持三种压缩等级,压缩率由小到大,压缩速度由快到慢依次为:BestSpeed、DefaultCompression、BestCompression。

BestCompression

BestCompression

功能:构造一个压缩率优先的压缩等级枚举实例,表示压缩率最高,压缩速度相对降低。

BestSpeed

BestSpeed

功能:构造一个压缩速度优先的压缩等级枚举实例,表示压缩速度最快,压缩率相对较低。

DefaultCompression

DefaultCompression

功能:构造一个压缩等级枚举实例,表示默认压缩等级。

enum WrapType

public enum WrapType {
    | DeflateFormat
    | GzipFormat
}

功能:压缩数据格式。

目前支持 DeflateFormat 和 GzipFormat 两种格式。

DeflateFormat

DeflateFormat

功能:构造一个表示 Deflate 压缩数据格式的枚举实例。

GzipFormat

GzipFormat

功能:构造一个表示 Gzip 压缩数据格式的枚举实例。

异常类

class ZlibException

public class ZlibException <: Exception {
    public init(message: String)
}

功能:zlib 包的异常类。

父类型:

  • Exception

init(String)

public init(message: String)

功能:根据异常信息创建 ZlibException 实例。

参数:

  • message: String - 异常提示信息。

示例:

import stdx.compress.zlib.*

main(): Unit {
    try {
        throw ZlibException("This is a test exception.")
    } catch (e: ZlibException) {
        println("捕获到 ZlibException: ${e.message}")
    }
}

运行结果:

捕获到 ZlibException: This is a test exception.

Deflate 格式数据的压缩和解压

示例:

import stdx.compress.zlib.*
import std.fs.*

main() {
    var arr: Array<Byte> = Array<Byte>(1024 * 1024, {i => UInt8(i % 256)})
    File.writeTo("./zlib1.txt", arr)

    if (compressFile("./zlib1.txt", "./zlib_copmressed1.zlib") <= 0) {
        println("Failed to compress file!")
    }

    if (decompressFile("./zlib_copmressed1.zlib", "./zlib_decopmressed1.txt") != arr.size) {
        println("Failed to decompress file!")
    }

    if (compareFile("./zlib1.txt", "./zlib_decopmressed1.txt")) {
        println("success")
    } else {
        println("failed")
    }

    remove("./zlib1.txt")
    remove("./zlib_copmressed1.zlib")
    remove("./zlib_decopmressed1.txt")
    return 0
}

func compressFile(srcFileName: String, destFileName: String): Int64 {
    var count: Int64 = 0
    var srcFile: File = File(srcFileName, Read)
    var destFile: File = File(destFileName, Write)

    var tempBuf: Array<UInt8> = Array<UInt8>(1024, repeat: 0)
    var compressOutputStream: CompressOutputStream = CompressOutputStream(destFile, wrap: DeflateFormat)
    while (true) {
        var readNum = srcFile.read(tempBuf)
        if (readNum > 0) {
            compressOutputStream.write(tempBuf.slice(0, readNum).toArray())
            count += readNum
        } else {
            break
        }
    }
    compressOutputStream.flush()
    compressOutputStream.close()

    srcFile.close()
    destFile.close()
    return count
}

func decompressFile(srcFileName: String, destFileName: String): Int64 {
    var count: Int64 = 0
    var srcFile: File = File(srcFileName, Read)
    var destFile: File = File(destFileName, Write)

    var tempBuf: Array<UInt8> = Array<UInt8>(1024, repeat: 0)
    var decompressInputStream: DecompressInputStream = DecompressInputStream(srcFile, wrap: DeflateFormat)
    while (true) {
        var readNum = decompressInputStream.read(tempBuf)
        if (readNum <= 0) {
            break
        }
        destFile.write(tempBuf.slice(0, readNum).toArray())
        count += readNum
    }
    decompressInputStream.close()

    srcFile.close()
    destFile.close()
    return count
}

func compareFile(fileName1: String, fileName2: String): Bool {
    return File.readFrom(fileName1) == File.readFrom(fileName2)
}

运行结果:

success

Gzip 格式数据的压缩和解压

示例:

import stdx.compress.zlib.*
import std.fs.*

main() {
    var arr: Array<Byte> = Array<Byte>(1024 * 1024, {i => UInt8(i % 256)})
    File.writeTo("./zlib.txt", arr)

    if (compressFile("./zlib.txt", "./zlib_copmressed.zlib") <= 0) {
        println("Failed to compress file!")
    }

    if (decompressFile("./zlib_copmressed.zlib", "./zlib_decopmressed.txt") != arr.size) {
        println("Failed to decompress file!")
    }

    if (compareFile("./zlib.txt", "./zlib_decopmressed.txt")) {
        println("success")
    } else {
        println("failed")
    }

    remove("./zlib.txt")
    remove("./zlib_copmressed.zlib")
    remove("./zlib_decopmressed.txt")
    return 0
}

func compressFile(srcFileName: String, destFileName: String): Int64 {
    var count: Int64 = 0
    var srcFile: File = File(srcFileName, Read)
    var destFile: File = File(destFileName, Write)

    var tempBuf: Array<UInt8> = Array<UInt8>(1024, repeat: 0)
    var compressOutputStream: CompressOutputStream = CompressOutputStream(destFile, wrap: GzipFormat, bufLen: 10000)
    while (true) {
        var readNum = srcFile.read(tempBuf)
        if (readNum > 0) {
            compressOutputStream.write(tempBuf.slice(0, readNum).toArray())
            count += readNum
        } else {
            break
        }
    }
    compressOutputStream.flush()
    compressOutputStream.close()

    srcFile.close()
    destFile.close()
    return count
}

func decompressFile(srcFileName: String, destFileName: String): Int64 {
    var count: Int64 = 0
    var srcFile: File = File(srcFileName, Read)
    var destFile: File = File(destFileName, Write)

    var tempBuf: Array<UInt8> = Array<UInt8>(1024, repeat: 0)
    var decompressInputStream: DecompressInputStream = DecompressInputStream(srcFile, wrap: GzipFormat, bufLen: 10000)
    while (true) {
        var readNum = decompressInputStream.read(tempBuf)
        if (readNum <= 0) {
            break
        }
        destFile.write(tempBuf.slice(0, readNum).toArray())
        count += readNum
    }
    decompressInputStream.close()

    srcFile.close()
    destFile.close()
    return count
}

func compareFile(fileName1: String, fileName2: String): Bool {
    return File.readFrom(fileName1) == File.readFrom(fileName2)
}

运行结果:

success

stdx.crypto.common

功能介绍

crypto.common 包提供了加解密相关接口。

API 列表

函数

函数名功能
getGlobalCryptoKit()获取当前全局使用的加密套件。
setGlobalCryptoKit(CryptoKit)设置全局使用的加密套件。

接口

接口名功能
Certificate证书接口,用于适配不同的加密套件。
CryptoKit加密套件接口。提供随机数生成器及解码 DER、PEM 的能力。
DHParametersDH 密钥参数接口。
Key密钥接口。
PrivateKey私钥接口。
PublicKey公钥接口。
RandomGenerator安全随机数生成器接口。

结构体

结构体名功能
DerBlobCrypto 支持配置二进制证书流。
PemPem 结构体。
PemEntryPEM 文本格式。

异常类

异常类名功能
CryptoException此类为加解密出现错误时抛出的异常。

函数

func getGlobalCryptoKit()

public func getGlobalCryptoKit(): CryptoKit

功能:获取当前全局使用的加密套件。

返回值:

  • CryptoKit - 当前全局使用的加密套件。

异常:

示例:

import stdx.crypto.common.*

// 导入stdx.crypto.kit包,将使用默认全局加密套件
import stdx.crypto.kit.*

main() {
    // 没有设置全局加密套件将会抛出异常
    let cryptoKit = getGlobalCryptoKit()
    return 0
}

func setGlobalCryptoKit(CryptoKit)

public func setGlobalCryptoKit(kit: CryptoKit): Unit

功能:设置全局使用的加密套件。

参数:

示例:

import stdx.crypto.common.*
import stdx.crypto.kit.*

main() {
    // 创建一个默认的加密套件
    let defaultKit = DefaultCryptoKit()

    // 设置全局加密套件
    setGlobalCryptoKit(defaultKit)
    return 0
}

接口

interface Certificate

public interface Certificate {}

功能:证书接口,用于适配不同的加密套件。

interface CryptoKit

public interface CryptoKit {
    func getRandomGen(): RandomGenerator
    func publicKeyFromDer(encoded: DerBlob): PublicKey
    func publicKeyFromPem(text: String): PublicKey
    func privateKeyFromDer(encoded: DerBlob): PrivateKey
    func privateKeyFromPem(text: String): PrivateKey
    func privateKeyFromDer(encoded: DerBlob, password!: ?String): PrivateKey
    func privateKeyFromPem(text: String, password!: ?String): PrivateKey
    func dhParametersFromDer(encoded: DerBlob): DHParameters
    func dhParametersFromPem(text: String): DHParameters
    func certificateFromDer(encoded: DerBlob): Certificate
    func certificateFromPem(text: String): Array<Certificate>
}

功能:加密套件接口。提供随机数生成器及解码 DER、PEM 的能力。

说明:

PEM 是一种基于 Base64 的编码格式。

func certificateFromDer(DerBlob)

func certificateFromDer(encoded: DerBlob): Certificate

功能:将证书从 DER 格式解码。

参数:

  • encoded: DerBlob - 待解码的 DerBlob 对象。

返回值:

func certificateFromPem(String)

func certificateFromPem(text: String): Array<Certificate>

功能:将证书从 PEM 格式解码。

参数:

  • text: String - 待解码的 PEM 格式字符串。

返回值:

func dhParametersFromDer(DerBlob)

func dhParametersFromDer(encoded: DerBlob): DHParameters

功能:将 DH 密钥参数从 DER 格式解码。

参数:

  • encoded: DerBlob - 待解码的 DerBlob 对象。

返回值:

func dhParametersFromPem(String)

func dhParametersFromPem(text: String): DHParameters

功能:将 DH 密钥参数从 PEM 格式解码。

参数:

  • text: String - 待解码的 PEM 格式字符串。

返回值:

func getRandomGen()

func getRandomGen(): RandomGenerator

功能:获取随机数生成器。

返回值:

func privateKeyFromDer(DerBlob)

func privateKeyFromDer(encoded: DerBlob): PrivateKey

功能:将私钥从 DER 格式解码。

参数:

  • encoded: DerBlob - 待解码的 DerBlob 对象。

返回值:

func privateKeyFromDer(DerBlob, ?String)

func privateKeyFromDer(encoded: DerBlob, password!: ?String): PrivateKey

功能:将私钥从 DER 格式解密解码。密码为 None 时则不解密。

参数:

  • encoded: DerBlob - 待解密解码的 DerBlob 对象。
  • password!: ?String - 解密密码。

返回值:

func privateKeyFromPem(String)

func privateKeyFromPem(text: String): PrivateKey

功能:将私钥从 PEM 格式解码。

参数:

  • text: String - 待解码的 PEM 格式字符串。

返回值:

func privateKeyFromPem(String, ?String)

func privateKeyFromPem(text: String, password!: ?String): PrivateKey

功能:将私钥从 PEM 格式解密解码。密码为 None 时则不解密。

参数:

  • text: String - 待解密解码的 PEM 格式字符串。
  • password!: ?String - 解密密码。

返回值:

func publicKeyFromDer(DerBlob)

func publicKeyFromDer(encoded: DerBlob): PublicKey

功能:将公钥从 DER 格式解码。

参数:

  • encoded: DerBlob - 待解码的 DerBlob 对象。

返回值:

func publicKeyFromPem(String)

func publicKeyFromPem(text: String): PublicKey

功能:将公钥从 PEM 格式解码。

参数:

  • text: String - 待解码的 PEM 格式字符串。

返回值:

interface DHParameters

public interface DHParameters <: Key {
    static func decodeDer(encoded: DerBlob): DHParameters
    static func decodeFromPem(text: String): DHParameters
}

功能:DH 密钥参数接口。

父类型:

static func decodeDer(DerBlob)

static func decodeDer(encoded: DerBlob): DHParameters

功能:将 DH 密钥参数从 DER 格式解码。

说明:

  • DH(Diffie-Hellman)密钥交换协议是一种确保共享 KEY 安全穿越不安全网络的方法。
  • DER 和 PEM 是两种常见的编码格式。

参数:

  • encoded: DerBlob - DER 格式的 DH 密钥参数对象。

返回值:

  • DHParameters - 由 DER 格式解码出的 DH 密钥参数。

static func decodeFromPem(String)

static func decodeFromPem(text: String): DHParameters

功能:将 DH 密钥参数从 PEM 格式解码。

参数:

  • text: String - PEM 格式的 DH 密钥参数字符流。

返回值:

  • DHParameters - 由 PEM 格式解码出的 DH 密钥参数。

interface Key

public interface Key <: ToString {
    func encodeToDer(): DerBlob
    func encodeToPem(): PemEntry
    static func decodeDer(encoded: DerBlob): Key
    static func decodeFromPem(text: String): Key
}

功能:密钥接口。公钥用于签名验证或加密,私钥用于签名或解密,公钥和私钥必须相互匹配并形成一对。该类为密钥类,无具体实现,供 PrivateKey/PublicKey 及用户扩展接口。

父类型:

  • ToString

static func decodeDer(DerBlob)

static func decodeDer(encoded: DerBlob): Key

功能:将密钥从 DER 格式解码。

参数:

  • encoded: DerBlob - DER 格式的对象。

返回值:

  • Key - 由 DER 格式解码出的密钥。

static func decodeFromPem(String)

static func decodeFromPem(text: String): Key

功能:将密钥从 PEM 格式解码。

参数:

  • text: String - PEM 格式的字符流。

返回值:

  • Key - 由 PEM 格式解码出的密钥。

func encodeToDer()

func encodeToDer(): DerBlob

功能:将密钥编码为 DER 格式。

返回值:

  • DerBlob - 密钥数据 DER 格式编码生成的对象。

func encodeToPem()

func encodeToPem(): PemEntry

功能:将密钥编码为 PEM 格式。

返回值:

  • PemEntry - 密钥数据 PEM 格式编码生成的对象。

interface PrivateKey

public interface PrivateKey <: Key {
    func encodeToDer(password!: ?String): DerBlob
    func encodeToPem(password!: ?String): PemEntry
    static func decodeDer(encoded: DerBlob): PrivateKey
    static func decodeFromPem(text: String): PrivateKey
    static func decodeDer(encoded: DerBlob, password!: ?String): PrivateKey
    static func decodeFromPem(text: String, password!: ?String): PrivateKey
}

功能:私钥接口。

父类型:

static func decodeDer(DerBlob)

static func decodeDer(encoded: DerBlob): PrivateKey

功能:将私钥从 DER 格式解码。

参数:

  • encoded: DerBlob - DER 格式的私钥对象。

返回值:

  • PrivateKey - 由 DER 格式解码出的私钥。

static func decodeDer(DerBlob, ?String)

static func decodeDer(encoded: DerBlob, password!: ?String): PrivateKey

功能:将 DER 格式的私钥解密解码成 PrivateKey 对象,密码为 None 时则不解密。

参数:

  • encoded: DerBlob - DER 格式的私钥。
  • password!: ?String - 解密密码。

返回值:

static func decodeFromPem(String)

static func decodeFromPem(text: String): PrivateKey

功能:将私钥从 PEM 格式解码。

参数:

  • text: String - PEM 格式的私钥字符流。

返回值:

  • PrivateKey - 由 PEM 格式解码出的私钥。

static func decodeFromPem(String, ?String)

static func decodeFromPem(text: String, password!: ?String): PrivateKey

功能:将 PEM 格式的私钥解密解码成 PrivateKey 对象,密码为 None 时则不解密。

参数:

  • text: String - PEM 格式的私钥。
  • password!: ?String - 解密密码。

返回值:

func encodeToDer(?String)

func encodeToDer(password!: ?String): DerBlob

功能:将私钥加密编码成 DER 格式,密码为 None 时则不加密。

参数:

  • password!: ?String - 加密密码。

返回值:

  • DerBlob - 加密后的 DER 格式的私钥。

func encodeToPem(?String)

func encodeToPem(password!: ?String): PemEntry

功能:将私钥加密编码成 PEM 格式,密码为 None 时则不加密。

参数:

  • password!: ?String - 加密密码。

返回值:

  • PemEntry - 加密后的 PEM 格式的私钥。

interface PublicKey

public interface PublicKey <: Key {
    static func decodeDer(encoded: DerBlob): PublicKey
    static func decodeFromPem(text: String): PublicKey
}

功能:公钥接口。

父类型:

static func decodeDer(DerBlob)

static func decodeDer(encoded: DerBlob): PublicKey

功能:将公钥从 DER 格式解码。

参数:

  • encoded: DerBlob - DER 格式的公钥对象。

返回值:

  • PublicKey - 由 DER 格式解码出的公钥。

static func decodeFromPem(String)

static func decodeFromPem(text: String): PublicKey

功能:将公钥从 PEM 格式解码。

参数:

  • text: String - PEM 格式的公钥字符流。

返回值:

  • PublicKey - 由 PEM 格式解码出的公钥。

interface RandomGenerator

public interface RandomGenerator {
    public func nextBits(bits: UInt64): UInt64
    public func nextBytes(bytes: Array<Byte>): Unit
}

功能:安全随机数生成器接口。

func nextBits(UInt64)

public func nextBits(bits: UInt64): UInt64

功能:生成一个指定位长的随机整数。

参数:

  • bits: UInt64 - 要生成的随机数的位数,取值范围 (0, 64]。

返回值:

  • UInt64 - 生成的指定位长的随机数。

func nextBytes(Array<Byte>)

public func nextBytes(bytes: Array<Byte>): Unit

功能:生成随机数替换入参数组中的每个元素。

参数:

  • bytes: Array<Byte> - 被替换的数组。

结构体

struct DerBlob

public struct DerBlob <: Equatable<DerBlob> & Hashable {
    public init(content: Array<Byte>)
}

功能:Crypto 支持配置二进制证书流,用户读取二进制证书数据并创建 DerBlob 对象后可将其解析成 X509Certificate / X509CertificateRequest / PublicKey / PrivateKey 对象。

父类型:

prop body

public prop body: Array<Byte>

功能:DerBlob 对象中的字符序列。

类型:Array<Byte>

示例:

import stdx.crypto.common.*

main(): Unit {
    // 创建一个 DerBlob 对象(仅演示二进制容器能力,数据无 ASN.1/DER 加密规范格式)
    let content = "Hello, DerBlob!".toArray()
    let derBlob = DerBlob(content)

    // 访问 body 属性
    let body = derBlob.body
    println("DerBlob body UTF-8: ${String.fromUtf8(body)}")
    println("DerBlob body: ${body}")
}

运行结果:

DerBlob body UTF-8: Hello, DerBlob!
DerBlob body: [72, 101, 108, 108, 111, 44, 32, 68, 101, 114, 66, 108, 111, 98, 33]

prop size

public prop size: Int64

功能:DerBlob 对象中字符序列的大小。

类型:Int64

示例:

import stdx.crypto.common.*

main(): Unit {
    // 创建一个 DerBlob 对象(仅演示二进制容器能力,数据无 ASN.1/DER 加密规范格式)
    let content = "Hello, DerBlob!".toArray()
    let derBlob = DerBlob(content)

    // 访问 size 属性
    let size = derBlob.size
    println("DerBlob size: ${size}")
}

运行结果:

DerBlob size: 15

init(Array<Byte>)

public init(content: Array<Byte>)

功能:构造 DerBlob 对象。

参数:

  • content: Array<Byte> - 二进制字符序列。

示例:

import stdx.crypto.common.*

main(): Unit {
    // 创建一个 DerBlob 对象(仅演示二进制容器能力,数据无 ASN.1/DER 加密规范格式)
    let content = "Hello, DerBlob!".toArray()
    let derBlob = DerBlob(content)

    println("DerBlob对象创建成功")
}

运行结果:

DerBlob对象创建成功

func hashCode()

public override func hashCode(): Int64

功能:返回 DerBlob 对象哈希值。

返回值:

  • Int64 - 对 DerBlob 对象进行哈希计算后得到的结果。

示例:

import stdx.crypto.common.*

main(): Unit {
    // 创建一个 DerBlob 对象(仅演示二进制容器能力,数据无 ASN.1/DER 加密规范格式)
    let content = "Hello, DerBlob!".toArray()
    let derBlob = DerBlob(content)

    // 获取哈希值
    let hashCode = derBlob.hashCode()
    println("DerBlob hashCode: ${hashCode}")
}

运行结果:

DerBlob hashCode: -1740040550816916903

operator func !=(DerBlob)

public override operator func !=(other: DerBlob): Bool

功能:判不等。

参数:

返回值:

  • Bool - 若对象不同,返回 true;否则,返回 false。

示例:

import stdx.crypto.common.*

main(): Unit {
    // 创建两个不同的 DerBlob 对象(仅演示二进制容器能力,数据无 ASN.1/DER 加密规范格式)
    let content1 = "Hello, DerBlob1!".toArray()
    let content2 = "Hello, DerBlob2!".toArray()
    let derBlob1 = DerBlob(content1)
    let derBlob2 = DerBlob(content2)

    // 测试不等操作符
    let notEqual = derBlob1 != derBlob2
    println("DerBlob1 != DerBlob2: ${notEqual}")

    // 测试相同对象
    let derBlob3 = DerBlob(content1)
    let notEqual2 = derBlob1 != derBlob3
    println("DerBlob1 != DerBlob3: ${notEqual2}")
}

运行结果:

DerBlob1 != DerBlob2: true
DerBlob1 != DerBlob3: false

operator func ==(DerBlob)

public override operator func ==(other: DerBlob): Bool

功能:判等。

参数:

返回值:

  • Bool - 若对象相同,返回 true;否则,返回 false。

示例:

import stdx.crypto.common.*

main(): Unit {
    // 创建两个相同的 DerBlob 对象(仅演示二进制容器能力,数据无 ASN.1/DER 加密规范格式)
    let content1 = "Hello, DerBlob!".toArray()
    let content2 = "Hello, DerBlob!".toArray()
    let derBlob1 = DerBlob(content1)
    let derBlob2 = DerBlob(content2)

    // 测试相等操作符
    let equal = derBlob1 == derBlob2
    println("DerBlob1 == DerBlob2: ${equal}")

    // 测试不同对象
    let derBlob3 = DerBlob("Hello, DerBlob3!".toArray())
    let equal2 = derBlob1 == derBlob3
    println("DerBlob1 == DerBlob3: ${equal2}")
}

运行结果:

DerBlob1 == DerBlob2: true
DerBlob1 == DerBlob3: false

struct Pem

public struct Pem <: Collection<PemEntry> & ToString {
    public Pem(private let items: Array<PemEntry>)
}

功能:结构体 Pem 为条目序列,可以包含多个 PemEntry

父类型:

Pem(Array<PemEntry>)

public Pem(private let items: Array<PemEntry>)

功能:构造 Pem 对象。

参数:

示例:

import stdx.crypto.common.*

main(): Unit {
    // 创建一个 PemEntry 对象(DerBlob 仅演示二进制容器能力,数据无 ASN.1/DER 加密规范格式)
    let derBlob = DerBlob("Hello, PEM!".toArray())
    let pemEntry = PemEntry(PemEntry.LABEL_CERTIFICATE, [("HeaderKey", "HeaderValue")], derBlob)

    // 创建 Pem 对象
    let pem = Pem([pemEntry])

    println("Pem对象创建成功")
}

运行结果:

Pem对象创建成功

prop size

public override prop size: Int64

功能:条目序列的数量。

类型:Int64

示例:

import stdx.crypto.common.*

main(): Unit {
    // 创建一个 PemEntry 对象(DerBlob 仅演示二进制容器能力,数据无 ASN.1/DER 加密规范格式)
    let derBlob = DerBlob("Hello, PEM!".toArray())
    let pemEntry = PemEntry(PemEntry.LABEL_CERTIFICATE, [("HeaderKey", "HeaderValue")], derBlob)

    // 创建 Pem 对象
    let pem = Pem([pemEntry])

    // 访问 size 属性
    println("Pem对象大小: ${pem.size}")
}

运行结果:

Pem对象大小: 1

static func decode(String)

public static func decode(text: String): Pem

功能:将 PEM 文本解码为条目序列。

参数:

  • text: String - PEM 字符串。

返回值:

  • Pem - PEM 条目序列。

异常:

  • X509Exception - 数据为空时,或解码失败抛出异常。

示例:

import stdx.crypto.common.*

main(): Unit {
    // 创建一个 PemEntry 对象(DerBlob 仅演示二进制容器能力,数据无 ASN.1/DER 加密规范格式)
    let derBlob = DerBlob("Hello, PEM!".toArray())
    let pemEntry = PemEntry(PemEntry.LABEL_CERTIFICATE, [("HeaderKey", "HeaderValue")], derBlob)

    // 创建 Pem 对象
    let pem = Pem([pemEntry])

    // 编码为 PEM 格式
    let encoded = pem.encode()
    println("编码后的PEM字符串: \n${encoded}")

    println("解码PEM字符串,获得Pem对象")
    let decoded = Pem.decode(encoded)
    println("解码后的Pem对象大小: ${decoded.size}")
}

运行结果:

编码后的PEM字符串: 
-----BEGIN CERTIFICATE-----
HeaderKey: HeaderValue

SGVsbG8sIFBFTSE=
-----END CERTIFICATE-----

解码PEM字符串,获得Pem对象
解码后的Pem对象大小: 1

func encode()

public func encode(): String

功能:返回 PEM 格式的字符串。行结束符将根据当前操作系统生成。

返回值:

  • String - PEM 格式的字符串。

示例:

import stdx.crypto.common.*

main(): Unit {
    // 创建一个 PemEntry 对象(DerBlob 仅演示二进制容器能力,数据无 ASN.1/DER 加密规范格式)
    let derBlob = DerBlob("Hello, PEM!".toArray())
    let pemEntry = PemEntry(PemEntry.LABEL_CERTIFICATE, [("HeaderKey", "HeaderValue")], derBlob)

    // 创建 Pem 对象
    let pem = Pem([pemEntry])

    // 编码为 PEM 格式
    let encoded = pem.encode()
    println("编码后的PEM字符串: \n${encoded}")
}

运行结果:

编码后的PEM字符串: 
-----BEGIN CERTIFICATE-----
HeaderKey: HeaderValue

SGVsbG8sIFBFTSE=
-----END CERTIFICATE-----

func isEmpty()

public override func isEmpty(): Bool

功能:判断 PEM 文本解码为条目序列是否为空。

返回值:

  • Bool - PEM 文本解码为条目序列为空返回 true;否则,返回 false。

示例:

import stdx.crypto.common.*

main(): Unit {
    // 创建一个 PemEntry 对象(DerBlob 仅演示二进制容器能力,数据无 ASN.1/DER 加密规范格式)
    let derBlob = DerBlob("Hello, PEM!".toArray())
    let pemEntry = PemEntry(PemEntry.LABEL_CERTIFICATE, [("HeaderKey", "HeaderValue")], derBlob)

    // 创建 Pem 对象
    let pem = Pem([pemEntry])

    // 检查是否为空
    println("Pem对象是否为空: ${pem.isEmpty()}")

    // 创建 Pem 对象
    let pemEmpty = Pem([])
    // 检查是否为空
    println("Pem对象是否为空: ${pemEmpty.isEmpty()}")
}

运行结果:

Pem对象是否为空: false
Pem对象是否为空: true

func iterator()

public override func iterator(): Iterator<PemEntry>

功能:生成 PEM 文本解码为条目序列的迭代器。

返回值:

  • Iterator<PemEntry> - PEM 文本解码为条目序列的迭代器。

示例:

import stdx.crypto.common.*

main(): Unit {
    // 创建一个 PemEntry 对象(DerBlob 仅演示二进制容器能力,数据无 ASN.1/DER 加密规范格式)
    let derBlob01 = DerBlob("Hello, PEM01!".toArray())
    let pemEntry01 = PemEntry("CERTIFICATE01", [("HeaderKey01", "HeaderValue01"), ("HeaderKey02", "HeaderValue02")],
        derBlob01)

    // 创建另一个 PemEntry 对象
    let derBlob02 = DerBlob("Hello!!, PEM02!".toArray())
    let pemEntry02 = PemEntry("CERTIFICATE02", [("HeaderKey03", "HeaderValue03"), ("HeaderKey04", "HeaderValue04")],
        derBlob02)

    // 创建 Pem 对象
    let pem = Pem([pemEntry01, pemEntry02])

    // 获取迭代器
    let iter = pem.iterator()
    for (entry in iter) {
        println("PemEntry: ${entry}")
        println("PemEntry.headers: ")
        for (header in entry.headers) {
            println("  ${header[0]}: ${header[1]}")
        }
        println("PemEntry.body: ${entry.body?.body ?? []}")
    }
    println("Pem迭代器获取成功")
}

运行结果:

PemEntry: PEM CERTIFICATE01 (13 bytes)
PemEntry.headers: 
  HeaderKey01: HeaderValue01
  HeaderKey02: HeaderValue02
PemEntry.body: [72, 101, 108, 108, 111, 44, 32, 80, 69, 77, 48, 49, 33]
PemEntry: PEM CERTIFICATE02 (15 bytes)
PemEntry.headers: 
  HeaderKey03: HeaderValue03
  HeaderKey04: HeaderValue04
PemEntry.body: [72, 101, 108, 108, 111, 33, 33, 44, 32, 80, 69, 77, 48, 50, 33]
Pem迭代器获取成功

func toString()

public override func toString(): String

功能:返回一个字符串,字符串内容是包含每个条目序列的标签。

返回值:

  • String - 包含每个条目序列的标签的字符串。

示例:

import stdx.crypto.common.*

main(): Unit {
    // 创建一个 PemEntry 对象(DerBlob 仅演示二进制容器能力,数据无 ASN.1/DER 加密规范格式)
    let derBlob = DerBlob("Hello, PEM!".toArray())
    let pemEntry = PemEntry(PemEntry.LABEL_CERTIFICATE, [("HeaderKey", "HeaderValue")], derBlob)

    // 创建 Pem 对象
    let pem = Pem([pemEntry])

    // 转换为字符串
    let str = pem.toString()
    println("Pem对象字符串表示: ${str}")
}

运行结果:

Pem对象字符串表示: CERTIFICATE

struct PemEntry

public struct PemEntry <: ToString {
    public static let LABEL_CERTIFICATE = "CERTIFICATE"
    public static let LABEL_X509_CRL = "X509 CRL"
    public static let LABEL_CERTIFICATE_REQUEST = "CERTIFICATE REQUEST"
    public static let LABEL_PRIVATE_KEY = "PRIVATE KEY"
    public static let LABEL_EC_PRIVATE_KEY = "EC PRIVATE KEY"
    public static let LABEL_ENCRYPTED_PRIVATE_KEY = "ENCRYPTED PRIVATE KEY"
    public static let LABEL_RSA_PRIVATE_KEY = "RSA PRIVATE KEY"
    public static let LABEL_SM2_PRIVATE_KEY = "SM2 PRIVATE KEY"
    public static let LABEL_PUBLIC_KEY = "PUBLIC KEY"
    public static let LABEL_EC_PARAMETERS = "EC PARAMETERS"
    public static let LABEL_DH_PARAMETERS = "DH PARAMETERS"
    public PemEntry(
        public let label: String,
        public let headers: Array<(String, String)>,
        public let body: ?DerBlob
    )
    public init(label: String, body: DerBlob)
}

功能:PEM 文本格式经常用于存储证书和密钥,PEM 编码结构包含以下几个部分:

第一行是 “-----BEGIN”,标签和 “-----” 组成的 utf8 编码的字符串; 中间是正文,是实际二进制内容经过 base64 编码得到的可打印字符串,详细的 PEM 编码规范可参考 RFC 7468; 最后一行是 “-----END”,标签和 “-----” 组成的 utf8 编码的字符串,详见 RFC 1421。 在旧版的 PEM 编码标准中在第一行和正文之间还包含条目头。

为了支持不同的用户场景,我们提供了 PemEntryPem 类型,PemEntry 用于存储单个 PEM 基础结构。

父类型:

  • ToString

PemEntry(String, Array<(String, String)>, ?DerBlob)

public PemEntry(
    public let label: String,
    public let headers: Array<(String, String)>,
    public let body: ?DerBlob
)

功能:构造 PemEntry 对象。

参数:

  • label: String - 标签。
  • headers: Array<(String, String)> - 条目头。
  • body: ?DerBlob - 二进制内容。

示例:

import stdx.crypto.common.*

main(): Unit {
    // 创建一个 DerBlob 对象(DerBlob 仅演示二进制容器能力,数据无 ASN.1/DER 加密规范格式)
    let derBlob = DerBlob("Hello, PEM Entry!".toArray())

    // 创建一个 PemEntry 对象
    let pemEntry = PemEntry(PemEntry.LABEL_CERTIFICATE, [("HeaderKey", "HeaderValue")], derBlob)

    println("PemEntry对象创建成功")
}

运行结果:

PemEntry对象创建成功

static let LABEL_CERTIFICATE

public static let LABEL_CERTIFICATE: String = "CERTIFICATE"

功能:记录条目类型为证书。

类型:String

示例:

import stdx.crypto.common.*

main(): Unit {
    // 使用预定义的标签常量
    let label = PemEntry.LABEL_CERTIFICATE
    println("证书标签: ${label}")
}

运行结果:

证书标签: CERTIFICATE

static let LABEL_CERTIFICATE_REQUEST

public static let LABEL_CERTIFICATE_REQUEST: String = "CERTIFICATE REQUEST"

功能:记录条目类型为证书签名请求。

类型:String

示例:

import stdx.crypto.common.*

main(): Unit {
    // 使用预定义的标签常量
    let label = PemEntry.LABEL_CERTIFICATE_REQUEST
    println("证书请求标签: ${label}")
}

运行结果:

证书请求标签: CERTIFICATE REQUEST

static let LABEL_DH_PARAMETERS

public static let LABEL_DH_PARAMETERS: String = "DH PARAMETERS"

功能:记录条目类型为 DH 密钥参数。

类型:String

示例:

import stdx.crypto.common.*

main(): Unit {
    // 使用预定义的标签常量
    let label = PemEntry.LABEL_DH_PARAMETERS
    println("DH参数标签: ${label}")
}

运行结果:

DH参数标签: DH PARAMETERS

static let LABEL_EC_PARAMETERS

public static let LABEL_EC_PARAMETERS: String = "EC PARAMETERS"

功能:记录条目类型为椭圆曲线参数。

类型:String

示例:

import stdx.crypto.common.*

main(): Unit {
    // 使用预定义的标签常量
    let label = PemEntry.LABEL_EC_PARAMETERS
    println("椭圆曲线参数标签: ${label}")
}

运行结果:

椭圆曲线参数标签: EC PARAMETERS

static let LABEL_EC_PRIVATE_KEY

public static let LABEL_EC_PRIVATE_KEY: String = "EC PRIVATE KEY"

功能:记录条目类型为椭圆曲线私钥。

类型:String

示例:

import stdx.crypto.common.*

main(): Unit {
    // 使用预定义的标签常量
    let label = PemEntry.LABEL_EC_PRIVATE_KEY
    println("椭圆曲线私钥标签: ${label}")
}

运行结果:

椭圆曲线私钥标签: EC PRIVATE KEY

static let LABEL_ENCRYPTED_PRIVATE_KEY

public static let LABEL_ENCRYPTED_PRIVATE_KEY: String = "ENCRYPTED PRIVATE KEY"

功能:记录条目类型为 PKCS #8 标准加密的私钥。

类型:String

示例:

import stdx.crypto.common.*

main(): Unit {
    // 使用预定义的标签常量
    let label = PemEntry.LABEL_ENCRYPTED_PRIVATE_KEY
    println("加密私钥标签: ${label}")
}

运行结果:

加密私钥标签: ENCRYPTED PRIVATE KEY

static let LABEL_PRIVATE_KEY

public static let LABEL_PRIVATE_KEY: String = "PRIVATE KEY"

功能:记录条目类型为 PKCS #8 标准未加密的私钥。

类型:String

示例:

import stdx.crypto.common.*

main(): Unit {
    // 使用预定义的标签常量
    let label = PemEntry.LABEL_PRIVATE_KEY
    println("私钥标签: ${label}")
}

运行结果:

私钥标签: PRIVATE KEY

static let LABEL_PUBLIC_KEY

public static let LABEL_PUBLIC_KEY: String = "PUBLIC KEY"

功能:记录条目类型为公钥。

类型:String

示例:

import stdx.crypto.common.*

main(): Unit {
    // 使用预定义的标签常量
    let label = PemEntry.LABEL_PUBLIC_KEY
    println("公钥标签: ${label}")
}

运行结果:

公钥标签: PUBLIC KEY

static let LABEL_RSA_PRIVATE_KEY

public static let LABEL_RSA_PRIVATE_KEY: String = "RSA PRIVATE KEY"

功能:记录条目类型为 RSA 私钥。

类型:String

示例:

import stdx.crypto.common.*

main(): Unit {
    // 使用预定义的标签常量
    let label = PemEntry.LABEL_RSA_PRIVATE_KEY
    println("RSA私钥标签: ${label}")
}

运行结果:

RSA私钥标签: RSA PRIVATE KEY

static let LABEL_SM2_PRIVATE_KEY

public static let LABEL_SM2_PRIVATE_KEY: String = "SM2 PRIVATE KEY"

功能:记录条目类型为 SM2 私钥。

类型:String

示例:

import stdx.crypto.common.*

main(): Unit {
    // 使用预定义的标签常量
    let label = PemEntry.LABEL_SM2_PRIVATE_KEY
    println("SM2私钥标签: ${label}")
}

运行结果:

SM2私钥标签: SM2 PRIVATE KEY

static let LABEL_X509_CRL

public static let LABEL_X509_CRL: String = "X509 CRL"

功能:记录条目类型为证书吊销列表。

类型:String

示例:

import stdx.crypto.common.*

main(): Unit {
    // 使用预定义的标签常量
    let label = PemEntry.LABEL_X509_CRL
    println("证书吊销列表标签: ${label}")
}

运行结果:

证书吊销列表标签: X509 CRL

let body

public let body: ?DerBlob

功能:PemEntry 实例的二进制内容。

类型:?DerBlob

示例:

import stdx.crypto.common.*

main(): Unit {
    // 创建一个 DerBlob 对象(DerBlob 仅演示二进制容器能力,数据无 ASN.1/DER 加密规范格式)
    let derBlob = DerBlob("Hello, PEM Entry!".toArray())

    // 创建一个 PemEntry 对象
    let pemEntry = PemEntry(PemEntry.LABEL_CERTIFICATE, derBlob)

    // 访问 body 属性
    match (pemEntry.body) {
        case Some(blob) => println("PemEntry包含二进制内容,大小: ${blob.size}")
        case None => println("PemEntry不包含二进制内容")
    }
}

运行结果:

PemEntry包含二进制内容,大小: 17

let headers

public let headers: Array<(String, String)>

功能:PemEntry 实例的条目头。

类型:Array<(String, String)>

示例:

import stdx.crypto.common.*

main(): Unit {
    // 创建一个 DerBlob 对象(DerBlob 仅演示二进制容器能力,数据无 ASN.1/DER 加密规范格式)
    let derBlob = DerBlob("Hello, PEM Entry!".toArray())

    // 创建一个 PemEntry 对象,包含头部信息
    let pemEntry = PemEntry(PemEntry.LABEL_CERTIFICATE, [("HeaderKey", "HeaderValue"), ("AnotherKey", "AnotherValue")],
        derBlob)

    // 访问 headers 属性
    println("PemEntry头部数量: ${pemEntry.headers.size}")

    // 遍历头部
    for (header in pemEntry.headers) {
        println("头部: ${header[0]} = ${header[1]}")
    }
}

运行结果:

PemEntry头部数量: 2
头部: HeaderKey = HeaderValue
头部: AnotherKey = AnotherValue

let label

public let label: String

功能:PemEntry 实例的标签。

类型:String

示例:

import stdx.crypto.common.*

main(): Unit {
    // 创建一个 DerBlob 对象(DerBlob 仅演示二进制容器能力,数据无 ASN.1/DER 加密规范格式)
    let derBlob = DerBlob("Hello, PEM Entry!".toArray())

    // 创建一个 PemEntry 对象
    let pemEntry = PemEntry(PemEntry.LABEL_CERTIFICATE, derBlob)

    // 访问 label 属性
    println("PemEntry标签: ${pemEntry.label}")
}

运行结果:

PemEntry标签: CERTIFICATE

init(String, DerBlob)

public init(label: String, body: DerBlob)

功能:构造 PemEntry 对象。

参数:

  • label: String - 标签
  • body: DerBlob - 二进制内容

示例:

import stdx.crypto.common.*

main(): Unit {
    // 创建一个 DerBlob 对象(DerBlob 仅演示二进制容器能力,数据无 ASN.1/DER 加密规范格式)
    let derBlob = DerBlob("Hello, PEM Entry!".toArray())

    // 创建一个 PemEntry 对象(使用简化构造函数)
    let pemEntry = PemEntry(PemEntry.LABEL_CERTIFICATE, derBlob)

    println("PemEntry对象创建成功")
}

运行结果:

PemEntry对象创建成功

func encode()

public func encode(): String

功能:返回 PEM 格式的字符串。行结束符将根据当前操作系统生成。

返回值:

  • String - PEM 格式的字符串。

示例:

import stdx.crypto.common.*

main(): Unit {
    // 创建一个 DerBlob 对象(DerBlob 仅演示二进制容器能力,数据无 ASN.1/DER 加密规范格式)
    let derBlob = DerBlob("Hello, PEM Entry!".toArray())

    // 创建一个 PemEntry 对象
    let pemEntry = PemEntry(PemEntry.LABEL_CERTIFICATE, derBlob)

    // 编码为 PEM 格式
    let encoded = pemEntry.encode()
    println("编码后字符串长度: ${encoded.size}")
    print("编码后字符串: \n${encoded}")
}

运行结果:

编码后字符串长度: 79
编码后字符串: 
-----BEGIN CERTIFICATE-----
SGVsbG8sIFBFTSBFbnRyeSE=
-----END CERTIFICATE-----

func header(String)

public func header(name: String): Iterator<String>

功能:通过条目头名称,找到对应条目内容。

参数:

  • name: String - 条目头名称。

返回值:

  • Iterator<String> - 条目头名称对应内容的迭代器。

示例:

import stdx.crypto.common.*

main(): Unit {
    // 创建一个 DerBlob 对象(DerBlob 仅演示二进制容器能力,数据无 ASN.1/DER 加密规范格式)
    let derBlob = DerBlob("Hello, PEM Entry!".toArray())

    // 创建一个 PemEntry 对象,包含头部信息
    let pemEntry = PemEntry(PemEntry.LABEL_CERTIFICATE, [("HeaderKey", "HeaderValue"), ("HeaderKey", "AnotherValue")],
        derBlob)

    // 获取特定头部
    let headerValueIter = pemEntry.header("HeaderKey")
    println("头部键迭代器获取成功")
    for (HeaderValue in headerValueIter) {
        println("头部键: ${HeaderValue}")
    }
}

运行结果:

头部键迭代器获取成功
头部键: HeaderValue
头部键: AnotherValue

func toString()

public override func toString(): String

功能:返回 PEM 对象的标签和二进制内容的长度。

返回值:

  • String - PEM 对象的标签和二进制内容的长度。

示例:

import stdx.crypto.common.*

main(): Unit {
    // 创建一个 DerBlob 对象(DerBlob 仅演示二进制容器能力,数据无 ASN.1/DER 加密规范格式)
    let derBlob = DerBlob("Hello, PEM Entry!".toArray())

    // 创建一个 PemEntry 对象
    let pemEntry = PemEntry(PemEntry.LABEL_CERTIFICATE, derBlob)

    // 转换为字符串
    let str = pemEntry.toString()
    println("PemEntry字符串表示: ${str}")
}

运行结果:

PemEntry字符串表示: PEM CERTIFICATE (17 bytes)

异常类

class CryptoException

public class CryptoException <: Exception {
    public init()
    public init(message: String)
}

功能:此类为加解密出现错误时抛出的异常。

父类型:

  • Exception

init()

public init()

功能:无参构造函数,构造 CryptoException 异常。

示例:

import stdx.crypto.common.*

main(): Unit {
    try {
        // 抛出一个无参的CryptoException异常
        throw CryptoException()
    } catch (e: CryptoException) {
        println("捕获到加解密异常")
    }
}

运行结果:

捕获到加解密异常

init(String)

public init(message: String)

功能:根据异常信息构造 CryptoException 异常类对象。

参数:

  • message: String - 异常信息。

示例:

import stdx.crypto.common.*

main(): Unit {
    try {
        // 抛出一个带消息的CryptoException异常
        throw CryptoException("这是一个加密异常")
    } catch (e: CryptoException) {
        println("捕获到加密异常: ${e.message}")
    }
}

运行结果:

捕获到加密异常: 这是一个加密异常

stdx.crypto.crypto

功能介绍

crypto 包提供安全随机数功能和提供国密 SM4 对称加解密。

使用本包需要外部依赖 OpenSSL 3 的 crypto 动态库文件,故使用前需安装相关工具。

  • 对于 Linux 操作系统,可参考以下方式:

    • 如果系统的包管理工具支持安装 OpenSSL 3 开发工具包,可通过这个方式安装,并确保系统安装目录下含有 libcrypto.so 和 libcrypto.so.3 这两个动态库文件,例如 Ubuntu 22.04 系统上可使用 sudo apt install libssl-dev 命令安装 libssl-dev 工具包;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libcrypto.so 和 libcrypto.so.3 这两个动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 LD_LIBRARY_PATH 以及 LIBRARY_PATH 中。
  • 对于 Windows 操作系统,可按照以下步骤:

    • 自行下载 OpenSSL 3.x.x 源码编译安装 x64 架构软件包或者自行下载安装第三方预编译的供开发人员使用的 OpenSSL 3.x.x 软件包;
    • 确保安装目录下含有 libcrypto.dll.a(或 libcrypto.lib)、libcrypto-3-x64.dll 这两个库文件;
    • 将 libcrypto.dll.a(或 libcrypto.lib)所在的目录路径设置到环境变量 LIBRARY_PATH 中,将 libcrypto-3-x64.dll 所在的目录路径设置到环境变量 PATH 中。
  • 对于 macOS 操作系统,可参考以下方式:

    • 使用 brew install openssl@3 安装,并确保系统安装目录下含有 libcrypto.dylib 和 libcrypto.3.dylib 这两个动态库文件;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libcrypto.dylib 和 libcrypto.3.dylib 这两个动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 DYLD_LIBRARY_PATH 以及 LIBRARY_PATH 中。
  • 对于 Android 操作系统,可参考以下方式:

    • 由于 Android 系统默认自带的 OpenSSL 是裁剪版本,部分接口可能找不到符号而抛出异常,因此需要用户自行编译安装完整的 OpenSSL 3.x.x 版本;
    • 可自行下载 OpenSSL 3.x.x 源码,使用 Android NDK 交叉编译生成对应架构(当前只支持 arm64-v8a)的动态库文件,确保编译产物中含有 libcrypto.so 和 libcrypto.so.3 这些动态库文件;
    • 将这些文件所在目录设置到环境变量 LD_LIBRARY_PATH 中。

说明:

如果未安装 OpenSSL 3 软件包或者安装低版本的软件包,程序可能无法使用并抛出相关异常 SecureRandomException:Can not load openssl library or function xxx。

API 列表

类名功能
SecureRandom安全随机数。
SM4提供国密 SM4 对称加解密。

结构体

结构体名功能
OperationMode对称加解密算法的工作模式。
PaddingMode对称加解密算法的填充模式。

异常类

异常类名功能
SecureRandomException安全随机数异常类。

class SecureRandom

public class SecureRandom <: RandomGenerator {
    public init(priv!: Bool = false)
}

父类型:

功能:用于生成加密安全的伪随机数。

和 Random 相比,主要有三个方面不同:

  • 随机数种子: Random 使用系统时钟作为默认的种子,时间戳一样,结果就相同;SecureRandom 使用操作系统或者硬件提供的随机数种子,生成的是真随机数。
  • 随机数生成: Random 使用了梅森旋转伪随机生成器;SecureRandom 则使用了 openssl 库提供的 MD5 等随机算法,使用熵源生成真随机数;如果硬件支持,还可以使用硬件随机数生成器来生成安全性更强的随机数。
  • 安全性: Random 不能用于加密安全的应用或者隐私数据的保护,可以使用 SecureRandom

使用示例见 SecureRandom 使用

init(Bool)

public init(priv!: Bool = false)

功能:创建 SecureRandom 实例,可指定是否使用更加安全的加密安全伪随机生成器,加密安全伪随机生成器可用于会话密钥和证书私钥等加密场景。

参数:

  • priv!: Bool - 设置为 true 表示使用加密安全伪随机生成器。

示例:

import stdx.crypto.crypto.*

main() {
    // 创建一个默认的SecureRandom实例
    let random1 = SecureRandom()
    println("创建默认SecureRandom实例成功")

    // 创建一个使用更加安全的SecureRandom实例
    let random2 = SecureRandom(priv: true)
    println("创建使用更加安全的SecureRandom实例成功")

    return 0
}

可能的运行结果:

创建默认SecureRandom实例成功
创建使用更加安全的SecureRandom实例成功

func nextBits(UInt64)

public func nextBits(bits: UInt64): UInt64

功能:生成一个指定位长的随机整数。

参数:

  • bits: UInt64 - 要生成的随机数的位数,取值范围 (0, 64]。

返回值:

  • UInt64 - 生成的用户指定位长的随机数。

异常:

  • IllegalArgumentException - 如果 bits 等于 0,或大于 64,超过所能截取的 UInt64 长度,则抛出异常。
  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成几个指定位数的随机数
    let num1 = random.nextBits(8) // 生成8位的随机数
    println("生成的8位随机数: ${num1}")

    let num2 = random.nextBits(16) // 生成16位的随机数
    println("生成的16位随机数: ${num2}")

    let num3 = random.nextBits(32) // 生成32位的随机数
    println("生成的32位随机数: ${num3}")

    return 0
}

可能的运行结果:

生成的8位随机数: 17
生成的16位随机数: 45263
生成的32位随机数: 2128153426

func nextBool()

public func nextBool(): Bool

功能:获取一个随机的 Bool 类型实例。

返回值:

  • Bool - 一个随机的 Bool 类型实例。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成几个布尔类型的随机数
    let bool1 = random.nextBool()
    println("生成的布尔随机数1: ${bool1}")

    let bool2 = random.nextBool()
    println("生成的布尔随机数2: ${bool2}")
    return 0
}

可能的运行结果:

生成的布尔随机数1: false
生成的布尔随机数2: false

func nextBytes(Array<Byte>)

public func nextBytes(bytes: Array<Byte>): Unit

功能:生成随机数替换入参数组中的每个元素。

参数:

  • bytes: Array<Byte> - 被替换的数组。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 创建一个字节数组并用随机数填充
    let bytes = Array<Byte>(10, repeat: 0) // 创建包含10个字节的数组,初始值为0
    println("填充前的数组: ${bytes}")

    random.nextBytes(bytes) // 用随机数填充数组
    println("填充后的数组: ${bytes}")

    return 0
}

可能的运行结果:

填充前的数组: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
填充后的数组: [120, 13, 17, 140, 252, 106, 71, 121, 211, 28]

func nextBytes(Int32)

public func nextBytes(length: Int32): Array<Byte>

功能:获取一个指定长度的随机字节的数组。

参数:

  • length: Int32 - 要生成的随机字节数组的长度。

返回值:

  • Array<Byte> - 一个随机字节数组。

异常:

  • IllegalArgumentException - 当参数 length 小于等于 0,抛出异常。
  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成一个包含5个随机字节的数组
    let bytes1 = random.nextBytes(5)
    println("成功生成5个随机字节的数组: ${bytes1}")

    // 生成一个包含10个随机字节的数组
    let bytes2 = random.nextBytes(10)
    println("成功生成10个随机字节的数组: ${bytes2}")

    return 0
}

可能的运行结果:

成功生成5个随机字节的数组: [89, 31, 206, 132, 25]
成功生成10个随机字节的数组: [232, 228, 56, 119, 208, 142, 53, 221, 166, 96]

func nextFloat16()

public func nextFloat16(): Float16

功能:获取一个 Float16 类型且在区间 [0.0, 1.0) 内的随机数。

返回值:

  • Float16 - 一个 Float16 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成几个Float16类型的随机数
    let num1 = random.nextFloat16()
    println("生成的Float16随机数1: ${num1}")

    let num2 = random.nextFloat16()
    println("生成的Float16随机数2: ${num2}")
    return 0
}

可能的运行结果:

生成的Float16随机数1: 0.237305
生成的Float16随机数2: 0.362305

func nextFloat32()

public func nextFloat32(): Float32

功能:获取一个 Float32 类型且在区间 [0.0, 1.0) 内的随机数。

返回值:

  • Float32 - 一个 Float32 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成几个Float32类型的随机数
    let num1 = random.nextFloat32()
    println("生成的Float32随机数1: ${num1}")

    let num2 = random.nextFloat32()
    println("生成的Float32随机数2: ${num2}")
    return 0
}

可能的运行结果:

生成的Float32随机数1: 0.830997
生成的Float32随机数2: 0.599951

func nextFloat64()

public func nextFloat64(): Float64

功能:获取一个 Float64 类型且在区间 [0.0, 1.0) 内的随机数。

返回值:

  • Float64 - 一个 Float64 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成几个Float64类型的随机数
    let num1 = random.nextFloat64()
    println("生成的Float64随机数1: ${num1}")

    let num2 = random.nextFloat64()
    println("生成的Float64随机数2: ${num2}")
    return 0
}

可能的运行结果:

生成的Float64随机数1: 0.665093
生成的Float64随机数2: 0.026271

func nextGaussianFloat16(Float16, Float16)

public func nextGaussianFloat16(mean!: Float16 = 0.0, sigma!: Float16 = 1.0): Float16

功能:默认获取一个 Float16 类型且符合均值为 0.0 标准差为 1.0 的高斯分布的随机数,其中均值是期望值,可解释为位置参数,决定了分布的位置,标准差可解释为尺度参数,决定了分布的幅度。

参数:

  • mean!: Float16 - 均值。
  • sigma!: Float16 - 标准差。

返回值:

  • Float16 - 一个 Float16 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成几个高斯分布的Float16类型的随机数,均值为0.5,标准差为0.1
    let num1 = random.nextGaussianFloat16(mean: 0.5, sigma: 0.1)
    println("生成的高斯Float16随机数1: ${num1}")

    let num2 = random.nextGaussianFloat16(mean: 0.5, sigma: 0.1)
    println("生成的高斯Float16随机数2: ${num2}")
    return 0
}

可能的运行结果:

生成的高斯Float16随机数1: 0.597168
生成的高斯Float16随机数2: 0.659668

func nextGaussianFloat32(Float32, Float32)

public func nextGaussianFloat32(mean!: Float32 = 0.0, sigma!: Float32 = 1.0): Float32

功能:默认获取一个 Float32 类型且符合均值为 0.0 标准差为 1.0 的高斯分布的随机数,其中均值是期望值,可解释为位置参数,决定了分布的位置,标准差可解释为尺度参数,决定了分布的幅度。

参数:

  • mean!: Float32 - 均值。
  • sigma!: Float32 - 标准差。

返回值:

  • Float32 - 一个 Float32 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成几个高斯分布的Float32类型的随机数,均值为0.5,标准差为0.1
    let num1 = random.nextGaussianFloat32(mean: 0.5, sigma: 0.1)
    println("生成的高斯Float32随机数1: ${num1}")

    let num2 = random.nextGaussianFloat32(mean: 0.5, sigma: 0.1)
    println("生成的高斯Float32随机数2: ${num2}")
    return 0
}

可能的运行结果:

生成的高斯Float32随机数1: 0.512646
生成的高斯Float32随机数2: 0.457472

func nextGaussianFloat64(Float64, Float64)

public func nextGaussianFloat64(mean!: Float64 = 0.0, sigma!: Float64 = 1.0): Float64

功能:默认获取一个 Float64 类型且符合均值为 0.0 标准差为 1.0 的高斯分布的随机数,其中均值是期望值,可解释为位置参数,决定了分布的位置,标准差可解释为尺度参数,决定了分布的幅度。

参数:

  • mean!: Float64 - 均值。
  • sigma!: Float64 - 标准差。

返回值:

  • Float64 - 一个 Float64 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成几个高斯分布的Float64类型的随机数,均值为0.5,标准差为0.1
    let num1 = random.nextGaussianFloat64(mean: 0.5, sigma: 0.1)
    println("生成的高斯Float64随机数1: ${num1}")

    let num2 = random.nextGaussianFloat64(mean: 0.5, sigma: 0.1)
    println("生成的高斯Float64随机数2: ${num2}")
    return 0
}

可能的运行结果:

生成的高斯Float64随机数1: 0.411050
生成的高斯Float64随机数2: 0.531717

func nextInt16()

public func nextInt16(): Int16

功能:获取一个 Int16 类型的随机数。

返回值:

  • Int16 - 一个 Int16 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成几个Int16类型的随机数
    let num1 = random.nextInt16()
    println("生成的Int16随机数1: ${num1}")

    let num2 = random.nextInt16()
    println("生成的Int16随机数2: ${num2}")
    return 0
}

可能的运行结果:

生成的Int16随机数1: -30796
生成的Int16随机数2: -23424

func nextInt16(Int16)

public func nextInt16(max: Int16): Int16

功能:获取一个 Int16 类型且在区间 [0, max) 内的随机数。

参数:

  • max: Int16 - 区间最大值。

返回值:

  • Int16 - 一个 Int16 类型的随机数。

异常:

  • IllegalArgumentException - 当 max 为非正数时,抛出异常。
  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成几个在指定范围内的Int16类型的随机数
    let num1 = random.nextInt16(100)
    println("生成的Int16随机数1 (0-100): ${num1}")

    let num2 = random.nextInt16(100)
    println("生成的Int16随机数2 (0-100): ${num2}")
    return 0
}

可能的运行结果:

生成的Int16随机数1 (0-100): 27
生成的Int16随机数2 (0-100): 23

func nextInt32()

public func nextInt32(): Int32

功能:获取一个 Int32 类型的随机数。

返回值:

  • Int32 - 一个 Int32 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成几个Int32类型的随机数
    let num1 = random.nextInt32()
    println("生成的Int32随机数1: ${num1}")

    let num2 = random.nextInt32()
    println("生成的Int32随机数2: ${num2}")
    return 0
}

可能的运行结果:

生成的Int32随机数1: -33263071
生成的Int32随机数2: -853238350

func nextInt32(Int32)

public func nextInt32(max: Int32): Int32

功能:获取一个 Int32 类型且在区间 [0, max) 内的随机数。

参数:

  • max: Int32 - 区间最大值。

返回值:

  • Int32 - 一个 Int32 类型的随机数。

异常:

  • IllegalArgumentException - 当 max 为非正数时,抛出异常。
  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成几个在指定范围内的Int32类型的随机数
    let num1 = random.nextInt32(1000)
    println("生成的Int32随机数1 (0-1000): ${num1}")

    let num2 = random.nextInt32(1000)
    println("生成的Int32随机数2 (0-1000): ${num2}")
    return 0
}

可能的运行结果:

生成的Int32随机数1 (0-1000): 469
生成的Int32随机数2 (0-1000): 47

func nextInt64()

public func nextInt64(): Int64

功能:获取一个 Int64 类型的随机数。

返回值:

  • Int64 - 一个 Int64 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成几个Int64类型的随机数
    let num1 = random.nextInt64()
    println("生成的Int64随机数1: ${num1}")

    let num2 = random.nextInt64()
    println("生成的Int64随机数2: ${num2}")
    return 0
}

可能的运行结果:

生成的Int64随机数1: -3331154220163065762
生成的Int64随机数2: 6412631069792762051

func nextInt64(Int64)

public func nextInt64(max: Int64): Int64

功能:获取一个 Int64 类型且在区间 [0, max) 内的随机数。

参数:

  • max: Int64 - 区间最大值。

返回值:

  • Int64 - 一个 Int64 类型的随机数。

异常:

  • IllegalArgumentException - 当 max 为非正数时,抛出异常。
  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成几个在指定范围内的Int64类型的随机数
    let num1 = random.nextInt64(1000000)
    println("生成的Int64随机数1 (0-1000000): ${num1}")

    let num2 = random.nextInt64(1000000)
    println("生成的Int64随机数2 (0-1000000): ${num2}")
    return 0
}

可能的运行结果:

生成的Int64随机数1 (0-1000000): 874128
生成的Int64随机数2 (0-1000000): 129569

func nextInt8()

public func nextInt8(): Int8

功能:获取一个 Int8 类型的随机数。

返回值:

  • Int8 - 一个 Int8 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成几个Int8类型的随机数
    let num1 = random.nextInt8()
    println("生成的Int8随机数1: ${num1}")

    let num2 = random.nextInt8()
    println("生成的Int8随机数2: ${num2}")
    return 0
}

可能的运行结果:

生成的Int8随机数1: -21
生成的Int8随机数2: 70

func nextInt8(Int8)

public func nextInt8(max: Int8): Int8

功能:获取一个 Int8 类型且在区间 [0, max) 内的随机数。

参数:

  • max: Int8 - 区间最大值。

返回值:

  • Int8 - 一个 Int8 类型的随机数。

异常:

  • IllegalArgumentException - 当 max 为非正数时,抛出异常。
  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成几个在指定范围内的Int8类型的随机数
    let num1 = random.nextInt8(100)
    println("生成的Int8随机数1 (0-100): ${num1}")

    let num2 = random.nextInt8(100)
    println("生成的Int8随机数2 (0-100): ${num2}")
    return 0
}

可能的运行结果:

生成的Int8随机数1 (0-100): 72
生成的Int8随机数2 (0-100): 35

func nextUInt16()

public func nextUInt16(): UInt16

功能:获取一个 UInt16 类型的随机数。

返回值:

  • UInt16 - 一个 UInt16 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成几个UInt16类型的随机数
    let num1 = random.nextUInt16()
    println("生成的UInt16随机数1: ${num1}")

    let num2 = random.nextUInt16()
    println("生成的UInt16随机数2: ${num2}")
    return 0
}

可能的运行结果:

生成的UInt16随机数1: 23354
生成的UInt16随机数2: 46516

func nextUInt16(UInt16)

public func nextUInt16(max: UInt16): UInt16

功能:获取一个 UInt16 类型且在区间 [0, max) 内的随机数。

参数:

  • max: UInt16 - 区间最大值。

返回值:

  • UInt16 - 一个 UInt16 类型的随机数。

异常:

  • IllegalArgumentException - 当 max 为 0 时,抛出异常。
  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成几个UInt16范围内的随机数
    let num1 = random.nextUInt16(1000) // 生成0-999之间的随机数
    println("生成的UInt16随机数(0-999): ${num1}")

    let num2 = random.nextUInt16(5000) // 生成0-4999之间的随机数
    println("生成的UInt16随机数(0-4999): ${num2}")
    return 0
}

可能的运行结果:

生成的UInt16随机数(0-999): 674
生成的UInt16随机数(0-4999): 3879

func nextUInt32()

public func nextUInt32(): UInt32

功能:获取一个 UInt32 类型的随机数。

返回值:

  • UInt32 - 一个 UInt32 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成几个UInt32类型的随机数
    let num1 = random.nextUInt32()
    println("生成的UInt32随机数1: ${num1}")

    let num2 = random.nextUInt32()
    println("生成的UInt32随机数2: ${num2}")
    return 0
}

可能的运行结果:

生成的UInt32随机数1: 2512231137
生成的UInt32随机数2: 1654221431

func nextUInt32(UInt32)

public func nextUInt32(max: UInt32): UInt32

功能:获取一个 UInt32 类型且在区间 [0, max) 内的随机数。

参数:

  • max: UInt32 - 区间最大值。

返回值:

  • UInt32 - 一个 UInt32 类型的随机数。

异常:

  • IllegalArgumentException - 当 max 为 0 时,抛出异常。
  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成几个UInt32范围内的随机数
    let num1 = random.nextUInt32(100000) // 生成0-99999之间的随机数
    println("生成的UInt32随机数(0-99999): ${num1}")

    let num2 = random.nextUInt32(1000000) // 生成0-999999之间的随机数
    println("生成的UInt32随机数(0-999999): ${num2}")
    return 0
}

可能的运行结果:

生成的UInt32随机数(0-99999): 99820
生成的UInt32随机数(0-999999): 661325

func nextUInt64()

public func nextUInt64(): UInt64

功能:获取一个 UInt64 类型的随机数。

返回值:

  • UInt64 - 一个 UInt64 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成几个UInt64类型的随机数
    let num1 = random.nextUInt64()
    println("生成的UInt64随机数1: ${num1}")

    let num2 = random.nextUInt64()
    println("生成的UInt64随机数2: ${num2}")
    return 0
}

可能的运行结果:

生成的UInt64随机数1: 11677076453013864441
生成的UInt64随机数2: 4153549476048086930

func nextUInt64(UInt64)

public func nextUInt64(max: UInt64): UInt64

功能:获取一个 UInt64 类型且在区间 [0, max) 内的随机数。

参数:

  • max: UInt64 - 区间最大值。

返回值:

  • UInt64 - 一个 UInt64 类型的随机数。

异常:

  • IllegalArgumentException - 当 max 为 0 时,抛出异常。
  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成几个UInt64范围内的随机数
    let num1 = random.nextUInt64(1000000000000) // 生成0-999999999999之间的随机数
    println("生成的UInt64随机数(0-999999999999): ${num1}")

    let num2 = random.nextUInt64(100000000000000) // 生成0-99999999999999之间的随机数
    println("生成的UInt64随机数(0-99999999999999): ${num2}")
    return 0
}

可能的运行结果:

生成的UInt64随机数(0-999999999999): 606328247182
生成的UInt64随机数(0-99999999999999): 24041701587638

func nextUInt8()

public func nextUInt8(): UInt8

功能:获取一个 UInt8 类型的随机数。

返回值:

  • UInt8 - 一个 UInt8 类型的随机数。

异常:

  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成几个UInt8类型的随机数
    let num1 = random.nextUInt8()
    println("生成的UInt8随机数1: ${num1}")

    let num2 = random.nextUInt8()
    println("生成的UInt8随机数2: ${num2}")
    return 0
}

可能的运行结果:

生成的UInt8随机数1: 21
生成的UInt8随机数2: 160

func nextUInt8(UInt8)

public func nextUInt8(max: UInt8): UInt8

功能:获取一个 UInt8 类型且在区间 [0, max) 内的随机数。

参数:

  • max: UInt8 - 区间最大值。

返回值:

  • UInt8 - 一个 UInt8 类型的随机数。

异常:

  • IllegalArgumentException - 当 max 为 0 时,抛出异常。
  • SecureRandomException - 当生成器不能正确生成随机数或生成随机数失败时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom()

    // 生成几个UInt8范围内的随机数
    let num1 = random.nextUInt8(100) // 生成0-99之间的随机数
    println("生成的UInt8随机数(0-99): ${num1}")

    let num2 = random.nextUInt8(50) // 生成0-49之间的随机数
    println("生成的UInt8随机数(0-49): ${num2}")
    return 0
}

可能的运行结果:

生成的UInt8随机数(0-99): 60
生成的UInt8随机数(0-49): 30

class SM4

public class SM4 <: BlockCipher {
    public init(
        optMode: OperationMode,
        key: Array<Byte>,
        iv!: Array<Byte> = Array<Byte>(),
        paddingMode!: PaddingMode = PaddingMode.PKCS7Padding,
        aad!: Array<Byte> = Array<Byte>(),
        tagSize!: Int64 = 16
    )
}

功能:提供国密 SM4 对称加解密。

目前 SM4 支持的加解密工作模式由 OperationMode 定义,目前支持 ECB、CBC、OFB、CFB、CTR、GCM 模式。

不同的工作模式可能对应的加解密实现不同,安全性也不同。需要选择和场景适配的加解密工作模式。

iv 初始化向量在 GCM 模式下可以设置推荐长度是 12 字节,在 CBC、OFB、CFB、CTR 模式下 iv 长度是 16 字节,在 ECB 模式下 iv 可以不设置。

paddingMode 填充模式模式由 PaddingMode 定义, 目前支持 NoPadding 非填充、PKCS7Padding PKCS7 填充。默认是 PKCS7 填充。

paddingMode 设置对 ECB 和 CBC 有效,ECB 和 CBC 分组加解密需要分组长度等于 blockSize。会根据填充模式进行填充。 paddingMode 设置对 OFB、CFB、CTR、GCM 工作模式无效,这些工作模式均无需填充。

如果选择 NoPadding 模式,即不填充。则在 ECB 和 CBC 工作模式下用户需要对数据是否可以分组负责,如果数据不能分组,或者最后一组数据长度不足 blockSize 则会报错。

aad 附加数据,仅在 GCM 模式下使用,由用户填充,参与摘要计算,默认为空。

tagSize 设置摘要长度,仅在 GCM 模式下使用,默认值为 SM4_GCM_TAG_SIZE 16 字节,最小不能低于 12 字节,最大不能超过 16 字节。

如果是 GCM 工作模式。加密结果的后 tagSize 字节是摘要数据。

使用示例见 SM4 使用

注意:

GCM 模式需要 OpenSSL 3.2 或者以上版本。

父类型:

  • BlockCipher

prop aad

public prop aad: Array<Byte>

功能:附加数据。

类型:Array<Byte>

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom(priv: true)

    let key = random.nextBytes(16) // 16字节密钥,生产环节从KMS密钥管理系统获取
    let iv = random.nextBytes(12) // GCM推荐12字节IV
    let aad = "additional authenticated data".toArray() // 附加认证数据

    // 创建SM4实例(仅GCM模式下aad参数生效,需要 OpenSSL 3.2 或者以上版本)
    let sm4 = SM4(OperationMode.GCM, key, iv: iv, aad: aad)

    // 获取附加数据
    let retrievedAad = sm4.aad
    println("附加数据长度: ${retrievedAad.size}")

    return 0
}

运行结果:

附加数据长度: 29

prop algorithm

public prop algorithm: String

功能:获取分组加解密算法的算法名称。

类型:String

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom(priv: true)

    let key = random.nextBytes(16) // 16字节密钥,生产环节从KMS密钥管理系统获取
    let iv = random.nextBytes(16) // 16字节IV

    // 创建SM4实例
    let sm4 = SM4(OperationMode.CBC, key, iv: iv)

    // 获取算法名称
    let algorithm = sm4.algorithm
    println("SM4算法名称: ${algorithm}")

    return 0
}

运行结果:

SM4算法名称: SM4

prop blockSize

public prop blockSize: Int64

功能:分组长度,单位字节。

类型:Int64

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom(priv: true)

    let key = random.nextBytes(16) // 16字节密钥,生产环节从KMS密钥管理系统获取
    let iv = random.nextBytes(16) // 16字节IV

    // 创建SM4实例
    let sm4 = SM4(OperationMode.CBC, key, iv: iv)

    // 获取分组长度
    let blockSize = sm4.blockSize
    println("SM4分组长度: ${blockSize}")

    return 0
}

运行结果:

SM4分组长度: 16

prop iv

public prop iv: Array<Byte>

功能:初始化向量。

类型:Array<Byte>

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom(priv: true)

    let key = random.nextBytes(16) // 16字节密钥,生产环节从KMS密钥管理系统获取
    let iv = random.nextBytes(16) // 16字节IV

    // 创建SM4实例
    let sm4 = SM4(OperationMode.CBC, key, iv: iv)

    // 获取初始化向量
    let ivValue = sm4.iv
    println("初始化向量长度: ${ivValue.size}")

    return 0
}

运行结果:

初始化向量长度: 16

prop ivSize

public prop ivSize: Int64

功能:初始化向量长度。

类型:Int64

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom(priv: true)

    let key = random.nextBytes(16) // 16字节密钥,生产环节从KMS密钥管理系统获取
    let iv = random.nextBytes(16) // 16字节IV

    // 创建SM4实例
    let sm4 = SM4(OperationMode.CBC, key, iv: iv)

    // 获取初始化向量长度
    let ivSize = sm4.ivSize
    println("初始化向量长度: ${ivSize}")

    return 0
}

运行结果:

初始化向量长度: 16

prop key

public prop key: Array<Byte>

功能:密钥。

类型:Array<Byte>

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom(priv: true)

    let key = random.nextBytes(16) // 16字节密钥,生产环节从KMS密钥管理系统获取
    let iv = random.nextBytes(16) // 16字节IV

    // 创建SM4实例
    let sm4 = SM4(OperationMode.CBC, key, iv: iv)

    // 获取密钥
    let keyValue = sm4.key
    println("密钥长度: ${keyValue.size}")

    return 0
}

运行结果:

密钥长度: 16

prop keySize

public prop keySize: Int64

功能:密钥长度。

类型:Int64

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom(priv: true)

    let key = random.nextBytes(16) // 16字节密钥,生产环节从KMS密钥管理系统获取
    let iv = random.nextBytes(16) // 16字节IV

    // 创建SM4实例
    let sm4 = SM4(OperationMode.CBC, key, iv: iv)

    // 获取密钥长度
    let keySize = sm4.keySize
    println("密钥长度: ${keySize}")

    return 0
}

运行结果:

密钥长度: 16

prop optMode

public prop optMode: OperationMode

功能:工作模式。

类型:OperationMode

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom(priv: true)

    let key = random.nextBytes(16) // 16字节密钥,生产环节从KMS密钥管理系统获取
    let iv = random.nextBytes(16) // 16字节IV

    // 创建SM4实例
    let sm4 = SM4(OperationMode.CBC, key, iv: iv)

    // 获取工作模式
    let optMode = sm4.optMode
    println("工作模式: ${optMode}")

    return 0
}

运行结果:

工作模式: CBC

prop paddingMode

public prop paddingMode: PaddingMode

功能:填充模式。

类型:PaddingMode

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom(priv: true)

    let key = random.nextBytes(16) // 16字节密钥,生产环节从KMS密钥管理系统获取
    let iv = random.nextBytes(16) // 16字节IV

    // 创建SM4实例
    let sm4 = SM4(OperationMode.CBC, key, iv: iv, paddingMode: PaddingMode.PKCS7Padding)

    // 获取填充模式
    let paddingMode = sm4.paddingMode
    return 0
}

prop tagSize

public prop tagSize: Int64

功能:摘要长度。

类型:Int64

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom(priv: true)

    let key = random.nextBytes(16) // 16字节密钥,生产环节从KMS密钥管理系统获取
    let iv = random.nextBytes(16) // 16字节IV

    // 创建SM4实例(GCM模式,需要 OpenSSL 3.2 或者以上版本)
    let sm4 = SM4(OperationMode.GCM, key, iv: iv, tagSize: 16)

    // 获取摘要长度
    let tagSize = sm4.tagSize
    println("摘要长度: ${tagSize}")

    return 0
}

运行结果:

摘要长度: 16

init(OperationMode, Array<Byte>, Array<Byte>, PaddingMode, Array<Byte>, Int64)

public init(
    optMode: OperationMode,
    key: Array<Byte>,
    iv!: Array<Byte> = Array<Byte>(),
    paddingMode!: PaddingMode = PaddingMode.PKCS7Padding,
    aad!: Array<Byte> = Array<Byte>(),
    tagSize!: Int64 = 16
)

功能:创建 SM4 实例,可指定在不同工作模式下参数。

参数:

  • optMode: OperationMode - 设置加解密工作模式。
  • key: Array<Byte> - 密钥,长度为 16 字节。
  • iv!: Array<Byte> - 初始化向量。
  • paddingMode!: PaddingMode - 设置填充模式。
  • aad!: Array<Byte> - 设置附加数据。
  • tagSize!: Int64 - 设置摘要长度。

异常:

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom(priv: true)

    let key = random.nextBytes(16) // 16字节密钥,生产环节从KMS密钥管理系统获取
    let iv = random.nextBytes(16) // 16字节IV

    // 使用CBC模式创建SM4实例
    let sm4 = SM4(OperationMode.CBC, key, iv: iv)

    println("SM4算法名称: ${sm4.algorithm}")
    println("分组长度: ${sm4.blockSize}")
    println("密钥长度: ${sm4.keySize}")

    return 0
}

运行结果:

SM4算法名称: SM4
分组长度: 16
密钥长度: 16

func decrypt(Array<Byte>)

public func decrypt(input: Array<Byte>): Array<Byte>

功能:解密一段数据数据。

参数:

  • input: Array<Byte> - 输入字节序列。

返回值:

  • Array<Byte> - 解密后的结果。

异常:

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom(priv: true)

    let key = random.nextBytes(16) // 16字节密钥,生产环节从KMS密钥管理系统获取
    let iv = random.nextBytes(16) // 16字节IV

    // 创建SM4实例
    let sm4 = SM4(OperationMode.CBC, key, iv: iv)

    // 要加密的数据
    let plainText = "Hello, Cangjie!".toArray()

    // 加密数据
    let encrypted = sm4.encrypt(plainText)
    println("加密成功,密文长度: ${encrypted.size}")

    // 解密数据
    let decrypted = sm4.decrypt(encrypted)
    let result = String.fromUtf8(decrypted)
    println("解密结果: ${result}")

    return 0
}

运行结果:

加密成功,密文长度: 16
解密结果: Hello, Cangjie!

func decrypt(Array<Byte>, Array<Byte>)

public func decrypt(input: Array<Byte>,  to!: Array<Byte>): Int64

功能:解密一段数据,将密文解密后的明文写入指定的输出字节数组,返回值为实际写入到输出数组的明文字节长度。数组长度不足时不会报错,仅会对解密后的明文进行截断处理。为保证能接收完整明文,建议输出数组的长度不小于密文数组的长度。

参数:

  • input: Array<Byte> - 待进行解密的数据。
  • to!: Array<Byte> - 输出数组。

返回值:

  • Int64 - 输出长度。

异常:

  • CryptoException - 解密失败,抛出异常。
  • IllegalArgumentException - 当 to 的 size = 0 时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom(priv: true)

    let key = random.nextBytes(16) // 16字节密钥,生产环节从KMS密钥管理系统获取
    let iv = random.nextBytes(16) // 16字节IV

    // 创建SM4实例
    let sm4 = SM4(OperationMode.CBC, key, iv: iv)

    // 要加密的数据
    let plainText = "Hello, Cangjie!".toArray()

    // 加密数据
    let encrypted = sm4.encrypt(plainText)
    println("加密成功,密文长度: ${encrypted.size}")

    // 准备输出数组,长度为密文长度
    var output = Array<Byte>(encrypted.size, repeat: 0)

    // 解密数据到指定输出数组
    let outputLen = sm4.decrypt(encrypted, to: output)
    println("解密成功,输出长度: ${outputLen}")
    println("解密成功,输出: ${String.fromUtf8(output.slice(0, outputLen))}")

    // 准备输出数组,长度为3(会发生截断)
    var output01 = Array<Byte>(3, repeat: 0)

    // 解密数据到指定输出数组
    let outputLen01 = sm4.decrypt(encrypted, to: output01)
    println("解密成功,输出长度: ${outputLen01}")
    println("解密成功,输出(发生截断): ${String.fromUtf8(output01)}")
    return 0
}

运行结果:

加密成功,密文长度: 16
解密成功,输出长度: 15
解密成功,输出: Hello, Cangjie!
解密成功,输出长度: 3
解密成功,输出(发生截断): Hel

func decrypt(InputStream, OutputStream)

public func decrypt(input: InputStream, output: OutputStream): Unit

功能:对输入流进行解密,如果数据过大无法一次对其解密,可以通过数据流进行解密。

参数:

  • input:InputStream - 待解密的输入数据流。
  • output: OutputStream - 解密后的输出数据流。

异常:

示例:

import stdx.crypto.crypto.*
import std.fs.*

main() {
    let random = SecureRandom(priv: true)

    let key = random.nextBytes(16) // 16字节密钥,生产环节从KMS密钥管理系统获取
    let iv = random.nextBytes(16) // 16字节IV

    // 创建SM4实例
    let sm4 = SM4(OperationMode.CBC, key, iv: iv)

    // 要加密的数据
    let plainText = "Hello, Cangjie!".toArray()

    // 创建一个测试文件里面放入加密数据
    let testEncrypt = Path("./test_encrypt.txt")
    removeIfExists(testEncrypt, recursive: true)
    let encrypted = sm4.encrypt(plainText)
    File.writeTo(testEncrypt, encrypted)

    // 从文件中读取加密数据并解密到文件中(File是文件流)
    let testDecrypt = Path("./test_decrypt.txt")
    removeIfExists(testDecrypt, recursive: true)
    sm4.decrypt(File(testEncrypt, Read), File(testDecrypt, Write))

    let decrypted = File.readFrom(testDecrypt)
    let result = String.fromUtf8(decrypted)
    println("从文件中解密结果: ${result}")

    // 清理临时文件
    removeIfExists(testEncrypt, recursive: true)
    removeIfExists(testDecrypt, recursive: true)
    return 0
}

运行结果:

从文件中解密结果: Hello, Cangjie!

func encrypt(Array<Byte>)

public func encrypt(input: Array<Byte>): Array<Byte>

功能:加密一段数据数据。

参数:

  • input: Array<Byte> - 输入字节序列。

返回值:

  • Array<Byte> - 加密后的结果。

异常:

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom(priv: true)

    let key = random.nextBytes(16) // 16字节密钥,生产环节从KMS密钥管理系统获取
    let iv = random.nextBytes(16) // 16字节IV

    // 创建SM4实例
    let sm4 = SM4(OperationMode.CBC, key, iv: iv)

    // 要加密的数据
    let plainText = "Hello, Cangjie!".toArray()

    // 加密数据
    let encrypted = sm4.encrypt(plainText)
    println("加密成功,密文字节数组(长度 ${encrypted.size}): ${encrypted}")

    return 0
}

可能的运行结果:

加密成功,密文字节数组(长度 16): [130, 245, 173, 223, 95, 40, 68, 161, 234, 44, 26, 22, 39, 217, 140, 138]

func encrypt(Array<Byte>, Array<Byte>)

public func encrypt(input: Array<Byte>, to!: Array<Byte>): Int64

功能:加密一段明文数据,将加密后的密文写入调用者预先创建的输出字节数组,返回值为实际写入到输出数组的密文字节长度。明文数组长度加上一个 blockSize(16),可适配所有填充场景。

注意:

  • 输出数组长度仅影响加密结果,不影响后续解密流程;数组长度不足时不会报错,若无法容纳完整密文,加密会失败或仅写入部分密文(返回值为实际写入长度)。
  • 填充模式(CBC/ECB):SM4 分组加密需填充,密文长度为 16 字节的整数倍,建议输出数组长度≥向上取整 (明文长度 / 16)×16(blockSize=16);最简方案为输出数组长度 = 明文长度 + 16,可适配所有填充场景。
  • 无填充模式(GCM/CTR/OFB/CFB):流加密无需填充,密文长度与明文长度一致,建议输出数组长度与明文长度一致。
  • 本接口为高性能底层实现,不做自动扩容与长度校验,需调用者自行保证输出数组长度足够。

参数:

  • input: Array<Byte> - 待进行加密的数据。
  • to!: Array<Byte> - 输出数组。

返回值:

  • Int64 - 输出长度。

异常:

  • CryptoException - 加密失败,抛出异常。
  • IllegalArgumentException - 当 to 的 size = 0 时,抛出异常。

示例:

import stdx.crypto.crypto.*

main() {
    let random = SecureRandom(priv: true)

    let key = random.nextBytes(16) // 16字节密钥,生产环节从KMS密钥管理系统获取
    let iv = random.nextBytes(16) // 16字节IV

    // 创建SM4实例
    let sm4 = SM4(OperationMode.CBC, key, iv: iv)

    // 要加密的数据
    let plainText = "Hello, Cangjie!".toArray()

    // 准备输出数组,长度应足够存储加密结果
    var output = Array<Byte>(plainText.size + 16, repeat: 0)

    // 加密数据到指定输出数组
    let outputLen = sm4.encrypt(plainText, to: output)
    println("加密成功,输出长度: ${outputLen}")

    return 0
}

运行结果:

加密成功,输出长度: 16

func encrypt(InputStream, OutputStream)

public func encrypt(input: InputStream, output: OutputStream): Unit

功能:对输入流进行加密,如果数据过大无法一次对其加密,可以通过数据流进行加密。

参数:

  • input:InputStream - 待加密的输入数据流。
  • output: OutputStream - 解密后的输出数据流。

异常:

示例:

import stdx.crypto.crypto.*
import std.fs.*

main() {
    let random = SecureRandom(priv: true)

    let key = random.nextBytes(16) // 16字节密钥,生产环节从KMS密钥管理系统获取
    let iv = random.nextBytes(16) // 16字节IV

    // 创建SM4实例
    let sm4 = SM4(OperationMode.CBC, key, iv: iv)

    // 要加密的数据
    let plainText = "Hello, Cangjie!"
    println("要加密的数据: ${plainText}")

    // 测试文件里面放入要加密的数据
    let testData = Path("./test_data.txt")
    removeIfExists(testData, recursive: true)
    File.writeTo(testData, plainText.toArray())

    // 加密的数据被写入到文件中
    let testEncrypt = Path("./test_encrypt.txt")
    removeIfExists(testEncrypt, recursive: true)
    sm4.encrypt(File(testData, Read), File(testEncrypt, Write))
    let encrypted = File.readFrom(testEncrypt)
    println("加密结果的大小: ${encrypted.size}")

    // 解密的数据被写入到文件中
    let testDecrypt = Path("./test_decrypt.txt")
    removeIfExists(testDecrypt, recursive: true)
    sm4.decrypt(File(testEncrypt, Read), File(testDecrypt, Write))

    let decrypted = File.readFrom(testDecrypt)
    let result = String.fromUtf8(decrypted)
    println("从文件中解密结果: ${result}")

    // 清理临时文件
    removeIfExists(testEncrypt, recursive: true)
    removeIfExists(testDecrypt, recursive: true)
    removeIfExists(testData, recursive: true)
    return 0
}

运行结果:

要加密的数据: Hello, Cangjie!
加密结果的大小: 16
从文件中解密结果: Hello, Cangjie!

结构体

struct OperationMode

public struct OperationMode <: ToString & Equatable<OperationMode> {
    public static let ECB: OperationMode
    public static let CBC: OperationMode
    public static let OFB: OperationMode
    public static let CFB: OperationMode
    public static let CTR: OperationMode
    public static let GCM: OperationMode
    public let mode: String
}

功能:对称加解密算法的工作模式。

父类型:

static let CBC

public static let CBC: OperationMode

功能:Cipher Block Chaining(密码分组链接)工作模式,CBC 初始值是 OperationMode("CBC")。

类型:OperationMode

示例:

import stdx.crypto.crypto.*

main() {
    let mode = OperationMode.CBC
    println("工作模式: ${mode}")
    return 0
}

运行结果:

工作模式: CBC

static let CFB

public static let CFB: OperationMode

功能:Cipher FeedBack(密文反馈)工作模式,CFB 初始值是 OperationMode("CFB")。

类型:OperationMode

示例:

import stdx.crypto.crypto.*

main() {
    let mode = OperationMode.CFB
    println("工作模式: ${mode}")
    return 0
}

运行结果:

工作模式: CFB

static let CTR

public static let CTR: OperationMode

功能:CounTeR(计数器)工作模式,CTR 初始值是 OperationMode("CTR")。

类型:OperationMode

示例:

import stdx.crypto.crypto.*

main() {
    let mode = OperationMode.CTR
    println("工作模式: ${mode}")
    return 0
}

运行结果:

工作模式: CTR

static let ECB

public static let ECB: OperationMode

功能:Electronic CodeBook(单子密码本)工作模式, ECB 初始值是 OperationMode("ECB")。

类型:OperationMode

示例:

import stdx.crypto.crypto.*

main() {
    let mode = OperationMode.ECB
    println("工作模式: ${mode}")
    return 0
}

运行结果:

工作模式: ECB

static let GCM

public static let GCM: OperationMode

功能:Galois Counter(伽罗瓦计数器)工作模式,GCM 初始值是 OperationMode("GCM")。

类型:OperationMode

示例:

import stdx.crypto.crypto.*

main() {
    let mode = OperationMode.GCM
    println("工作模式: ${mode}")
    return 0
}

运行结果:

工作模式: GCM

static let OFB

public static let OFB: OperationMode

功能:Output FeedBack(输出反馈)工作模式,OFB 初始值是 OperationMode("OFB")。

类型:OperationMode

示例:

import stdx.crypto.crypto.*

main() {
    let mode = OperationMode.OFB
    println("工作模式: ${mode}")
    return 0
}

运行结果:

工作模式: OFB

let mode

public let mode: String

功能:operation 分组加解密的工作模式,目前支持 ECB、CBC CFB OFB CTR GCM。

类型:String

示例:

import stdx.crypto.crypto.*

main() {
    let mode = OperationMode.CBC
    println("模式字符串: ${mode.mode}")
    return 0
}

运行结果:

模式字符串: CBC

func toString()

public override func toString(): String

功能:获取工作模式字符串。

返回值:

  • String - 工作模式字符串。

示例:

import stdx.crypto.crypto.*

main() {
    let modeStr = OperationMode.OFB.toString()
    println("OFB模式toString: ${modeStr}")
    return 0
}

运行结果:

OFB模式toString: OFB

operator func !=(OperationMode)

public override operator func !=(other: OperationMode): Bool

功能:工作模式比较是否不相同。

参数:

返回值:

  • Bool - true 不相同,false 相同。

示例:

import stdx.crypto.crypto.*

main() {
    let mode1 = OperationMode.CBC
    let mode2 = OperationMode.ECB
    let mode3 = OperationMode.CBC

    let isNotEqual1 = mode1 != mode2
    let isNotEqual2 = mode1 != mode3

    println("CBC != ECB: ${isNotEqual1}")
    println("CBC != CBC: ${isNotEqual2}")
    return 0
}

运行结果:

CBC != ECB: true
CBC != CBC: false

operator func ==(OperationMode)

public override operator func ==(other: OperationMode): Bool

功能:工作模式比较是否相同。

参数:

返回值:

  • Bool - true 相同,false 不相同。

示例:

import stdx.crypto.crypto.*

main() {
    let mode1 = OperationMode.CBC
    let mode2 = OperationMode.ECB
    let mode3 = OperationMode.CBC

    let isEqual1 = mode1 == mode2
    let isEqual2 = mode1 == mode3

    println("CBC == ECB: ${isEqual1}")
    println("CBC == CBC: ${isEqual2}")
    return 0
}

运行结果:

CBC == ECB: false
CBC == CBC: true

struct PaddingMode

public struct PaddingMode <: Equatable<PaddingMode> {
    public static let NoPadding: PaddingMode
    public static let PKCS7Padding: PaddingMode
    public let paddingType: Int64
}

功能:对称加解密算法的填充模式。

父类型:

static let NoPadding

public static let NoPadding: PaddingMode

功能:不填充,NoPadding 初始值是 PaddingMode(0)。

类型:PaddingMode

示例:

import stdx.crypto.crypto.*

main() {
    let padding = PaddingMode.NoPadding
    println("NoPadding模式的paddingType: ${padding.paddingType}")
    return 0
}

运行结果:

NoPadding模式的paddingType: 0

static let PKCS7Padding

public static let PKCS7Padding: PaddingMode

功能:采用 PKCS7 协议填充,PKCS7Padding 初始值是 PaddingMode(1)。

类型:PaddingMode

示例:

import stdx.crypto.crypto.*

main() {
    let padding = PaddingMode.PKCS7Padding
    println("PKCS7Padding模式的paddingType: ${padding.paddingType}")
    return 0
}

运行结果:

PKCS7Padding模式的paddingType: 1

let paddingType

public let paddingType: Int64

功能:分组加解密填充方式,目前支持非填充和 pkcs7 填充。

类型:Int64

示例:

import stdx.crypto.crypto.*

main() {
    let padding = PaddingMode.PKCS7Padding
    println("PKCS7Padding模式的paddingType: ${padding.paddingType}")
    return 0
}

运行结果:

PKCS7Padding模式的paddingType: 1

operator func !=(PaddingMode)

public override operator func !=(other: PaddingMode): Bool

功能:工作模式比较是否不相同。

参数:

返回值:

  • Bool - true 不相同,false 相同。

示例:

import stdx.crypto.crypto.*

main() {
    let padding1 = PaddingMode.NoPadding
    let padding2 = PaddingMode.PKCS7Padding
    let padding3 = PaddingMode.NoPadding

    let isNotEqual1 = padding1 != padding2
    let isNotEqual2 = padding1 != padding3

    println("NoPadding != PKCS7Padding: ${isNotEqual1}")
    println("NoPadding != NoPadding: ${isNotEqual2}")
    return 0
}

运行结果:

NoPadding != PKCS7Padding: true
NoPadding != NoPadding: false

operator func ==(PaddingMode)

public override operator func ==(other: PaddingMode): Bool

功能:填充模式比较是否相同。

参数:

返回值:

  • Bool - true 相同,false 不相同。

示例:

import stdx.crypto.crypto.*

main() {
    let padding1 = PaddingMode.NoPadding
    let padding2 = PaddingMode.PKCS7Padding
    let padding3 = PaddingMode.NoPadding

    let isEqual1 = padding1 == padding2
    let isEqual2 = padding1 == padding3

    println("NoPadding == PKCS7Padding: ${isEqual1}")
    println("NoPadding == NoPadding: ${isEqual2}")
    return 0
}

运行结果:

NoPadding == PKCS7Padding: false
NoPadding == NoPadding: true

异常类

class SecureRandomException

public class SecureRandomException <: Exception {
    public init()
    public init(message: String)
}

功能:crypto 包安全随机数的异常类。

父类型:

  • Exception

init()

public init()

功能:创建默认的 SecureRandomException 实例,异常提示消息为空。

示例:

import stdx.crypto.crypto.*

main(): Unit {
    try {
        // 抛出一个无参的SecureRandomException异常
        throw SecureRandomException()
    } catch (e: SecureRandomException) {
        println("捕获到安全随机数异常")
    }
}

运行结果:

捕获到安全随机数异常

init(String)

public init(message: String)

功能:根据异常信息创建 SecureRandomException 实例。

参数:

  • message: String - 异常提示信息。

示例:

import stdx.crypto.crypto.*

main(): Unit {
    try {
        // 抛出一个带消息的SecureRandomException异常
        throw SecureRandomException("安全随机数生成失败")
    } catch (e: SecureRandomException) {
        println("捕获到安全随机数异常: ${e.message}")
    }
}

运行结果:

捕获到安全随机数异常: 安全随机数生成失败

SecureRandom 使用

Random 创建随机数对象。

示例:

import stdx.crypto.crypto.*

main() {
    let r = SecureRandom()
    for (_ in 0..10) {
        let flip = r.nextBool()
        println(flip)
    }
    return 0
}

运行结果:

说明

可能出现的运行结果如下(true/false 的选择是随机的)。

false
true
false
false
false
true
true
false
false
true

SM4 使用

SM4 加解密数据。

示例:

import stdx.crypto.crypto.*

main() {
    var plains = "hello cangjie!"
    var key = "YOUR_KEYYYYYYYYY" // 16 bytes key for SM4
    var iv = "YOUR_IVVVVVVVVVV" // 16 bytes IV for CBC mode
    var sm4 = SM4(OperationMode.CBC, key.toArray(), iv: iv.toArray())
    var enRe = sm4.encrypt(plains.toArray())
    var dd = sm4.decrypt(enRe)
    println(String.fromUtf8(dd))
}

运行结果:

hello cangjie!

stdx.crypto.digest

功能介绍

digest 包提供常用的消息摘要算法,包括 MD5、SHA1、SHA224、SHA256、SHA384、SHA512、HMAC、SM3 等。

使用本包需要外部依赖 OpenSSL 3 的 crypto 动态库文件,故使用前需安装相关工具。

  • 对于 Linux 操作系统,可参考以下方式:

    • 如果系统的包管理工具支持安装 OpenSSL 3 开发工具包,可通过这个方式安装,并确保系统安装目录下含有 libcrypto.so 和 libcrypto.so.3 这两个动态库文件,例如 Ubuntu 22.04 系统上可使用 sudo apt install libssl-dev 命令安装 libssl-dev 工具包;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libcrypto.so 和 libcrypto.so.3 这两个动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 LD_LIBRARY_PATH 以及 LIBRARY_PATH 中。
  • 对于 Windows 操作系统,可按照以下步骤:

    • 自行下载 OpenSSL 3.x.x 源码编译安装 x64 架构软件包或者自行下载安装第三方预编译的供开发人员使用的 OpenSSL 3.x.x 软件包;
    • 确保安装目录下含有 libcrypto.dll.a(或 libcrypto.lib)、libcrypto-3-x64.dll 这两个库文件;
    • 将 libcrypto.dll.a(或 libcrypto.lib)所在的目录路径设置到环境变量 LIBRARY_PATH 中,将 libcrypto-3-x64.dll 所在的目录路径设置到环境变量 PATH 中。
  • 对于 macOS 操作系统,可参考以下方式:

    • 使用 brew install openssl@3 安装,并确保系统安装目录下含有 libcrypto.dylib 和 libcrypto.3.dylib 这两个动态库文件;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libcrypto.dylib 和 libcrypto.3.dylib 这两个动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 DYLD_LIBRARY_PATH 以及 LIBRARY_PATH 中。
  • 对于 Android 操作系统,可参考以下方式:

    • 由于 Android 系统默认自带的 OpenSSL 是裁剪版本,部分接口可能找不到符号而抛出异常,因此需要用户自行编译安装完整的 OpenSSL 3.x.x 版本;
    • 可自行下载 OpenSSL 3.x.x 源码,使用 Android NDK 交叉编译生成对应架构(当前只支持 arm64-v8a)的动态库文件,确保编译产物中含有 libcrypto.so 和 libcrypto.so.3 这些动态库文件;
    • 将这些文件所在目录设置到环境变量 LD_LIBRARY_PATH 中。

说明:

如果未安装 OpenSSL 3 软件包或者安装低版本的软件包,程序可能无法使用并抛出相关异常 CryptoException:Can not load openssl library or function xxx。

API 列表

类名功能
HMACHMAC 摘要算法。
MD5MD5 摘要算法。
SHA1SHA1 摘要算法。
SHA224SHA224 摘要算法。
SHA256SHA256 摘要算法。
SHA384SHA384 摘要算法。
SHA512SHA512 摘要算法。
SM3SM3 摘要算法。

结构体

结构体名功能
HashType摘要算法类型。

class HMAC

public class HMAC <: Digest {
    public init(key: Array<Byte>, digest: () -> Digest)
    public init(key: Array<Byte>, algorithm: HashType)
}

功能:提供 HMAC 算法的实现。目前支持的摘要算法包括 MD5、SHA1、SHA224、SHA256、SHA384、SHA512、SM3。

父类型:

  • Digest

prop algorithm

public prop algorithm: String

功能:HMAC 所选 Hash 算法的算法名称。

类型:String

示例:

import stdx.crypto.digest.*
import stdx.crypto.crypto.*

main() {
    let random = SecureRandom(priv: true)
    let key = random.nextBytes(32)

    let hmac = HMAC(key, HashType.SHA256)

    let algorithm = hmac.algorithm
    println("HMAC算法: ${algorithm}")

    return 0
}

运行结果:

HMAC算法: HMAC-SHA256

prop blockSize

public prop blockSize: Int64

功能:HMAC 所选 Hash 算法信息块长度,单位字节。

类型:Int64

示例:

import stdx.crypto.digest.*
import stdx.crypto.crypto.*

main() {
    let random = SecureRandom(priv: true)
    let key = random.nextBytes(32)

    let hmac = HMAC(key, HashType.SHA256)

    let blockSize = hmac.blockSize
    println("块大小: ${blockSize}")

    return 0
}

运行结果:

块大小: 64

prop size

public prop size: Int64

功能:HMAC 所选 Hash 算法的摘要信息长度,单位字节。

类型:Int64

示例:

import stdx.crypto.digest.*
import stdx.crypto.crypto.*

main() {
    let random = SecureRandom(priv: true)
    let key = random.nextBytes(32)

    let hmac = HMAC(key, HashType.SHA256)

    let size = hmac.size
    println("摘要长度: ${size}")

    return 0
}

运行结果:

摘要长度: 32

init(Array<Byte>, () -> Digest)

public init(key: Array<Byte>, digest: () -> Digest)

功能:构造函数,创建 HMAC 对象。

参数:

  • key: Array<Byte> - 密钥,建议该参数不小于所选 Hash 算法摘要的长度。
  • digest: () -> Digest - hash 算法。

异常:

示例:

import stdx.crypto.digest.*
import stdx.crypto.crypto.*

main() {
    let random = SecureRandom(priv: true)
    let key = random.nextBytes(32)
    let hmac = HMAC(key, {=> SHA256()})

    println("HMAC算法: ${hmac.algorithm}")
    println("摘要长度: ${hmac.size}")
    println("密钥长度: ${key.size}")
    println("密钥长度不小于摘要长度: ${key.size >= hmac.size}")
    return 0
}

运行结果:

HMAC算法: HMAC-SHA256
摘要长度: 32
密钥长度: 32
密钥长度不小于摘要长度: true

init(Array<Byte>, HashType)

public init(key: Array<Byte>, algorithm: HashType)

功能:构造函数,创建 HMAC 对象。

参数:

  • key: Array<Byte> - 密钥,建议该参数不小于所选 Hash 算法摘要的长度。
  • algorithm: HashType - hash 算法。

异常:

示例:

import stdx.crypto.digest.*
import stdx.crypto.crypto.*

main() {
    let random = SecureRandom(priv: true)
    let key = random.nextBytes(32)
    let hmac = HMAC(key, HashType.SHA256)

    println("HMAC算法: ${hmac.algorithm}")
    println("摘要长度: ${hmac.size}")
    println("密钥长度: ${key.size}")
    println("密钥长度不小于摘要长度: ${key.size >= hmac.size}")
    return 0
}

运行结果:

HMAC算法: HMAC-SHA256
摘要长度: 32
密钥长度: 32
密钥长度不小于摘要长度: true

static func equal(Array<Byte>, Array<Byte>)

public static func equal(mac1: Array<Byte>, mac2: Array<Byte>): Bool

功能:比较两个信息摘要是否相等,且不泄露比较时间,即比较不采用传统短路原则,从而防止 timing attack 类型的攻击。

参数:

  • mac1: Array<Byte> - 需要比较的信息摘要序列。
  • mac2: Array<Byte> - 需要比较的信息摘要序列。

返回值:

  • Bool - 信息摘要是否相同,true 相同,false 不相同。

示例:

import stdx.crypto.digest.*
import stdx.crypto.crypto.*

main() {
    let key1 = "mySecretKey".toArray()
    let key2 = "mySecretKey".toArray()
    let data1 = "Hello, World!".toArray()
    let data2 = "Hello, World!".toArray()

    let hmac1 = HMAC(key1, HashType.SHA256)
    let hmac2 = HMAC(key2, HashType.SHA256)

    hmac1.write(data1)
    hmac2.write(data2)

    let mac1 = hmac1.finish()
    let mac2 = hmac2.finish()

    let isEqual = HMAC.equal(mac1, mac2)
    println("摘要是否相同: ${isEqual}")

    return 0
}

运行结果:

摘要是否相同: true

func finish()

public func finish(): Array<Byte>

功能:返回生成的信息摘要值,注意调用 finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

返回值:

  • Array<Byte> - 生成的信息摘要字节序列。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算,抛此异常。

示例:

import stdx.crypto.digest.*
import stdx.crypto.crypto.*

main() {
    let random = SecureRandom(priv: true)
    let key = random.nextBytes(32)
    let data = "Hello, World!".toArray()

    let hmac = HMAC(key, HashType.MD5)
    hmac.write(data)

    let result = hmac.finish()
    println("${hmac.algorithm}摘要: ${result}")

    return 0
}

可能的运行结果:

HMAC-MD5摘要: [22, 198, 33, 44, 225, 231, 29, 141, 214, 143, 8, 188, 108, 114, 150, 21]

func finish(Array<Byte>)

public func finish(to!: Array<Byte>): Unit

功能:获取生成的信息摘要值,注意调用 finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

参数:

  • to!: Array<Byte> - 目标数组。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算或者指定输出数组大小不等于摘要算法信息长度,抛此异常。

示例:

import stdx.crypto.digest.*
import stdx.crypto.crypto.*

main() {
    let random = SecureRandom(priv: true)
    let key = random.nextBytes(32)
    let data = "Hello, World!".toArray()

    let hmac = HMAC(key, HashType.MD5)
    hmac.write(data)

    let output = Array<Byte>(hmac.size, repeat: 0)
    hmac.finish(to: output)
    println("输出数组: ${output}")

    return 0
}

可能的运行结果:

输出数组: [253, 224, 17, 238, 0, 31, 114, 118, 132, 239, 222, 219, 11, 248, 114, 169]

func reset()

public func reset(): Unit

功能:重置 HMAC 对象到初始状态,清理 HMAC 上下文。

异常:

示例:

import stdx.crypto.digest.*
import stdx.crypto.crypto.*

main() {
    let random = SecureRandom(priv: true)
    let key = random.nextBytes(32)
    let data1 = "Hello".toArray()
    let data2 = "World".toArray()

    let hmac = HMAC(key, HashType.MD5)
    hmac.write(data1)

    let result1 = hmac.finish()
    println("${hmac.algorithm}第一次摘要: ${result1}")

    hmac.reset() // 重置HMAC对象
    println("保留密钥和算法,可重新计算新数据的摘要")

    hmac.write(data2)

    let result2 = hmac.finish()
    println("${hmac.algorithm}重置后摘要: ${result2}")

    return 0
}

运行结果:

HMAC-MD5第一次摘要: [138, 105, 2, 119, 31, 115, 202, 188, 146, 122, 244, 175, 173, 233, 58, 189]
保留密钥和算法,可重新计算新数据的摘要
HMAC-MD5重置后摘要: [108, 167, 54, 164, 167, 9, 223, 48, 21, 26, 111, 32, 217, 239, 25, 57]

func write(Array<Byte>)

public func write(buffer: Array<Byte>): Unit

功能:使用给定的 buffer 更新 HMAC 对象,在调用 finish 前可以多次更新。

参数:

  • buffer: Array<Byte> - 需要追加的字节序列。

异常:

  • CryptoException - 当 buffer 为空、finish 已经调用生成信息摘要场景,抛此异常。

示例:

import stdx.crypto.digest.*
import stdx.crypto.crypto.*

main() {
    let random = SecureRandom(priv: true)
    let key = random.nextBytes(32)
    let data1 = "Hello".toArray()
    let data2 = " ".toArray()
    let data3 = "World".toArray()

    let hmac = HMAC(key, HashType.MD5)
    hmac.write(data1) // 写入第一部分数据
    hmac.write(data2) // 写入第二部分数据
    hmac.write(data3) // 写入第三部分数据

    let result = hmac.finish()
    println("${hmac.algorithm}摘要: ${result}")

    return 0
}

可能的运行结果:

HMAC-MD5摘要: [99, 114, 182, 143, 83, 216, 88, 65, 50, 42, 136, 210, 128, 83, 39, 229]

class MD5

public class MD5 <: Digest {
    public init()
}

功能:提供 MD5 算法的实现接口。使用示例见 MD5 算法示例

父类型:

  • Digest

prop algorithm

public prop algorithm: String

功能:MD5 摘要算法的算法名称。

类型:String

示例:

import stdx.crypto.digest.*

main() {
    let md5 = MD5()

    let algorithm = md5.algorithm
    println("MD5算法: ${algorithm}")

    return 0
}

运行结果:

MD5算法: MD5

prop blockSize

public prop blockSize: Int64

功能:MD5 信息块长度,单位字节。

类型:Int64

示例:

import stdx.crypto.digest.*

main() {
    let md5 = MD5()

    let blockSize = md5.blockSize
    println("块大小: ${blockSize}")

    return 0
}

运行结果:

块大小: 64

prop size

public prop size: Int64

功能:MD5 摘要信息长度,单位字节。

类型:Int64

示例:

import stdx.crypto.digest.*

main() {
    let md5 = MD5()

    let size = md5.size
    println("摘要长度: ${size}")

    return 0
}

运行结果:

摘要长度: 16

init()

public init()

功能:无参构造函数,创建 MD5 对象。

示例:

import stdx.crypto.digest.*

main() {
    let md5 = MD5()

    println("MD5对象创建成功")
    println("算法: ${md5.algorithm}")
    println("块大小: ${md5.blockSize}")
    println("摘要长度: ${md5.size}")

    return 0
}

运行结果:

MD5对象创建成功
算法: MD5
块大小: 64
摘要长度: 16

func finish()

public func finish(): Array<Byte>

功能:返回生成的 MD5 值,注意调用 finish 后 MD5 上下文会发生改变,finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

返回值:

  • Array<Byte> - 生成的 MD5 字节序列。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算,抛此异常。

示例:

import stdx.crypto.digest.*

main() {
    let md5 = MD5()
    let data = "Hello, World!".toArray()

    md5.write(data)

    let result = md5.finish()
    println("MD5摘要: ${result}")

    return 0
}

运行结果:

MD5摘要: [101, 168, 226, 125, 136, 121, 40, 56, 49, 182, 100, 189, 139, 127, 10, 212]

func finish(Array<Byte>)

public func finish(to!: Array<Byte>): Unit

功能:获取生成的信息摘要值,注意调用 finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

参数:

  • to!: Array<Byte> - 目标数组。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算或者指定输出数组大小不等于摘要算法信息长度,抛此异常。

示例:

import stdx.crypto.digest.*

main() {
    let md5 = MD5()
    let data = "Hello, World!".toArray()

    md5.write(data)

    var output = Array<Byte>(md5.size, repeat: 0)
    md5.finish(to: output)
    println("输出数组: ${output}")

    return 0
}

运行结果:

输出数组: [101, 168, 226, 125, 136, 121, 40, 56, 49, 182, 100, 189, 139, 127, 10, 212]

func reset()

public func reset(): Unit

功能:重置 MD5 对象到初始状态,清理 MD5 上下文。

示例:

import stdx.crypto.digest.*

main() {
    let md5 = MD5()
    let data1 = "Hello".toArray()
    let data2 = "World".toArray()

    md5.write(data1)
    let result1 = md5.finish()
    println("第一次摘要: ${result1}")

    md5.reset() // 重置MD5对象
    md5.write(data2)
    let result2 = md5.finish()
    println("重置后摘要: ${result2}")

    return 0
}

运行结果:

第一次摘要: [139, 26, 153, 83, 196, 97, 18, 150, 168, 39, 171, 248, 196, 120, 4, 215]
重置后摘要: [245, 167, 146, 78, 98, 30, 132, 201, 40, 10, 154, 39, 225, 188, 183, 246]

func write(Array<Byte>)

public func write(buffer: Array<Byte>): Unit

功能:使用给定的 buffer 更新 MD5 对象,在调用 finish 前可以多次更新。

参数:

  • buffer: Array<Byte> - 输入字节序列。

异常:

  • CryptoException - 已经调用 finish 进行摘要计算后未重置上下文,抛此异常。

示例:

import stdx.crypto.digest.*

main() {
    let md5 = MD5()
    let data1 = "Hello".toArray()
    let data2 = " ".toArray()
    let data3 = "World".toArray()

    md5.write(data1) // 写入第一部分数据
    md5.write(data2) // 写入第二部分数据
    md5.write(data3) // 写入第三部分数据

    let result = md5.finish()
    println("MD5摘要: ${result}")

    return 0
}

运行结果:

MD5摘要: [177, 10, 141, 177, 100, 224, 117, 65, 5, 183, 169, 155, 231, 46, 63, 229]

class SHA1

public class SHA1 <: Digest {
    public init()
}

功能:提供 SHA1 算法的实现接口。使用示例见 SHA1 算法示例

父类型:

  • Digest

prop algorithm

public prop algorithm: String

功能:SHA1 摘要算法的算法名称。

类型:String

示例:

import stdx.crypto.digest.*

main() {
    let sha1 = SHA1()

    let algorithm = sha1.algorithm
    println("SHA1算法: ${algorithm}")

    return 0
}

运行结果:

SHA1算法: SHA1

prop blockSize

public prop blockSize: Int64

功能:SHA1 信息块长度,单位字节。

类型:Int64

示例:

import stdx.crypto.digest.*

main() {
    let sha1 = SHA1()

    let blockSize = sha1.blockSize
    println("块大小: ${blockSize}")

    return 0
}

运行结果:

块大小: 64

prop size

public prop size: Int64

功能:SHA1 摘要信息长度,单位字节。

类型:Int64

示例:

import stdx.crypto.digest.*

main() {
    let sha1 = SHA1()

    let size = sha1.size
    println("摘要长度: ${size}")

    return 0
}

运行结果:

摘要长度: 20

init()

public init()

功能:无参构造函数,创建 SHA1 对象。

示例:

import stdx.crypto.digest.*

main() {
    let sha1 = SHA1()

    println("SHA1对象创建成功")
    println("算法: ${sha1.algorithm}")
    println("块大小: ${sha1.blockSize}")
    println("摘要长度: ${sha1.size}")

    return 0
}

运行结果:

SHA1对象创建成功
算法: SHA1
块大小: 64
摘要长度: 20

func finish()

public func finish(): Array<Byte>

功能:返回生成的 SHA1 值,注意调用 finish 后 SHA1 上下文会发生改变,finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

返回值:

  • Array<Byte> - 生成的 SHA1 字节序列。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算,抛此异常。

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    let sha1 = SHA1()
    let data = "Hello, World!".toArray()

    sha1.write(data)

    let result = sha1.finish()
    let hexResult = toHexString(result)
    println("SHA1摘要: ${hexResult}")

    return 0
}

运行结果:

SHA1摘要: 0a0a9f2a6772942557ab5355d76af442f8f65e01

func finish(Array<Byte>)

public func finish(to!: Array<Byte>): Unit

功能:获取生成的信息摘要值,注意调用 finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

参数:

  • to!: Array<Byte> - 目标数组。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算或者指定输出数组大小不等于摘要算法信息长度,抛此异常。

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    let sha1 = SHA1()
    let data = "Hello, World!".toArray()

    sha1.write(data)

    var output = Array<Byte>(sha1.size, repeat: 0)
    sha1.finish(to: output)
    let hexOutput = toHexString(output)
    println("输出摘要: ${hexOutput}")

    return 0
}

运行结果:

输出摘要: 0a0a9f2a6772942557ab5355d76af442f8f65e01

func reset()

public func reset(): Unit

功能:重置 SHA1 对象到初始状态,清理 SHA1 上下文。

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    let sha1 = SHA1()
    let data1 = "Hello".toArray()
    let data2 = "World".toArray()

    sha1.write(data1)
    let result1 = sha1.finish()
    let hexResult1 = toHexString(result1)
    println("第一次摘要: ${hexResult1}")

    sha1.reset() // 重置SHA1对象
    sha1.write(data2)
    let result2 = sha1.finish()
    let hexResult2 = toHexString(result2)
    println("重置后摘要: ${hexResult2}")

    return 0
}

运行结果:

第一次摘要: f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0
重置后摘要: 70c07ec18ef89c5309bbb0937f3a6342411e1fdd

func write(Array<Byte>)

public func write(buffer: Array<Byte>): Unit

功能:使用给定的 buffer 更新 SHA1 对象,在调用 finish 前可以多次更新。

参数:

  • buffer: Array<Byte> - 输入字节序列。

异常:

  • CryptoException - 已经调用 finish 进行摘要计算后未重置上下文,抛此异常。

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    let sha1 = SHA1()
    let data1 = "Hello".toArray()
    let data2 = " ".toArray()
    let data3 = "World".toArray()

    sha1.write(data1) // 写入第一部分数据
    sha1.write(data2) // 写入第二部分数据
    sha1.write(data3) // 写入第三部分数据

    let result = sha1.finish()
    let hexResult = toHexString(result)
    println("SHA1摘要: ${hexResult}")

    return 0
}

运行结果:

SHA1摘要: 0a4d55a8d778e5022fab701977c5d840bbc486d0

class SHA224

public class SHA224 <: Digest {
    public init()
}

功能:提供 SHA224 算法的实现接口。使用示例见 SHA224 算法示例

父类型:

  • Digest

prop algorithm

public prop algorithm: String

功能:SHA224 摘要算法的算法名称。

类型:String

示例:

import stdx.crypto.digest.*

main() {
    let sha224 = SHA224()

    let algorithm = sha224.algorithm
    println("SHA224算法: ${algorithm}")

    return 0
}

运行结果:

SHA224算法: SHA224

prop blockSize

public prop blockSize: Int64

功能:SHA224 信息块长度,单位字节。

类型:Int64

示例:

import stdx.crypto.digest.*

main() {
    let sha224 = SHA224()

    let blockSize = sha224.blockSize
    println("块大小: ${blockSize}")

    return 0
}

运行结果:

块大小: 64

prop size

public prop size: Int64

功能:SHA224 摘要信息长度,单位字节。

类型:Int64

示例:

import stdx.crypto.digest.*

main() {
    let sha224 = SHA224()

    let size = sha224.size
    println("摘要长度: ${size}")

    return 0
}

运行结果:

摘要长度: 28

init()

public init()

功能:无参构造函数,创建 SHA224 对象。

示例:

import stdx.crypto.digest.*

main() {
    let sha224 = SHA224()

    println("SHA224对象创建成功")
    println("算法: ${sha224.algorithm}")
    println("块大小: ${sha224.blockSize}")
    println("摘要长度: ${sha224.size}")

    return 0
}

运行结果:

SHA224对象创建成功
算法: SHA224
块大小: 64
摘要长度: 28

func finish()

public func finish(): Array<Byte>

功能:返回生成的 SHA224 值,注意调用 finish 后 SHA224 上下文会发生改变,finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

返回值:

  • Array<Byte> - 生成的 SHA224 字节序列。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算,抛此异常。

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    let sha224 = SHA224()
    let data = "Hello, World!".toArray()

    sha224.write(data)

    let result = sha224.finish()
    let hexResult = toHexString(result)
    println("SHA224摘要: ${hexResult}")

    return 0
}

运行结果:

SHA224摘要: 72a23dfa411ba6fde01dbfabf3b00a709c93ebf273dc29e2d8b261ff

func finish(Array<Byte>)

public func finish(to!: Array<Byte>): Unit

功能:获取生成的信息摘要值,注意调用 finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

参数:

  • to!: Array<Byte> - 目标数组。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算或者指定输出数组大小不等于摘要算法信息长度,抛此异常。

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    let sha224 = SHA224()
    let data = "Hello, World!".toArray()

    sha224.write(data)

    var output = Array<Byte>(sha224.size, repeat: 0)
    sha224.finish(to: output)
    let hexOutput = toHexString(output)
    println("输出摘要: ${hexOutput}")

    return 0
}

运行结果:

输出摘要: 72a23dfa411ba6fde01dbfabf3b00a709c93ebf273dc29e2d8b261ff

func reset()

public func reset(): Unit

功能:重置 SHA224 对象到初始状态,清理 SHA224 上下文。

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    let sha224 = SHA224()
    let data1 = "Hello".toArray()
    let data2 = "World".toArray()

    sha224.write(data1)
    let result1 = sha224.finish()
    let hexResult1 = toHexString(result1)
    println("第一次摘要: ${hexResult1}")

    sha224.reset() // 重置SHA224对象
    sha224.write(data2)
    let result2 = sha224.finish()
    let hexResult2 = toHexString(result2)
    println("重置后摘要: ${hexResult2}")

    return 0
}

运行结果:

第一次摘要: 4149da18aa8bfc2b1e382c6c26556d01a92c261b6436dad5e3be3fcc
重置后摘要: 12972632b6d3b6aa52bd6434552f08c1303d56b817119406466e9236

func write(Array<Byte>)

public func write(buffer: Array<Byte>): Unit

功能:使用给定的 buffer 更新 SHA224 对象,在调用 finish 前可以多次更新。

参数:

  • buffer: Array<Byte> - 输入字节序列。

异常:

  • CryptoException - 已经调用 finish 进行摘要计算后未重置上下文,抛此异常。

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    let sha224 = SHA224()
    let data1 = "Hello".toArray()
    let data2 = " ".toArray()
    let data3 = "World".toArray()

    sha224.write(data1) // 写入第一部分数据
    sha224.write(data2) // 写入第二部分数据
    sha224.write(data3) // 写入第三部分数据

    let result = sha224.finish()
    let hexResult = toHexString(result)
    println("SHA224摘要: ${hexResult}")

    return 0
}

运行结果:

SHA224摘要: c4890faffdb0105d991a461e668e276685401b02eab1ef4372795047

class SHA256

public class SHA256 <: Digest {
    public init()
}

功能:提供 SHA256 算法的实现接口。使用示例见 SHA256 算法示例

父类型:

  • Digest

prop algorithm

public prop algorithm: String

功能:SHA256 摘要算法的算法名称。

类型:String

示例:

import stdx.crypto.digest.*

main() {
    let sha256 = SHA256()

    let algorithm = sha256.algorithm
    println("SHA256算法: ${algorithm}")

    return 0
}

运行结果:

SHA256算法: SHA256

prop blockSize

public prop blockSize: Int64

功能:SHA256 信息块长度,单位字节。

类型:Int64

示例:

import stdx.crypto.digest.*

main() {
    let sha256 = SHA256()

    let blockSize = sha256.blockSize
    println("块大小: ${blockSize}")

    return 0
}

运行结果:

块大小: 64

prop size

public prop size: Int64

功能:SHA256 摘要信息长度,单位字节。

类型:Int64

示例:

import stdx.crypto.digest.*

main() {
    let sha256 = SHA256()

    let size = sha256.size
    println("摘要长度: ${size}")

    return 0
}

运行结果:

摘要长度: 32

init()

public init()

功能:无参构造函数,创建 SHA256 对象。

示例:

import stdx.crypto.digest.*

main() {
    let sha256 = SHA256()

    println("SHA256对象创建成功")
    println("算法: ${sha256.algorithm}")
    println("块大小: ${sha256.blockSize}")
    println("摘要长度: ${sha256.size}")

    return 0
}

运行结果:

SHA256对象创建成功
算法: SHA256
块大小: 64
摘要长度: 32

func finish()

public func finish(): Array<Byte>

功能:返回生成的 SHA256 值,注意调用 finish 后 SHA256 上下文会发生改变,finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

返回值:

  • Array<Byte> - 生成的 SHA256 字节序列。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算,抛此异常。

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    let sha256 = SHA256()
    let data = "Hello, World!".toArray()

    sha256.write(data)

    let result = sha256.finish()
    let hexResult = toHexString(result)
    println("SHA256摘要: ${hexResult}")

    return 0
}

运行结果:

SHA256摘要: dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f

func finish(Array<Byte>)

public func finish(to!: Array<Byte>): Unit

功能:获取生成的信息摘要值,注意调用 finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

参数:

  • to!: Array<Byte> - 目标数组。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算或者指定输出数组大小不等于摘要算法信息长度,抛此异常。

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    let sha256 = SHA256()
    let data = "Hello, World!".toArray()

    sha256.write(data)

    var output = Array<Byte>(sha256.size, repeat: 0)
    sha256.finish(to: output)
    let hexOutput = toHexString(output)
    println("输出摘要: ${hexOutput}")

    return 0
}

运行结果:

输出摘要: dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f

func reset()

public func reset(): Unit

功能:重置 SHA256 对象到初始状态,清理 SHA256 上下文。

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    let sha256 = SHA256()
    let data1 = "Hello".toArray()
    let data2 = "World".toArray()

    sha256.write(data1)
    let result1 = sha256.finish()
    let hexResult1 = toHexString(result1)
    println("第一次摘要: ${hexResult1}")

    sha256.reset() // 重置SHA256对象
    sha256.write(data2)
    let result2 = sha256.finish()
    let hexResult2 = toHexString(result2)
    println("重置后摘要: ${hexResult2}")

    return 0
}

运行结果:

第一次摘要: 185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969
重置后摘要: 78ae647dc5544d227130a0682a51e30bc7777fbb6d8a8f17007463a3ecd1d524

func write(Array<Byte>)

public func write(buffer: Array<Byte>): Unit

功能:使用给定的 buffer 更新 SHA256 对象,在调用 finish 前可以多次更新。

参数:

  • buffer: Array<Byte> - 输入字节序列。

异常:

  • CryptoException - 已经调用 finish 进行摘要计算后未重置上下文,抛此异常。

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    let sha256 = SHA256()
    let data1 = "Hello".toArray()
    let data2 = " ".toArray()
    let data3 = "World".toArray()

    sha256.write(data1) // 写入第一部分数据
    sha256.write(data2) // 写入第二部分数据
    sha256.write(data3) // 写入第三部分数据

    let result = sha256.finish()
    let hexResult = toHexString(result)
    println("SHA256摘要: ${hexResult}")

    return 0
}

运行结果:

SHA256摘要: a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e

class SHA384

public class SHA384 <: Digest {
    public init()
}

功能:提供 SHA384 算法的实现接口。使用示例见 SHA384 算法示例

父类型:

  • Digest

prop algorithm

public prop algorithm: String

功能:SHA384 摘要算法的算法名称。

类型:String

示例:

import stdx.crypto.digest.*

main() {
    let sha384 = SHA384()

    let algorithm = sha384.algorithm
    println("SHA384算法: ${algorithm}")

    return 0
}

运行结果:

SHA384算法: SHA384

prop blockSize

public prop blockSize: Int64

功能:SHA384 信息块长度,单位字节。

类型:Int64

示例:

import stdx.crypto.digest.*

main() {
    let sha384 = SHA384()

    let blockSize = sha384.blockSize
    println("块大小: ${blockSize}")

    return 0
}

运行结果:

块大小: 128

prop size

public prop size: Int64

功能:SHA384 摘要信息长度,单位字节。

类型:Int64

示例:

import stdx.crypto.digest.*

main() {
    let sha384 = SHA384()

    let size = sha384.size
    println("摘要长度: ${size}")

    return 0
}

运行结果:

摘要长度: 48

init()

public init()

功能:无参构造函数,创建 SHA384 对象。

示例:

import stdx.crypto.digest.*

main() {
    let sha384 = SHA384()

    println("SHA384对象创建成功")
    println("算法: ${sha384.algorithm}")
    println("块大小: ${sha384.blockSize}")
    println("摘要长度: ${sha384.size}")

    return 0
}

运行结果:

SHA384对象创建成功
算法: SHA384
块大小: 128
摘要长度: 48

func finish()

public func finish(): Array<Byte>

功能:返回生成的 SHA384 值,注意调用 finish 后 SHA384 上下文会发生改变,finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

返回值:

  • Array<Byte> - 生成的 SHA384 字节序列。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算,抛此异常。

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    let sha384 = SHA384()
    let data = "Hello, World!".toArray()

    sha384.write(data)

    let result = sha384.finish()
    let hexResult = toHexString(result)
    println("SHA384摘要: ${hexResult}")

    return 0
}

运行结果:

SHA384摘要: 5485cc9b3365b4305dfb4e8337e0a598a574f8242bf17289e0dd6c20a3cd44a089de16ab4ab308f63e44b1170eb5f515

func finish(Array<Byte>)

public func finish(to!: Array<Byte>): Unit

功能:获取生成的信息摘要值,注意调用 finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

参数:

  • to!: Array<Byte> - 目标数组。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算或者指定输出数组大小不等于摘要算法信息长度,抛此异常。

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    let sha384 = SHA384()
    let data = "Hello, World!".toArray()

    sha384.write(data)

    var output = Array<Byte>(sha384.size, repeat: 0)
    sha384.finish(to: output)
    let hexOutput = toHexString(output)
    println("输出摘要: ${hexOutput}")

    return 0
}

运行结果:

输出摘要: 5485cc9b3365b4305dfb4e8337e0a598a574f8242bf17289e0dd6c20a3cd44a089de16ab4ab308f63e44b1170eb5f515

func reset()

public func reset(): Unit

功能:重置 SHA384 对象到初始状态,清理 SHA384 上下文。

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    let sha384 = SHA384()
    let data1 = "Hello".toArray()
    let data2 = "World".toArray()

    sha384.write(data1)
    let result1 = sha384.finish()
    let hexResult1 = toHexString(result1)
    println("第一次摘要: ${hexResult1}")

    sha384.reset() // 重置SHA384对象
    sha384.write(data2)
    let result2 = sha384.finish()
    let hexResult2 = toHexString(result2)
    println("重置后摘要: ${hexResult2}")

    return 0
}

运行结果:

第一次摘要: 3519fe5ad2c596efe3e276a6f351b8fc0b03db861782490d45f7598ebd0ab5fd5520ed102f38c4a5ec834e98668035fc
重置后摘要: ed7ced84875773603af90402e42c65f3b48a5e77f84adc7a19e8f3e8d310101022f552aec70e9e1087b225930c1d260a

func write(Array<Byte>)

public func write(buffer: Array<Byte>): Unit

功能:使用给定的 buffer 更新 SHA384 对象,在调用 finish 前可以多次更新。

参数:

  • buffer: Array<Byte> - 输入字节序列。

异常:

  • CryptoException - 已经调用 finish 进行摘要计算后未重置上下文,抛此异常。

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    let sha384 = SHA384()
    let data1 = "Hello".toArray()
    let data2 = " ".toArray()
    let data3 = "World".toArray()

    sha384.write(data1) // 写入第一部分数据
    sha384.write(data2) // 写入第二部分数据
    sha384.write(data3) // 写入第三部分数据

    let result = sha384.finish()
    let hexResult = toHexString(result)
    println("SHA384摘要: ${hexResult}")

    return 0
}

运行结果:

SHA384摘要: 99514329186b2f6ae4a1329e7ee6c610a729636335174ac6b740f9028396fcc803d0e93863a7c3d90f86beee782f4f3f

class SHA512

public class SHA512 <: Digest {
    public init()
}

功能:提供 SHA512 算法的实现接口。使用示例见 SHA512 算法示例

父类型:

  • Digest

prop algorithm

public prop algorithm: String

功能:SHA512 摘要算法的算法名称。

类型:String

示例:

import stdx.crypto.digest.*

main() {
    let sha512 = SHA512()

    let algorithm = sha512.algorithm
    println("SHA512算法: ${algorithm}")

    return 0
}

运行结果:

SHA512算法: SHA512

prop blockSize

public prop blockSize: Int64

功能:SHA512 信息块长度,单位字节。

类型:Int64

示例:

import stdx.crypto.digest.*

main() {
    let sha512 = SHA512()

    let blockSize = sha512.blockSize
    println("块大小: ${blockSize}")

    return 0
}

运行结果:

块大小: 128

prop size

public prop size: Int64

功能:SHA512 摘要信息长度,单位字节。

类型:Int64

示例:

import stdx.crypto.digest.*

main() {
    let sha512 = SHA512()

    let size = sha512.size
    println("摘要长度: ${size}")

    return 0
}

运行结果:

摘要长度: 64

init()

public init()

功能:无参构造函数,创建 SHA512 对象。

示例:

import stdx.crypto.digest.*

main() {
    let sha512 = SHA512()

    println("SHA512对象创建成功")
    println("算法: ${sha512.algorithm}")
    println("块大小: ${sha512.blockSize}")
    println("摘要长度: ${sha512.size}")

    return 0
}

运行结果:

SHA512对象创建成功
算法: SHA512
块大小: 128
摘要长度: 64

func finish()

public func finish(): Array<Byte>

功能:返回生成的 SHA512 值,注意调用 finish 后 SHA512 上下文会发生改变,finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

返回值:

  • Array<Byte> - 生成的 SHA512 字节序列。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算,抛此异常。

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    let sha512 = SHA512()
    let data = "Hello, World!".toArray()

    sha512.write(data)

    let result = sha512.finish()
    let hexResult = toHexString(result)
    println("SHA512摘要: ${hexResult}")

    return 0
}

运行结果:

SHA512摘要: 374d794a95cdcfd8b35993185fef9ba368f160d8daf432d08ba9f1ed1e5abe6cc69291e0fa2fe0006a52570ef18c19def4e617c33ce52ef0a6e5fbe318cb0387

func finish(Array<Byte>)

public func finish(to!: Array<Byte>): Unit

功能:获取生成的信息摘要值,注意调用 finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

参数:

  • to!: Array<Byte> - 目标数组。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算或者指定输出数组大小不等于摘要算法信息长度,抛此异常。

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    let sha512 = SHA512()
    let data = "Hello, World!".toArray()

    sha512.write(data)

    var output = Array<Byte>(sha512.size, repeat: 0)
    sha512.finish(to: output)
    let hexOutput = toHexString(output)
    println("输出摘要: ${hexOutput}")

    return 0
}

运行结果:

输出摘要: 374d794a95cdcfd8b35993185fef9ba368f160d8daf432d08ba9f1ed1e5abe6cc69291e0fa2fe0006a52570ef18c19def4e617c33ce52ef0a6e5fbe318cb0387

func reset()

public func reset(): Unit

功能:重置 SHA512 对象到初始状态,清理 SHA512 上下文。

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    let sha512 = SHA512()
    let data1 = "Hello".toArray()
    let data2 = "World".toArray()

    sha512.write(data1)
    let result1 = sha512.finish()
    let hexResult1 = toHexString(result1)
    println("第一次摘要: ${hexResult1}")

    sha512.reset() // 重置SHA512对象
    sha512.write(data2)
    let result2 = sha512.finish()
    let hexResult2 = toHexString(result2)
    println("重置后摘要: ${hexResult2}")

    return 0
}

运行结果:

第一次摘要: 3615f80c9d293ed7402687f94b22d58e529b8cc7916f8fac7fddf7fbd5af4cf777d3d795a7a00a16bf7e7f3fb9561ee9baae480da9fe7a18769e71886b03f315
重置后摘要: 8ea77393a42ab8fa92500fb077a9509cc32bc95e72712efa116edaf2edfae34fbb682efdd6c5dd13c117e08bd4aaef71291d8aace2f890273081d0677c16df0f

func write(Array<Byte>)

public func write(buffer: Array<Byte>): Unit

功能:使用给定的 buffer 更新 SHA512 对象,在调用 finish 前可以多次更新。

参数:

  • buffer: Array<Byte> - 输入字节序列。

异常:

  • CryptoException - 已经调用 finish 进行摘要计算后未重置上下文,抛此异常。

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    let sha512 = SHA512()
    let data1 = "Hello".toArray()
    let data2 = " ".toArray()
    let data3 = "World".toArray()

    sha512.write(data1) // 写入第一部分数据
    sha512.write(data2) // 写入第二部分数据
    sha512.write(data3) // 写入第三部分数据

    let result = sha512.finish()
    let hexResult = toHexString(result)
    println("SHA512摘要: ${hexResult}")

    return 0
}

运行结果:

SHA512摘要: 2c74fd17edafd80e8447b0d46741ee243b7eb74dd2149a0ab1b9246fb30382f27e853d8585719e0e67cbda0daa8f51671064615d645ae27acb15bfb1447f459b

class SM3

public class SM3 <: Digest {
    public init()
}

功能:提供 SM3 算法的实现接口。使用示例见 SM3 算法示例

父类型:

  • Digest

prop algorithm

public prop algorithm: String

功能:SM3 摘要算法的算法名称。

类型:String

示例:

import stdx.crypto.digest.*

main() {
    let sm3 = SM3()

    let algorithm = sm3.algorithm
    println("SM3算法: ${algorithm}")

    return 0
}

运行结果:

SM3算法: SM3

prop blockSize

public prop blockSize: Int64

功能:SM3 信息块长度,单位字节。

类型:Int64

示例:

import stdx.crypto.digest.*

main() {
    let sm3 = SM3()

    let blockSize = sm3.blockSize
    println("块大小: ${blockSize}")

    return 0
}

运行结果:

块大小: 64

prop size

public prop size: Int64

功能:SM3 摘要信息长度,单位字节。

类型:Int64

示例:

import stdx.crypto.digest.*

main() {
    let sm3 = SM3()

    let size = sm3.size
    println("摘要长度: ${size}")

    return 0
}

运行结果:

摘要长度: 32

init()

public init()

功能:无参构造函数,创建 SM3 对象。

示例:

import stdx.crypto.digest.*

main() {
    let sm3 = SM3()

    println("SM3对象创建成功")
    println("算法: ${sm3.algorithm}")
    println("块大小: ${sm3.blockSize}")
    println("摘要长度: ${sm3.size}")

    return 0
}

运行结果:

SM3对象创建成功
算法: SM3
块大小: 64
摘要长度: 32

func finish()

public func finish(): Array<Byte>

功能:返回生成的 SM3 值,注意调用 finish 后 SM3 上下文会发生改变,finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

返回值:

  • Array<Byte> - 生成的 SM3 字节序列。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算,抛此异常。

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    let sm3 = SM3()
    let data = "Hello, World!".toArray()

    sm3.write(data)

    let result = sm3.finish()
    let hexResult = toHexString(result)
    println("SM3摘要: ${hexResult}")

    return 0
}

运行结果:

SM3摘要: 7ed26cbf0bee4ca7d55c1e64714c4aa7d1f163089ef5ceb603cd102c81fbcbc5

func finish(Array<Byte>)

public func finish(to!: Array<Byte>): Unit

功能:获取生成的信息摘要值,注意调用 finish 后不可以再进行摘要计算,如重新计算需要 reset 重置上下文。

参数:

  • to!: Array<Byte> - 目标数组。

异常:

  • CryptoException - 未重置上下文再次调用 finish 进行摘要计算或者指定输出数组大小不等于摘要算法信息长度,抛此异常。

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    let sm3 = SM3()
    let data = "Hello, World!".toArray()

    sm3.write(data)

    var output = Array<Byte>(sm3.size, repeat: 0)
    sm3.finish(to: output)
    let hexOutput = toHexString(output)
    println("输出摘要: ${hexOutput}")

    return 0
}

运行结果:

输出摘要: 7ed26cbf0bee4ca7d55c1e64714c4aa7d1f163089ef5ceb603cd102c81fbcbc5

func reset()

public func reset(): Unit

功能:重置 SM3 对象到初始状态,清理 SM3 上下文。

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    let sm3 = SM3()
    let data1 = "Hello".toArray()
    let data2 = "World".toArray()

    sm3.write(data1)
    let result1 = sm3.finish()
    let hexResult1 = toHexString(result1)
    println("第一次摘要: ${hexResult1}")

    sm3.reset() // 重置SM3对象
    sm3.write(data2)
    let result2 = sm3.finish()
    let hexResult2 = toHexString(result2)
    println("重置后摘要: ${hexResult2}")

    return 0
}

运行结果:

第一次摘要: dc74f051ad5bc19ba721bf0023e10de03bae29bbe013c43988bae55828bcebbc
重置后摘要: 5c54fe15f19a6b15bb0dcf4d1aef6b6c6439d95aacfea9e86bb7e6ba569b081a

func write(Array<Byte>)

public func write(buffer: Array<Byte>): Unit

功能:使用给定的 buffer 更新 SM3 对象,在调用 finish 前可以多次更新。

参数:

  • buffer: Array<Byte> - 输入字节序列。

异常:

  • CryptoException - 已经调用 finish 进行摘要计算后未重置上下文,抛此异常。

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    let sm3 = SM3()
    let data1 = "Hello".toArray()
    let data2 = " ".toArray()
    let data3 = "World".toArray()

    sm3.write(data1) // 写入第一部分数据
    sm3.write(data2) // 写入第二部分数据
    sm3.write(data3) // 写入第三部分数据

    let result = sm3.finish()
    let hexResult = toHexString(result)
    println("SM3摘要: ${hexResult}")

    return 0
}

运行结果:

SM3摘要: 77015816143ee627f4fa410b6dad2bdb9fcbdf1e061a452a686b8711a484c5d7

结构体

struct HashType

public struct HashType <: ToString & Equatable<HashType>

功能:此类为 Hash 算法类别结构体,MD5SHA1SHA224SHA256SHA384SHA512 均为常用摘要算法。

父类型:

prop MD5

public static prop MD5: HashType

功能:返回 MD5 类型。

类型:HashType

示例:

import stdx.crypto.digest.*

main() {
    let md5Type = HashType.MD5
    println("MD5类型: ${md5Type}")

    return 0
}

运行结果:

MD5类型: MD5

prop SHA1

public static prop SHA1: HashType

功能:返回 SHA1 类型。

类型:HashType

示例:

import stdx.crypto.digest.*

main() {
    let sha1Type = HashType.SHA1
    println("SHA1类型: ${sha1Type}")

    return 0
}

运行结果:

SHA1类型: SHA1

prop SHA224

public static prop SHA224: HashType

功能:返回 SHA224 类型。

类型:HashType

示例:

import stdx.crypto.digest.*

main() {
    let sha224Type = HashType.SHA224
    println("SHA224类型: ${sha224Type}")

    return 0
}

运行结果:

SHA224类型: SHA224

prop SHA256

public static prop SHA256: HashType

功能:返回 SHA256 类型。

类型:HashType

示例:

import stdx.crypto.digest.*

main() {
    let sha256Type = HashType.SHA256
    println("SHA256类型: ${sha256Type}")

    return 0
}

运行结果:

SHA256类型: SHA256

prop SHA384

public static prop SHA384: HashType

功能:返回 SHA384 类型。

类型:HashType

示例:

import stdx.crypto.digest.*

main() {
    let sha384Type = HashType.SHA384
    println("SHA384类型: ${sha384Type}")

    return 0
}

运行结果:

SHA384类型: SHA384

prop SHA512

public static prop SHA512: HashType

功能:返回 SHA512 类型。

类型:HashType

示例:

import stdx.crypto.digest.*

main() {
    let sha512Type = HashType.SHA512
    println("SHA512类型: ${sha512Type}")

    return 0
}

运行结果:

SHA512类型: SHA512

prop SM3

public static prop SM3: HashType

功能:返回 SM3 类型。

类型:HashType

示例:

import stdx.crypto.digest.*

main() {
    let sm3Type = HashType.SM3
    println("SM3类型: ${sm3Type}")

    return 0
}

运行结果:

SM3类型: SM3

func toString()

public func toString(): String

功能:获取 Hash 算法名称。

返回值:

  • String - Hash 算法名称。

示例:

import stdx.crypto.digest.*

main() {
    let md5Type = HashType.MD5
    let sha1Type = HashType.SHA1

    let md5Name = md5Type.toString()
    let sha1Name = sha1Type.toString()

    println("MD5名称: ${md5Name}")
    println("SHA1名称: ${sha1Name}")

    return 0
}

运行结果:

MD5名称: MD5
SHA1名称: SHA1

operator func !=(HashType)

public override operator func !=(other: HashType): Bool

功能:判断两 HashType 是否引用不同实例。

参数:

  • other: HashType - 对比的 HashType。

返回值:

  • Bool - 不相同返回 true;否则,返回 false

示例:

import stdx.crypto.digest.*

main() {
    let md5Type = HashType.MD5
    let sha1Type = HashType.SHA1
    let anotherMd5Type = HashType.MD5

    let isNotEqual1 = md5Type != sha1Type
    let isNotEqual2 = md5Type != anotherMd5Type

    println("MD5 != SHA1: ${isNotEqual1}")
    println("MD5 != MD5: ${isNotEqual2}")

    return 0
}

运行结果:

MD5 != SHA1: true
MD5 != MD5: false

operator func ==(HashType)

public override operator func ==(other: HashType): Bool

功能:判断两 HashType 是否引用同一实例。

参数:

  • other: HashType - 对比的 HashType。

返回值:

  • Bool - 相同返回 true;否则,返回 false

示例:

import stdx.crypto.digest.*

main() {
    let md5Type = HashType.MD5
    let sha1Type = HashType.SHA1
    let anotherMd5Type = HashType.MD5

    let isEqual1 = md5Type == sha1Type
    let isEqual2 = md5Type == anotherMd5Type

    println("MD5 == SHA1: ${isEqual1}")
    println("MD5 == MD5: ${isEqual2}")

    return 0
}

运行结果:

MD5 == SHA1: false
MD5 == MD5: true

digest 使用

MD5 算法示例

调用 MD5 成员函数

示例:

import stdx.crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import stdx.encoding.hex.*

main() {
    var str: String = "helloworld"
    var md5Instance = MD5()
    md5Instance.write(str.toArray())
    var md: Array<Byte> = md5Instance.finish()
    var result: String = toHexString(md)
    println(result)
    return 0
}

运行结果:

fc5e038d38a57032085441e7fe7010b0

SHA1 算法示例

调用 SHA1 成员函数

示例:

import stdx.crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import stdx.encoding.hex.*

main() {
    var str: String = "helloworld"
    var sha1Instance = SHA1()
    sha1Instance.write(str.toArray())
    var md: Array<Byte> = sha1Instance.finish()
    var result: String = toHexString(md)
    println(result)
    return 0
}

运行结果:

6adfb183a4a2c94a2f92dab5ade762a47889a5a1

SHA224 算法示例

调用 SHA224 成员函数

示例:

import stdx.crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import stdx.encoding.hex.*

main() {
    var str: String = "helloworld"
    var sha224Instance = SHA224()
    sha224Instance.write(str.toArray())
    var md: Array<Byte> = sha224Instance.finish()
    var result: String = toHexString(md)
    println(result)
    return 0
}

运行结果:

b033d770602994efa135c5248af300d81567ad5b59cec4bccbf15bcc

SHA256 算法示例

调用 SHA256 成员函数

示例:

import stdx.crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import stdx.encoding.hex.*

main() {
    var str: String = "helloworld"
    var sha256Instance = SHA256()
    sha256Instance.write(str.toArray())
    var md: Array<Byte> = sha256Instance.finish()
    var result: String = toHexString(md)
    println(result)
    return 0
}

运行结果:

936a185caaa266bb9cbe981e9e05cb78cd732b0b3280eb944412bb6f8f8f07af

SHA384 算法示例

调用 SHA384 成员函数

示例:

import stdx.crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import stdx.encoding.hex.*

main() {
    var str: String = "helloworld"
    var sha384Instance = SHA384()
    sha384Instance.write(str.toArray())
    var md: Array<Byte> = sha384Instance.finish()
    var result: String = toHexString(md)
    println(result)
    return 0
}

运行结果:

97982a5b1414b9078103a1c008c4e3526c27b41cdbcf80790560a40f2a9bf2ed4427ab1428789915ed4b3dc07c454bd9

SHA512 算法示例

调用 SHA512 成员函数

示例:

import stdx.crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import stdx.encoding.hex.*

main() {
    var str: String = "helloworld"
    var sha512Instance = SHA512()
    sha512Instance.write(str.toArray())
    var md: Array<Byte> = sha512Instance.finish()
    var result: String = toHexString(md)
    println(result)
    return 0
}

运行结果:

1594244d52f2d8c12b142bb61f47bc2eaf503d6d9ca8480cae9fcf112f66e4967dc5e8fa98285e36db8af1b8ffa8b84cb15e0fbcf836c3deb803c13f37659a60

HMAC 算法示例

说明

目前只支持 HMAC-SHA512。

调用 HMAC-SHA512 成员函数

示例:

import stdx.crypto.digest.*
import stdx.encoding.hex.*

main() {
    var algorithm: HashType = HashType.SHA512
    var key: Array<UInt8> = "cangjie".toArray()
    var data1: Array<UInt8> = "123".toArray()
    var data2: Array<UInt8> = "456".toArray()
    var data3: Array<UInt8> = "789".toArray()
    var data4: Array<UInt8> = "123456789".toArray()
    var hmac = HMAC(key, algorithm)
    hmac.write(data1)
    hmac.write(data2)
    hmac.write(data3)
    var md1: Array<Byte> = hmac.finish()
    var result1: String = toHexString(md1)
    println(result1)

    hmac.reset()
    hmac.write(data4)
    var md2: Array<Byte> = hmac.finish()
    var result2: String = toHexString(md2)
    println(result2)
    println(HMAC.equal(md1, md2))
    return 0
}

运行结果:

2bafeb53b60a119d38793a886c7744f5027d7eaa3702351e75e4ff9bf255e3ce296bf41f80adda2861e81bd8efc52219df821852d84a17fb625e3965ebf2fdd9
2bafeb53b60a119d38793a886c7744f5027d7eaa3702351e75e4ff9bf255e3ce296bf41f80adda2861e81bd8efc52219df821852d84a17fb625e3965ebf2fdd9
true

SM3 算法示例

调用 SM3 成员函数

示例:

import stdx.crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import stdx.encoding.hex.*

main() {
    var str: String = "helloworld"
    var sm3Instance = SM3()
    sm3Instance.write(str.toArray())
    var md: Array<Byte> = sm3Instance.finish()
    var result: String = toHexString(md)
    println(result)
    return 0
}

运行结果:

c70c5f73da4e8b8b73478af54241469566f6497e16c053a03a0170fa00078283

stdx.crypto.keys

功能介绍

keys 包提供非对称加密和签名算法,包括 RSA 和 SM2 非对称加密算法以及 ECDSA 签名算法。

使用本包需要外部依赖 OpenSSL 3 的 crypto 动态库文件,故使用前需安装相关工具。

  • 对于 Linux 操作系统,可参考以下方式:

    • 如果系统的包管理工具支持安装 OpenSSL 3 开发工具包,可通过这个方式安装,并确保系统安装目录下含有 libcrypto.so 和 libcrypto.so.3 这两个动态库文件,例如 Ubuntu 22.04 系统上可使用 sudo apt install libssl-dev 命令安装 libssl-dev 工具包;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libcrypto.so 和 libcrypto.so.3 这两个动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 LD_LIBRARY_PATH 以及 LIBRARY_PATH 中。
  • 对于 Windows 操作系统,可按照以下步骤:

    • 自行下载 OpenSSL 3.x.x 源码编译安装 x64 架构软件包或者自行下载安装第三方预编译的供开发人员使用的 OpenSSL 3.x.x 软件包;
    • 确保安装目录下含有 libcrypto.dll.a(或 libcrypto.lib)、libcrypto-3-x64.dll 这两个库文件;
    • 将 libcrypto.dll.a(或 libcrypto.lib)所在的目录路径设置到环境变量 LIBRARY_PATH 中,将 libcrypto-3-x64.dll 所在的目录路径设置到环境变量 PATH 中。
  • 对于 macOS 操作系统,可参考以下方式:

    • 使用 brew install openssl@3 安装,并确保系统安装目录下含有 libcrypto.dylib 和 libcrypto.3.dylib 这两个动态库文件;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libcrypto.dylib 和 libcrypto.3.dylib 这两个动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 DYLD_LIBRARY_PATH 以及 LIBRARY_PATH 中。
  • 对于 Android 操作系统,可参考以下方式:

    • 由于 Android 系统默认自带的 OpenSSL 是裁剪版本,部分接口可能找不到符号而抛出异常,因此需要用户自行编译安装完整的 OpenSSL 3.x.x 版本;
    • 可自行下载 OpenSSL 3.x.x 源码,使用 Android NDK 交叉编译生成对应架构(当前只支持 arm64-v8a)的动态库文件,确保编译产物中含有 libcrypto.so 和 libcrypto.so.3 这些动态库文件;
    • 将这些文件所在目录设置到环境变量 LD_LIBRARY_PATH 中。

说明:

如果未安装 OpenSSL 3 软件包或者安装低版本的软件包,程序可能无法使用并抛出相关异常 CryptoException:Can not load openssl library or function xxx。

API 列表

类名功能
ECDSAPrivateKeyECDSA 私钥类。
ECDSAPublicKeyECDSA 公钥类。
GeneralPrivateKey通用的私钥参数加解密功能实现。
GeneralPublicKey通用的公钥参数加解密功能实现。
RSAPrivateKeyRSA 私钥类。
RSAPublicKeyRSA 公钥类。
SM2PrivateKeySM2 私钥类。
SM2PublicKeySM2 公钥类。

枚举

枚举名功能
Curve枚举类型 Curve 用于选择生成 ECDSA 密钥时使用的椭圆曲线类型。
PadOption用于设置 RSA 的填充模式。

结构体

结构体名功能
OAEPOption最优非对称加密填充。
PSSOption概率签名方案。

class ECDSAPrivateKey

public class ECDSAPrivateKey <: PrivateKey {
    public init(curve: Curve)
}

功能:ECDSA 私钥类,提供生成 ECDSA 私钥能力,ECDSA 的私钥支持签名操作,同时支持 PEM 和 DER 格式的编码解码。使用示例见 ECDSA 密钥示例

父类型:

init(Curve)

public init(curve: Curve)

功能:init 初始化生成私钥。

参数:

  • curve: Curve - 椭圆曲线类型。

异常:

示例:

import stdx.crypto.keys.*

main() {
    let key = ECDSAPrivateKey(Curve.P256)
    println("ECDSA私钥创建成功")
    println("密钥类型: ${key}")

    return 0
}

运行结果:

ECDSA私钥创建成功
密钥类型: ECDSA PRIVATE KEY

static func decodeDer(DerBlob)

public static func decodeDer(blob: DerBlob): ECDSAPrivateKey

功能:将私钥从 DER 格式解码。

参数:

  • blob: DerBlob - 二进制格式的私钥对象。

返回值:

异常:

示例:

import stdx.crypto.keys.*

main() {
    // 模拟场景:从外部(文件/网络)获取的 DerBlob(此处通过生成私钥并编码模拟)
    let originalKey = ECDSAPrivateKey(Curve.P256)
    let encodedBlob = originalKey.encodeToDer()

    // 核心演示:从 DerBlob 解码还原 ECDSA 私钥
    let decodedKey = ECDSAPrivateKey.decodeDer(encodedBlob)
    println("解码成功")
    println("解码后密钥类型: ${decodedKey}")

    return 0
}

运行结果:

解码成功
解码后密钥类型: ECDSA PRIVATE KEY

static func decodeDer(DerBlob, ?String)

public static func decodeDer(blob: DerBlob, password!: ?String): ECDSAPrivateKey

功能:将加密的私钥从 DER 格式解码。

参数:

  • blob: DerBlob - 二进制格式的私钥对象。
  • password!: ?String - 解密私钥需要提供的密码,密码为 None 时则不解密。

返回值:

异常:

  • CryptoException - 解码失败、解密失败或者参数密码为空字符串,抛出异常。

示例:

import stdx.crypto.keys.*

main() {
    // 模拟场景:从外部(文件/网络)获取的 DerBlob(此处通过生成私钥并编码模拟)
    let originalKey = ECDSAPrivateKey(Curve.P256)
    let encodedBlob = originalKey.encodeToDer(password: "mypassword")

    // 核心演示:从 DerBlob 解码还原 ECDSA 私钥
    let decodedKey = ECDSAPrivateKey.decodeDer(encodedBlob, password: "mypassword")
    println("解码加密DER成功")
    println("解码后密钥类型: ${decodedKey}")

    return 0
}

运行结果:

解码加密DER成功
解码后密钥类型: ECDSA PRIVATE KEY

static func decodeFromPem(String)

public static func decodeFromPem(text: String): ECDSAPrivateKey

功能:将私钥从 PEM 格式解码。

参数:

  • text: String - PEM 格式的私钥字符流。

返回值:

异常:

  • CryptoException - 解码失败、字符流不符合 PEM 格式或文件头不符合私钥头标准时,抛出异常。

示例:

import stdx.crypto.keys.*

main() {
    // 模拟场景:从外部(文件/网络)获取的 PEM 字符串
    let originalKey = ECDSAPrivateKey(Curve.P256)
    let pemEntry = originalKey.encodeToPem()
    let pemString = pemEntry.encode()

    // 核心演示:从 PEM 字符串解码还原 ECDSA 私钥
    let decodedKey = ECDSAPrivateKey.decodeFromPem(pemString)
    println("从PEM解码成功")
    println("解码后密钥类型: ${decodedKey}")

    return 0
}

运行结果:

从PEM解码成功
解码后密钥类型: ECDSA PRIVATE KEY

static func decodeFromPem(String, ?String)

public static func decodeFromPem(text: String, password!: ?String): ECDSAPrivateKey

功能:将私钥从 PEM 格式解码。

参数:

  • text: String - PEM 格式的私钥字符流。
  • password!: ?String - 解密私钥需要提供的密码,密码为 None 时则不解密。

返回值:

异常:

  • CryptoException - 解码失败、解密失败、参数密码为空字符串、字符流不符合 PEM 格式或文件头不符合私钥头标准时,抛出异常。

示例:

import stdx.crypto.keys.*

main() {
    // 模拟场景:从外部(文件/网络)获取的 PEM 字符串
    let originalKey = ECDSAPrivateKey(Curve.P256)
    let pemEntry = originalKey.encodeToPem(password: "mypassword")
    let pemString = pemEntry.encode()

    // 核心演示:从加密的 PEM 字符串解码还原 ECDSA 私钥
    let decodedKey = ECDSAPrivateKey.decodeFromPem(pemString, password: "mypassword")
    println("从加密PEM解码成功")
    println("解码后密钥类型: ${decodedKey}")

    return 0
}

运行结果:

从加密PEM解码成功
解码后密钥类型: ECDSA PRIVATE KEY

func encodeToDer()

public override func encodeToDer(): DerBlob

功能:将私钥编码为 DER 格式。

返回值:

  • DerBlob - 编码后的 Der 格式私钥。

异常:

示例:

import stdx.crypto.keys.*

main() {
    let key = ECDSAPrivateKey(Curve.P256)
    let derBlob = key.encodeToDer()

    println("编码为DER格式成功")
    println("DER数据大小: ${derBlob.size}")

    return 0
}

运行结果:

编码为DER格式成功
DER数据大小: 121

func encodeToDer(?String)

public func encodeToDer(password!: ?String): DerBlob

功能:使用 AES-256-CBC 加密私钥,将私钥编码为 DER 格式。

参数:

  • password!: ?String - 加密私钥需要提供的密码,密码为 None 时则不加密。

返回值:

  • DerBlob - 编码后的 DER 格式私钥。

异常:

  • CryptoException - 编码失败、加密失败或者参数密码为空字符串,抛出异常。

示例:

import stdx.crypto.keys.*

main() {
    let key = ECDSAPrivateKey(Curve.P256)
    let derBlob = key.encodeToDer(password: "mypassword")

    println("编码为加密DER格式成功")
    println("DER数据大小: ${derBlob.size}")

    return 0
}

运行结果:

编码为加密DER格式成功
DER数据大小: 239

func encodeToPem()

public func encodeToPem(): PemEntry

功能:将私钥编码为 PEM 格式。

返回值:

  • PemEntry - 私钥 PEM 格式的对象。

异常:

示例:

import stdx.crypto.keys.*

main() {
    let key = ECDSAPrivateKey(Curve.P256)
    let pemEntry = key.encodeToPem()

    println("编码为PEM格式成功")
    println("PEM标签: ${pemEntry.label}")

    return 0
}

运行结果:

编码为PEM格式成功
PEM标签: EC PRIVATE KEY

func encodeToPem(?String)

public func encodeToPem(password!: ?String): PemEntry

功能:将加密的私钥编码为 PEM 格式。

参数:

  • password!: ?String - 加密私钥需要提供的密码,密码为 None 时则不加密。

返回值:

  • PemEntry - 私钥 PEM 格式的对象。

异常:

  • CryptoException - 编码失败、加密失败或者参数密码为空字符串,抛出异常。

示例:

import stdx.crypto.keys.*

main() {
    let key = ECDSAPrivateKey(Curve.P256)
    let pemEntry = key.encodeToPem(password: "mypassword")

    println("编码为加密PEM格式成功")
    println("PEM标签: ${pemEntry.label}")

    return 0
}

运行结果:

编码为加密PEM格式成功
PEM标签: ENCRYPTED PRIVATE KEY

func sign(Array<Byte>)

public func sign(digest: Array<Byte>): Array<Byte>

功能:sign 对数据的摘要结果进行签名。

参数:

  • digest: Array<Byte> - 数据的摘要结果。

返回值:

  • Array<Byte> - 签名后的数据。

异常:

示例:

import stdx.crypto.keys.*
import stdx.crypto.digest.*

main() {
    let priKey = ECDSAPrivateKey(Curve.P256)
    let data = "Hello, World!".toArray()

    // 先计算数据的摘要
    let sha256 = SHA256()
    sha256.write(data)
    let digest = sha256.finish()

    let signature = priKey.sign(digest)
    println("签名成功")
    println("签名长度: ${signature.size}")

    return 0
}

可能的运行结果:

签名成功
签名长度: 70

func toString()

public override func toString(): String

功能:输出私钥种类。

返回值:

  • String - 密钥类别描述。

示例:

import stdx.crypto.keys.*

main() {
    let key = ECDSAPrivateKey(Curve.P256)

    let keyType = key.toString()
    println("密钥类型: ${keyType}")

    return 0
}

运行结果:

密钥类型: ECDSA PRIVATE KEY

class ECDSAPublicKey

public class ECDSAPublicKey <: PublicKey {
    public init(pri: ECDSAPrivateKey)
}

功能:ECDSA 公钥类,提供生成 ECDSA 公钥能力,ECDSA 公钥支持验证签名操作,支持 PEM 和 DER 格式的编码解码。使用示例见 ECDSA 密钥示例

父类型:

init(ECDSAPrivateKey)

public init(pri: ECDSAPrivateKey)

功能:init 初始化公钥,从私钥中获取对应的公钥。

参数:

异常:

示例:

import stdx.crypto.keys.*

main() {
    let priKey = ECDSAPrivateKey(P256)
    // 公钥需要从私钥派生
    let pubKey = ECDSAPublicKey(priKey)

    println("ECDSA公钥创建成功")
    println("公钥类型: ${pubKey}")

    return 0
}

运行结果:

ECDSA公钥创建成功
公钥类型: ECDSA PUBLIC KEY

static func decodeDer(DerBlob)

public static func decodeDer(blob: DerBlob): ECDSAPublicKey

功能:将公钥从 DER 格式解码。

参数:

  • blob: DerBlob - 二进制格式的公钥对象。

返回值:

异常:

示例:

import stdx.crypto.keys.*

main() {
    // 模拟场景:从外部(文件/网络)获取的 DER 字节数组
    let priKey = ECDSAPrivateKey(P256)
    let pubKey = ECDSAPublicKey(priKey)
    let derBlob = pubKey.encodeToDer()

    // 从 DER 字节数组解码公钥
    let decodedPubKey = ECDSAPublicKey.decodeDer(derBlob)
    println("从DER解码公钥成功")
    println("解码后公钥类型: ${decodedPubKey}")

    return 0
}

运行结果:

从DER解码公钥成功
解码后公钥类型: ECDSA PUBLIC KEY

static func decodeFromPem(String)

public static func decodeFromPem(text: String): ECDSAPublicKey

功能:将公钥从 PEM 格式解码。

参数:

  • text: String - PEM 格式的公钥字符流。

返回值:

异常:

  • CryptoException - 解码失败、字符流不符合 PEM 格式或文件头不符合公钥头标准时,抛出异常。

示例:

import stdx.crypto.keys.*

main() {
    // 模拟场景:从外部(文件/网络)获取的 PEM 字符串
    let priKey = ECDSAPrivateKey(P256)
    let pubKey = ECDSAPublicKey(priKey)
    let pemEntry = pubKey.encodeToPem()
    let pemString = pemEntry.encode()

    // 从 PEM 字符串解码公钥
    let decodedPubKey = ECDSAPublicKey.decodeFromPem(pemString)
    println("从PEM解码公钥成功")
    println("解码后公钥类型: ${decodedPubKey}")

    return 0
}

运行结果:

从PEM解码公钥成功
解码后公钥类型: ECDSA PUBLIC KEY

func encodeToDer()

public override func encodeToDer(): DerBlob

功能:将公钥编码为 DER 格式。

返回值:

  • DerBlob - 编码后的 Der 格式公钥。

异常:

示例:

import stdx.crypto.keys.*

main() {
    let priKey = ECDSAPrivateKey(P256)
    // 公钥需要从私钥派生
    let pubKey = ECDSAPublicKey(priKey)
    let derBlob = pubKey.encodeToDer()

    println("编码为DER格式成功")
    println("DER数据大小: ${derBlob.size}")

    return 0
}

运行结果:

编码为DER格式成功
DER数据大小: 91

func encodeToPem()

public func encodeToPem(): PemEntry

功能:将公钥编码为 PEM 格式。

返回值:

异常:

示例:

import stdx.crypto.keys.*

main() {
    let priKey = ECDSAPrivateKey(P256)
    // 公钥需要从私钥派生
    let pubKey = ECDSAPublicKey(priKey)
    let pemEntry = pubKey.encodeToPem()

    println("编码为PEM格式成功")
    println("PEM标签: ${pemEntry.label}")

    return 0
}

运行结果:

编码为PEM格式成功
PEM标签: PUBLIC KEY

func toString()

public override func toString(): String

功能:输出公钥种类。

返回值:

  • String - 密钥类别描述。

示例:

import stdx.crypto.keys.*

main() {
    let priKey = ECDSAPrivateKey(P256)
    let pubKey = ECDSAPublicKey(priKey)

    let keyType = pubKey.toString()
    println("公钥类型: ${keyType}")

    return 0
}

运行结果:

公钥类型: ECDSA PUBLIC KEY

func verify(Array<Byte>, Array<Byte>)

public func verify(digest: Array<Byte>, sig: Array<Byte>): Bool

功能:verify 验证签名结果。

参数:

  • digest: Array<Byte> - 数据的摘要结果。
  • sig: Array<Byte> - 数据的签名结果。

返回值:

  • Bool - 返回 true 表示验证成功,false 失败。

示例:

import stdx.crypto.keys.*
import stdx.crypto.digest.*

main() {
    let priKey = ECDSAPrivateKey(P256)
    let pubKey = ECDSAPublicKey(priKey)
    let data = "Hello, World!".toArray()

    // 计算数据摘要
    let sha256 = SHA256()
    sha256.write(data)
    let digest = sha256.finish()

    // 使用私钥签名
    let signature = priKey.sign(digest)

    // 使用公钥验证签名
    let isValid = pubKey.verify(digest, signature)
    println("签名验证结果: ${isValid}")

    // 验证错误的签名
    let wrongData = "Wrong data".toArray()
    sha256.reset()
    sha256.write(wrongData)
    let wrongDigest = sha256.finish()
    let isWrongValid = pubKey.verify(wrongDigest, signature)
    println("错误数据验证结果: ${isWrongValid}")

    return 0
}

运行结果:

签名验证结果: true
错误数据验证结果: false

class GeneralPrivateKey

public class GeneralPrivateKey <: PrivateKey

功能:通用的私钥参数加解密功能实现。

父类型:

static func decodeDer(DerBlob)

static func decodeDer(encoded: DerBlob): PrivateKey

功能:将私钥从 DER 格式解码。

参数:

  • encoded: DerBlob - DER 格式的私钥对象。

返回值:

  • PrivateKey - 由 DER 格式解码出的私钥。

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.keys.*
import stdx.crypto.common.*

main() {
    // 生成测试用文件
    let privatePem = "./test_private.key"
    let privateDer = "./test_private.der"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl genrsa -out ${privatePem} 2048; " +
        "openssl rsa -in ${privatePem} -out ${privateDer} -outform der"

    executeWithOutput("sh", ["-c", cmdStr])

    // 核心演示:从 DerBlob 解码还原私钥
    let decodedKey = GeneralPrivateKey.decodeDer(DerBlob(readToEnd(File(privateDer, Read))))
    println("解码成功")
    println("解码后密钥类型: ${decodedKey}")

    // 删除测试用文件
    removeIfExists(privatePem)
    removeIfExists(privateDer)
    return 0
}

可能的运行结果:

解码成功
解码后密钥类型: PrivateKey(1217 bytes, RSA 2048 bits)

static func decodeDer(DerBlob, ?String)

static func decodeDer(encoded: DerBlob, password!: ?String): PrivateKey

功能:将 DER 格式的私钥解密解码成 PrivateKey 对象,密码为 None 时则不解密。

参数:

  • encoded: DerBlob - DER 格式的私钥。
  • password!: ?String - 解密密码。

返回值:

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.keys.*
import stdx.crypto.common.*

main() {
    // 生成测试用加密文件
    let privatePem = "./test_private.key"
    let privateDer = "./test_private.der"
    let password = "mypassword"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl genrsa -out ${privatePem} 2048; " +
        "openssl rsa -in ${privatePem} -aes256 -passout pass:${password} -out ${privateDer} -outform der"

    executeWithOutput("sh", ["-c", cmdStr])

    // 核心演示:从加密的 DerBlob 解码还原私钥
    let decodedKey = GeneralPrivateKey.decodeDer(DerBlob(readToEnd(File(privateDer, Read))), password: password)
    println("解码加密DER成功")
    println("解码后密钥类型: ${decodedKey}")

    // 删除测试用文件
    removeIfExists(privatePem)
    removeIfExists(privateDer)
    return 0
}

可能的运行结果:

解码加密DER成功
解码后密钥类型: PrivateKey(1217 bytes, RSA 2048 bits)

static func decodeFromPem(String)

static func decodeFromPem(text: String): PrivateKey

功能:将私钥从 PEM 格式解码。

参数:

  • text: String - PEM 格式的私钥字符流。

返回值:

  • PrivateKey - 由 PEM 格式解码出的私钥。

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.keys.*

main() {
    // 生成测试用文件
    let privatePem = "./test_private.key"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl genrsa -out ${privatePem} 2048"

    executeWithOutput("sh", ["-c", cmdStr])

    // 核心演示:从 PEM 字符串解码还原私钥
    let pemContent = String.fromUtf8(readToEnd(File(privatePem, Read)))
    let decodedKey = GeneralPrivateKey.decodeFromPem(pemContent)
    println("从PEM解码成功")
    println("解码后密钥类型: ${decodedKey}")

    // 删除测试用文件
    removeIfExists(privatePem)
    return 0
}

可能的运行结果:

从PEM解码成功
解码后密钥类型: PrivateKey(1217 bytes, RSA 2048 bits)

static func decodeFromPem(String, ?String)

static func decodeFromPem(text: String, password!: ?String): PrivateKey

功能:将 PEM 格式的私钥解密解码成 PrivateKey 对象,密码为 None 时则不解密。

参数:

  • text: String - PEM 格式的私钥。
  • password!: ?String - 解密密码。

返回值:

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.keys.*

main() {
    // 生成测试用加密文件
    let privatePem = "./test_private.key"
    let password = "mypassword"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl genpkey -algorithm rsa -out ${privatePem} -aes256 -pass pass:${password}"

    executeWithOutput("sh", ["-c", cmdStr])

    // 核心演示:从加密的 PEM 字符串解码还原私钥
    let pemContent = String.fromUtf8(readToEnd(File(privatePem, Read)))
    let decodedKey = GeneralPrivateKey.decodeFromPem(pemContent, password: password)
    println("从加密PEM解码成功")
    println("解码后密钥类型: ${decodedKey}")

    // 删除测试用文件
    removeIfExists(privatePem)
    return 0
}

可能的运行结果:

从加密PEM解码成功
解码后密钥类型: PrivateKey(1217 bytes, RSA 2048 bits)

func encodeToDer()

func encodeToDer(): DerBlob

功能:将私钥编码成 DER 格式。

返回值:

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.keys.*
import stdx.crypto.common.*

main() {
    // 生成测试用文件
    let privatePem = "./test_private.key"
    let privateDer = "./test_private.der"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl genrsa -out ${privatePem} 2048; " +
        "openssl rsa -in ${privatePem} -out ${privateDer} -outform der"

    executeWithOutput("sh", ["-c", cmdStr])

    // 从 DER 文件读取并解码为私钥
    let originalKey = GeneralPrivateKey.decodeDer(DerBlob(readToEnd(File(privateDer, Read))))

    // 核心演示:将私钥编码为 DER 格式
    let encodedBlob = originalKey.encodeToDer()
    println("编码为DER格式成功")
    println("DER数据大小: ${encodedBlob.size}")

    // 删除测试用文件
    removeIfExists(privatePem)
    removeIfExists(privateDer)
    return 0
}

可能的运行结果:

编码为DER格式成功
DER数据大小: 1217

func encodeToDer(?String)

func encodeToDer(password!: ?String): DerBlob

功能:将私钥加密编码成 DER 格式,密码为 None 时则不加密。

参数:

  • password!: ?String - 加密密码。

返回值:

  • DerBlob - 加密后的 DER 格式的私钥。

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.keys.*
import stdx.crypto.common.*

main() {
    // 生成测试用文件
    let privatePem = "./test_private.key"
    let privateDer = "./test_private.der"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl genrsa -out ${privatePem} 2048; " +
        "openssl rsa -in ${privatePem} -out ${privateDer} -outform der"

    executeWithOutput("sh", ["-c", cmdStr])

    // 从 DER 文件读取并解码为私钥
    let originalKey = GeneralPrivateKey.decodeDer(DerBlob(readToEnd(File(privateDer, Read))))

    // 核心演示:将私钥加密编码为 DER 格式
    let encodedBlob = originalKey.encodeToDer(password: "mypassword")
    println("编码为加密DER格式成功")
    println("DER数据大小: ${encodedBlob.size}")

    // 删除测试用文件
    removeIfExists(privatePem)
    removeIfExists(privateDer)
    return 0
}

可能的运行结果:

编码为加密DER格式成功
DER数据大小: 1354

func encodeToPem()

func encodeToPem(): PemEntry

功能:将私钥编码成 PEM 格式。

返回值:

  • PemEntry - 编码后的 PEM 格式的私钥。

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.keys.*

main() {
    // 生成测试用文件
    let privatePem = "./test_private.key"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl genrsa -out ${privatePem} 2048"

    executeWithOutput("sh", ["-c", cmdStr])

    // 从 PEM 文件读取并解码为私钥
    let pemContent = String.fromUtf8(readToEnd(File(privatePem, Read)))
    let originalKey = GeneralPrivateKey.decodeFromPem(pemContent)

    // 核心演示:将私钥编码为 PEM 格式
    let encodedPem = originalKey.encodeToPem()
    println("编码为PEM格式成功")
    println("PEM标签: ${encodedPem.label}")

    // 删除测试用文件
    removeIfExists(privatePem)
    return 0
}

运行结果:

编码为PEM格式成功
PEM标签: PRIVATE KEY

func encodeToPem(?String)

func encodeToPem(password!: ?String): PemEntry

功能:将私钥加密编码成 PEM 格式,密码为 None 时则不加密。

参数:

  • password!: ?String - 加密密码。

返回值:

  • PemEntry - 加密后的 PEM 格式的私钥。

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.keys.*

main() {
    // 生成测试用文件
    let privatePem = "./test_private.key"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl genrsa -out ${privatePem} 2048"

    executeWithOutput("sh", ["-c", cmdStr])

    // 从 PEM 文件读取并解码为私钥
    let pemContent = String.fromUtf8(readToEnd(File(privatePem, Read)))
    let originalKey = GeneralPrivateKey.decodeFromPem(pemContent)

    // 核心演示:将私钥加密编码为 PEM 格式
    let encodedPem = originalKey.encodeToPem(password: "mypassword")
    println("编码为加密PEM格式成功")
    println("PEM标签: ${encodedPem.label}")

    // 删除测试用文件
    removeIfExists(privatePem)
    return 0
}

运行结果:

编码为加密PEM格式成功
PEM标签: ENCRYPTED PRIVATE KEY

func toString()

public func toString(): String

功能:转换为字符串格式。

返回值:

  • String - 字符串。

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.keys.*

main() {
    // 生成测试用文件
    let privatePem = "./test_private.key"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl genrsa -out ${privatePem} 2048"

    executeWithOutput("sh", ["-c", cmdStr])

    // 从 PEM 文件读取并解码为私钥
    let pemContent = String.fromUtf8(readToEnd(File(privatePem, Read)))
    let key = GeneralPrivateKey.decodeFromPem(pemContent)

    // 核心演示:获取私钥类型描述
    let keyType = key.toString()
    println("私钥类型: ${keyType}")

    // 删除测试用文件
    removeIfExists(privatePem)
    return 0
}

可能的运行结果:

私钥类型: PrivateKey(1216 bytes, RSA 2048 bits)

class GeneralPublicKey

public class GeneralPublicKey <: PublicKey

功能:通用的公钥参数加解密功能实现。

父类型:

static func decodeDer(DerBlob)

static func decodeDer(encoded: DerBlob): PublicKey

功能:将公钥从 DER 格式解码。

参数:

  • encoded: DerBlob - DER 格式的公钥对象。

返回值:

  • PublicKey - 由 DER 格式解码出的公钥。

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.keys.*
import stdx.crypto.common.*

main() {
    // 生成测试用文件
    let privatePem = "./test_private.key"
    let publicPem = "./test_public.key"
    let publicDer = "./test_public.der"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl genrsa -out ${privatePem} 2048; " + "openssl rsa -in ${privatePem} -pubout -out ${publicPem}; " +
        "openssl rsa -in ${publicPem} -pubin -out ${publicDer} -outform der"

    executeWithOutput("sh", ["-c", cmdStr])

    // 核心演示:从 DerBlob 解码还原公钥
    let decodedKey = GeneralPublicKey.decodeDer(DerBlob(readToEnd(File(publicDer, Read))))
    println("解码成功")
    println("解码后公钥类型: ${decodedKey}")

    // 删除测试用文件
    removeIfExists(privatePem)
    removeIfExists(publicPem)
    removeIfExists(publicDer)
    return 0
}

运行结果:

解码成功
解码后公钥类型: PublicKey(294 bytes)

static func decodeFromPem(String)

static func decodeFromPem(text: String): PublicKey

功能:将公钥从 PEM 格式解码。

参数:

  • text: String - PEM 格式的公钥字符流。

返回值:

  • PublicKey - 由 PEM 格式解码出的公钥。

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.keys.*

main() {
    // 生成测试用文件
    let privatePem = "./test_private.key"
    let publicPem = "./test_public.key"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl genrsa -out ${privatePem} 2048; " + "openssl rsa -in ${privatePem} -pubout -out ${publicPem}"

    executeWithOutput("sh", ["-c", cmdStr])

    // 核心演示:从 PEM 字符串解码还原公钥
    let pemContent = String.fromUtf8(readToEnd(File(publicPem, Read)))
    let decodedKey = GeneralPublicKey.decodeFromPem(pemContent)
    println("从PEM解码成功")
    println("解码后公钥类型: ${decodedKey}")

    // 删除测试用文件
    removeIfExists(privatePem)
    removeIfExists(publicPem)
    return 0
}

运行结果:

从PEM解码成功
解码后公钥类型: PublicKey(294 bytes)

func encodeToDer()

func encodeToDer(): DerBlob

功能:将公钥编码成 DER 格式。

返回值:

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.keys.*
import stdx.crypto.common.*

main() {
    // 生成测试用文件
    let privatePem = "./test_private.key"
    let publicPem = "./test_public.key"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl genrsa -out ${privatePem} 2048; " + "openssl rsa -in ${privatePem} -pubout -out ${publicPem}"

    executeWithOutput("sh", ["-c", cmdStr])

    // 从 PEM 文件读取并解码为公钥
    let pemContent = String.fromUtf8(readToEnd(File(publicPem, Read)))
    let originalKey = GeneralPublicKey.decodeFromPem(pemContent)

    // 核心演示:将公钥编码为 DER 格式
    let encodedBlob = originalKey.encodeToDer()
    println("编码为DER格式成功")
    println("DER数据大小: ${encodedBlob.size}")

    // 删除测试用文件
    removeIfExists(privatePem)
    removeIfExists(publicPem)
    return 0
}

运行结果:

编码为DER格式成功
DER数据大小: 294

func encodeToPem()

func encodeToPem(): PemEntry

功能:将公钥编码为 PEM 格式。

返回值:

  • PemEntry - 公钥数据 PEM 格式编码生成的对象。

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.keys.*

main() {
    // 生成测试用文件
    let privatePem = "./test_private.key"
    let publicPem = "./test_public.key"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl genrsa -out ${privatePem} 2048; " + "openssl rsa -in ${privatePem} -pubout -out ${publicPem}"

    executeWithOutput("sh", ["-c", cmdStr])

    // 从 PEM 文件读取并解码为公钥
    let pemContent = String.fromUtf8(readToEnd(File(publicPem, Read)))
    let originalKey = GeneralPublicKey.decodeFromPem(pemContent)

    // 核心演示:将公钥编码为 PEM 格式
    let encodedPem = originalKey.encodeToPem()
    println("编码为PEM格式成功")
    println("PEM标签: ${encodedPem.label}")

    // 删除测试用文件
    removeIfExists(privatePem)
    removeIfExists(publicPem)
    return 0
}

运行结果:

编码为PEM格式成功
PEM标签: PUBLIC KEY

func toString()

public func toString(): String

功能:转换为字符串格式。

返回值:

  • String - 字符串。

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.keys.*

main() {
    // 生成测试用文件
    let privatePem = "./test_private.key"
    let publicPem = "./test_public.key"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl genrsa -out ${privatePem} 2048; " + "openssl rsa -in ${privatePem} -pubout -out ${publicPem}"

    executeWithOutput("sh", ["-c", cmdStr])

    // 从 PEM 文件读取并解码为公钥
    let pemContent = String.fromUtf8(readToEnd(File(publicPem, Read)))
    let key = GeneralPublicKey.decodeFromPem(pemContent)

    // 核心演示:获取公钥类型描述
    let keyType = key.toString()
    println("公钥类型: ${keyType}")

    // 删除测试用文件
    removeIfExists(privatePem)
    removeIfExists(publicPem)
    return 0
}

运行结果:

公钥类型: PublicKey(294 bytes)

class RSAPrivateKey

public class RSAPrivateKey <: PrivateKey{
    public init(bits: Int32)
    public init(bits: Int32, e: BigInt)
}

功能:RSA 私钥类,提供生成 RSA 私钥能力,RSA 私钥支持签名和解密操作,支持 PEM 和 DER 格式的编码解码,符合 PKCS1 标准。使用示例见 RSA 密钥示例

父类型:

init(Int32)

public init(bits: Int32)

功能:init 初始化生成私钥,公钥指数默认值为 65537,业界推荐。公钥指数 e 的大小直接影响了 RSA 算法的安全性和加密效率。通常情况下,e 的值越小,加密速度越快,但安全性越低。

参数:

  • bits: Int32 - 密钥长度,需要大于等于 512 位,并且小于等于 16384 位。

异常:

  • CryptoException - 密钥长度不符合要求或初始化失败,抛出异常。

示例:

import stdx.crypto.keys.*

main() {
    let key = RSAPrivateKey(2048)
    println("RSA私钥创建成功")
    println("密钥类型: ${key}")

    return 0
}

运行结果:

RSA私钥创建成功
密钥类型: RSA PRIVATE KEY

init(Int32, BigInt)

public init(bits: Int32, e: BigInt)

功能:init 初始化生成私钥,允许用户指定公共指数。

参数:

  • bits: Int32 - 密钥长度,需要大于等于 512 位,并且小于等于 16384 位,推荐使用的密钥长度不小于 3072 位。
  • e: BigInt - 公钥公共指数,范围是 [3, 2^256-1] 的奇数。

异常:

  • CryptoException - 密钥长度不符合要求、公钥公共指数值不符合要求或初始化失败,抛出异常。

示例:

import stdx.crypto.keys.*
import std.math.numeric.*

main() {
    let e = BigInt(65537)
    let key = RSAPrivateKey(2048, e)
    println("RSA私钥创建成功")
    println("密钥类型: ${key}")

    return 0
}

运行结果:

RSA私钥创建成功
密钥类型: RSA PRIVATE KEY

static func decodeDer(DerBlob)

public static func decodeDer(blob: DerBlob): RSAPrivateKey

功能:将私钥从 DER 格式解码。

参数:

  • blob: DerBlob - 二进制格式的私钥对象。

返回值:

异常:

示例:

import stdx.crypto.keys.*

main() {
    // 模拟场景:从外部(文件/网络)获取的 DerBlob(此处通过生成私钥并编码模拟)
    let originalKey = RSAPrivateKey(2048)
    let encodedBlob = originalKey.encodeToDer()

    // 核心演示:从 DerBlob 解码还原 RSA 私钥
    let decodedKey = RSAPrivateKey.decodeDer(encodedBlob)
    println("解码成功")
    println("解码后密钥类型: ${decodedKey}")

    return 0
}

运行结果:

解码成功
解码后密钥类型: RSA PRIVATE KEY

static func decodeDer(DerBlob, ?String)

public static func decodeDer(blob: DerBlob, password!: ?String): RSAPrivateKey

功能:将加密的私钥从 DER 格式解码。

参数:

  • blob: DerBlob - 二进制格式的私钥对象。
  • password!: ?String - 解密私钥需要提供的密码,密码为 None 时则不解密。

返回值:

异常:

  • CryptoException - 解码失败、解密失败或者参数密码为空字符串,抛出异常。

示例:

import stdx.crypto.keys.*

main() {
    // 模拟场景:从外部(文件/网络)获取的 DerBlob(此处通过生成私钥并编码模拟)
    let originalKey = RSAPrivateKey(2048)
    let encodedBlob = originalKey.encodeToDer(password: "mypassword")

    // 核心演示:从加密的 DerBlob 解码还原 RSA 私钥
    let decodedKey = RSAPrivateKey.decodeDer(encodedBlob, password: "mypassword")
    println("解码加密DER成功")
    println("解码后密钥类型: ${decodedKey}")

    return 0
}

运行结果:

解码加密DER成功
解码后密钥类型: RSA PRIVATE KEY

static func decodeFromPem(String)

public static func decodeFromPem(text: String): RSAPrivateKey

功能:将私钥从 PEM 格式解码。

参数:

  • text: String - PEM 格式的私钥字符流。

返回值:

异常:

  • CryptoException - 解码失败、解密失败、字符流不符合 PEM 格式或文件头不符合私钥头标准时,抛出异常。

示例:

import stdx.crypto.keys.*

main() {
    // 模拟场景:从外部(文件/网络)获取的 PEM 字符串
    let originalKey = RSAPrivateKey(2048)
    let pemEntry = originalKey.encodeToPem()
    let pemString = pemEntry.encode()

    // 核心演示:从 PEM 字符串解码还原 RSA 私钥
    let decodedKey = RSAPrivateKey.decodeFromPem(pemString)
    println("从PEM解码成功")
    println("解码后密钥类型: ${decodedKey}")

    return 0
}

运行结果:

从PEM解码成功
解码后密钥类型: RSA PRIVATE KEY

static func decodeFromPem(String, ?String)

public static func decodeFromPem(text: String, password!: ?String): RSAPrivateKey

功能:将私钥从 PEM 格式解码。

参数:

  • text: String - PEM 格式的私钥字符流。
  • password!: ?String - 解密私钥需要提供的密码,密码为 None 时则不解密。

返回值:

异常:

  • CryptoException - 解码失败、解密失败、参数密码为空字符串、字符流不符合 PEM 格式或文件头不符合私钥头标准时,抛出异常。

示例:

import stdx.crypto.keys.*

main() {
    // 模拟场景:从外部(文件/网络)获取的 PEM 字符串
    let originalKey = RSAPrivateKey(2048)
    let pemEntry = originalKey.encodeToPem(password: "mypassword")
    let pemString = pemEntry.encode()

    // 核心演示:从加密的 PEM 字符串解码还原 RSA 私钥
    let decodedKey = RSAPrivateKey.decodeFromPem(pemString, password: "mypassword")
    println("从加密PEM解码成功")
    println("解码后密钥类型: ${decodedKey}")

    return 0
}

运行结果:

从加密PEM解码成功
解码后密钥类型: RSA PRIVATE KEY

func decrypt(InputStream, OutputStream, PadOption)

public func decrypt(input: InputStream, output: OutputStream, padType!: PadOption): Unit

功能:decrypt 解密出原始数据。

参数:

  • input: InputStream - 加密的数据。
  • output: OutputStream - 解密后的数据。
  • padType!: PadOption - 填充模式,可以选择 PKCS1 或 OAEP 模式,不支持 PSS 模式,在对安全场景要求较高的情况下,推荐使用 OAEP 填充模式。

异常:

  • CryptoException - 设置填充模式失败或解密失败,抛出异常。

示例:

import stdx.crypto.keys.*
import std.io.*

main() {
    let priKey = RSAPrivateKey(2048)
    let pubKey = RSAPublicKey(priKey)

    // 准备要加密的数据
    let data = "Hello, World!".toArray()
    let input = ByteBuffer()
    let output = ByteBuffer()
    let decrypted = ByteBuffer()
    input.write(data)

    // 使用公钥加密数据
    pubKey.encrypt(input, output, padType: PKCS1)

    // 使用私钥解密数据
    priKey.decrypt(output, decrypted, padType: PKCS1)

    let result = Array<Byte>(data.size, repeat: 0)
    decrypted.read(result)

    if (data == result) {
        println("解密成功")
    } else {
        println("解密失败")
    }

    return 0
}

运行结果:

解密成功

func encodeToDer()

public override func encodeToDer(): DerBlob

功能:将私钥编码为 DER 格式。

返回值:

  • DerBlob - 编码后的 DER 格式私钥。

异常:

示例:

import stdx.crypto.keys.*

main() {
    let key = RSAPrivateKey(2048)
    let derBlob = key.encodeToDer()

    println("编码为DER格式成功")

    return 0
}

运行结果:

编码为DER格式成功

func encodeToDer(?String)

public func encodeToDer(password!: ?String): DerBlob

功能:使用 AES-256-CBC 加密私钥,将私钥编码为 DER 格式。

参数:

  • password!: ?String - 加密私钥需要提供的密码,密码为 None 时则不加密。

返回值:

  • DerBlob - 编码后的 DER 格式私钥。

异常:

  • CryptoException - 编码失败、加密失败或者参数密码为空字符串,抛出异常。

示例:

import stdx.crypto.keys.*

main() {
    let key = RSAPrivateKey(2048)
    let derBlob = key.encodeToDer(password: "mypassword")

    println("编码为加密DER格式成功")

    return 0
}

运行结果:

编码为加密DER格式成功

func encodeToPem()

public func encodeToPem(): PemEntry

功能:将私钥编码为 PEM 格式。

返回值:

  • PemEntry - 私钥 PEM 格式的对象。

异常:

示例:

import stdx.crypto.keys.*

main() {
    let key = RSAPrivateKey(2048)
    let pemEntry = key.encodeToPem()

    println("编码为PEM格式成功")
    println("PEM标签: ${pemEntry.label}")

    return 0
}

运行结果:

编码为PEM格式成功
PEM标签: RSA PRIVATE KEY

func encodeToPem(?String)

public func encodeToPem(password!: ?String): PemEntry

功能:将加密的私钥编码为 PEM 格式。

参数:

  • password!: ?String - 加密私钥需要提供的密码,密码为 None 时则不加密。

返回值:

  • PemEntry - 私钥 PEM 格式的对象。

异常:

  • CryptoException - 编码失败、加密失败或者参数密码为空字符串,抛出异常。

示例:

import stdx.crypto.keys.*

main() {
    let key = RSAPrivateKey(2048)
    let pemEntry = key.encodeToPem(password: "mypassword")

    println("编码为加密PEM格式成功")
    println("PEM标签: ${pemEntry.label}")

    return 0
}

运行结果:

编码为加密PEM格式成功
PEM标签: ENCRYPTED PRIVATE KEY

func sign(Digest, Array<Byte>, PadOption)

public func sign(hash: Digest, digest: Array<Byte>, padType!: PadOption): Array<Byte>

功能:对数据的摘要结果进行签名。

参数:

  • hash: Digest - 摘要方法,获取 digest 结果使用的摘要方法。
  • digest: Array<Byte> - 数据的摘要结果。
  • padType!: PadOption - 填充模式,可以选择 PKCS1 或 PSS 模式,不支持 OAEP 模式,在对安全场景要求较高的情况下,推荐使用 PSS 填充模式。

返回值:

  • Array<Byte> - 签名后的数据。

异常:

  • CryptoException - 设置摘要方法失败、设置填充模式失败或签名失败,抛出异常。

示例:

import stdx.crypto.keys.*
import stdx.crypto.digest.*

main() {
    let priKey = RSAPrivateKey(2048)
    let pubKey = RSAPublicKey(priKey)
    let data = "Hello, World!".toArray()

    // 先计算数据的摘要
    let sha256 = SHA256()
    sha256.write(data)
    let digest = sha256.finish()

    // 使用私钥签名
    let signature = priKey.sign(sha256, digest, padType: PKCS1)

    // 使用公钥验证签名
    let isValid = pubKey.verify(sha256, digest, signature, padType: PKCS1)

    println("签名验证结果: ${isValid}")

    return 0
}

运行结果:

签名验证结果: true

func toString()

public override func toString(): String

功能:输出私钥种类。

返回值:

  • String - 密钥类别描述。

示例:

import stdx.crypto.keys.*

main() {
    let key = RSAPrivateKey(2048)

    let keyType = key.toString()
    println("密钥类型: ${keyType}")

    return 0
}

运行结果:

密钥类型: RSA PRIVATE KEY

class RSAPublicKey

public class RSAPublicKey <: PublicKey {
    public init(pri: RSAPrivateKey)
}

功能:RSA 公钥类,提供生成 RSA 公钥能力,RSA 公钥支持验证签名和加密操作,支持 PEM 和 DER 格式的编码解码。使用示例见 RSA 密钥示例

父类型:

init(RSAPrivateKey)

public init(pri: RSAPrivateKey)

功能:init 初始化公钥,从私钥中获取对应的公钥。

参数:

异常:

示例:

import stdx.crypto.keys.*

main() {
    let priKey = RSAPrivateKey(2048)
    let pubKey = RSAPublicKey(priKey)

    println("RSA公钥创建成功")
    println("公钥类型: ${pubKey}")

    return 0
}

运行结果:

RSA公钥创建成功
公钥类型: RSA PUBLIC KEY

static func decodeDer(DerBlob)

public static func decodeDer(blob: DerBlob): RSAPublicKey

功能:将公钥从 DER 格式解码。

参数:

  • blob: DerBlob - 二进制格式的公钥对象。

返回值:

异常:

示例:

import stdx.crypto.keys.*

main() {
    // 模拟场景:从外部(文件/网络)获取的 DER 字节数组
    let priKey = RSAPrivateKey(2048)
    let pubKey = RSAPublicKey(priKey)
    let derBlob = pubKey.encodeToDer()

    // 从 DER 字节数组解码公钥
    let decodedPubKey = RSAPublicKey.decodeDer(derBlob)
    println("从DER解码公钥成功")
    println("解码后公钥类型: ${decodedPubKey}")

    return 0
}

运行结果:

从DER解码公钥成功
解码后公钥类型: RSA PUBLIC KEY

static func decodeFromPem(String)

public static func decodeFromPem(text: String): RSAPublicKey

功能:将公钥从 PEM 格式解码。

参数:

  • text: String - PEM 格式的公钥字符流。

返回值:

异常:

  • CryptoException - 解码失败、字符流不符合 PEM 格式或文件头不符合公钥头标准时,抛出异常。

示例:

import stdx.crypto.keys.*

main() {
    // 模拟场景:从外部(文件/网络)获取的 PEM 字符串
    let priKey = RSAPrivateKey(2048)
    let pubKey = RSAPublicKey(priKey)
    let pemEntry = pubKey.encodeToPem()
    let pemString = pemEntry.encode()

    // 从 PEM 字符串解码公钥
    let decodedPubKey = RSAPublicKey.decodeFromPem(pemString)
    println("从PEM解码公钥成功")
    println("解码后公钥类型: ${decodedPubKey}")

    return 0
}

运行结果:

从PEM解码公钥成功
解码后公钥类型: RSA PUBLIC KEY

func encodeToDer()

public override func encodeToDer(): DerBlob

功能:将公钥编码为 DER 格式。

返回值:

  • DerBlob - 编码后的 Der 格式公钥。

异常:

示例:

import stdx.crypto.keys.*

main() {
    let priKey = RSAPrivateKey(2048)
    // 公钥需要从私钥派生
    let pubKey = RSAPublicKey(priKey)
    let derBlob = pubKey.encodeToDer()

    println("编码为DER格式成功")
    println("DER数据大小: ${derBlob.size}")

    return 0
}

运行结果:

编码为DER格式成功
DER数据大小: 294

func encodeToPem()

public func encodeToPem(): PemEntry

功能:将公钥编码为 PEM 格式。

返回值:

异常:

示例:

import stdx.crypto.keys.*

main() {
    let priKey = RSAPrivateKey(2048)
    // 公钥需要从私钥派生
    let pubKey = RSAPublicKey(priKey)
    let pemEntry = pubKey.encodeToPem()

    println("编码为PEM格式成功")
    println("PEM标签: ${pemEntry.label}")

    return 0
}

运行结果:

编码为PEM格式成功
PEM标签: PUBLIC KEY

func encrypt(InputStream, OutputStream, PadOption)

public func encrypt(input: InputStream, output: OutputStream, padType!: PadOption): Unit

功能:encrypt 给一段数据进行加密。

参数:

  • input: InputStream - 需要加密的数据。
  • output: OutputStream - 加密后的数据。
  • padType!: PadOption - 填充模式,可以选择 PKCS1 或 OAEP 模式,不支持 PSS 模式,在对安全场景要求较高的情况下,推荐使用 OAEP 填充模式。

异常:

  • CryptoException - 设置填充模式失败或加密失败,抛出异常。

示例:

import stdx.crypto.keys.*
import std.io.*

main() {
    let priKey = RSAPrivateKey(2048)
    let pubKey = RSAPublicKey(priKey)

    // 准备要加密的数据
    let data = "Hello, World!".toArray()
    let input = ByteBuffer()
    let output = ByteBuffer()
    input.write(data)

    // 使用公钥加密数据
    pubKey.encrypt(input, output, padType: PKCS1)

    println("加密成功")

    return 0
}

运行结果:

加密成功

func toString()

public override func toString(): String

功能:输出公钥种类。

返回值:

  • String - 密钥类别描述。

示例:

import stdx.crypto.keys.*

main() {
    let priKey = RSAPrivateKey(2048)
    let pubKey = RSAPublicKey(priKey)

    let keyType = pubKey.toString()
    println("公钥类型: ${keyType}")

    return 0
}

运行结果:

公钥类型: RSA PUBLIC KEY

func verify(Digest, Array<Byte>, Array<Byte>, PadOption)

public func verify(hash: Digest, digest: Array<Byte>, sig: Array<Byte>, padType!: PadOption): Bool

功能:verify 验证签名结果。

参数:

  • hash: Digest - 摘要方法,获取 digest 结果使用的摘要方法。
  • digest: Array<Byte> - 数据的摘要结果。
  • sig: Array<Byte> - 数据的签名结果。
  • padType!: PadOption - 填充模式,可以选择 PKCS1 或 PSS 模式,不支持 OAEP 模式,在对安全场景要求较高的情况下,推荐使用 PSS 填充模式。

返回值:

  • Bool - 返回 true 表示验证成功,false 失败。

异常:

  • CryptoException - 设置填充模式失败或验证失败,抛出异常。

示例:

import stdx.crypto.keys.*
import stdx.crypto.digest.*

main() {
    let priKey = RSAPrivateKey(2048)
    let pubKey = RSAPublicKey(priKey)
    let data = "Hello, World!".toArray()

    // 计算数据摘要
    let sha256 = SHA256()
    sha256.write(data)
    let digest = sha256.finish()

    // 使用私钥签名
    let signature = priKey.sign(sha256, digest, padType: PKCS1)

    // 使用公钥验证签名
    let isValid = pubKey.verify(sha256, digest, signature, padType: PKCS1)
    println("签名验证结果: ${isValid}")

    // 验证错误的签名
    let wrongData = "Wrong data".toArray()
    sha256.reset()
    sha256.write(wrongData)
    let wrongDigest = sha256.finish()
    let isWrongValid = pubKey.verify(sha256, wrongDigest, signature, padType: PKCS1)
    println("错误数据验证结果: ${isWrongValid}")

    return 0
}

运行结果:

签名验证结果: true
错误数据验证结果: false

class SM2PrivateKey

public class SM2PrivateKey <: PrivateKey {
    public init()
}

功能:SM2 私钥类,提供生成 SM2 私钥能力,SM2 私钥支持签名和解密操作,支持 PEM 和 DER 格式的编码解码,符合 PKCS1 标准。使用示例见 SM2 密钥示例

父类型:

init()

public init()

功能:init 初始化生成私钥。

异常:

示例:

import stdx.crypto.keys.*

main() {
    let key = SM2PrivateKey()
    println("SM2私钥创建成功")
    println("密钥类型: ${key}")

    return 0
}

运行结果:

SM2私钥创建成功
密钥类型: SM2 PRIVATE KEY

static func decodeDer(DerBlob)

public static func decodeDer(blob: DerBlob): SM2PrivateKey

功能:将私钥从 DER 格式解码。

参数:

  • blob: DerBlob - 二进制格式的私钥对象。

返回值:

异常:

示例:

import stdx.crypto.keys.*

main() {
    // 模拟场景:从外部(文件/网络)获取的 DerBlob(此处通过生成私钥并编码模拟)
    let originalKey = SM2PrivateKey()
    let encodedBlob = originalKey.encodeToDer()

    // 核心演示:从 DerBlob 解码还原 SM2 私钥
    let decodedKey = SM2PrivateKey.decodeDer(encodedBlob)
    println("解码成功")
    println("解码后密钥类型: ${decodedKey}")

    return 0
}

运行结果:

解码成功
解码后密钥类型: SM2 PRIVATE KEY

static func decodeDer(DerBlob, ?String)

public static func decodeDer(blob: DerBlob, password!: ?String): SM2PrivateKey

功能:将加密的私钥从 DER 格式解码。

参数:

  • blob: DerBlob - 二进制格式的私钥对象。
  • password!: ?String - 解密私钥需要提供的密码,密码为 None 时则不解密。

返回值:

异常:

  • CryptoException - 解码失败、解密失败或者参数密码为空字符串,抛出异常。

示例:

import stdx.crypto.keys.*

main() {
    // 模拟场景:从外部(文件/网络)获取的 DerBlob(此处通过生成私钥并编码模拟)
    let originalKey = SM2PrivateKey()
    let encodedBlob = originalKey.encodeToDer(password: "mypassword")

    // 核心演示:从加密的 DerBlob 解码还原 SM2 私钥
    let decodedKey = SM2PrivateKey.decodeDer(encodedBlob, password: "mypassword")
    println("解码加密DER成功")
    println("解码后密钥类型: ${decodedKey}")

    return 0
}

运行结果:

解码加密DER成功
解码后密钥类型: SM2 PRIVATE KEY

static func decodeFromPem(String)

public static func decodeFromPem(text: String): SM2PrivateKey

功能:将私钥从 PEM 格式解码。

参数:

  • text: String - PEM 格式的私钥字符流。

返回值:

异常:

  • CryptoException - 解码失败、解密失败、字符流不符合 PEM 格式或文件头不符合私钥头标准时,抛出异常。

示例:

import stdx.crypto.keys.*

main() {
    // 模拟场景:从外部(文件/网络)获取的 PEM 字符串
    let originalKey = SM2PrivateKey()
    let pemEntry = originalKey.encodeToPem()
    let pemString = pemEntry.encode()

    // 核心演示:从 PEM 字符串解码还原 SM2 私钥
    let decodedKey = SM2PrivateKey.decodeFromPem(pemString)
    println("从PEM解码成功")
    println("解码后密钥类型: ${decodedKey}")

    return 0
}

运行结果:

从PEM解码成功
解码后密钥类型: SM2 PRIVATE KEY

static func decodeFromPem(String, ?String)

public static func decodeFromPem(text: String, password!: ?String): SM2PrivateKey

功能:将私钥从 PEM 格式解码。

参数:

  • text: String - PEM 格式的私钥字符流。
  • password!: ?String - 解密私钥需要提供的密码,密码为 None 时则不解密。

返回值:

异常:

  • CryptoException - 解码失败、解密失败、参数密码为空字符串、字符流不符合 PEM 格式或文件头不符合私钥头标准时,抛出异常。

示例:

import stdx.crypto.keys.*

main() {
    // 模拟场景:从外部(文件/网络)获取的 PEM 字符串
    let originalKey = SM2PrivateKey()
    let pemEntry = originalKey.encodeToPem(password: "mypassword")
    let pemString = pemEntry.encode()

    // 核心演示:从加密的 PEM 字符串解码还原 SM2 私钥
    let decodedKey = SM2PrivateKey.decodeFromPem(pemString, password: "mypassword")
    println("从加密PEM解码成功")
    println("解码后密钥类型: ${decodedKey}")

    return 0
}

运行结果:

从加密PEM解码成功
解码后密钥类型: SM2 PRIVATE KEY

func decrypt(Array<Byte>)

public func decrypt(input: Array<Byte>): Array<Byte>

功能:decrypt 解密出原始数据,待解密密文需要遵循 ASN.1 编码规则。

参数:

  • input: Array<Byte> - 加密的数据。

返回值:

  • Array<Byte> - 解密后的数据。

异常:

示例:

import stdx.crypto.keys.*

main() {
    let priKey = SM2PrivateKey()
    let pubKey = SM2PublicKey(priKey)

    // 准备要加密的数据
    let data = "Hello, World!".toArray()

    // 使用公钥加密数据
    let encryptedData = pubKey.encrypt(data)

    // 使用私钥解密数据
    let decryptedData = priKey.decrypt(encryptedData)

    let result = String.fromUtf8(decryptedData)
    println("解密结果: ${result}")

    return 0
}

运行结果:

解密结果: Hello, World!

func encodeToDer()

public func encodeToDer(): DerBlob

功能:将私钥编码为 DER 格式。

返回值:

  • DerBlob - 编码后的 DER 格式私钥。

异常:

示例:

import stdx.crypto.keys.*

main() {
    let key = SM2PrivateKey()
    let derBlob = key.encodeToDer()

    println("编码为DER格式成功")
    println("DER数据大小: ${derBlob.size}")

    return 0
}

运行结果:

编码为DER格式成功
DER数据大小: 121

func encodeToDer(?String)

public func encodeToDer(password!: ?String): DerBlob

功能:使用 AES-256-CBC 加密私钥,将私钥编码为 DER 格式。

参数:

  • password!: ?String - 加密私钥需要提供的密码,密码为 None 时则不加密。

返回值:

  • DerBlob - 编码后的 DER 格式公钥。

异常:

  • CryptoException - 编码失败、加密失败或者参数密码为空字符串,抛出异常。

示例:

import stdx.crypto.keys.*

main() {
    let key = SM2PrivateKey()
    let derBlob = key.encodeToDer(password: "mypassword")

    println("编码为加密DER格式成功")
    println("DER数据大小: ${derBlob.size}")

    return 0
}

运行结果:

编码为加密DER格式成功
DER数据大小: 239

func encodeToPem()

public func encodeToPem(): PemEntry

功能:将私钥编码为 PEM 格式。

返回值:

  • PemEntry - 私钥 PEM 格式的对象。

异常:

示例:

import stdx.crypto.keys.*

main() {
    let key = SM2PrivateKey()
    let pemEntry = key.encodeToPem()

    println("编码为PEM格式成功")
    println("PEM标签: ${pemEntry.label}")

    return 0
}

运行结果:

编码为PEM格式成功
PEM标签: EC PRIVATE KEY

func encodeToPem(?String)

public func encodeToPem(password!: ?String): PemEntry

功能:将加密的私钥编码为 PEM 格式。

参数:

  • password!: ?String - 加密私钥需要提供的密码,密码为 None 时则不加密。

返回值:

  • PemEntry - 私钥 PEM 格式的对象。

异常:

  • CryptoException - 编码失败、加密失败或者参数密码为空字符串,抛出异常。

示例:

import stdx.crypto.keys.*

main() {
    let key = SM2PrivateKey()
    let pemEntry = key.encodeToPem(password: "mypassword")

    println("编码为加密PEM格式成功")
    println("PEM标签: ${pemEntry.label}")

    return 0
}

运行结果:

编码为加密PEM格式成功
PEM标签: EC PRIVATE KEY

func sign(Array<Byte>)

public func sign(data: Array<Byte>): Array<Byte>

功能:sign 对数据进行签名,SM2 采用SM3数据摘要算法。

参数:

  • data: Array<Byte> - 数据。

返回值:

  • Array<Byte> - 签名后的数据。

异常:

示例:

import stdx.crypto.keys.*

main() {
    let priKey = SM2PrivateKey()
    let pubKey = SM2PublicKey(priKey)
    let data = "Hello, World!".toArray()

    // 使用私钥签名,直接传原始数据,内部自动算 SM3
    let signature = priKey.sign(data)

    // 使用公钥验证签名
    let isValid = pubKey.verify(data, signature)

    println("签名验证结果: ${isValid}")

    return 0
}

运行结果:

签名验证结果: true

func toString()

public override func toString(): String

功能:输出私钥种类。

返回值:

  • String - 密钥类别描述。

示例:

import stdx.crypto.keys.*

main() {
    let key = SM2PrivateKey()

    let keyType = key.toString()
    println("密钥类型: ${keyType}")

    return 0
}

运行结果:

密钥类型: SM2 PRIVATE KEY

class SM2PublicKey

public class SM2PublicKey <: PublicKey {
    public init(pri: SM2PrivateKey)
}

功能:SM2 公钥类,提供生成 SM2 公钥能力,SM2 公钥支持验证签名和加密操作,支持 PEM 和 DER 格式的编码解码。使用示例见 SM2 密钥示例

父类型:

init(SM2PrivateKey)

public init(pri: SM2PrivateKey)

功能:init 初始化公钥,从私钥中获取对应的公钥。

参数:

异常:

示例:

import stdx.crypto.keys.*

main() {
    let priKey = SM2PrivateKey()
    let pubKey = SM2PublicKey(priKey)

    println("SM2公钥创建成功")
    println("公钥类型: ${pubKey}")

    return 0
}

运行结果:

SM2公钥创建成功
公钥类型: SM2 PUBLIC KEY

static func decodeDer(DerBlob)

public static func decodeDer(blob: DerBlob): SM2PublicKey

功能:将公钥从 DER 格式解码。

参数:

  • blob: DerBlob - 二进制格式的公钥对象。

返回值:

异常:

示例:

import stdx.crypto.keys.*

main() {
    // 模拟场景:从外部(文件/网络)获取的 DER 字节数组
    let priKey = SM2PrivateKey()
    let pubKey = SM2PublicKey(priKey)
    let derBlob = pubKey.encodeToDer()

    // 从 DER 字节数组解码公钥
    let decodedPubKey = SM2PublicKey.decodeDer(derBlob)
    println("从DER解码公钥成功")
    println("解码后公钥类型: ${decodedPubKey}")

    return 0
}

运行结果:

从DER解码公钥成功
解码后公钥类型: SM2 PUBLIC KEY

static func decodeFromPem(String)

public static func decodeFromPem(text: String): SM2PublicKey

功能:将公钥从 PEM 格式解码。

参数:

  • text: String - PEM 格式的公钥字符流。

返回值:

异常:

  • CryptoException - 解码失败、字符流不符合 PEM 格式或文件头不符合公钥头标准时,抛出异常。

示例:

import stdx.crypto.keys.*

main() {
    // 模拟场景:从外部(文件/网络)获取的 PEM 字符串
    let priKey = SM2PrivateKey()
    let pubKey = SM2PublicKey(priKey)
    let pemEntry = pubKey.encodeToPem()
    let pemString = pemEntry.encode()

    // 从 PEM 字符串解码公钥
    let decodedPubKey = SM2PublicKey.decodeFromPem(pemString)
    println("从PEM解码公钥成功")
    println("解码后公钥类型: ${decodedPubKey}")

    return 0
}

运行结果:

从PEM解码公钥成功
解码后公钥类型: SM2 PUBLIC KEY

func encodeToDer()

public func encodeToDer(): DerBlob

功能:将公钥编码为 DER 格式。

返回值:

  • DerBlob - 编码后的 Der 格式公钥。

异常:

示例:

import stdx.crypto.keys.*

main() {
    let priKey = SM2PrivateKey()
    // 公钥需要从私钥派生
    let pubKey = SM2PublicKey(priKey)
    let derBlob = pubKey.encodeToDer()

    println("编码为DER格式成功")
    println("DER数据大小: ${derBlob.size}")

    return 0
}

运行结果:

编码为DER格式成功
DER数据大小: 92

func encodeToPem()

public func encodeToPem(): PemEntry

功能:将公钥编码为 PEM 格式。

返回值:

异常:

示例:

import stdx.crypto.keys.*

main() {
    let priKey = SM2PrivateKey()
    // 公钥需要从私钥派生
    let pubKey = SM2PublicKey(priKey)
    let pemEntry = pubKey.encodeToPem()

    println("编码为PEM格式成功")
    println("PEM标签: ${pemEntry.label}")

    return 0
}

运行结果:

编码为PEM格式成功
PEM标签: PUBLIC KEY

func encrypt(Array<Byte>)

public func encrypt(input: Array<Byte>): Array<Byte>

功能:encrypt 给一段数据进行加密,输出密文遵循 ASN.1 编码规则。

参数:

  • input: Array<Byte> - 需要加密的数据。

返回值:

  • Array<Byte> - 加密后的数据。

异常:

示例:

import stdx.crypto.keys.*

main() {
    let priKey = SM2PrivateKey()
    let pubKey = SM2PublicKey(priKey)

    // 准备要加密的数据
    let data = "Hello, World!".toArray()

    // 使用公钥加密数据
    let encryptedData = pubKey.encrypt(data)

    println("加密成功")
    println("加密后数据大小: ${encryptedData.size}")

    return 0
}

可能的运行结果:

加密成功
加密后数据大小: 121

func toString()

public override func toString(): String

功能:输出公钥种类。

返回值:

  • String - 密钥类别描述。

示例:

import stdx.crypto.keys.*

main() {
    let priKey = SM2PrivateKey()
    let pubKey = SM2PublicKey(priKey)

    let keyType = pubKey.toString()
    println("公钥类型: ${keyType}")

    return 0
}

运行结果:

公钥类型: SM2 PUBLIC KEY

func verify(Array<Byte>, Array<Byte>)

public func verify(data: Array<Byte>, sig: Array<Byte>): Bool

功能:verify 验证签名结果。

参数:

  • data: Array<Byte> - 数据。
  • sig: Array<Byte> - 数据的签名结果。

返回值:

  • Bool - 返回 true 表示验证成功,false 失败。

异常:

  • CryptoException - 设置填充模式失败或验证失败,抛出异常。

示例:

import stdx.crypto.keys.*

main() {
    let priKey = SM2PrivateKey()
    let pubKey = SM2PublicKey(priKey)
    let data = "Hello, World!".toArray()

    // 使用私钥签名
    let signature = priKey.sign(data)

    // 使用公钥验证签名
    let isValid = pubKey.verify(data, signature)

    println("签名验证结果: ${isValid}")

    // 验证错误的签名
    let wrongData = "Wrong data".toArray()
    let isWrongValid = pubKey.verify(wrongData, signature)
    println("错误数据验证结果: ${isWrongValid}")

    return 0
}

运行结果:

签名验证结果: true
错误数据验证结果: false

枚举

enum Curve

public enum Curve {
    | P224 | P256 | P384 | P521 | BP256 | BP320 | BP384 | BP512
}

功能:枚举类型 Curve 用于选择生成 ECDSA 密钥时使用的椭圆曲线类型。

椭圆曲线是一种数学曲线,常用于加密算法中的密钥生成。在密码学中,椭圆曲线密码算法是一种基于椭圆曲线的公钥密码算法。它的基本思想是利用椭圆曲线上的点集构成一个计算困难性,来实现公钥密码的安全性。

Curve 枚举类型支持 NIST P-224,NIST P-256,NIST P-384,NIST P-521,Brainpool P-256,Brainpool P-320,Brainpool P-384,Brainpool P-512 八种椭圆曲线。

  • NIST P-224:基于椭圆曲线的加密算法,使用 224 位的素数作为模数,安全性较高,适用于轻量级应用。

  • NIST P-256:基于椭圆曲线的加密算法,使用 256 位的素数作为模数,安全性较高,适用于中等级应用。

  • NIST P-384:基于椭圆曲线的加密算法,使用 384 位的素数作为模数,安全性非常高,适用于高级别应用。

  • NIST P-521:基于椭圆曲线的加密算法,使用 521 位的素数作为模数,安全性非常高,适用于极高级别应用。

  • Brainpool P-256:基于椭圆曲线的加密算法,使用 256 位的素数作为模数,安全性较高,但比 NIST P-256 更快。

  • Brainpool P-320:基于椭圆曲线的加密算法,使用 320 位的素数作为模数,安全性非常高,但比 NIST P-384 更快。

  • Brainpool P-384:基于椭圆曲线的加密算法,使用 384 位的素数作为模数,安全性非常高,但比 NIST P-384 更快。

  • Brainpool P-512:基于椭圆曲线的加密算法,使用 512 位的素数作为模数,安全性非常高,但比 NIST P-521 更快

BP256

BP256

功能:使用 Brainpool P-256 椭圆曲线初始化 Curve 实例。

BP320

BP320

功能:使用 Brainpool P-320 椭圆曲线初始化 Curve 实例。

BP384

BP384

功能:使用 Brainpool P-384 椭圆曲线初始化 Curve 实例。

BP512

BP512

功能:使用 Brainpool P-512 椭圆曲线初始化 Curve 实例。

P224

P224

功能:使用 NIST P-224 椭圆曲线初始化 Curve 实例。

P256

P256

功能:使用 NIST P-256 椭圆曲线初始化 Curve 实例。

P384

P384

功能:使用 NIST P-384 椭圆曲线初始化 Curve 实例。

P521

P521

功能:使用 NIST P-521 椭圆曲线初始化 Curve 实例。

enum PadOption

public enum PadOption {
    | OAEP(OAEPOption) | PSS(PSSOption) | PKCS1
}

功能:用于设置 RSA 的填充模式。

RSA 有三种常用的填充模式:

  • OAEP 为最优非对称加密填充,只能用于加密解密;
  • PSS 为概率签名方案,只能用于签名和验证;
  • PKCS1 是一种普通的填充模式,用于填充数据长度,可以用于加密、解密、签名和验证。

RSA 的 PKCS1 填充模式是在早期的 PKCS #1 v1.5 规范中定义的填充模式,当前对使用 PKCS1 填充模式的攻击较为成熟,容易被攻击者解密或伪造签名,建议采用 PKCS #1 v2 版本中更加安全的 PSS 或 OAEP 填充模式。

OAEP(OAEPOption)

OAEP(OAEPOption)

功能:使用最优非对称加密初始化 PadOption 实例。

PKCS1

PKCS1

功能:使用 PKCS #1 公钥密码学标准初始化 PadOption 实例。

PSS(PSSOption)

PSS(PSSOption)

功能:使用概率签名方案初始化 PadOption 实例。

结构体

struct OAEPOption

public struct OAEPOption {
    public init(hash: Digest, mgfHash: Digest, label!: String = "")
}

功能:此结构体为 OAEP 填充模式需要设置的参数。

init(Digest, Digest, String)

public init(hash: Digest, mgfHash: Digest, label!: String = "")

功能:初始化 OAEP 填充参数。

参数:

  • hash: Digest - 摘要方法,用于对 label 进行摘要。
  • mgfHash: Digest - 摘要方法,用于设置 MGF1 函数中的摘要方法。
  • label!: String - label 是可选参数,默认为空字符串,可以通过设置 label 来区分不同的加密操作。

示例:

import stdx.crypto.keys.*
import stdx.crypto.digest.*

main() {
    let sha256 = SHA256()
    let sha512 = SHA512()
    let oaepOption = OAEPOption(sha256, sha512, label: "test")
    return 0
}

struct PSSOption

public struct PSSOption {
    public init(saltLen: Int32)
}

功能:此结构体为 PSS 填充模式需要设置的参数。

init(Int32)

public init(saltLen: Int32)

功能:初始化 PSS 填充参数。

参数:

  • saltLen: Int32 - 随机盐长度,长度应大于等于 0,小于等于(RSA 长度 - 摘要长度 - 2),长度单位为字节,长度过长会导致签名失败。

异常:

示例:

import stdx.crypto.keys.*

main() {
    // 正常情况
    let pssOption = PSSOption(20)

    try {
        // 演示小于0的异常情况
        let pssOption = PSSOption(-1)
    } catch (e: Exception) {
        println("异常信息: ${e.message}")
    }
    return 0
}

运行结果:

异常信息: Salt length can not less than 0.

keys 使用

RSA 密钥示例

生成 rsa 公钥及私钥,并使用公钥的 OAEP 填充模式加密,用私钥的 OAEP 填充模式解密

示例:

import stdx.crypto.keys.*
import stdx.crypto.digest.*
import std.io.*
import std.crypto.digest.*

main() {
    var rsaPri = RSAPrivateKey(2048)
    var rsaPub = RSAPublicKey(rsaPri)

    var str: String = "hello world, hello cangjie"
    var bas1 = ByteBuffer()
    var bas2 = ByteBuffer()
    var bas3 = ByteBuffer()
    bas1.write(str.toArray())

    var encOpt = OAEPOption(SHA1(), SHA256())
    rsaPub.encrypt(bas1, bas2, padType: OAEP(encOpt))
    var encOpt2 = OAEPOption(SHA1(), SHA256())
    rsaPri.decrypt(bas2, bas3, padType: OAEP(encOpt2))

    var buf = Array<Byte>(str.size, repeat: 0)
    bas3.read(buf)
    if (str.toArray() == buf) {
        println("success")
    } else {
        println("fail")
    }
}

运行结果:

success

从文件中读取 rsa 公钥和私钥,并使用私钥的 PKCS1 填充模式签名,用公钥的 PKCS1 填充模式验证签名结果

说明:

  • 需要自行准备公私钥文件。

示例:

import stdx.crypto.keys.*
import stdx.crypto.digest.*
import std.crypto.digest.*
import std.fs.*
import std.io.*

main() {
    var pemPri = String.fromUtf8(readToEnd(File("./files/rsaPri.pem", Read)))
    var rsaPri = RSAPrivateKey.decodeFromPem(pemPri)

    var pemPub = String.fromUtf8(readToEnd(File("./files/rsaPub.pem", Read)))
    var rsaPub = RSAPublicKey.decodeFromPem(pemPub)

    var str: String = "helloworld"
    var sha512Instance = SHA512()
    sha512Instance.write(str.toArray())
    var md: Array<Byte> = sha512Instance.finish()

    var sig = rsaPri.sign(sha512Instance, md, padType: PKCS1)
    if (rsaPub.verify(sha512Instance, md, sig, padType: PKCS1)) {
        println("verify successful")
    }
}

运行结果:

verify successful

ECDSA 密钥示例

生成 ECDSA 公钥及私钥,并使用私钥签名,公钥验证签名结果

示例:

import stdx.crypto.keys.*
import stdx.crypto.digest.*

main() {
    var ecPri = ECDSAPrivateKey(P224)
    var ecPub = ECDSAPublicKey(ecPri)

    var str: String = "helloworld"
    var sha512Instance = SHA512()
    sha512Instance.write(str.toArray())
    var md: Array<Byte> = sha512Instance.finish()

    var sig = ecPri.sign(md)
    if (ecPub.verify(md, sig)) {
        println("verify successful")
    }
}

运行结果:

verify successful

SM2 密钥示例

生成 SM2 公钥及私钥,并使用私钥签名,公钥验证签名结果

示例:

import stdx.crypto.keys.*
import std.fs.*
import std.io.*

main(): Unit {
    /* 无参生成公钥私钥 */
    let sm2PrivateKey = SM2PrivateKey()
    let sm2PublicKey = SM2PublicKey(sm2PrivateKey)

    /* 公钥和私钥导出 */
    let priPem = sm2PrivateKey.encodeToPem()
    let file1: File = File("./sm2Pri.pem", Write)
    file1.write(priPem.encode().toArray())
    file1.close()

    let pubPem = sm2PublicKey.encodeToPem()
    let file2: File = File("./sm2Pub.pem", Write)
    file2.write(pubPem.encode().toArray())
    file2.close()

    /* 公钥加密,私钥解密 */
    let str: String = "helloworld"
    let encresult = sm2PublicKey.encrypt(str.toArray())
    let decresult = sm2PrivateKey.decrypt(encresult)
    println(String.fromUtf8(decresult))

    /* 私钥签名,公钥验证 */
    let strSig: String = "helloworld"
    let sigRe = sm2PrivateKey.sign(strSig.toArray())
    let verifyre = sm2PublicKey.verify(strSig.toArray(), sigRe)
    println(verifyre)

    /* 私钥公钥导入 */
    let pemPri = String.fromUtf8(readToEnd(File("./sm2Pri.pem", Read)))
    let sm2PrivateKeyNew = SM2PrivateKey.decodeFromPem(pemPri)
    println(sm2PrivateKeyNew)
    let pemPub = String.fromUtf8(readToEnd(File("./sm2Pub.pem", Read)))
    let sm2PublicKeyNew = SM2PublicKey.decodeFromPem(pemPub)
    println(sm2PublicKeyNew)
    removeIfExists("./sm2Pri.pem")
    removeIfExists("./sm2Pub.pem")
}

运行结果:

helloworld
true
SM2 PRIVATE KEY
SM2 PUBLIC KEY

stdx.crypto.kit

功能介绍

crypto.kit 包提供了一套 CryptoKit 的默认实现,提供随机数生成器及解码 DER、PEM 的能力。

API 列表

类名功能
DefaultCryptoKitCryptoKit 的默认实现。提供随机数生成器及解码 DER、PEM 的能力。

class DefaultCryptoKit

public class DefaultCryptoKit <: CryptoKit

功能:CryptoKit 的默认实现。提供随机数生成器及解码 DER、PEM 的能力。

父类型:

说明:

PEM 是一种基于 Base64 的编码格式。

func certificateFromDer(DerBlob)

func certificateFromDer(encoded: DerBlob): Certificate

功能:将证书从 DER 格式解码。

参数:

  • encoded: DerBlob - 待解码的 DerBlob 对象。

返回值:

异常:

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.kit.*
import stdx.crypto.common.*

main() {
    // 创建默认的CryptoKit实例
    let cryptoKit = DefaultCryptoKit()

    // 生成测试用证书文件
    let certPem = "./test_cert.pem"
    let certDer = "./test_cert.der"
    let keyPem = "./test_key.pem"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl req -x509 -newkey rsa:2048 -keyout ${keyPem} -out ${certPem} -days 1 -nodes -subj '/CN=test' && " +
        "openssl x509 -in ${certPem} -outform DER -out ${certDer}"

    executeWithOutput("sh", ["-c", cmdStr])

    // 核心演示:从 DerBlob 解码证书
    let certBlob = DerBlob(readToEnd(File(certDer, Read)))
    let certificate = cryptoKit.certificateFromDer(certBlob)
    println("证书解码成功")

    // 删除测试用文件
    removeIfExists(certPem)
    removeIfExists(certDer)
    removeIfExists(keyPem)
    return 0
}

运行结果:

证书解码成功

func certificateFromPem(String)

func certificateFromPem(text: String): Array<Certificate>

功能:将证书从 PEM 格式解码。

参数:

  • text: String - 待解码的 PEM 格式字符串。

返回值:

异常:

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.kit.*

main() {
    // 创建默认的CryptoKit实例
    let cryptoKit = DefaultCryptoKit()

    // 生成测试用证书文件
    let certPem = "./test_cert.pem"
    let keyPem = "./test_key.pem"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl req -x509 -newkey rsa:2048 -keyout ${keyPem} -out ${certPem} -days 1 -nodes -subj '/CN=test'"

    executeWithOutput("sh", ["-c", cmdStr])

    // 读取PEM格式的证书内容
    let pemContent = String.fromUtf8(readToEnd(File(certPem, Read)))

    // 核心演示:从 PEM 字符串解码证书
    let certificates = cryptoKit.certificateFromPem(pemContent)
    println("证书PEM解码成功")
    println("证书数量: ${certificates.size}")

    // 删除测试用文件
    removeIfExists(certPem)
    removeIfExists(keyPem)
    return 0
}

运行结果:

证书PEM解码成功
证书数量: 1

func dhParametersFromDer(DerBlob)

func dhParametersFromDer(encoded: DerBlob): DHParameters

功能:将 DH 密钥参数从 DER 格式解码。

参数:

  • encoded: DerBlob - 待解码的 DerBlob 对象。

返回值:

异常:

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.kit.*
import stdx.crypto.common.*

main() {
    // 创建默认的CryptoKit实例
    let cryptoKit = DefaultCryptoKit()

    // 生成测试用DH参数文件
    let dhPem = "./test_dh01.pem"
    let dhDer = "./test_dh.der"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl dhparam -out ${dhPem} 1024 && " + "openssl dhparam -in ${dhPem} -outform DER -out ${dhDer}"

    executeWithOutput("sh", ["-c", cmdStr])

    // 核心演示:从 DerBlob 解码DH参数
    let dhBlob = DerBlob(readToEnd(File(dhDer, Read)))
    let dhParams = cryptoKit.dhParametersFromDer(dhBlob)
    println("DH参数DER解码成功")

    // 删除测试用文件
    removeIfExists(dhPem)
    removeIfExists(dhDer)
    return 0
}

运行结果:

DH参数DER解码成功

func dhParametersFromPem(String)

func dhParametersFromPem(text: String): DHParameters

功能:将 DH 密钥参数从 PEM 格式解码。

参数:

  • text: String - 待解码的 PEM 格式字符串。

返回值:

异常:

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.kit.*

main() {
    // 创建默认的CryptoKit实例
    let cryptoKit = DefaultCryptoKit()

    // 生成测试用DH参数文件
    let dhPem = "./test_dh02.pem"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl dhparam -out ${dhPem} 1024"

    executeWithOutput("sh", ["-c", cmdStr])

    // 读取PEM格式的DH参数内容
    let pemContent = String.fromUtf8(readToEnd(File(dhPem, Read)))

    // 核心演示:从 PEM 字符串解码DH参数
    let dhParams = cryptoKit.dhParametersFromPem(pemContent)
    println("DH参数PEM解码成功")

    // 删除测试用文件
    removeIfExists(dhPem)
    return 0
}

运行结果:

DH参数PEM解码成功

func getRandomGen()

func getRandomGen(): RandomGenerator

功能:获取随机数生成器。

返回值:

示例:

import stdx.crypto.kit.*
import stdx.crypto.common.*

main() {
    // 创建默认的CryptoKit实例
    let cryptoKit = DefaultCryptoKit()

    // 核心演示:获取随机数生成器
    let randomGen = cryptoKit.getRandomGen()

    let randomNum = randomGen.nextBits(32)
    println("随机数生成器获取成功,随机数: ${randomNum}")

    return 0
}

可能的运行结果:

随机数生成器获取成功,随机数: 1153017157

func privateKeyFromDer(DerBlob)

func privateKeyFromDer(encoded: DerBlob): PrivateKey

功能:将私钥从 DER 格式解码。

参数:

  • encoded: DerBlob - 待解码的 DerBlob 对象。

返回值:

异常:

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.kit.*
import stdx.crypto.common.*

main() {
    // 创建默认的CryptoKit实例
    let cryptoKit = DefaultCryptoKit()

    // 生成测试用私钥文件
    let privateKeyPem = "./test_private.pem"
    let privateKeyDer = "./test_private.der"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl genrsa -out ${privateKeyPem} 2048 && " +
        "openssl rsa -in ${privateKeyPem} -outform DER -out ${privateKeyDer}"

    executeWithOutput("sh", ["-c", cmdStr])

    // 核心演示:从 DerBlob 解码私钥
    let keyBlob = DerBlob(readToEnd(File(privateKeyDer, Read)))
    let privateKey = cryptoKit.privateKeyFromDer(keyBlob)
    println("私钥DER解码成功")

    // 删除测试用文件
    removeIfExists(privateKeyPem)
    removeIfExists(privateKeyDer)
    return 0
}

运行结果:

私钥DER解码成功

func privateKeyFromDer(DerBlob, ?String)

func privateKeyFromDer(encoded: DerBlob, password!: ?String): PrivateKey

功能:将私钥从 DER 格式解密解码。密码为 None 时则不解密。

参数:

  • encoded: DerBlob - 待解密解码的 DerBlob 对象。
  • password!: ?String - 解密密码。

返回值:

异常:

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.kit.*
import stdx.crypto.common.*

main() {
    // 创建默认的CryptoKit实例
    let cryptoKit = DefaultCryptoKit()

    // 生成测试用加密私钥文件
    let encryptedKeyPem = "./test_encrypted_private.pem"
    let encryptedKeyDer = "./test_encrypted_private.der"
    let password = "testpass"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl genrsa -out ${encryptedKeyPem} 2048 && " +
        "openssl rsa -in ${encryptedKeyPem} -outform DER -aes256 -passout pass:${password} -out ${encryptedKeyDer}"

    executeWithOutput("sh", ["-c", cmdStr])

    // 核心演示:从 DerBlob 解密解码私钥
    let encryptedKeyBlob = DerBlob(readToEnd(File(encryptedKeyDer, Read)))
    let privateKey = cryptoKit.privateKeyFromDer(encryptedKeyBlob, password: password)
    println("加密私钥DER解码成功")

    // 删除测试用文件
    removeIfExists(encryptedKeyPem)
    removeIfExists(encryptedKeyDer)
    return 0
}

运行结果:

加密私钥DER解码成功

func privateKeyFromPem(String)

func privateKeyFromPem(text: String): PrivateKey

功能:将私钥从 PEM 格式解码。

参数:

  • text: String - 待解码的 PEM 格式字符串。

返回值:

异常:

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.kit.*

main() {
    // 创建默认的CryptoKit实例
    let cryptoKit = DefaultCryptoKit()

    // 生成测试用私钥文件
    let privateKeyPem = "./test_private.pem"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl genrsa -out ${privateKeyPem} 2048"

    executeWithOutput("sh", ["-c", cmdStr])

    // 读取PEM格式的私钥内容
    let pemContent = String.fromUtf8(readToEnd(File(privateKeyPem, Read)))

    // 核心演示:从 PEM 字符串解码私钥
    let privateKey = cryptoKit.privateKeyFromPem(pemContent)
    println("私钥PEM解码成功")

    // 删除测试用文件
    removeIfExists(privateKeyPem)
    return 0
}

运行结果:

私钥PEM解码成功

func privateKeyFromPem(String, ?String)

func privateKeyFromPem(text: String, password!: ?String): PrivateKey

功能:将私钥从 PEM 格式解密解码。密码为 None 时则不解密。

参数:

  • text: String - 待解密解码的 PEM 格式字符串。
  • password!: ?String - 解密密码。

返回值:

异常:

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.kit.*

main() {
    // 创建默认的CryptoKit实例
    let cryptoKit = DefaultCryptoKit()

    // 生成测试用加密私钥文件
    let encryptedKeyPem = "./test_encrypted_private.pem"
    let password = "testpass"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl genrsa -out ${encryptedKeyPem} 2048 && " +
        "openssl rsa -in ${encryptedKeyPem} -aes256 -passout pass:${password} -out ${encryptedKeyPem}"

    executeWithOutput("sh", ["-c", cmdStr])

    // 读取PEM格式的加密私钥内容
    let pemContent = String.fromUtf8(readToEnd(File(encryptedKeyPem, Read)))

    // 核心演示:从 PEM 字符串解密解码私钥
    let privateKey = cryptoKit.privateKeyFromPem(pemContent, password: password)
    println("加密私钥PEM解码成功")

    // 删除测试用文件
    removeIfExists(encryptedKeyPem)
    return 0
}

运行结果:

加密私钥PEM解码成功

func publicKeyFromDer(DerBlob)

func publicKeyFromDer(encoded: DerBlob): PublicKey

功能:将公钥从 DER 格式解码。

参数:

  • encoded: DerBlob - 待解码的 DerBlob 对象。

返回值:

异常:

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.kit.*
import stdx.crypto.common.*

main() {
    // 创建默认的CryptoKit实例
    let cryptoKit = DefaultCryptoKit()

    // 生成测试用私钥和公钥文件
    let privateKeyPem = "./test_private.pem"
    let publicKeyPem = "./test_public.pem"
    let publicKeyDer = "./test_public.der"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl genrsa -out ${privateKeyPem} 2048 && " +
        "openssl rsa -in ${privateKeyPem} -pubout -out ${publicKeyPem} && " +
        "openssl rsa -in ${publicKeyPem} -pubin -outform DER -out ${publicKeyDer}"

    executeWithOutput("sh", ["-c", cmdStr])

    // 核心演示:从 DerBlob 解码公钥
    let keyBlob = DerBlob(readToEnd(File(publicKeyDer, Read)))
    let publicKey = cryptoKit.publicKeyFromDer(keyBlob)
    println("公钥DER解码成功")

    // 删除测试用文件
    removeIfExists(privateKeyPem)
    removeIfExists(publicKeyPem)
    removeIfExists(publicKeyDer)
    return 0
}

运行结果:

公钥DER解码成功

func publicKeyFromPem(String)

func publicKeyFromPem(text: String): PublicKey

功能:将公钥从 PEM 格式解码。

参数:

  • text: String - 待解码的 PEM 格式字符串。

返回值:

异常:

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.kit.*

main() {
    // 创建默认的CryptoKit实例
    let cryptoKit = DefaultCryptoKit()

    // 生成测试用私钥和公钥文件
    let privateKeyPem = "./test_private.pem"
    let publicKeyPem = "./test_public.pem"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl genrsa -out ${privateKeyPem} 2048 && " +
        "openssl rsa -in ${privateKeyPem} -pubout -out ${publicKeyPem}"

    executeWithOutput("sh", ["-c", cmdStr])

    // 读取PEM格式的公钥内容
    let pemContent = String.fromUtf8(readToEnd(File(publicKeyPem, Read)))

    // 核心演示:从 PEM 字符串解码公钥
    let publicKey = cryptoKit.publicKeyFromPem(pemContent)
    println("公钥PEM解码成功")

    // 删除测试用文件
    removeIfExists(privateKeyPem)
    removeIfExists(publicKeyPem)
    return 0
}

运行结果:

公钥PEM解码成功

stdx.crypto.x509

功能介绍

x509 包提供处理数字证书功能,提供包括解析和序列化 X509 证书、验证证书、创建自签名证书、创建和验证证书链等主要功能。

使用本包需要外部依赖 OpenSSL 3 的 crypto 动态库文件,故使用前需安装相关工具。

  • 对于 Linux 操作系统,可参考以下方式:

    • 如果系统的包管理工具支持安装 OpenSSL 3 开发工具包,可通过这个方式安装,并确保系统安装目录下含有 libcrypto.so 和 libcrypto.so.3 这两个动态库文件,例如 Ubuntu 22.04 系统上可使用 sudo apt install libssl-dev 命令安装 libssl-dev 工具包;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libcrypto.so 和 libcrypto.so.3 这两个动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 LD_LIBRARY_PATH 以及 LIBRARY_PATH 中。
  • 对于 Windows 操作系统,可按照以下步骤:

    • 自行下载 OpenSSL 3.x.x 源码编译安装 x64 架构软件包或者自行下载安装第三方预编译的供开发人员使用的 OpenSSL 3.x.x 软件包;
    • 确保安装目录下含有 libcrypto.dll.a(或 libcrypto.lib)、libcrypto-3-x64.dll 这两个库文件;
    • 将 libcrypto.dll.a(或 libcrypto.lib) 所在的目录路径设置到环境变量 LIBRARY_PATH 中,将 libcrypto-3-x64.dll 所在的目录路径设置到环境变量 PATH 中。
  • 对于 macOS 操作系统,可参考以下方式:

    • 使用 brew install openssl@3 安装,并确保系统安装目录下含有 libcrypto.dylib 和 libcrypto.3.dylib 这两个动态库文件;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libcrypto.dylib 和 libcrypto.3.dylib 这两个动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 DYLD_LIBRARY_PATH 以及 LIBRARY_PATH 中。
  • 对于 Android 操作系统,可参考以下方式:

    • 由于 Android 系统默认自带的 OpenSSL 是裁剪版本,部分接口可能找不到符号而抛出异常,因此需要用户自行编译安装完整的 OpenSSL 3.x.x 版本;
    • 可自行下载 OpenSSL 3.x.x 源码,使用 Android NDK 交叉编译生成对应架构(当前只支持 arm64-v8a)的动态库文件,确保编译产物中含有 libcrypto.so 和 libcrypto.so.3 这些动态库文件;
    • 将这些文件所在目录设置到环境变量 LD_LIBRARY_PATH 中。

说明:

如果未安装 OpenSSL 3 软件包或者安装低版本的软件包,程序可能无法使用并抛出相关异常 X509Exception: Can not load openssl library or function xxx。

API 列表

类型别名

类型别名功能
IPx509 用 Array<Byte> 来记录 IP。

类名功能
GeneralDHParameters通用的 DH 密钥参数加解密功能实现。
X509CertificateX509 数字证书是一种用于加密通信的数字证书。
X509CertificateRequest数字证书签名请求。
X509Name证书实体可辨识名称。

枚举

枚举名功能
PublicKeyAlgorithm数字证书中包含的公钥信息。
SignatureAlgorithm证书签名算法。

结构体

结构体名功能
ExtKeyUsage数字证书扩展字段。
KeyUsage数字证书扩展字段中通常会包含携带公钥的用法说明。
SerialNumber数字证书的序列号。
Signature数字证书的签名。
VerifyOption校验选项。
X509CertificateInfo证书信息。
X509CertificateRequestInfo证书请求信息。

异常类

异常类名功能
X509Exceptionx509 包的异常类。

类型别名

type IP

public type IP = Array<Byte>

功能:x509 包用 Array<Byte> 来记录 IP

示例:

import stdx.crypto.x509.*

main() {
    // 创建 IP 地址列表
    let ipList = [[192u8, 168u8, 1u8, 1u8], [10u8, 0u8, 0u8, 1u8]]

    // 创建一个 X509CertificateRequestInfo 对象
    let certRequestInfo = X509CertificateRequestInfo(IPAddresses: ipList)

    // 输出 IP 地址列表
    println("IP Addresses: ${certRequestInfo.IPAddresses}")
}

运行结果:

IP Addresses: [[192, 168, 1, 1], [10, 0, 0, 1]]

class GeneralDHParameters

public class GeneralDHParameters <: DHParameters

功能:通用的 DH 密钥参数加解密功能实现。

父类型:

static func decodeDer(DerBlob)

static func decodeDer(encoded: DerBlob): DHParameters

功能:将 DH 密钥参数从 DER 格式解码。

说明:

  • DH(Diffie-Hellman)密钥交换协议是一种确保共享 KEY 安全穿越不安全网络的方法。
  • DER 和 PEM 是两种常见的编码格式。

参数:

  • encoded: DerBlob - DER 格式的 DH 密钥参数对象。

返回值:

  • DHParameters - 由 DER 格式解码出的 DH 密钥参数。

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.x509.*
import stdx.crypto.common.*

main() {
    // 生成测试用DH参数文件
    let dhPem = "./test_dh.pem03"
    let dhDer = "./test_dh.der"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl dhparam -out ${dhPem} 1024 && " + "openssl dhparam -in ${dhPem} -outform DER -out ${dhDer}"

    executeWithOutput("sh", ["-c", cmdStr])

    // 核心演示:从 DerBlob 解码DH参数
    let dhBlob = DerBlob(readToEnd(File(dhDer, Read)))
    let dhParams = GeneralDHParameters.decodeDer(dhBlob)
    println("DH参数DER解码成功")
    println("解码后类型: ${dhParams}")

    // 删除测试用文件
    removeIfExists(dhPem)
    removeIfExists(dhDer)
    return 0
}

运行结果:

DH参数DER解码成功
解码后类型: DHParameters(138 bytes)

static func decodeFromPem(String)

static func decodeFromPem(text: String): DHParameters

功能:将 DH 密钥参数从 PEM 格式解码。

参数:

  • text: String - PEM 格式的 DH 密钥参数字符流。

返回值:

  • DHParameters - 由 PEM 格式解码出的 DH 密钥参数。

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.x509.*

main() {
    // 生成测试用DH参数文件
    let dhPem = "./test_dh.pem04"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl dhparam -out ${dhPem} 1024"

    executeWithOutput("sh", ["-c", cmdStr])

    // 读取PEM格式的DH参数内容
    let pemContent = String.fromUtf8(readToEnd(File(dhPem, Read)))

    // 核心演示:从 PEM 字符串解码DH参数
    let dhParams = GeneralDHParameters.decodeFromPem(pemContent)
    println("DH参数PEM解码成功")
    println("解码后类型: ${dhParams}")

    // 删除测试用文件
    removeIfExists(dhPem)
    return 0
}

运行结果:

DH参数PEM解码成功
解码后类型: DHParameters(138 bytes)

func encodeToDer()

func encodeToDer(): DerBlob

功能:将 DH 密钥参数编码为 DER 格式。

返回值:

  • DerBlob - DH 密钥参数数据 DER 格式编码生成的对象。

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.x509.*
import stdx.crypto.common.*

main() {
    // 生成测试用DH参数文件
    let dhPem = "./test_dh.pem05"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl dhparam -out ${dhPem} 1024"

    executeWithOutput("sh", ["-c", cmdStr])

    // 读取PEM格式的DH参数内容并解码
    let pemContent = String.fromUtf8(readToEnd(File(dhPem, Read)))
    let dhParams = GeneralDHParameters.decodeFromPem(pemContent)

    // 核心演示:将DH参数编码为DER格式
    let derBlob = dhParams.encodeToDer()
    println("DH参数编码为DER格式成功")
    println("DER数据大小: ${derBlob.size}")

    // 删除测试用文件
    removeIfExists(dhPem)
    return 0
}

运行结果:

DH参数编码为DER格式成功
DER数据大小: 138

func encodeToPem()

func encodeToPem(): PemEntry

功能:将 DH 密钥参数编码为 PEM 格式。

返回值:

  • PemEntry - DH 密钥参数数据 PEM 格式编码生成的对象。

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.x509.*

main() {
    // 生成测试用DH参数文件
    let dhPem = "./test_dh.pem06"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl dhparam -out ${dhPem} 1024"

    executeWithOutput("sh", ["-c", cmdStr])

    // 读取PEM格式的DH参数内容并解码
    let pemContent = String.fromUtf8(readToEnd(File(dhPem, Read)))
    let dhParams = GeneralDHParameters.decodeFromPem(pemContent)

    // 核心演示:将DH参数编码为PEM格式
    let pemEntry = dhParams.encodeToPem()
    println("DH参数编码为PEM格式成功")
    println("PEM标签: ${pemEntry.label}")

    // 删除测试用文件
    removeIfExists(dhPem)
    return 0
}

运行结果:

DH参数编码为PEM格式成功
PEM标签: DH PARAMETERS

func toString()

public override func toString(): String

功能:转换为字符串格式。

返回值:

  • String - 字符串。

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.x509.*

main() {
    // 生成测试用DH参数文件
    let dhPem = "./test_dh.pem07"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl dhparam -out ${dhPem} 1024"

    executeWithOutput("sh", ["-c", cmdStr])

    // 读取PEM格式的DH参数内容并解码
    let pemContent = String.fromUtf8(readToEnd(File(dhPem, Read)))
    let dhParams = GeneralDHParameters.decodeFromPem(pemContent)

    // 核心演示:获取DH参数的字符串表示
    let typeStr = dhParams.toString()
    println("DH参数类型: ${typeStr}")

    // 删除测试用文件
    removeIfExists(dhPem)
    return 0
}

运行结果:

DH参数类型: DHParameters(138 bytes)

class X509Certificate

public class X509Certificate <: Certificate & Equatable<X509Certificate> & Hashable & ToString {
    public init(
        certificateInfo: X509CertificateInfo,
        parent!: X509Certificate,
        publicKey!: PublicKey,
        privateKey!: PrivateKey,
        signatureAlgorithm!: ?SignatureAlgorithm = None
    )
}

功能:X509 数字证书是一种用于加密通信的数字证书,它是公钥基础设施(PKI)的核心组件之一。X509 数字证书包含了一个实体的公钥和身份信息,用于验证该实体的身份和确保通信的安全性。

父类型:

prop dnsNames

public prop dnsNames: Array<String>

功能:解析数字证书备选名称中的域名。

类型:Array<String>

示例:

import stdx.crypto.x509.*

main() {
    // 找到系统根证书中的ISRG Root X1证书用作演示
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        // 如果找不到ISRG Root X1可以选择其他证书作演示
        if (cert.issuer.commonName == "ISRG Root X1") {
            let x509Certificate: X509Certificate = cert
            // 打印证书的DNS名称
            println("DNS Names: ${x509Certificate.dnsNames}")
            break
        }
    }
}

运行结果:

DNS Names: []

prop emailAddresses

public prop emailAddresses: Array<String>

功能:解析数字证书备选名称中的 email 地址。

类型:Array<String>

示例:

import stdx.crypto.x509.*

main() {
    // 找到系统根证书中的ISRG Root X1证书用作演示
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        // 如果找不到ISRG Root X1可以选择其他证书作演示
        if (cert.issuer.commonName == "ISRG Root X1") {
            let x509Certificate: X509Certificate = cert
            // 打印证书的Email地址
            println("Email Addresses: ${x509Certificate.emailAddresses}")
            break
        }
    }
}

运行结果:

Email Addresses: []

prop extKeyUsage

public prop extKeyUsage: ExtKeyUsage

功能:解析数字证书中的扩展密钥用法。

类型:ExtKeyUsage

示例:

import stdx.crypto.x509.*

main() {
    // 找到系统根证书中的ISRG Root X1证书用作演示
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        // 如果找不到ISRG Root X1可以选择其他证书作演示
        if (cert.issuer.commonName == "ISRG Root X1") {
            let x509Certificate: X509Certificate = cert
            // 打印证书的扩展密钥用法
            println("Ext Key Usage: ${x509Certificate.extKeyUsage}")
            break
        }
    }
}

运行结果:

Ext Key Usage:

prop IPAddresses

public prop IPAddresses: Array<IP>

功能:解析数字证书备选名称中的 IP 地址。

类型:Array<IP>

示例:

import stdx.crypto.x509.*

main() {
    // 找到系统根证书中的ISRG Root X1证书用作演示
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        // 如果找不到ISRG Root X1可以选择其他证书作演示
        if (cert.issuer.commonName == "ISRG Root X1") {
            let x509Certificate: X509Certificate = cert
            // 打印证书的IP地址
            println("IP Addresses: ${x509Certificate.IPAddresses}")
            break
        }
    }
}

运行结果:

IP Addresses: []

prop issuer

public prop issuer: X509Name

功能:解析数字证书的颁发者信息。

类型:X509Name

示例:

import stdx.crypto.x509.*

main() {
    // 找到系统根证书中的ISRG Root X1证书用作演示
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        // 如果找不到ISRG Root X1可以选择其他证书作演示
        if (cert.issuer.commonName == "ISRG Root X1") {
            let x509Certificate: X509Certificate = cert
            // 打印证书的颁发者信息
            println("Issuer: ${x509Certificate.issuer}")
            break
        }
    }
}

运行结果:

Issuer: c=US,o=Internet Security Research Group,cn=ISRG Root X1

prop keyUsage

public prop keyUsage: KeyUsage

功能:解析数字证书中的密钥用法。

类型:KeyUsage

示例:

import stdx.crypto.x509.*

main() {
    // 找到系统根证书中的ISRG Root X1证书用作演示
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        // 如果找不到ISRG Root X1可以选择其他证书作演示
        if (cert.issuer.commonName == "ISRG Root X1") {
            let x509Certificate: X509Certificate = cert
            // 打印证书的密钥用法
            println("Key Usage: ${x509Certificate.keyUsage}")
            break
        }
    }
}

运行结果:

Key Usage: CRLSign, CertSign

prop notAfter

public prop notAfter: DateTime

功能:解析数字证书的有效期截止时间。

类型:DateTime

示例:

import stdx.crypto.x509.*

main() {
    // 找到系统根证书中的ISRG Root X1证书用作演示
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        // 如果找不到ISRG Root X1可以选择其他证书作演示
        if (cert.issuer.commonName == "ISRG Root X1") {
            let x509Certificate: X509Certificate = cert
            // 打印证书的有效期截止时间
            println("Not After: ${x509Certificate.notAfter}")
            break
        }
    }
}

运行结果:

Not After: 2035-06-04T11:04:38Z

prop notBefore

public prop notBefore: DateTime

功能:解析数字证书的有效期开始时间。

类型:DateTime

示例:

import stdx.crypto.x509.*

main() {
    // 找到系统根证书中的ISRG Root X1证书用作演示
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        // 如果找不到ISRG Root X1可以选择其他证书作演示
        if (cert.issuer.commonName == "ISRG Root X1") {
            let x509Certificate: X509Certificate = cert
            // 打印证书的有效期开始时间
            println("Not Before: ${x509Certificate.notBefore}")
            break
        }
    }
}

运行结果:

Not Before: 2015-06-04T11:04:38Z

prop publicKey

public prop publicKey: PublicKey

功能:解析数字证书的公钥。

类型:PublicKey

示例:

import stdx.crypto.x509.*

main() {
    // 找到系统根证书中的ISRG Root X1证书用作演示
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        // 如果找不到ISRG Root X1可以选择其他证书作演示
        if (cert.issuer.commonName == "ISRG Root X1") {
            let x509Certificate: X509Certificate = cert
            // 打印证书的公钥信息
            println("Public Key: ${x509Certificate.publicKey}")
            break
        }
    }
}

运行结果:

Public Key: PublicKey(for 2.5.4.6: US
2.5.4.10: Internet Security Research Group
2.5.4.3: ISRG Root X1
)

prop publicKeyAlgorithm

public prop publicKeyAlgorithm: PublicKeyAlgorithm

功能:解析数字证书的公钥算法。

类型:PublicKeyAlgorithm

示例:

import stdx.crypto.x509.*

main() {
    // 找到系统根证书中的ISRG Root X1证书用作演示
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        // 如果找不到ISRG Root X1可以选择其他证书作演示
        if (cert.issuer.commonName == "ISRG Root X1") {
            let x509Certificate: X509Certificate = cert
            // 打印证书的公钥算法
            println("Public Key Algorithm: ${x509Certificate.publicKeyAlgorithm}")
            break
        }
    }
}

运行结果:

Public Key Algorithm: Public Key Algorithm: rsaEncryption

prop serialNumber

public prop serialNumber: SerialNumber

功能:解析数字证书的序列号。

类型:SerialNumber

示例:

import stdx.crypto.x509.*

main() {
    // 找到系统根证书中的ISRG Root X1证书用作演示
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        // 如果找不到ISRG Root X1可以选择其他证书作演示
        if (cert.issuer.commonName == "ISRG Root X1") {
            let x509Certificate: X509Certificate = cert
            // 打印证书的序列号
            println("Serial Number: ${x509Certificate.serialNumber}")
            break
        }
    }
}

运行结果:

Serial Number: 8210CFB0D240E3594463E0BB63828B00

prop signature

public prop signature: Signature

功能:解析数字证书的签名。

类型:Signature

示例:

import stdx.crypto.x509.*

main() {
    // 找到系统根证书中的ISRG Root X1证书用作演示
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        // 如果找不到ISRG Root X1可以选择其他证书作演示
        if (cert.issuer.commonName == "ISRG Root X1") {
            let x509Certificate: X509Certificate = cert
            // 获取证书的签名
            let signature = x509Certificate.signature
            break
        }
    }
}

prop signatureAlgorithm

public prop signatureAlgorithm: SignatureAlgorithm

功能:解析数字证书的签名算法。

类型:SignatureAlgorithm

示例:

import stdx.crypto.x509.*

main() {
    // 找到系统根证书中的ISRG Root X1证书用作演示
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        // 如果找不到ISRG Root X1可以选择其他证书作演示
        if (cert.issuer.commonName == "ISRG Root X1") {
            let x509Certificate: X509Certificate = cert
            // 打印证书的签名算法
            println(x509Certificate.signatureAlgorithm)
            break
        }
    }
}

运行结果:

Signature Algorithm: sha256WithRSAEncryption

prop subject

public prop subject: X509Name

功能:解析数字证书的使用者信息。

类型:X509Name

示例:

import stdx.crypto.x509.*

main() {
    // 找到系统根证书中的ISRG Root X1证书用作演示
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        // 如果找不到ISRG Root X1可以选择其他证书作演示
        if (cert.issuer.commonName == "ISRG Root X1") {
            let x509Certificate: X509Certificate = cert
            // 打印证书的使用者信息
            println("Subject: ${x509Certificate.subject}")
            break
        }
    }
}

运行结果:

Subject: c=US,o=Internet Security Research Group,cn=ISRG Root X1

init(X509CertificateInfo, X509Certificate, PublicKey, PrivateKey, ?SignatureAlgorithm)

public init(
    certificateInfo: X509CertificateInfo,
    parent!: X509Certificate,
    publicKey!: PublicKey,
    privateKey!: PrivateKey,
    signatureAlgorithm!: ?SignatureAlgorithm = None
)

功能:创建数字证书对象。

参数:

  • certificateInfo: X509CertificateInfo - 数字证书配置信息。
  • parent!: X509Certificate - 颁发者证书。
  • publicKey!: PublicKey - 申请人公钥,仅支持 RSA、ECDSA 和 DSA 公钥。
  • privateKey!: PrivateKey - 颁发者私钥,仅支持 RSA、ECDSA 和 DSA 私钥。
  • signatureAlgorithm!: ?SignatureAlgorithm - 证书签名算法,默认值为 None,使用默认值时默认的摘要类型是 SHA256

异常:

  • X509Exception - 公钥或私钥类型不支持、私钥类型和证书签名算法中的私钥类型不匹配或数字证书信息设置失败时,抛出异常。

示例:

import std.fs.*
import std.io.*
import std.time.*
import std.process.*
import stdx.crypto.x509.*
import stdx.crypto.keys.*

main() {
    // 生成测试用的根证书和密钥对
    let rootCertPem = "./test_root_cert.pem"
    let rootKeyPem = "./test_root_key.pem"
    let caKeyPem = "./test_ca_key.pem"

    let cmdStr =
        // OpenSSL 官方标准、无风险的测试用命令
        "openssl genrsa -out ${rootKeyPem} 2048 && " +
        "openssl req -new -x509 -key ${rootKeyPem} -out ${rootCertPem} -days 365 -subj '/CN=TestRootCA' && " +
        "openssl genrsa -out ${caKeyPem} 2048"

    executeWithOutput("sh", ["-c", cmdStr])

    // 读取根证书
    let rootCertContent = String.fromUtf8(readToEnd(File(rootCertPem, Read)))
    let rootCerts = X509Certificate.decodeFromPem(rootCertContent)
    let rootCert = rootCerts[0]

    // 读取根私钥
    let rootKeyContent = String.fromUtf8(readToEnd(File(rootKeyPem, Read)))
    let rootPrivateKey = GeneralPrivateKey.decodeFromPem(rootKeyContent)

    // 读取CA私钥
    let caKeyContent = String.fromUtf8(readToEnd(File(caKeyPem, Read)))
    let caKey = RSAPrivateKey.decodeFromPem(caKeyContent)

    // 获取CA的公钥
    let caPubKey = RSAPublicKey(caKey)

    // 创建X509证书对象的参数
    let x509Name = X509Name(commonName: "TestCA")
    let startTime = DateTime.of(year: 2023, month: 1, dayOfMonth: 1)
    let endTime = DateTime.of(year: 2025, month: 1, dayOfMonth: 1)
    let serialNumber = SerialNumber()
    let certInfo = X509CertificateInfo(
        serialNumber: serialNumber,
        notBefore: startTime,
        notAfter: endTime,
        subject: x509Name,
        dnsNames: [],
        IPAddresses: [],
        emailAddresses: [],
        keyUsage: KeyUsage(KeyUsage.DigitalSignature | KeyUsage.CertSign | KeyUsage.CRLSign),
        extKeyUsage: ExtKeyUsage([ExtKeyUsage.ServerAuth])
    )

    // 核心演示:创建X509证书对象
    let cert = X509Certificate(certInfo, parent: rootCert, publicKey: caPubKey, privateKey: rootPrivateKey)

    // 删除测试用文件
    removeIfExists(rootCertPem)
    removeIfExists(rootKeyPem)
    removeIfExists(caKeyPem)
    return 0
}

static func decodeFromDer(DerBlob)

public static func decodeFromDer(der: DerBlob): X509Certificate

功能:将 DER 格式的数字证书解码。

参数:

  • der: DerBlob - DER 格式的二进制数据。

返回值:

异常:

  • X509Exception - 数据为空时,或数据不是有效的数字证书 DER 格式时抛出异常。

示例:

import stdx.crypto.common.*
import stdx.crypto.x509.*

main() {
    // 模拟场景:从外部(文件/网络)获取的 DerBlob(此处通过系统根证书ISRG Root X1模拟)
    var derDataOpt: ?DerBlob = None
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        if (cert.issuer.commonName == "ISRG Root X1") {
            // 将证书编码为DER格式
            derDataOpt = cert.encodeToDer()
            break
        }
    }
    // 获取到DER数据
    let derData = derDataOpt.getOrThrow()

    // 核心演示:从DER数据解码证书
    let decodedCert = X509Certificate.decodeFromDer(derData)

    println("解码后根证书的通用名称: ${decodedCert.issuer.commonName}")
}

运行结果:

解码后根证书的通用名称: Some(ISRG Root X1)

static func decodeFromPem(String)

public static func decodeFromPem(pem: String): Array<X509Certificate>

功能:将数字证书从 PEM 格式解码。

参数:

  • pem: String - PEM 格式的数字证书字符流。

返回值:

异常:

  • X509Exception - 字符流不符合 PEM 格式时,或文件头不符合数字证书头标准时抛出异常。

示例:

import stdx.crypto.x509.*

main() {
    // 模拟场景:从外部(文件/网络)获取的PEM格式证书字符串(此处通过系统根证书ISRG Root X1模拟)
    var pemStrOpt: ?String = None
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        if (cert.issuer.commonName == "ISRG Root X1") {
            // 将证书编码为PEM格式
            let pemEntry = cert.encodeToPem()
            pemStrOpt = pemEntry.encode()
            break
        }
    }
    // 获取到PEM字符串
    let pemStr = pemStrOpt.getOrThrow()

    // 核心演示:从PEM字符串解码证书
    let decodedCerts = X509Certificate.decodeFromPem(pemStr)

    println("解码后证书数组长度: ${decodedCerts.size}")
    println("解码后根证书的通用名称: ${decodedCerts[0].issuer.commonName}")
}

运行结果:

解码后证书数组长度: 1
解码后根证书的通用名称: Some(ISRG Root X1)

static func systemRootCerts()

public static func systemRootCerts(): Array<X509Certificate>

功能:返回操作系统的根证书。

返回值:

示例:

import stdx.crypto.x509.*

main() {
    // 核心演示:获取系统根证书
    let rootCerts = X509Certificate.systemRootCerts()

    println("系统根证书数量: ${rootCerts.size}")
    if (rootCerts.size > 0) {
        // 打印第一个证书的通用名称
        println("第一个根证书的通用名称: ${rootCerts[0].issuer.commonName}")
    }
}

可能的运行结果:

系统根证书数量: 100
第一个根证书的通用名称: Some(ISRG Root X1)

func encodeToDer()

public func encodeToDer(): DerBlob

功能:将数字证书编码成 Der 格式。

返回值:

  • DerBlob - 编码后的 Der 格式的数字证书。

示例:

import stdx.crypto.x509.*

main() {
    // 模拟场景:已有的X509证书对象(此处通过系统根证书ISRG Root X1模拟)
    var certOpt: ?X509Certificate = None
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        if (cert.issuer.commonName == "ISRG Root X1") {
            certOpt = cert
            break
        }
    }
    // 核心演示:将证书编码为DER格式
    let derBlob = certOpt?.encodeToDer()

    println("DER格式证书数据长度: ${derBlob?.size ?? 0}")
}

运行结果:

DER格式证书数据长度: 1391

func encodeToPem()

public func encodeToPem(): PemEntry

功能:将数字证书编码成 PEM 格式。

返回值:

  • PemEntry - 编码后的 PEM 格式的数字证书。

示例:

import stdx.crypto.x509.*

main() {
    // 模拟场景:已有的X509证书对象(此处通过系统根证书ISRG Root X1模拟)
    var certOpt: ?X509Certificate = None
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        if (cert.issuer.commonName == "ISRG Root X1") {
            certOpt = cert
            break
        }
    }

    // 核心演示:将证书编码为PEM格式
    let pemEntry = certOpt?.encodeToPem()

    println("PEM格式证书编码后字符串长度: ${pemEntry?.encode().size ?? 0}")
}

运行结果:

PEM格式证书编码后字符串长度: 1939

func hashCode()

public override func hashCode(): Int64

功能:返回证书哈希值。

返回值:

  • Int64 - 对证书对象进行哈希计算后得到的结果。

示例:

import stdx.crypto.x509.*

main() {
    // 模拟场景:已有的X509证书对象(此处通过系统根证书ISRG Root X1模拟)
    var certOpt: ?X509Certificate = None
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        if (cert.issuer.commonName == "ISRG Root X1") {
            certOpt = cert
            break
        }
    }

    // 核心演示:获取证书哈希值
    let hashCode = certOpt?.hashCode()

    println("证书哈希值: ${hashCode ?? 0}")
}

运行结果:

证书哈希值: -3207102703759299675

func toString()

public override func toString(): String

功能:生成证书名称字符串,包含证书的使用者信息、有效期以及颁发者信息。

返回值:

  • String - 证书名称字符串。

示例:

import stdx.crypto.x509.*

main() {
    // 模拟场景:已有的X509证书对象(此处通过系统根证书ISRG Root X1模拟)
    var certOpt: ?X509Certificate = None
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        if (cert.issuer.commonName == "ISRG Root X1") {
            certOpt = cert
            break
        }
    }

    // 核心演示:获取证书字符串表示
    let certStr = certOpt?.toString()

    println("证书字符串表示: ${certStr ?? "未找到证书"}")
}

运行结果:

证书字符串表示: X509Certificate(for=c=US,o=Internet Security Research Group,cn=ISRG Root X1, valid in 2015-06-04T11:04:38Z..2035-06-04T11:04:38Z, issued by c=US,o=Internet Security Research Group,cn=ISRG Root X1)

func verify(VerifyOption)

public func verify(verifyOption: VerifyOption): Bool

功能:根据验证选项验证当前证书的有效性。

验证优先级:

  1. 优先验证有效期;
  2. 可选验证 DNS 域名;
  3. 最后根据根证书和中间证书验证其有效性。

参数:

返回值:

  • Bool - 证书有效返回 true,否则返回 false。

异常:

  • X509Exception - 检验过程中失败,比如内存分配异常等内部错误,则抛出异常。

示例:

import stdx.crypto.x509.*
import std.time.*

main() {
    // 模拟场景:已有的X509证书对象(此处通过系统根证书ISRG Root X1模拟)
    var certOpt: ?X509Certificate = None
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        if (cert.issuer.commonName == "ISRG Root X1") {
            certOpt = cert
            break
        }
    }

    // 创建验证选项
    var verifyOpt = VerifyOption()
    // 设置验证时间
    verifyOpt.time = DateTime.of(year: 2036, month: 1, dayOfMonth: 1)
    // 核心演示:验证证书
    let isValid = certOpt?.verify(verifyOpt)

    println("证书是否有效: ${isValid ?? false}")

    // 创建另一个验证选项
    var verifyOpt2 = VerifyOption()
    verifyOpt2.time = DateTime.of(year: 2026, month: 1, dayOfMonth: 1)
    // 核心演示:验证证书
    let isValid2 = certOpt?.verify(verifyOpt2)

    println("证书是否有效: ${isValid2 ?? false}")
}

运行结果:

证书是否有效: false
证书是否有效: true

operator func !=(X509Certificate)

public override operator func !=(other: X509Certificate): Bool

功能:判不等。

参数:

返回值:

  • Bool - 若证书不同,返回 true;否则,返回 false。

示例:

import stdx.crypto.x509.*

main() {
    // 模拟场景:已有的X509证书对象(此处通过系统根证书ISRG Root X1模拟)
    var certOpt1: ?X509Certificate = None
    var certOpt2: ?X509Certificate = None
    let certs = X509Certificate.systemRootCerts()
    var i = 0
    for (cert in certs) {
        if (i == 0 && cert.issuer.commonName == "ISRG Root X1") {
            certOpt1 = cert
            i = 1
        } else if (i == 1) {
            certOpt2 = cert
            break
        }
    }

    // 核心演示:比较两个证书是否不相等
    let isNotEqual = certOpt1 != certOpt2

    println("两个不同证书是否不相等: ${isNotEqual}")

    // 比较同一个证书是否不相等
    let isNotEqualSelf = certOpt1 != certOpt1
    println("同一个证书是否与自身不相等: ${isNotEqualSelf}")
}

运行结果:

两个不同证书是否不相等: true
同一个证书是否与自身不相等: false

operator func ==(X509Certificate)

public override operator func ==(other: X509Certificate): Bool

功能:判等。

参数:

返回值:

  • Bool - 若证书相同,返回 true;否则,返回 false。

示例:

import stdx.crypto.x509.*

main() {
    // 模拟场景:已有的X509证书对象(此处通过系统根证书ISRG Root X1模拟)
    var certOpt1: ?X509Certificate = None
    var certOpt2: ?X509Certificate = None
    let certs = X509Certificate.systemRootCerts()
    var i = 0
    for (cert in certs) {
        if (i == 0 && cert.issuer.commonName == "ISRG Root X1") {
            certOpt1 = cert
            i = 1
        } else if (i == 1) {
            certOpt2 = cert
            break
        }
    }

    // 核心演示:比较两个不同证书是否相等
    let isEqual = certOpt1 == certOpt2

    println("两个不同证书是否相等: ${isEqual}")

    // 比较同一个证书是否相等
    let isEqualSelf = certOpt1 == certOpt1
    println("同一个证书是否与自身相等: ${isEqualSelf}")
}

运行结果:

两个不同证书是否相等: false
同一个证书是否与自身相等: true

class X509CertificateRequest

public class X509CertificateRequest <: Hashable & ToString {
    public init(
        privateKey: PrivateKey,
        certificateRequestInfo!: ?X509CertificateRequestInfo = None,
        signatureAlgorithm!: ?SignatureAlgorithm = None
    )
}

功能:数字证书签名请求。

父类型:

  • Hashable
  • ToString

prop dnsNames

public prop dnsNames: Array<String>

功能:解析数字证书签名请求备选名称中的域名。

类型:Array<String>

示例:

import stdx.crypto.x509.*
import stdx.crypto.keys.*

main() {
    // 创建测试用的私钥
    let rsaKey = RSAPrivateKey(2048)

    // 创建证书请求信息
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "Beijing",
        localityName: "Haidian",
        organizationName: "ExampleTech Inc.",
        organizationalUnitName: "CA Department",
        commonName: "example.com",
        email: "test@email.com"
    )

    let csrInfo = X509CertificateRequestInfo(subject: x509Name, dnsNames: ["test.example.com"])
    let csr = X509CertificateRequest(rsaKey, certificateRequestInfo: csrInfo, signatureAlgorithm: SHA256WithRSA)

    // 核心演示:获取证书请求的DNS名称
    let dnsNames = csr.dnsNames
    println("DNS Names: ${dnsNames}")
}

运行结果:

DNS Names: [test.example.com]

prop emailAddresses

public prop emailAddresses: Array<String>

功能:解析数字证书签名请求备选名称中的 email 地址。

类型:Array<String>

示例:

import stdx.crypto.x509.*
import stdx.crypto.keys.*

main() {
    // 创建测试用的私钥
    let rsaKey = RSAPrivateKey(2048)

    // 创建证书请求信息
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "Beijing",
        localityName: "Haidian",
        organizationName: "ExampleTech Inc.",
        organizationalUnitName: "CA Department",
        commonName: "example.com",
        email: "test@email.com"
    )

    let csrInfo = X509CertificateRequestInfo(subject: x509Name, emailAddresses: ["user@example.com"])
    let csr = X509CertificateRequest(rsaKey, certificateRequestInfo: csrInfo, signatureAlgorithm: SHA256WithRSA)

    // 核心演示:获取证书请求的邮箱地址
    let emailAddresses = csr.emailAddresses
    println("Email Addresses: ${emailAddresses}")
}

运行结果:

Email Addresses: [user@example.com]

prop IPAddresses

public prop IPAddresses: Array<IP>

功能:解析数字证书签名请求备选名称中的 IP 地址。

类型:Array<IP>

示例:

import stdx.crypto.x509.*
import stdx.crypto.keys.*

main() {
    // 创建测试用的私钥
    let rsaKey = RSAPrivateKey(2048)

    // 创建证书请求信息
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "Beijing",
        localityName: "Haidian",
        organizationName: "ExampleTech Inc.",
        organizationalUnitName: "CA Department",
        commonName: "192, 168, 1, 1",
        email: "test@email.com"
    )

    let ip1: IP = [192, 168, 1, 1] // 演示常用,无实际指向
    let ip2: IP = [32, 1, 13, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] // 示例IPv6(RFC 3849保留地址) 

    let csrInfo = X509CertificateRequestInfo(subject: x509Name, IPAddresses: [ip1, ip2])
    let csr = X509CertificateRequest(rsaKey, certificateRequestInfo: csrInfo, signatureAlgorithm: SHA256WithRSA)

    // 核心演示:获取证书请求的IP地址
    let ipAddresses = csr.IPAddresses
    println("IP Addresses: ${ipAddresses}")
}

运行结果:

IP Addresses: [[192, 168, 1, 1], [32, 1, 13, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]]

prop publicKey

public prop publicKey: PublicKey

功能:解析数字证书签名请求的公钥。

类型:PublicKey

示例:

import stdx.crypto.x509.*
import stdx.crypto.keys.*

main() {
    // 创建测试用的私钥
    let rsaKey = RSAPrivateKey(2048)

    // 创建证书请求信息
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "Beijing",
        localityName: "Haidian",
        organizationName: "ExampleTech Inc.",
        organizationalUnitName: "CA Department",
        commonName: "example.com",
        email: "test@email.com"
    )

    let csrInfo = X509CertificateRequestInfo(subject: x509Name)
    let csr = X509CertificateRequest(rsaKey, certificateRequestInfo: csrInfo, signatureAlgorithm: SHA256WithRSA)

    // 核心演示:获取证书请求的公钥
    let publicKey = csr.publicKey
    println("Public Key: ${publicKey}")
}

运行结果:

Public Key: PublicKey(for 2.5.4.6: CN
2.5.4.8: Beijing
2.5.4.7: Haidian
2.5.4.10: ExampleTech Inc.
2.5.4.11: CA Department
2.5.4.3: example.com
1.2.840.113549.1.9.1: test@email.com
)

prop publicKeyAlgorithm

public prop publicKeyAlgorithm: PublicKeyAlgorithm

功能:解析数字证书签名请求的公钥算法。

类型:PublicKeyAlgorithm

示例:

import stdx.crypto.x509.*
import stdx.crypto.keys.*

main() {
    // 创建测试用的私钥
    let rsaKey = RSAPrivateKey(2048)

    // 创建证书请求信息
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "Beijing",
        localityName: "Haidian",
        organizationName: "ExampleTech Inc.",
        organizationalUnitName: "CA Department",
        commonName: "example.com",
        email: "test@email.com"
    )

    let csrInfo = X509CertificateRequestInfo(subject: x509Name)
    let csr = X509CertificateRequest(rsaKey, certificateRequestInfo: csrInfo, signatureAlgorithm: SHA256WithRSA)

    // 核心演示:获取证书请求的公钥算法
    let publicKeyAlgorithm = csr.publicKeyAlgorithm
    println(publicKeyAlgorithm)
}

运行结果:

Public Key Algorithm: rsaEncryption

prop signature

public prop signature: Signature

功能:解析数字证书签名请求的签名。

类型:Signature

示例:

import stdx.crypto.x509.*
import stdx.crypto.keys.*

main() {
    // 创建测试用的私钥
    let rsaKey = RSAPrivateKey(2048)

    // 创建证书请求信息
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "Beijing",
        localityName: "Haidian",
        organizationName: "ExampleTech Inc.",
        organizationalUnitName: "CA Department",
        commonName: "example.com",
        email: "test@email.com"
    )

    let csrInfo = X509CertificateRequestInfo(subject: x509Name)
    let csr = X509CertificateRequest(rsaKey, certificateRequestInfo: csrInfo, signatureAlgorithm: SHA256WithRSA)

    // 核心演示:获取证书请求的签名
    let signature = csr.signature
}

prop signatureAlgorithm

public prop signatureAlgorithm: SignatureAlgorithm

功能:解析数字证书签名请求的签名算法。

类型:SignatureAlgorithm

示例:

import stdx.crypto.x509.*
import stdx.crypto.keys.*

main() {
    // 创建测试用的私钥
    let rsaKey = RSAPrivateKey(2048)

    // 创建证书请求信息
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "Beijing",
        localityName: "Haidian",
        organizationName: "ExampleTech Inc.",
        organizationalUnitName: "CA Department",
        commonName: "example.com",
        email: "test@email.com"
    )

    let csrInfo = X509CertificateRequestInfo(subject: x509Name)
    let csr = X509CertificateRequest(rsaKey, certificateRequestInfo: csrInfo, signatureAlgorithm: SHA256WithRSA)

    // 核心演示:获取证书请求的签名算法
    let signatureAlgorithm = csr.signatureAlgorithm
    println(signatureAlgorithm)
}

运行结果:

Signature Algorithm: sha256WithRSAEncryption

prop subject

public prop subject: X509Name

功能:解析数字证书签名请求的使用者信息。

类型:X509Name

示例:

import stdx.crypto.x509.*
import stdx.crypto.keys.*

main() {
    // 创建测试用的私钥
    let rsaKey = RSAPrivateKey(2048)

    // 创建证书请求信息
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "Beijing",
        localityName: "Haidian",
        organizationName: "ExampleTech Inc.",
        organizationalUnitName: "CA Department",
        commonName: "example.com",
        email: "test@email.com"
    )

    let csrInfo = X509CertificateRequestInfo(subject: x509Name)
    let csr = X509CertificateRequest(rsaKey, certificateRequestInfo: csrInfo, signatureAlgorithm: SHA256WithRSA)

    // 核心演示:获取证书请求的使用者信息
    let subject = csr.subject
    println("Subject: ${subject}")
}

运行结果:

Subject: c=CN,st=Beijing,l=Haidian,o=ExampleTech Inc.,ou=CA Department,cn=example.com,email=test@email.com

init(PrivateKey, ?X509CertificateRequestInfo, ?SignatureAlgorithm)

public init(
    privateKey: PrivateKey,
    certificateRequestInfo!: ?X509CertificateRequestInfo = None,
    signatureAlgorithm!: ?SignatureAlgorithm = None
)

功能:创建数字证书签名请求对象。

参数:

  • privateKey: PrivateKey - 私钥,仅支持 RSA、ECDSA 和 DSA 私钥。
  • certificateRequestInfo!: ?X509CertificateRequestInfo - 数字证书签名信息,默认值为 None。
  • signatureAlgorithm!: ?SignatureAlgorithm - 证书签名算法,默认值为 None,使用默认值时默认的摘要类型是 SHA256

异常:

  • X509Exception - 私钥类型不支持、私钥类型和证书签名算法中的私钥类型不匹配或数字证书签名信息设置失败时,抛出异常。

示例:

import stdx.crypto.x509.*
import stdx.crypto.keys.*

main() {
    // 创建测试用的私钥
    let rsaKey = RSAPrivateKey(2048)

    // 创建证书请求信息
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "Beijing",
        localityName: "Haidian",
        organizationName: "ExampleTech Inc.",
        organizationalUnitName: "CA Department",
        commonName: "example.com",
        email: "test@email.com"
    )

    let csrInfo = X509CertificateRequestInfo(subject: x509Name)
    let csr = X509CertificateRequest(rsaKey, certificateRequestInfo: csrInfo, signatureAlgorithm: SHA256WithRSA)

    // 输出证书请求对象信息
    println("Certificate Request Subject: ${csr.subject}")
}

运行结果:

Certificate Request Subject: c=CN,st=Beijing,l=Haidian,o=ExampleTech Inc.,ou=CA Department,cn=example.com,email=test@email.com

static func decodeFromDer(DerBlob)

public static func decodeFromDer(der: DerBlob): X509CertificateRequest

功能:将 DER 格式的数字证书签名请求解码。

参数:

  • der: DerBlob - DER 格式的二进制数据。

返回值:

异常:

  • X509Exception - 数据为空时,或数据不是有效的数字证书签名请求 DER 格式时抛出异常。

示例:

import stdx.crypto.x509.*
import stdx.crypto.keys.*

main() {
    // 创建测试用的私钥
    let rsaKey = RSAPrivateKey(2048)

    // 创建证书请求信息
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "Beijing",
        localityName: "Haidian",
        organizationName: "ExampleTech Inc.",
        organizationalUnitName: "CA Department",
        commonName: "example.com",
        email: "test@email.com"
    )

    let csrInfo = X509CertificateRequestInfo(subject: x509Name)
    let originalCsr = X509CertificateRequest(rsaKey, certificateRequestInfo: csrInfo, signatureAlgorithm: SHA256WithRSA)

    // 模拟场景:从外部(文件/网络)获取的 DerBlob(此处通过代码生成)
    let derBlob = originalCsr.encodeToDer()

    // 核心演示:从DER格式解码证书请求
    let decodedCsr = X509CertificateRequest.decodeFromDer(derBlob)

    // 输出解码后的证书请求信息
    println("Decoded CSR Subject: ${decodedCsr.subject}")
}

运行结果:

Decoded CSR Subject: c=CN,st=Beijing,l=Haidian,o=ExampleTech Inc.,ou=CA Department,cn=example.com,email=test@email.com

static func decodeFromPem(String)

public static func decodeFromPem(pem: String): Array<X509CertificateRequest>

功能:将数字证书签名请求从 PEM 格式解码。

参数:

  • pem: String - PEM 格式的数字证书签名请求字符流。

返回值:

异常:

  • X509Exception - 字符流不符合 PEM 格式时,或文件头不符合数字证书签名请求头标准时抛出异常。

示例:

import stdx.crypto.x509.*
import stdx.crypto.keys.*

main() {
    // 创建测试用的私钥
    let rsaKey = RSAPrivateKey(2048)

    // 创建证书请求信息
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "Beijing",
        localityName: "Haidian",
        organizationName: "ExampleTech Inc.",
        organizationalUnitName: "CA Department",
        commonName: "example.com",
        email: "test@email.com"
    )

    let csrInfo = X509CertificateRequestInfo(subject: x509Name)
    let originalCsr = X509CertificateRequest(rsaKey, certificateRequestInfo: csrInfo, signatureAlgorithm: SHA256WithRSA)

    // 模拟场景:从外部(文件/网络)获取的PEM字符串(此处通过代码生成)
    let pemEntry = originalCsr.encodeToPem()
    let pemString = pemEntry.encode()

    // 核心演示:从PEM格式解码证书请求
    let decodedCsrs = X509CertificateRequest.decodeFromPem(pemString)
    let decodedCsr = decodedCsrs[0]

    // 输出解码后的证书请求信息
    println("Decoded CSR Subject: ${decodedCsr.subject}")
}

运行结果:

Decoded CSR Subject: c=CN,st=Beijing,l=Haidian,o=ExampleTech Inc.,ou=CA Department,cn=example.com,email=test@email.com

func encodeToDer()

public func encodeToDer(): DerBlob

功能:将数字证书签名请求编码成 Der 格式。

返回值:

  • DerBlob - 编码后的 Der 格式的数字证书签名请求。

示例:

import stdx.crypto.x509.*
import stdx.crypto.keys.*

main() {
    // 创建测试用的私钥
    let rsaKey = RSAPrivateKey(2048)

    // 创建证书请求信息
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "Beijing",
        localityName: "Haidian",
        organizationName: "ExampleTech Inc.",
        organizationalUnitName: "CA Department",
        commonName: "example.com",
        email: "test@email.com"
    )

    let csrInfo = X509CertificateRequestInfo(subject: x509Name)
    let csr = X509CertificateRequest(rsaKey, certificateRequestInfo: csrInfo, signatureAlgorithm: SHA256WithRSA)

    // 核心演示:将证书请求编码为DER格式
    let derBlob = csr.encodeToDer()

    // 输出DER数据的大小
    println("DER Blob Size: ${derBlob.size}")
}

运行结果:

DER Blob Size: 767

func encodeToPem()

public func encodeToPem(): PemEntry

功能:将数字证书签名请求编码成 PEM 格式。

返回值:

  • PemEntry - 编码后的 PEM 格式的数字证书签名请求。

示例:

import stdx.crypto.x509.*
import stdx.crypto.keys.*

main() {
    // 创建测试用的私钥
    let rsaKey = RSAPrivateKey(2048)

    // 创建证书请求信息
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "Beijing",
        localityName: "Haidian",
        organizationName: "ExampleTech Inc.",
        organizationalUnitName: "CA Department",
        commonName: "example.com",
        email: "test@email.com"
    )

    let csrInfo = X509CertificateRequestInfo(subject: x509Name)
    let csr = X509CertificateRequest(rsaKey, certificateRequestInfo: csrInfo, signatureAlgorithm: SHA256WithRSA)

    // 核心演示:将证书请求编码为PEM格式
    let pemEntry = csr.encodeToPem()

    // 输出PEM条目的标签
    println("PEM Entry Label: ${pemEntry.label}")
}

运行结果:

PEM Entry Label: CERTIFICATE REQUEST

func hashCode()

public override func hashCode(): Int64

功能:返回证书签名请求哈希值。

返回值:

  • Int64 - 对证书签名请求对象进行哈希计算后得到的结果。

示例:

import stdx.crypto.x509.*
import stdx.crypto.keys.*

main() {
    // 创建测试用的私钥
    let rsaKey = RSAPrivateKey(2048)

    // 创建证书请求信息
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "Beijing",
        localityName: "Haidian",
        organizationName: "ExampleTech Inc.",
        organizationalUnitName: "CA Department",
        commonName: "example.com",
        email: "test@email.com"
    )

    let csrInfo = X509CertificateRequestInfo(subject: x509Name)
    let csr = X509CertificateRequest(rsaKey, certificateRequestInfo: csrInfo, signatureAlgorithm: SHA256WithRSA)

    // 获取证书请求的哈希值
    let hashCode = csr.hashCode()

    // 输出哈希值
    println("Hash Code: ${hashCode}")
}

可能的运行结果:

Hash Code: -461863998621080557

func toString()

public override func toString(): String

功能:生成证书签名请求名称字符串,包含证书签名请求的使用者信息。

返回值:

  • String - 证书签名请求名称字符串。

示例:

import stdx.crypto.x509.*
import stdx.crypto.keys.*

main() {
    // 创建测试用的私钥
    let rsaKey = RSAPrivateKey(2048)

    // 创建证书请求信息
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "Beijing",
        localityName: "Haidian",
        organizationName: "ExampleTech Inc.",
        organizationalUnitName: "CA Department",
        commonName: "example.com",
        email: "test@email.com"
    )

    let csrInfo = X509CertificateRequestInfo(subject: x509Name)
    let csr = X509CertificateRequest(rsaKey, certificateRequestInfo: csrInfo, signatureAlgorithm: SHA256WithRSA)

    // 获取证书请求的字符串表示
    let str = csr.toString()

    // 输出字符串表示
    println("String representation: ${str}")
}

运行结果:

String representation: X509CertificateRequest(for c=CN,st=Beijing,l=Haidian,o=ExampleTech Inc.,ou=CA Department,cn=example.com,email=test@email.com)

class X509Name

public class X509Name <: ToString {
    public init(
        countryName!: ?String = None,
        provinceName!: ?String = None,
        localityName!: ?String = None,
        organizationName!: ?String = None,
        organizationalUnitName!: ?String = None,
        commonName!: ?String = None,
        email!: ?String = None
    )
}

功能:证书实体可辨识名称(Distinguished Name)是数字证书中的一个重要组成部分,作用是确保证书的持有者身份的真实性和可信度,同时也是数字证书验证的重要依据之一。

X509Name 通常包含证书实体的国家或地区名称(Country Name)、州或省名称(State or Province Name)、城市名称(Locality Name)、组织名称(Organization Name)、组织单位名称(Organizational Unit Name)、通用名称(Common Name)。有时也会包含 email 地址。

父类型:

  • ToString

prop commonName

public prop commonName: ?String

功能:返回证书实体的通用名称。

类型:?String

示例:

import stdx.crypto.x509.*

main() {
    // 创建X509Name对象
    let x509Name = X509Name(commonName: "example.com")

    // 获取通用名称
    let cn = x509Name.commonName
    println("Common Name: ${cn}")
}

运行结果:

Common Name: Some(example.com)

prop countryName

public prop countryName: ?String

功能:返回证书实体的国家或地区名称。

类型:?String

示例:

import stdx.crypto.x509.*

main() {
    // 创建X509Name对象
    let x509Name = X509Name(countryName: "CN")

    // 获取国家或地区名称
    let country = x509Name.countryName
    println("Country Name: ${country}")
}

运行结果:

Country Name: Some(CN)

prop email

public prop email: ?String

功能:返回证书实体的 email 地址。

类型:?String

示例:

import stdx.crypto.x509.*

main() {
    // 创建X509Name对象
    let x509Name = X509Name(email: "test@example.com")

    // 获取email地址
    let email = x509Name.email
    println("Email: ${email}")
}

运行结果:

Email: Some(test@example.com)

prop localityName

public prop localityName: ?String

功能:返回证书实体的城市名称。

类型:?String

示例:

import stdx.crypto.x509.*

main() {
    // 创建X509Name对象
    let x509Name = X509Name(localityName: "Beijing")

    // 获取城市名称
    let locality = x509Name.localityName
    println("Locality Name: ${locality}")
}

运行结果:

Locality Name: Some(Beijing)

prop organizationalUnitName

public prop organizationalUnitName: ?String

功能:返回证书实体的组织单位名称。

类型:?String

示例:

import stdx.crypto.x509.*

main() {
    // 创建X509Name对象
    let x509Name = X509Name(organizationalUnitName: "IT Department")

    // 获取组织单位名称
    let orgUnit = x509Name.organizationalUnitName
    println("Organizational Unit Name: ${orgUnit}")
}

运行结果:

Organizational Unit Name: Some(IT Department)

prop organizationName

public prop organizationName: ?String

功能:返回证书实体的组织名称。

类型:?String

示例:

import stdx.crypto.x509.*

main() {
    // 创建X509Name对象
    let x509Name = X509Name(organizationName: "Example Corp")

    // 获取组织名称
    let org = x509Name.organizationName
    println("Organization Name: ${org}")
}

运行结果:

Organization Name: Some(Example Corp)

prop provinceName

public prop provinceName: ?String

功能:返回证书实体的州或省名称。

类型:?String

示例:

import stdx.crypto.x509.*

main() {
    // 创建X509Name对象
    let x509Name = X509Name(provinceName: "Beijing")

    // 获取州或省名称
    let province = x509Name.provinceName
    println("Province Name: ${province}")
}

运行结果:

Province Name: Some(Beijing)

init(?String, ?String, ?String, ?String, ?String, ?String, ?String)

    public init(
        countryName!: ?String = None,
        provinceName!: ?String = None,
        localityName!: ?String = None,
        organizationName!: ?String = None,
        organizationalUnitName!: ?String = None,
        commonName!: ?String = None,
        email!: ?String = None
    )

功能:构造 X509Name 对象。

参数:

  • countryName!: ?String - 国家或地区名称,默认值为 None。
  • provinceName!: ?String - 州或省名称,默认值为 None。
  • localityName!: ?String - 城市名称,默认值为 None。
  • organizationName!: ?String - 组织名称,默认值为 None。
  • organizationalUnitName!: ?String - 组织单位名称,默认值为 None。
  • commonName!: ?String - 通用名称,默认值为 None。
  • email!: ?String - email 地址,默认值为 None。

异常:

  • X509Exception - 设置证书实体可辨识名称时失败,比如内存分配异常等内部错误,则抛出异常。

示例:

import stdx.crypto.x509.*

main() {
    // 创建包含所有字段的X509Name对象
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "Beijing",
        localityName: "Haidian",
        organizationName: "Example Corp",
        organizationalUnitName: "IT Department",
        commonName: "example.com",
        email: "admin@example.com"
    )

    // 输出X509Name对象信息
    println("X509Name: ${x509Name}")
}

运行结果:

X509Name: c=CN,st=Beijing,l=Haidian,o=Example Corp,ou=IT Department,cn=example.com,email=admin@example.com

func toString()

public override func toString(): String

功能:生成证书实体名称字符串。

返回值:

  • String - 证书实体名称字符串,包含实体名称中存在的字段信息。

示例:

import stdx.crypto.x509.*

main() {
    // 创建X509Name对象
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "Beijing",
        localityName: "Haidian",
        organizationName: "Example Corp",
        commonName: "example.com"
    )

    // 获取X509Name的字符串表示
    let nameStr = x509Name.toString()
    println("X509Name String: ${nameStr}")
}

运行结果:

X509Name String: c=CN,st=Beijing,l=Haidian,o=Example Corp,cn=example.com

枚举

enum PublicKeyAlgorithm

public enum PublicKeyAlgorithm <: Equatable<PublicKeyAlgorithm> & ToString {
    RSA | DSA | ECDSA | UnknownPublicKeyAlgorithm
}

功能:数字证书中包含的公钥信息,目前支持的种类有:RSA、DSA、ECDSA。

父类型:

DSA

DSA

功能:DSA 公钥算法。

ECDSA

ECDSA

功能:ECDSA 公钥算法。

RSA

RSA

功能:RSA 公钥算法。

UnknownPublicKeyAlgorithm

UnknownPublicKeyAlgorithm

功能:未知公钥算法。

func toString()

public override func toString(): String

功能:生成证书携带的公钥算法名称字符串。

返回值:

  • String - 证书携带的公钥算法名称字符串。

示例:

import stdx.crypto.x509.*

main() {
    // 创建一个 PublicKeyAlgorithm 枚举值
    let algorithm = PublicKeyAlgorithm.RSA

    // 获取算法的字符串表示
    let str = algorithm.toString()
    println("Algorithm String: ${str}")
}

运行结果:

Algorithm String: Public Key Algorithm: rsaEncryption

operator func !=(PublicKeyAlgorithm)

public override operator func !=(other: PublicKeyAlgorithm): Bool

功能:判不等。

参数:

返回值:

  • Bool - 若公钥算法不同,返回 true;否则,返回 false。

示例:

import stdx.crypto.x509.*

main() {
    // 创建两个 PublicKeyAlgorithm 枚举值
    let alg1 = PublicKeyAlgorithm.RSA
    let alg2 = PublicKeyAlgorithm.ECDSA

    // 比较两个算法是否不相等
    let isNotEqual = alg1 != alg2
    println("RSA != ECDSA: ${isNotEqual}")

    // 比较两个相同算法是否不相等
    let isNotEqualSame = alg1 != PublicKeyAlgorithm.RSA
    println("RSA != RSA: ${isNotEqualSame}")
}

运行结果:

RSA != ECDSA: true
RSA != RSA: false

operator func ==(PublicKeyAlgorithm)

public override operator func ==(other: PublicKeyAlgorithm): Bool

功能:判等。

参数:

返回值:

  • Bool - 若公钥算法相同,返回 true;否则,返回 false。

示例:

import stdx.crypto.x509.*

main() {
    // 创建两个 PublicKeyAlgorithm 枚举值
    let alg1 = PublicKeyAlgorithm.RSA
    let alg2 = PublicKeyAlgorithm.ECDSA

    // 比较两个算法是否相等
    let isEqual = alg1 == alg2
    println("RSA == ECDSA: ${isEqual}")

    // 比较两个相同算法是否相等
    let isEqualSame = alg1 == PublicKeyAlgorithm.RSA
    println("RSA == RSA: ${isEqualSame}")
}

运行结果:

RSA == ECDSA: false
RSA == RSA: true

enum SignatureAlgorithm

public enum SignatureAlgorithm <: Equatable<SignatureAlgorithm> & ToString {
    | MD2WithRSA | MD5WithRSA | SHA1WithRSA | SHA256WithRSA | SHA384WithRSA
    | SHA512WithRSA | DSAWithSHA1 | DSAWithSHA256 | ECDSAWithSHA1 | ECDSAWithSHA256
    | ECDSAWithSHA384 | ECDSAWithSHA512 | UnknownSignatureAlgorithm
}

功能:证书签名算法(Signature Algorithm)是用于数字证书签名的算法,它是一种将数字证书中的公钥和其他信息进行加密的算法,以确保数字证书的完整性和真实性。

目前支持签名算法的种类包括:MD2WithRSA 、MD5WithRSA 、SHA1WithRSA 、SHA256WithRSA 、SHA384WithRSA、SHA512WithRSA、DSAWithSHA1、DSAWithSHA256、ECDSAWithSHA1、ECDSAWithSHA256、ECDSAWithSHA384 和 ECDSAWithSHA512。

父类型:

DSAWithSHA1

DSAWithSHA1

功能:DSAwithSHA1 签名算法。

DSAWithSHA256

DSAWithSHA256

功能:DSAwithSHA256 签名算法。

ECDSAWithSHA1

ECDSAWithSHA1

功能:ECDSAwithSHA1 签名算法。

ECDSAWithSHA256

ECDSAWithSHA256

功能:ECDSAwithSHA256 签名算法。

ECDSAWithSHA384

ECDSAWithSHA384

功能:ECDSAwithSHA384 签名算法。

ECDSAWithSHA512

ECDSAWithSHA512

功能:ECDSAwithSHA512 签名算法。

MD2WithRSA

MD2WithRSA

功能:MD2withRSA 签名算法。

MD5WithRSA

MD5WithRSA

功能:MD5withRSA 签名算法。

SHA1WithRSA

SHA1WithRSA

功能:SHA1withRSA 签名算法。

SHA256WithRSA

SHA256WithRSA

功能:SHA256withRSA 签名算法。

SHA384WithRSA

SHA384WithRSA

功能:SHA384withRSA 签名算法。

SHA512WithRSA

SHA512WithRSA

功能:SHA512withRSA 签名算法。

UnknownSignatureAlgorithm

UnknownSignatureAlgorithm

功能:未知签名算法。

func toString()

public override func toString(): String

功能:生成证书签名算法名称字符串。

返回值:

  • String - 证书签名算法名称字符串。

示例:

import stdx.crypto.x509.*

main() {
    // 创建一个 SignatureAlgorithm 枚举值
    let algorithm = SignatureAlgorithm.SHA256WithRSA

    // 获取算法的字符串表示
    let str = algorithm.toString()
    println("Algorithm String: ${str}")
}

运行结果:

Algorithm String: Signature Algorithm: sha256WithRSAEncryption

operator func != (SignatureAlgorithm)

public override operator func !=(other: SignatureAlgorithm): Bool

功能:判不等。

参数:

返回值:

  • Bool - 若签名算法不同,返回 true;否则,返回 false。

示例:

import stdx.crypto.x509.*

main() {
    // 创建两个 SignatureAlgorithm 枚举值
    let alg1 = SignatureAlgorithm.SHA256WithRSA
    let alg2 = SignatureAlgorithm.ECDSAWithSHA256

    // 比较两个算法是否不相等
    let isNotEqual = alg1 != alg2
    println("SHA256WithRSA != ECDSAWithSHA256: ${isNotEqual}")

    // 比较两个相同算法是否不相等
    let isNotEqualSame = alg1 != SignatureAlgorithm.SHA256WithRSA
    println("SHA256WithRSA != SHA256WithRSA: ${isNotEqualSame}")
}

运行结果:

SHA256WithRSA != ECDSAWithSHA256: true
SHA256WithRSA != SHA256WithRSA: false

operator func == (SignatureAlgorithm)

public override operator func ==(other: SignatureAlgorithm): Bool

功能:判等。

参数:

返回值:

  • Bool - 若签名算法相同,返回 true;否则,返回 false。

示例:

import stdx.crypto.x509.*

main() {
    // 创建两个 SignatureAlgorithm 枚举值
    let alg1 = SignatureAlgorithm.SHA256WithRSA
    let alg2 = SignatureAlgorithm.ECDSAWithSHA256

    // 比较两个算法是否相等
    let isEqual = alg1 == alg2
    println("SHA256WithRSA == ECDSAWithSHA256: ${isEqual}")

    // 比较两个相同算法是否相等
    let isEqualSame = alg1 == SignatureAlgorithm.SHA256WithRSA
    println("SHA256WithRSA == SHA256WithRSA: ${isEqualSame}")
}

运行结果:

SHA256WithRSA == ECDSAWithSHA256: false
SHA256WithRSA == SHA256WithRSA: true

结构体

struct ExtKeyUsage

public struct ExtKeyUsage <: ToString {
    public static let AnyKey: UInt16 = 0
    public static let ServerAuth: UInt16 = 1
    public static let ClientAuth: UInt16 = 2
    public static let EmailProtection: UInt16 = 3
    public static let CodeSigning: UInt16 = 4
    public static let OCSPSigning: UInt16 = 5
    public static let TimeStamping: UInt16 = 6
    public init(keys: Array<UInt16>)
}

功能:数字证书扩展字段中通常会包含携带扩展密钥用法说明,目前支持的用途有:ServerAuth、ClientAuth、EmailProtection、CodeSigning、OCSPSigning、TimeStamping。

父类型:

  • ToString

static let AnyKey

public static let AnyKey: UInt16 = 0

功能:表示应用于任意用途。

类型:UInt16

示例:

import stdx.crypto.x509.*

main() {
    // 获取AnyKey常量值
    let anyKeyValue = ExtKeyUsage.AnyKey
    println("AnyKey Value: ${anyKeyValue}")
}

运行结果:

AnyKey Value: 0

static let ClientAuth

public static let ClientAuth: UInt16 = 2

功能:表示用于 SSL 的客户端验证。

类型:UInt16

示例:

import stdx.crypto.x509.*

main() {
    // 获取ClientAuth常量值
    let clientAuthValue = ExtKeyUsage.ClientAuth
    println("ClientAuth Value: ${clientAuthValue}")
}

运行结果:

ClientAuth Value: 2

static let CodeSigning

public static let CodeSigning: UInt16 = 4

功能:表示用于代码签名。

类型:UInt16

示例:

import stdx.crypto.x509.*

main() {
    // 获取CodeSigning常量值
    let codeSigningValue = ExtKeyUsage.CodeSigning
    println("CodeSigning Value: ${codeSigningValue}")
}

运行结果:

CodeSigning Value: 4

static let EmailProtection

public static let EmailProtection: UInt16 = 3

功能:表示用于电子邮件的加解密、签名等。

类型:UInt16

示例:

import stdx.crypto.x509.*

main() {
    // 获取EmailProtection常量值
    let emailProtectionValue = ExtKeyUsage.EmailProtection
    println("EmailProtection Value: ${emailProtectionValue}")
}

运行结果:

EmailProtection Value: 3

static let OCSPSigning

public static let OCSPSigning: UInt16 = 5

功能:用于对 OCSP 响应包进行签名。

类型:UInt16

示例:

import stdx.crypto.x509.*

main() {
    // 获取OCSPSigning常量值
    let ocspSigningValue = ExtKeyUsage.OCSPSigning
    println("OCSPSigning Value: ${ocspSigningValue}")
}

运行结果:

OCSPSigning Value: 5

static let ServerAuth

public static let ServerAuth: UInt16 = 1

功能:表示用于 SSL 的服务端验证。

类型:UInt16

示例:

import stdx.crypto.x509.*

main() {
    // 获取ServerAuth常量值
    let serverAuthValue = ExtKeyUsage.ServerAuth
    println("ServerAuth Value: ${serverAuthValue}")
}

运行结果:

ServerAuth Value: 1

static let TimeStamping

public static let TimeStamping: UInt16 = 6

功能:用于将对象摘要值与时间绑定。

类型:UInt16

示例:

import stdx.crypto.x509.*

main() {
    // 获取TimeStamping常量值
    let timeStampingValue = ExtKeyUsage.TimeStamping
    println("TimeStamping Value: ${timeStampingValue}")
}

运行结果:

TimeStamping Value: 6

init(Array<UInt16>)

public init(keys: Array<UInt16>)

功能:构造指定用途的扩展密钥用法,需要注意同一个密钥可以有多种用途。

参数:

  • keys: Array<UInt16> - 密钥。

示例:

import stdx.crypto.x509.*

main() {
    // 创建包含多个扩展密钥用途的数组
    let keyUsages = [ExtKeyUsage.ServerAuth, ExtKeyUsage.ClientAuth, ExtKeyUsage.CodeSigning]

    // 使用数组创建ExtKeyUsage对象
    let extKeyUsage = ExtKeyUsage(keyUsages)

    // 输出ExtKeyUsage对象信息
    println("ExtKeyUsage: ${extKeyUsage}")
}

运行结果:

ExtKeyUsage: ServerAuth, ClientAuth, CodeSigning

func toString()

public override func toString(): String

功能:生成扩展密钥用途字符串。

返回值:

  • String - 证书扩展密钥用途字符串。

示例:

import stdx.crypto.x509.*

main() {
    // 创建包含多个扩展密钥用途的数组
    let keyUsages = [ExtKeyUsage.ServerAuth, ExtKeyUsage.EmailProtection]

    // 使用数组创建ExtKeyUsage对象
    let extKeyUsage = ExtKeyUsage(keyUsages)

    // 获取ExtKeyUsage的字符串表示
    let str = extKeyUsage.toString()
    println("ExtKeyUsage String: ${str}")
}

运行结果:

ExtKeyUsage String: ServerAuth, EmailProtection

struct KeyUsage

public struct KeyUsage <: ToString {
    public static let DigitalSignature: UInt16 = 0x0080
    public static let NonRepudiation: UInt16 = 0x0040
    public static let KeyEncipherment: UInt16 = 0x0020
    public static let DataEncipherment: UInt16 = 0x0010
    public static let KeyAgreement: UInt16 = 0x0008
    public static let CertSign: UInt16 = 0x0004
    public static let CRLSign: UInt16 = 0x0002
    public static let EncipherOnly: UInt16 = 0x0001
    public static let DecipherOnly: UInt16 = 0x0100
    public init(keys: UInt16)
}

功能:数字证书扩展字段中通常会包含携带公钥的用法说明,目前支持的用途有:DigitalSignature、NonRepudiation、KeyEncipherment、DataEncipherment、KeyAgreement、CertSign、CRLSign、EncipherOnly、DecipherOnly。

父类型:

  • ToString

static let CertSign

public static let CertSign: UInt16 = 0x0004

功能:表示私钥用于证书签名,而公钥用于验证证书签名,专用于 CA 证书。

类型:UInt16

示例:

import stdx.crypto.x509.*

main() {
    // 获取CertSign常量值
    let certSignValue = KeyUsage.CertSign
    println("CertSign Value: ${certSignValue}")
}

运行结果:

CertSign Value: 4

static let CRLSign

public static let CRLSign: UInt16 = 0x0002

功能:表示私钥可用于对 CRL 签名,而公钥可用于验证 CRL 签名。

类型:UInt16

示例:

import stdx.crypto.x509.*

main() {
    // 获取CRLSign常量值
    let crlSignValue = KeyUsage.CRLSign
    println("CRLSign Value: ${crlSignValue}")
}

运行结果:

CRLSign Value: 2

static let DataEncipherment

public static let DataEncipherment: UInt16 = 0x0010

功能:表示公钥用于直接加密数据。

类型:UInt16

示例:

import stdx.crypto.x509.*

main() {
    // 获取DataEncipherment常量值
    let dataEnciphermentValue = KeyUsage.DataEncipherment
    println("DataEncipherment Value: ${dataEnciphermentValue}")
}

运行结果:

DataEncipherment Value: 16

static let DecipherOnly

public static let DecipherOnly: UInt16 = 0x0100

功能:表示证书中的公钥在密钥协商过程中,仅仅用于解密计算,配合 key Agreement 使用才有意义。

类型:UInt16

示例:

import stdx.crypto.x509.*

main() {
    // 获取DecipherOnly常量值
    let decipherOnlyValue = KeyUsage.DecipherOnly
    println("DecipherOnly Value: ${decipherOnlyValue}")
}

运行结果:

DecipherOnly Value: 256

static let DigitalSignature

public static let DigitalSignature: UInt16 = 0x0080

功能:表示私钥可以用于除了签发证书、签发 CRL 和非否认性服务的各种数字签名操作,而公钥用来验证这些签名。

类型:UInt16

示例:

import stdx.crypto.x509.*

main() {
    // 获取DigitalSignature常量值
    let digitalSignatureValue = KeyUsage.DigitalSignature
    println("DigitalSignature Value: ${digitalSignatureValue}")
}

运行结果:

DigitalSignature Value: 128

static let EncipherOnly

public static let EncipherOnly: UInt16 = 0x0001

功能:表示证书中的公钥在密钥协商过程中,仅仅用于加密计算,配合 key Agreement 使用才有意义。

类型:UInt16

示例:

import stdx.crypto.x509.*

main() {
    // 获取EncipherOnly常量值
    let encipherOnlyValue = KeyUsage.EncipherOnly
    println("EncipherOnly Value: ${encipherOnlyValue}")
}

运行结果:

EncipherOnly Value: 1

static let KeyAgreement

public static let KeyAgreement: UInt16 = 0x0008

功能:表示密钥用于密钥协商。

类型:UInt16

示例:

import stdx.crypto.x509.*

main() {
    // 获取KeyAgreement常量值
    let keyAgreementValue = KeyUsage.KeyAgreement
    println("KeyAgreement Value: ${keyAgreementValue}")
}

运行结果:

KeyAgreement Value: 8

static let KeyEncipherment

public static let KeyEncipherment: UInt16 = 0x0020

功能:表示密钥用来加密传输其他的密钥。

类型:UInt16

示例:

import stdx.crypto.x509.*

main() {
    // 获取KeyEncipherment常量值
    let keyEnciphermentValue = KeyUsage.KeyEncipherment
    println("KeyEncipherment Value: ${keyEnciphermentValue}")
}

运行结果:

KeyEncipherment Value: 32

static let NonRepudiation

public static let NonRepudiation: UInt16 = 0x0040

功能:表示私钥可以用于进行非否认性服务中的签名,而公钥用来验证签名。

类型:UInt16

示例:

import stdx.crypto.x509.*

main() {
    // 获取NonRepudiation常量值
    let nonRepudiationValue = KeyUsage.NonRepudiation
    println("NonRepudiation Value: ${nonRepudiationValue}")
}

运行结果:

NonRepudiation Value: 64

init(UInt16)

public init(keys: UInt16)

功能:构造指定用途的扩展密钥用法,需要注意同一个密钥可以有多种用途。

参数:

  • keys: UInt16 - 密钥的用法,建议使用本结构中所提供的密钥用法变量通过按位或的方式传入参数。

示例:

import stdx.crypto.x509.*

main() {
    // 使用按位或运算组合多个密钥用途
    let combinedKeys = KeyUsage.DigitalSignature | KeyUsage.KeyEncipherment

    // 使用组合的密钥用途创建KeyUsage对象
    let keyUsage = KeyUsage(combinedKeys)

    // 输出KeyUsage对象信息
    println("KeyUsage: ${keyUsage}")
}

运行结果:

KeyUsage: KeyEncipherment, DigitalSignature

func toString()

public override func toString(): String

功能:生成密钥用途字符串。

返回值:

  • String - 证书密钥用途字符串。

示例:

import stdx.crypto.x509.*

main() {
    // 创建包含多个密钥用途的组合
    let combinedKeys = KeyUsage.CertSign | KeyUsage.CRLSign | KeyUsage.DataEncipherment

    // 使用组合的密钥用途创建KeyUsage对象
    let keyUsage = KeyUsage(combinedKeys)

    // 获取KeyUsage的字符串表示
    let str = keyUsage.toString()
    println("KeyUsage String: ${str}")
}

运行结果:

KeyUsage String: CRLSign, CertSign, DataEncipherment

struct SerialNumber

public struct SerialNumber <: Equatable<SerialNumber> & Hashable & ToString {
    public init(length!: UInt8 = 16)
}

功能:结构体 SerialNumber 为数字证书的序列号,是数字证书中的一个唯一标识符,用于标识数字证书的唯一性。根据规范,证书序列号的长度不应超过 20 字节。详见rfc5280

父类型:

init(UInt8)

public init(length!: UInt8 = 16)

功能:生成指定长度的随机序列号。

参数:

  • length!: UInt8 - 序列号长度,单位为字节,类型为 UInt8,默认值为 16。

异常:

  • X509Exception - length 等于 0 或大于 20 时,抛出异常。

示例:

import stdx.crypto.x509.*

main() {
    // 创建一个默认长度为16字节的序列号
    let serialNumber = SerialNumber()
    println("Serial Number: ${serialNumber}")
}

可能的运行结果:

Serial Number: 74F81AD0DC4DBF5957BFD8BFE62011BD

func hashCode()

public override func hashCode(): Int64

功能:返回证书序列号哈希值。

返回值:

  • Int64 - 对证书序列号对象进行哈希计算后得到的结果。

示例:

import stdx.crypto.x509.*

main() {
    // 创建一个序列号对象
    let serialNumber = SerialNumber()

    // 获取序列号的哈希值
    let hashCode = serialNumber.hashCode()
    println("Serial Number HashCode: ${hashCode}")
}

可能的运行结果:

Serial Number HashCode: -5281749894544737892

func toString()

public override func toString(): String

功能:生成证书序列号字符串,格式为 16 进制。

返回值:

  • String - 证书序列号字符串。

示例:

import stdx.crypto.x509.*

main() {
    // 创建一个序列号对象
    let serialNumber = SerialNumber()

    // 获取序列号的字符串表示
    let str = serialNumber.toString()
    println("Serial Number String: ${str}")
}

可能的运行结果:

Serial Number String: D2377B71EDD485F1D7C458B72A73E446

operator func !=(SerialNumber)

public override operator func !=(other: SerialNumber): Bool

功能:判不等。

参数:

  • other: SerialNumber - 被比较的证书序列号对象。

返回值:

  • Bool - 若序列号不同,返回 true;否则,返回 false。

示例:

import stdx.crypto.x509.*

main() {
    // 创建两个不同的序列号对象
    let serialNumber1 = SerialNumber()
    let serialNumber2 = SerialNumber()

    // 比较两个序列号是否不相等
    let isNotEqual = serialNumber1 != serialNumber2
    println("Serial Numbers Not Equal: ${isNotEqual}")
}

运行结果:

Serial Numbers Not Equal: true

operator func ==(SerialNumber)

public override operator func ==(other: SerialNumber): Bool

功能:判等。

参数:

  • other: SerialNumber - 被比较的证书序列号对象。

返回值:

  • Bool - 若序列号相同,返回 true;否则,返回 false。

示例:

import stdx.crypto.x509.*

main() {
    // 创建两个相同的序列号对象(使用相同长度)
    let serialNumber1 = SerialNumber(length: 8)
    let serialNumber2 = SerialNumber(length: 8)

    // 比较两个序列号是否相等
    let isEqual = serialNumber1 == serialNumber2
    println("Serial Numbers Equal: ${isEqual}")
}

运行结果:

Serial Numbers Equal: false

struct Signature

public struct Signature <: Equatable<Signature> & Hashable {
}

功能:数字证书的签名,用来验证身份的正确性。

父类型:

prop signatureValue

public prop signatureValue: DerBlob

功能:返回证书签名的二进制。

类型:DerBlob

示例:

import stdx.crypto.x509.*

main() {
    // 找到系统根证书中的ISRG Root X1证书用作演示
    var signatureOpt: ?Signature = None
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        // 如果找不到ISRG Root X1可以选择其他证书作演示
        if (cert.issuer.commonName == "ISRG Root X1") {
            let x509Certificate: X509Certificate = cert
            // 获取证书的签名
            signatureOpt = x509Certificate.signature
            break
        }
    }

    // 核心演示:获得证书签名的二进制
    let signatureValue = signatureOpt?.signatureValue
    println("Signature DerBlob size: ${signatureValue?.size ?? 0}")
}

运行结果:

Signature DerBlob size: 512

func hashCode()

public override func hashCode(): Int64

功能:返回证书签名哈希值。

返回值:

  • Int64 - 对证书签名对象进行哈希计算后得到的结果。

示例:

import stdx.crypto.x509.*

main() {
    // 找到系统根证书中的ISRG Root X1证书用作演示
    var signatureOpt: ?Signature = None
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        // 如果找不到ISRG Root X1可以选择其他证书作演示
        if (cert.issuer.commonName == "ISRG Root X1") {
            let x509Certificate: X509Certificate = cert
            // 获取证书的签名
            signatureOpt = x509Certificate.signature
            break
        }
    }

    // 获取签名的哈希值
    let hashCode = signatureOpt?.hashCode()
    println("Signature HashCode: ${hashCode ?? 0}")
}

运行结果:

Signature HashCode: -3222683054313786172

operator func !=(Signature)

public override operator func !=(other: Signature): Bool

功能:判不等。

参数:

  • other: Signature - 被比较的证书签名。

返回值:

  • Bool - 若证书签名不同,返回 true;否则,返回 false。

示例:

import stdx.crypto.x509.*

main() {
    // 获取两个不同的系统根证书
    var sig1Opt: ?Signature = None
    var sig2Opt: ?Signature = None
    let certs = X509Certificate.systemRootCerts()
    var count = 0
    for (cert in certs) {
        if (count == 0) {
            sig1Opt = cert.signature
        } else if (count == 1) {
            sig2Opt = cert.signature
            break
        }
        count = count + 1
    }

    // 比较两个签名是否不相等
    let isNotEqual = sig1Opt != sig2Opt
    println("两个签名是否不相等: ${isNotEqual}")
}

运行结果:

两个签名是否不相等: true

operator func ==(Signature)

public override operator func ==(other: Signature): Bool

功能:判等。

参数:

  • other: Signature - 被比较的证书签名。

返回值:

  • Bool - 若证书签名相同,返回 true;否则,返回 false。

示例:

import stdx.crypto.x509.*

main() {
    // 获取同一个证书的两个引用进行相等性比较
    var signatureOpt1: ?Signature = None
    var signatureOpt2: ?Signature = None
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        if (cert.issuer.commonName == "ISRG Root X1") {
            let x509Certificate: X509Certificate = cert
            signatureOpt1 = x509Certificate.signature
            break
        }
    }
    // 重新获取同一个证书的签名
    for (cert in certs) {
        if (cert.issuer.commonName == "ISRG Root X1") {
            let x509Certificate: X509Certificate = cert
            signatureOpt2 = x509Certificate.signature
            break
        }
    }

    // 比较两个签名是否相等
    let isEqual = signatureOpt1 == signatureOpt2
    println("两个签名是否相等: ${isEqual}")
}

运行结果:

两个签名是否相等: true

struct VerifyOption

public struct VerifyOption {
    public var time: DateTime = DateTime.now()
    public var dnsName: String = ""
    public var roots: Array<X509Certificate> = X509Certificate.systemRootCerts()
    public var intermediates: Array<X509Certificate> = Array<X509Certificate>()
}

功能:用于为 x509 证书验证函数 verify 提供配置选项。

var dnsName

public var dnsName: String = ""

功能:校验域名,默认为空,只有设置域名时才会进行此处校验。

类型:String

示例:

import stdx.crypto.x509.*

main() {
    // 模拟场景:已有的X509证书对象(此处通过系统根证书ISRG Root X1模拟)
    var certOpt: ?X509Certificate = None
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        if (cert.issuer.commonName == "ISRG Root X1") {
            certOpt = cert
            break
        }
    }
    // 创建验证选项
    var verifyOpt = VerifyOption()
    // 设置验证域名
    verifyOpt.dnsName = "example.com"
    // 验证证书
    let isValid = certOpt?.verify(verifyOpt)

    println("证书是否有效: ${isValid ?? false}")

    // 创建另一个验证选项
    var verifyOpt2 = VerifyOption()
    // 设置验证域名,因为根证书没有绑定域名,所以设置为空
    verifyOpt2.dnsName = ""
    // 验证证书
    let isValid2 = certOpt?.verify(verifyOpt2)

    println("证书是否有效: ${isValid2 ?? false}")
}

运行结果:

证书是否有效: false
证书是否有效: true

var intermediates

public var intermediates: Array<X509Certificate> = Array<X509Certificate>()

功能:中间证书链,默认为空。

类型:Array<X509Certificate>

示例:

import stdx.crypto.x509.*

main() {
    // 模拟场景:已有的X509证书对象(此处通过系统根证书ISRG Root X1模拟)
    var certOpt: ?X509Certificate = None
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        if (cert.issuer.commonName == "ISRG Root X1") {
            certOpt = cert
            break
        }
    }
    // 创建验证选项
    var verifyOpt = VerifyOption()
    // 设置中间证书链
    verifyOpt.intermediates = []
    // 验证证书
    let isValid = certOpt?.verify(verifyOpt)

    println("证书是否有效: ${isValid ?? false}")
}

运行结果:

证书是否有效: true

var roots

public var roots: Array<X509Certificate> = X509Certificate.systemRootCerts()

功能:根证书链,默认为系统根证书链。

类型:Array<X509Certificate>

示例:

import stdx.crypto.x509.*

main() {
    // 获取两个不同的系统根证书
    var cert1Opt: ?X509Certificate = None
    var cert2Opt: ?X509Certificate = None
    let certs = X509Certificate.systemRootCerts()
    var count = 0
    for (cert in certs) {
        if (count == 0) {
            cert1Opt = cert
        } else if (count == 1) {
            cert2Opt = cert
            break
        }
        count = count + 1
    }
    let cert1 = cert1Opt.getOrThrow()
    let cert2 = cert2Opt.getOrThrow()

    // 创建验证选项
    var verifyOpt = VerifyOption()
    // 核心演示:设置信任根证书集合,不设置默认为系统根证书链
    verifyOpt.roots = [cert1, cert2]
    // 验证证书,因为cert1在信任根证书集合中,所以有效
    let isValid = cert1.verify(verifyOpt)

    println("证书cert1是否有效: ${isValid}")

    // 核心演示:设置信任根证书集合,不设置默认为系统根证书链
    var verifyOpt2 = VerifyOption()
    verifyOpt2.roots = [cert2]
    // 验证证书,因为cert1不在信任根证书集合中,所以无效
    let isValid2 = cert1.verify(verifyOpt2)

    println("证书cert1是否有效: ${isValid2}")
}

运行结果:

证书cert1是否有效: true
证书cert1是否有效: false

var time

public var time: DateTime = DateTime.now()

功能:校验时间,默认为创建选项的时间。

类型:DateTime

示例:

import stdx.crypto.x509.*
import std.time.*

main() {
    // 模拟场景:已有的X509证书对象(此处通过系统根证书ISRG Root X1模拟)
    var certOpt: ?X509Certificate = None
    let certs = X509Certificate.systemRootCerts()
    for (cert in certs) {
        if (cert.issuer.commonName == "ISRG Root X1") {
            certOpt = cert
            break
        }
    }
    // 创建验证选项
    var verifyOpt = VerifyOption()
    // 核心演示:设置验证时间
    verifyOpt.time = DateTime.of(year: 2036, month: 1, dayOfMonth: 1)
    // 验证证书
    let isValid = certOpt?.verify(verifyOpt)

    println("证书是否有效: ${isValid ?? false}")

    // 核心演示:创建另一个验证时间
    var verifyOpt2 = VerifyOption()
    verifyOpt2.time = DateTime.of(year: 2026, month: 1, dayOfMonth: 1)
    // 验证证书
    let isValid2 = certOpt?.verify(verifyOpt2)

    println("证书是否有效: ${isValid2 ?? false}")
}

运行结果:

证书是否有效: false
证书是否有效: true

struct X509CertificateInfo

public struct X509CertificateInfo {
    public var serialNumber: SerialNumber
    public var notBefore: DateTime
    public var notAfter: DateTime
    public var subject: ?X509Name
    public var dnsNames: Array<String>
    public var emailAddresses: Array<String>
    public var IPAddresses: Array<IP>
    public var keyUsage: ?KeyUsage
    public var extKeyUsage: ?ExtKeyUsage

    public init(
        serialNumber!: ?SerialNumber = None,
        notBefore!: ?DateTime = None,
        notAfter!: ?DateTime = None,
        subject!: ?X509Name = None,
        dnsNames!: Array<String> = Array<String>(),
        emailAddresses!: Array<String> = Array<String>(),
        IPAddresses!: Array<IP> = Array<IP>(),
        keyUsage!: ?KeyUsage = None,
        extKeyUsage!: ?ExtKeyUsage = None
    )
}

功能:X509CertificateInfo 结构包含了证书信息,包括证书序列号、有效期、实体可辨识名称、域名、email 地址、IP 地址、密钥用法和扩展密钥用法。

var dnsNames

public var dnsNames: Array<String>

功能:记录证书的 DNS 域名。

类型:Array<String>

示例:

import stdx.crypto.x509.*

main() {
    // 创建一个X509CertificateInfo对象
    let certInfo = X509CertificateInfo(dnsNames: ["example.com", "test.com"])

    // 输出DNS域名列表
    println("DNS Names: ${certInfo.dnsNames}")
}

运行结果:

DNS Names: [example.com, test.com]

var emailAddresses

public var emailAddresses: Array<String>

功能:记录证书的 email 地址。

类型:Array<String>

示例:

import stdx.crypto.x509.*

main() {
    // 创建一个X509CertificateInfo对象
    let certInfo = X509CertificateInfo(emailAddresses: ["user@example.com", "admin@test.com"])

    // 输出Email地址列表
    println("Email Addresses: ${certInfo.emailAddresses}")
}

运行结果:

Email Addresses: [user@example.com, admin@test.com]

var extKeyUsage

public var extKeyUsage: ?ExtKeyUsage

功能:记录证书的扩展密钥用法。

类型:?ExtKeyUsage

示例:

import stdx.crypto.x509.*

main() {
    // 创建扩展密钥用法对象
    let keyUsages = [ExtKeyUsage.ServerAuth, ExtKeyUsage.ClientAuth]
    let extKeyUsage = ExtKeyUsage(keyUsages)

    // 创建一个X509CertificateInfo对象
    let certInfo = X509CertificateInfo(extKeyUsage: extKeyUsage)

    // 输出扩展密钥用法
    println("Ext Key Usage: ${certInfo.extKeyUsage}")
}

运行结果:

Ext Key Usage: Some(ServerAuth, ClientAuth)

var IPAddresses

public var IPAddresses: Array<IP>

功能:记录证书的 IP 地址。

类型:Array<IP>

示例:

import stdx.crypto.x509.*

main() {
    // 创建IP地址列表
    let ipList = [[192u8, 168u8, 1u8, 1u8], [10u8, 0u8, 0u8, 1u8]]

    // 创建一个X509CertificateInfo对象
    let certInfo = X509CertificateInfo(IPAddresses: ipList)

    // 输出IP地址列表
    println("IP Addresses: ${certInfo.IPAddresses}")
}

运行结果:

IP Addresses: [[192, 168, 1, 1], [10, 0, 0, 1]]

var keyUsage

public var keyUsage: ?KeyUsage

功能:记录证书的密钥用法。

类型:?KeyUsage

示例:

import stdx.crypto.x509.*

main() {
    // 创建密钥用法对象
    let keyUsageValue = KeyUsage(KeyUsage.DigitalSignature | KeyUsage.KeyEncipherment)

    // 创建一个X509CertificateInfo对象
    let certInfo = X509CertificateInfo(keyUsage: keyUsageValue)

    // 输出密钥用法
    println("Key Usage: ${certInfo.keyUsage}")
}

运行结果:

Key Usage: Some(KeyEncipherment, DigitalSignature)

var notAfter

public var notAfter: DateTime

功能:记录证书有效期的结束日期。

类型:DateTime

示例:

import std.time.*
import stdx.crypto.x509.*

main() {
    // 创建一个DateTime对象表示结束日期
    let endDate = DateTime.now()

    // 创建一个X509CertificateInfo对象
    let certInfo = X509CertificateInfo(notAfter: endDate)

    // 输出证书有效期结束日期
    println("Not After: ${certInfo.notAfter}")
}

可能的运行结果:

Not After: 2026-01-05T10:32:07.77851204+08:00

var notBefore

public var notBefore: DateTime

功能:记录证书有效期的起始日期。

类型:DateTime

示例:

import stdx.crypto.x509.*
import std.time.DateTime

main() {
    // 创建一个DateTime对象表示起始日期
    let startDate = DateTime.now()

    // 创建一个X509CertificateInfo对象
    let certInfo = X509CertificateInfo(notBefore: startDate)

    // 输出证书有效期起始日期
    println("Not Before: ${certInfo.notBefore}")
}

可能的运行结果:

Not Before: 2026-01-05T10:53:18.564805132+08:00

var serialNumber

public var serialNumber: SerialNumber

功能:记录证书的序列号。

类型:SerialNumber

示例:

import stdx.crypto.x509.*

main() {
    // 创建一个序列号对象
    let serialNum = SerialNumber(length: 8)

    // 创建一个X509CertificateInfo对象
    let certInfo = X509CertificateInfo(serialNumber: serialNum)

    // 输出证书序列号
    println("Serial Number: ${certInfo.serialNumber}")
}

可能的运行结果:

Serial Number: 8BF8AAB1A3B47073

var subject

public var subject: ?X509Name

功能:记录证书实体可辨识名称。

类型:?X509Name

示例:

import stdx.crypto.x509.*

main() {
    // 创建一个X509Name对象
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "Beijing",
        localityName: "Haidian",
        organizationName: "Huawei",
        organizationalUnitName: "Cloud",
        commonName: "example.com"
    )

    // 创建一个X509CertificateInfo对象
    let certInfo = X509CertificateInfo(subject: x509Name)

    // 输出证书实体可辨识名称
    println("Subject: ${certInfo.subject}")
}

运行结果:

Subject: Some(c=CN,st=Beijing,l=Haidian,o=Huawei,ou=Cloud,cn=example.com)

init(?SerialNumber, ?DateTime, ?DateTime, ?X509Name, Array<String>, Array<String>, Array<IP>, ?KeyUsage, ?ExtKeyUsage)

public init(
    serialNumber!: ?SerialNumber = None,
    notBefore!: ?DateTime = None,
    notAfter!: ?DateTime = None,
    subject!: ?X509Name = None,
    dnsNames!: Array<String> = Array<String>(),
    emailAddresses!: Array<String> = Array<String>(),
    IPAddresses!: Array<IP> = Array<IP>(),
    keyUsage!: ?KeyUsage = None,
    extKeyUsage!: ?ExtKeyUsage = None
)

功能:构造 X509CertificateInfo 对象。

参数:

  • serialNumber!: ?SerialNumber - 数字证书序列号,默认值为 None,使用默认值时默认的序列号长度为 128 比特。
  • notBefore!: ?DateTime - 数字证书有效期开始时间,默认值为 None,使用默认值时默认的时间为 X509CertificateInfo 创建的时间。
  • notAfter!: ?DateTime - 数字证书有效期截止时间,默认值为 None,使用默认值时默认的时间为 notBefore 往后 1 年的时间。
  • subject!: ?X509Name - 数字证书使用者信息,默认值为 None。
  • dnsNames!: Array<String> - 域名列表,需要用户保证输入域名的有效性,默认值为空的字符串数组。
  • emailAddresses!: Array<String> - email 地址列表,需要用户保证输入 email 的有效性,默认值为空的字符串数组。
  • IPAddresses!: Array<IP> - IP 地址列表,默认值为空的 IP 数组。
  • keyUsage!: ?KeyUsage - 密钥用法,默认值为 None。
  • extKeyUsage!: ?ExtKeyUsage - 扩展密钥用法,默认值为 None。

异常:

  • X509Exception - 输入的 IP 地址列表中包含无效的 IP 地址,则抛出异常。

示例:

import stdx.crypto.x509.*
import std.time.DateTime

main() {
    // 创建X509Name对象
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "Beijing",
        localityName: "Haidian",
        organizationName: "Huawei",
        organizationalUnitName: "Cloud",
        commonName: "example.com"
    )

    // 创建IP地址列表
    let ipList = [[192u8, 168u8, 1u8, 1u8], [10u8, 0u8, 0u8, 1u8]]

    // 创建密钥用法对象
    let keyUsageValue = KeyUsage(KeyUsage.DigitalSignature | KeyUsage.KeyEncipherment)

    // 创建扩展密钥用法对象
    let keyUsages = [ExtKeyUsage.ServerAuth, ExtKeyUsage.ClientAuth]
    let extKeyUsage = ExtKeyUsage(keyUsages)

    // 使用所有参数构造X509CertificateInfo对象
    let certInfo = X509CertificateInfo(
        serialNumber: SerialNumber(length: 8),
        notBefore: DateTime.now(),
        notAfter: DateTime.now(),
        subject: x509Name,
        dnsNames: ["example.com", "test.com"],
        emailAddresses: ["user@example.com", "admin@test.com"],
        IPAddresses: ipList,
        keyUsage: keyUsageValue,
        extKeyUsage: extKeyUsage
    )
}

struct X509CertificateRequestInfo

public struct X509CertificateRequestInfo {
    public var subject: ?X509Name
    public var dnsNames: Array<String>
    public var emailAddresses: Array<String>
    public var IPAddresses: Array<IP>

    public init(
        subject!: ?X509Name = None,
        dnsNames!: Array<String> = Array<String>(),
        emailAddresses!: Array<String> = Array<String>(),
        IPAddresses!: Array<IP> = Array<IP>()
    )
}

功能:X509CertificateRequestInfo 结构包含了证书请求信息,包括证书实体可辨识名称、域名、email 地址和 IP 地址。

var dnsNames

public var dnsNames: Array<String>

功能:记录证书签名请求的 DNS 域名。

类型:Array<String>

示例:

import stdx.crypto.x509.*

main() {
    // 创建一个X509CertificateRequestInfo对象
    let certRequestInfo = X509CertificateRequestInfo(dnsNames: ["example.com", "test.com"])

    // 输出DNS域名列表
    println("DNS Names: ${certRequestInfo.dnsNames}")
}

运行结果:

DNS Names: [example.com, test.com]

var emailAddresses

public var emailAddresses: Array<String>

功能:记录证书签名请求的 email 地址。

类型:Array<String>

示例:

import stdx.crypto.x509.*

main() {
    // 创建一个X509CertificateRequestInfo对象
    let certRequestInfo = X509CertificateRequestInfo(emailAddresses: ["user@example.com", "admin@test.com"])

    // 输出Email地址列表
    println("Email Addresses: ${certRequestInfo.emailAddresses}")
}

运行结果:

Email Addresses: [user@example.com, admin@test.com]

var IPAddresses

public var IPAddresses: Array<IP>

功能:记录证书签名请求的 IP 地址。

类型:Array<IP>

示例:

import stdx.crypto.x509.*

main() {
    // 创建IP地址列表
    let ipList = [[192u8, 168u8, 1u8, 1u8], [10u8, 0u8, 0u8, 1u8]]

    // 创建一个X509CertificateRequestInfo对象
    let certRequestInfo = X509CertificateRequestInfo(IPAddresses: ipList)

    // 输出IP地址列表
    println("IP Addresses: ${certRequestInfo.IPAddresses}")
}

运行结果:

IP Addresses: [[192, 168, 1, 1], [10, 0, 0, 1]]

var subject

public var subject: ?X509Name

功能:记录证书签名请求的实体可辨识名称。

类型:?X509Name

示例:

import stdx.crypto.x509.*

main() {
    // 创建一个X509Name对象
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "Beijing",
        localityName: "Haidian",
        organizationName: "Huawei",
        organizationalUnitName: "Cloud",
        commonName: "example.com"
    )

    // 创建一个X509CertificateRequestInfo对象
    let certRequestInfo = X509CertificateRequestInfo(subject: x509Name)

    // 输出证书请求的实体可辨识名称
    println("Subject: ${certRequestInfo.subject?.toString() ?? "None"}")
}

运行结果:

Subject: c=CN,st=Beijing,l=Haidian,o=Huawei,ou=Cloud,cn=example.com

init(?X509Name, Array<String>, Array<String>, Array<IP>)

public init(
    subject!: ?X509Name = None,
    dnsNames!: Array<String> = Array<String>(),
    emailAddresses!: Array<String> = Array<String>(),
    IPAddresses!: Array<IP> = Array<IP>()
)

功能:构造 X509CertificateRequestInfo 对象。

参数:

  • subject!: ?X509Name - 数字证书的使用者信息,默认值为 None。
  • dnsNames!: Array<String> - 域名列表,需要用户保证输入域名的有效性,默认值为空的字符串数组。
  • emailAddresses!: Array<String> - email 地址列表,需要用户保证输入 email 的有效性,默认值为空的字符串数组。
  • IPAddresses!: Array<IP> - IP 地址列表,默认值为空的 IP 数组。

异常:

  • X509Exception - 输入的 IP 地址列表中包含无效的 IP 地址,则抛出异常。

示例:

import stdx.crypto.x509.*

main() {
    // 创建一个X509Name对象
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "Beijing",
        localityName: "Haidian",
        organizationName: "Huawei",
        organizationalUnitName: "Cloud",
        commonName: "example.com"
    )

    // 创建IP地址列表
    let ipList = [[192u8, 168u8, 1u8, 1u8], [10u8, 0u8, 0u8, 1u8]]

    // 使用所有参数构造X509CertificateRequestInfo对象
    let certRequestInfo = X509CertificateRequestInfo(
        subject: x509Name,
        dnsNames: ["example.com", "test.com"],
        emailAddresses: ["user@example.com", "admin@test.com"],
        IPAddresses: ipList
    )
}

异常类

class X509Exception

public class X509Exception <: Exception {
    public init()
    public init(message: String)
}

功能:此异常为 X509 包抛出的异常类型。

父类型:

  • Exception

init()

public init()

功能:构造 X509Exception 对象。

示例:

import stdx.crypto.x509.*

main() {
    try {
        // 抛出一个无参的X509Exception异常
        throw X509Exception()
    } catch (e: X509Exception) {
        println("捕获到X509异常: ${e}")
    }
}

运行结果:

捕获到X509异常: X509Exception

init(String)

public init(message: String)

功能:构造 X509Exception 对象。

参数:

  • message: String - 异常的信息。

示例:

import stdx.crypto.x509.*

main() {
    try {
        // 抛出一个带消息的X509Exception异常
        throw X509Exception("证书验证失败")
    } catch (e: X509Exception) {
        println("捕获到X509异常: ${e}")
    }
}

运行结果:

捕获到X509异常: X509Exception: 证书验证失败

x509 使用

读取、解析证书

说明:

需要自行准备证书文件。

示例:

import std.fs.File
import stdx.crypto.x509.*

let readPath = "./files/root_rsa.cer"

main() {
    /* 读取本地证书*/
    let pem = String.fromUtf8(File.readFrom(readPath))
    let certificates = X509Certificate.decodeFromPem(pem)

    /* 解析证书中的必选字段 */
    let cert = certificates[0]
    println(cert)
    println("Serial Number: ${cert.serialNumber}")
    println("Issuer: ${cert.issuer}")
    println("NotBefore: ${cert.notBefore}")
    println("NotAfter: ${cert.notAfter}")
    println(cert.signatureAlgorithm)
    let signature = cert.signature
    println(signature.hashCode())
    println(cert.publicKeyAlgorithm)
    let pubKey = cert.publicKey
    println(pubKey.encodeToPem().encode())

    /* 解析证书中的扩展字段 */
    println("DNSNames: ${cert.dnsNames}")
    println("EmailAddresses: ${cert.emailAddresses}")
    println("IPAddresses: ${cert.IPAddresses}")
    println("KeyUsage: ${cert.keyUsage}")
    println("ExtKeyUsage: ${cert.extKeyUsage}")

    /* 解析证书使用者的可辨识名称 */
    println("Subject: ${cert.subject}")

    return 0
}

读取、验证证书

说明:

需要自行准备证书文件。

示例:

import std.fs.File
import stdx.crypto.x509.*
import std.time.DateTime

let prefixPath = "./files/"
let certFile = "servers.crt"
let rootFile = "roots.crt"
let middleFile = "middles.crt"

func getX509Cert(path: String) {
    let pem = String.fromUtf8(File.readFrom(path))
    X509Certificate.decodeFromPem(pem)
}

func testVerifyByTime(cert: X509Certificate, roots: Array<X509Certificate>, middles: Array<X509Certificate>) {
    var opt = VerifyOption()
    opt.roots = roots
    opt.intermediates = middles
    cert.verify(opt)
    println("Verify result: ${cert.verify(opt)}")
    opt.time = DateTime.of(year: 2023, month: 7, dayOfMonth: 1)
    println("Verify result:: ${cert.verify(opt)}")
}

func testVerifyByDNS(cert: X509Certificate) {
    var opt = VerifyOption()
    opt.dnsName = "www.example.com"
    println("cert DNS names: ${cert.dnsNames}")
    let res = cert.verify(opt)
    println("Verify result: ${res}")
}

/**
 * The relation of certs.
 *    root[0]         root[1]
 *    /      \            |
 *  mid[0]  mid[1]    mid[2]
 *   |                  |
 *  server[0]         server[1]
 */
func testVerify(cert: X509Certificate, roots: Array<X509Certificate>, middles: Array<X509Certificate>) {
    var opt = VerifyOption()
    opt.roots = roots
    opt.intermediates = middles
    let res = cert.verify(opt)
    println("Verify result: ${res}")
}

main() {
    /* 两个服务端证书 */
    let certs = getX509Cert(prefixPath + certFile)
    /* 两个根证书 */
    let roots = getX509Cert(prefixPath + rootFile)
    /* 三个中间证书 */
    let middles = getX509Cert(prefixPath + middleFile)
    /* 验证有效期 */
    testVerifyByTime(certs[0], [roots[0]], [middles[0]])
    /* 验证 DNS 域名 */
    testVerifyByDNS(certs[0])

    /* 根据根证书和中间证书验证其有效性 */
    /* cert0 <- root0: false */
    testVerify(certs[0], [roots[0]], [])
    /* cert0 <- middle0 <- root0: true */
    testVerify(certs[0], [roots[0]], [middles[0]])
    /* cert0 <- (middle0, middle1, middle2) <- (root0, root1) : true */
    testVerify(certs[0], roots, middles)
    /* cert1 <- middle0 <- root0: false */
    testVerify(certs[1], [roots[0]], [middles[0]])
    /* cert1 <- middle2 <- root1: true */
    testVerify(certs[1], [roots[1]], [middles[2]])
    /* cert1 <- (middle0, middle1, middle2) <- (root0, root1) : true */
    testVerify(certs[1], roots, middles)
    return 0
}

创建、解析证书

说明:

需要自行准备根证书文件。

示例:

import std.fs.*
import stdx.crypto.x509.*
import stdx.crypto.keys.*
import std.time.*
import std.io.*

main() {
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "beijing",
        localityName: "haidian",
        organizationName: "organization",
        organizationalUnitName: "organization unit",
        commonName: "x509",
        email: "test@email.com"
    )
    let serialNumber = SerialNumber(length: 20)
    let startTime: DateTime = DateTime.now()
    let endTime: DateTime = startTime.addYears(1)
    let ip1: IP = [8, 8, 8, 8]
    let ip2: IP = [0, 1, 0, 1, 0, 1, 0, 1, 0, 8, 0, 8, 0, 8, 0, 8]
    let parentCertPem = String.fromUtf8(readToEnd(File("./certificate.pem", Read)))
    let parentCert = X509Certificate.decodeFromPem(parentCertPem)[0]
    let parentKeyPem = String.fromUtf8(readToEnd(File("./rsa_private_key.pem", Read)))
    let parentPrivateKey = GeneralPrivateKey.decodeFromPem(parentKeyPem)
    let usrKeyPem = String.fromUtf8(readToEnd(File("./ecdsa_public_key.pem", Read)))
    let usrPublicKey = GeneralPublicKey.decodeFromPem(usrKeyPem)

    let certInfo = X509CertificateInfo(serialNumber: serialNumber, notBefore: startTime, notAfter: endTime,
        subject: x509Name, dnsNames: ["b.com"], IPAddresses: [ip1, ip2]);
    let cert = X509Certificate(certInfo, parent: parentCert, publicKey: usrPublicKey, privateKey: parentPrivateKey)

    println(cert)
    println("Serial Number: ${cert.serialNumber}")
    println("Issuer: ${cert.issuer}")
    println("Subject: ${cert.subject}")
    println("NotBefore: ${cert.notBefore}")
    println("NotAfter: ${cert.notAfter}")
    println(cert.signatureAlgorithm)
    println("DNSNames: ${cert.dnsNames}")
    println("IPAddresses: ${cert.IPAddresses}")

    return 0
}

创建、解析证书签名请求

说明:

需要自行准备私钥等文件。

示例:

import std.fs.*
import std.io.*
import stdx.crypto.x509.*
import stdx.crypto.keys.GeneralPrivateKey

main() {
    let x509Name = X509Name(
        countryName: "CN",
        provinceName: "beijing",
        localityName: "haidian",
        organizationName: "organization",
        organizationalUnitName: "organization unit",
        commonName: "x509",
        email: "test@email.com"
    )
    let ip1: IP = [8, 8, 8, 8]
    let ip2: IP = [0, 1, 0, 1, 0, 1, 0, 1, 0, 8, 0, 8, 0, 8, 0, 8]
    let rsaPem = String.fromUtf8(readToEnd(File("./rsa_private_key.pem", Read)))
    let rsa = GeneralPrivateKey.decodeFromPem(rsaPem)

    let csrInfo = X509CertificateRequestInfo(subject: x509Name, dnsNames: ["b.com"], IPAddresses: [ip1, ip2]);
    let csr = X509CertificateRequest(rsa, certificateRequestInfo: csrInfo, signatureAlgorithm: SHA256WithRSA)

    println("Subject: ${csr.subject.toString()}")
    println("IPAddresses: ${csr.IPAddresses}")
    println("dnsNames: ${csr.dnsNames}")

    return 0
}

stdx.effect

功能介绍

Effect Handlers 是一种强大的非局部控制操作,最初在函数式编程语言中引入,旨在表达副作用,但随后也被证明在面向对象和过程式语言中同样具有实用价值。

与异常机制类似,异常可以被抛出(throw)和捕获(catch),而效应则通过执行(perform)与处理(handle)来控制。但二者存在一个重要差异,当异常被捕获时,触发异常的计算过程已经中止,无法恢复;而在处理一个效应时,Effect Handlers 可以选择恢复触发该效应的计算过程,将控制权返回至 perform 执行点。

核心结构

Effect Handlers 在语法上扩展了传统的 try-catch 结构,增加了用于处理 effect 的 handle 子句。一个 try 表达式除了可以包含 catch 块来处理异常外,还可以包含一个或多个 handle 块来处理通过 perform 触发的 effect。Effect Handlers 有以下核心结构:

  • Command<T> 接口:

    所有 effect 都必须继承 Command<T>T 是该 effect 恢复执行时返回的类型。可以通过重写 defaultImpl 方法提供默认行为(未被任何 handler 捕获时调用)。

  • perform 表达式:

    perform expr 会触发一个 effect,其中 expr 必须是 Command<T> 的实例。如果被 handler 恢复,perform 表达式的值类型为 T

  • handle 子句:

    handle 子句用于定义 effect 被触发时的处理逻辑。运行时会匹配最近的 handle 子句并进入处理代码块。在 handle 中,需要调用 resume 表达式来恢复执行。

    语法:

    try{
        ...  
    } handle (cmd: Command<T>) {
        // 处理逻辑
        resume with value
    }
    

    其中:

    • cmd 绑定到触发的 effect 对象
    • with valuevalue 类型必须与 T 相同
  • resume 表达式:

    resume with value 会将执行流程恢复到 perform 处,并返回 value 作为该 perform 表达式的结果,也可以用 resume throwing exn 抛出异常。

基本语法

class MyEffect <: Command<String> {}

try {
    let result = perform MyEffect()
    println(result)
} handle (e: MyEffect) {
    resume with "Hello"
}

运行流程:

  1. 进入 try 块,执行到 perform MyEffect() 时触发 effect
  2. 匹配到 handle (e: MyEffect),进入 handler
  3. 执行 resume with "Hello"
  4. 回到 perform 处,该表达式结果为 "Hello"
  5. 继续往下执行 println

类型规则

  • perform expr 的类型为 Command<T>T
  • handle 捕获的类型必须是 Command 的子类
  • resume with valuevalue 的类型必须是 T
  • resume throwing exnexn 必须是 ExceptionError 的子类型

示例

示例 1:基础用法

import stdx.effect.Command

class Eff <: Command<Int64> {}

main() {
    try {
        let x = perform Eff()
        println(x)
    } handle (e: Eff) {
        resume with 42
    }
}

输出:

42

示例 2:抛出异常

import stdx.effect.Command

class Eff <: Command<Unit> {}

main() {
    try {
        perform Eff()
    } handle (e: Eff) {
        resume throwing Exception("Error from effect")
    } catch (exn: Exception) {
        println(exn.message)
    }
}

输出:

Error from effect

示例 3:默认实现

import stdx.effect.Command

class Print <: Command<Unit> {
    Print (let msg: String) {}
    override func defaultImpl(): Unit {
        println(msg)
    }
}

main() {
    perform Print("No handler here") // 调用默认实现
}

输出:

No handler here

说明: Effect Handler 是一项实验性功能,需要配合支持该机制的 Cangjie 编译器使用。 编译带有 Effect Handlers 的代码时需要启用编译选项 --experimental--enable-eh。 并且因为 Effect Handlers 还是一项实验性特性,所以对工具的支持工作还在进行中,具体情况如下:

工具支持情况
Cjdb已可正常使用
LSP暂不识别与 Effect Handlers 相关的关键字
Formatter尚未支持
Coverage尚未支持
Cjlint尚未支持

API 列表

类名功能
Command<Res>一个抽象类,表示一种效应(effect),该效应预期会返回类型为 Res 的结果。该类提供了一个可以被重写的默认处理本类效应的方法 defaultImpl,该默认处理方法在效应没有被处理的时候调用,默认实现会抛出 UnhandledCommandException 异常。

异常类

异常类名功能
DoubleResumeException当对同一个效应尝试进行多次 resume(恢复)操作时抛出的异常。每个效应最多只能恢复一次。
UnhandledCommandException当某个效应没有被任何 handler 捕获和处理时抛出的异常。

class Command<Res>

public abstract class Command<Res> {
    public open func defaultImpl(): Res
}

功能:该抽象类表示一种可以被触发和处理的效应(effect)

func defaultImpl()

public open func defaultImpl(): Res

功能:这是该效应的默认处理。当某个效应没有被任何 handler 明确处理时,此方法会抛出 UnhandledCommandException 异常。你可以在具体的 Command 子类中重写此方法,为该效应提供默认的逻辑实现。

返回值:

  • Res - 效应执行后的结果(如果你提供了默认实现的话)。

异常:

示例: 以下程序连续使用了多个 effect handler 操作,以展示:每调用一次 deeper 函数,所影响(增加)的调用层数。 GetDepth 的默认 handler 由 GetDepth.defaultImpl 提供,定义了在没有显式 handler 的情况下,调用层数为 0。 而 deeper 函数使用的每个 handler 程序都会重新执行 GetDepth 函数,并将计算的调用层数增加 1,即比该调用 deeper 之前更深一层。

import stdx.effect.*

public class GetDepth <: Command<Int64> {
    public func defaultImpl(): Int64 {
        0
    }
}

func deeper<T>(f: () -> T): Unit {
    try {
        f()
    } handle(e: GetDepth) {
        resume with ((perform e) + 1)
    }
}

main() {
    println("Depth: ${perform GetDepth()}")
    deeper {
        println("Depth: ${perform GetDepth()}")
        deeper {
            println("Depth: ${perform GetDepth()}")
        }
        println("Depth: ${perform GetDepth()}")
    }
    println("Depth: ${perform GetDepth()}")
}

运行结果如下:

Depth: 0
Depth: 1
Depth: 2
Depth: 1
Depth: 0

这段代码里首先对 defaultImpl 进行了重载,其始终返回一个值,便意味着该程序永远不会抛出 UnhandledCommandException 异常。 这个程序的行为与将 main 函数的主体包裹在 handler 程序 try {... } handle(_: GetDepth) { resume with 0 } 中的效果等价。

异常类

class DoubleResumeException

public class DoubleResumeException <: Exception {
    public init()
}

功能:当尝试对一个已经 resume(恢复)过的 Resumption 再次进行恢复时,将抛出此异常。Effect Handler 的语义要求每个 Resumption 只能被恢复一次,以防止程序状态不一致或不可预期的行为。

父类型:

  • Exception

init()

public init()

功能: 这是 DoubleResumeException 的构造函数。它会用默认信息 "Resumption resumed multiple times" 初始化该异常。

class UnhandledCommandException

public class UnhandledCommandException <: Exception {
    public init()
}

功能:当某个 Command(即某个效应)被 perform(触发)但没有任何 handler 对其进行处理时,会抛出此异常。这是一个运行时安全机制,提示开发者需要为该效应提供明确的处理逻辑。

父类型:

  • Exception

init()

public init()

功能: 这是 UnhandledCommandException 的构造函数。它使用默认信息 "Unhandled command" 来初始化异常对象。

即时效应处理器(Immediate Effect Handler)

本示例展示了如何使用简单的 effect handler:定义一个效应(Command),并在其未被处理时进行捕获。

import stdx.effect.{Command, UnhandledCommandException}

// 定义两个效应类型:生成随机数和发送消息
class Random <: Command<Int64> {}
class Send <: Command<Unit> {
    Send(let msg: String) {}
}

main() {
    try {
        // 触发 Random 效应
        let x = perform Random()
        println("Got random number ${x}, sending...")

        // 触发 Send 效应
        perform Send("Sending ${x}")
    } handle(_: Random) {
        // 处理 Random 效应,立即返回 42
        resume with 42
    } catch(_: UnhandledCommandException) {
        // 如果某个效应没有被处理(这里是 Send),会抛出该异常
        println("Attempting to perform an unhandled command")
    }
}

执行输出

Got random number 42, sending...
Attempting to perform an unhandled command

stdx.encoding.base64

功能介绍

base 包提供字符串的 Base64 编码及解码。

Base64 编码能够将二进制数据转换成仅由 64 个可打印的字符(A-Z、a-z、0-9、+、/)组成的文本格式,这使得二进制数据能够在文本环境中安全传输和存储。

API 列表

函数

函数名功能
fromBase64String(String)用于 Base64 编码的字符串的解码。
toBase64String(Array<Byte>)用于将字符数组转换成 Base64 编码的字符串。

函数

func fromBase64String(String)

public func fromBase64String(data: String): Option<Array<Byte>>

功能:此函数用于 Base64 编码的字符串的解码。

参数:

  • data: String - 要解码的 Base64 编码的字符串。

返回值:

  • Option<Array<Byte>> - 输入空字符串会返回 Option<Array<Byte>>.Some(Array<Byte>()),解码失败会返回 Option<Array<Byte>>.None。

示例:

import stdx.encoding.base64.*

main() {
    // 对Base64编码的字符串进行解码
    let base64Str = "SGVsbG8gV29ybGQh" // "Hello World!"的Base64编码
    let result = fromBase64String(base64Str)

    if (let Some(str) <- result) {
        println("解码成功: ${str}")
        println("转成字符串: ${String.fromUtf8(str)}")
    } else {
        println("解码失败")
    }
}

运行结果:

解码成功: [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]
转成字符串: Hello World!

func toBase64String(Array<Byte>)

public func toBase64String(data: Array<Byte>): String

功能:此函数用于将 Byte 数组转换成 Base64 编码的字符串。

参数:

  • data: Array<Byte> - 要编码的 Byte 数组。

返回值:

  • String - 返回编码后的字符串。

示例:

import stdx.encoding.base64.*

main() {
    // 将字符串转换成Byte数组
    let str = "Hello World!"
    let bytes = str.toArray()
    println("字节数组: ${bytes}")

    // 将Byte数组转换成Base64编码的字符串
    let result = toBase64String(bytes)
    println("编码结果: ${result}")
}

运行结果:

字节数组: [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]
编码结果: SGVsbG8gV29ybGQh

Byte 数组和 Base64 互转

示例:

import stdx.encoding.base64.*

main(): Int64 {
    var arr: Array<Byte> = [77, 97, 110]
    var str = toBase64String(arr)
    print("${str},")
    var opArr: Option<Array<Byte>> = fromBase64String(str)
    var arr2: Array<Byte> = match (opArr) {
        case Some(s) => s
        case None => Array<Byte>()
    }
    for (i in 0..arr2.size) {
        print("${arr2[i]},")
    }
    return 0
}

运行结果:

TWFu,77,97,110,

stdx.encoding.hex

功能介绍

hex 包提供字符串的 Hex 编码及解码。

Hex 编码(也称为十六进制编码)是一种将数据转换为十六进制表示形式的编码方法。Hex 编码使用 16 个字符来表示数据,这 16 个字符分别是 0-9 的数字和 A-F 的字母(不区分大小写,即 a-f 和 A-F 是等价的)。

API 列表

函数

函数名功能
fromHexString(String)用于 Hex 编码的字符串的解码。
toHexString(Array<Byte>)用于将字符数组转换成 Hex 编码的字符串。

函数

func fromHexString(String)

public func fromHexString(data: String): Option<Array<Byte>>

功能:此函数用于 Hex 编码的字符串的解码。

参数:

  • data: String - 要解码的 Hex 编码的字符串。

返回值:

  • Option<Array<Byte>> - 输入空字符串会返回 Option<Array<Byte>>.Some(Array<Byte>()),解码失败会返回 Option<Array<Byte>>.None。

示例:

import stdx.encoding.hex.*

main() {
    // 将Hex编码的字符串解码为字节数组
    let hexStr = "48656c6c6f20576f726c6421" // "Hello World!"的Hex编码
    let result = fromHexString(hexStr)

    if (let Some(bytes) <- result) {
        println("解码成功: ${bytes}")
        println("转成字符串: ${String.fromUtf8(bytes)}")
    } else {
        println("解码失败")
    }
}

运行结果:

解码成功: [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]
转成字符串: Hello World!

func toHexString(Array<Byte>)

public func toHexString(data: Array<Byte>): String

功能:此函数用于将 Byte 数组转换成 Hex 编码的字符串。

参数:

  • data: Array<Byte> - 要编码的 Byte 数组。

返回值:

  • String - 返回编码后的字符串。

示例:

import stdx.encoding.hex.*

main() {
    // 将字符串转换成Byte数组
    let str = "Hello World!"
    let bytes = str.toArray()
    println("字节数组: ${bytes}")

    // 将Byte数组转换成Hex编码的字符串
    let result = toHexString(bytes)
    println("编码结果: ${result}")
}

运行结果:

字节数组: [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]
编码结果: 48656c6c6f20576f726c6421

Byte 数组和 Hex 互转

示例:

import stdx.encoding.hex.*

main(): Int64 {
    var arr: Array<Byte> = [65, 66, 94, 97]
    var str = toHexString(arr)
    print("${str},")
    var opArr: Option<Array<Byte>> = fromHexString(str)
    var arr2: Array<Byte> = match (opArr) {
        case Some(s) => s
        case None => Array<Byte>()
    }
    for (i in 0..arr2.size) {
        print("${arr2[i]},")
    }
    return 0
}

运行结果:

41425e61,65,66,94,97,

stdx.encoding.json

功能介绍

json 包用于对 JSON 数据的处理,实现 String, JsonValue, DataModel 之间的相互转换。

JsonValue 是对 JSON 数据格式的封装,包括 object, array, string, number, true, false 和 null。

DataModel 详细信息可参考:serialization 包文档

JSON 语法规则可参考:介绍 JSON

JSON 数据转换标准可参考:ECMA-404 The JSON Data Interchange Standard

API 列表

接口

接口名功能
ToJson用于实现 JsonValue 和 DataModel 的相互转换。

类名功能
JsonArray创建空 JsonArray。
JsonBool将指定的 Bool 类型实例封装成 JsonBool 实例。
JsonFloat将指定的 Float64 类型实例封装成 JsonFloat 实例。
JsonInt将指定的 Int64 类型实例封装成 JsonInt 实例。
JsonNull将 JsonNull 转换为字符串。
JsonObject创建空 JsonObject。
JsonString将指定的 String 类型实例封装成 JsonString 实例。
JsonValue此类为 JSON 数据层, 主要用于 JsonValue 和 String 数据之间的互相转换。

枚举

枚举名功能
JsonKind表示 JsonValue 的具体类型。

异常类

异常类名功能
JsonException用于 JsonValue 类型使用时出现异常的场景。

接口

interface ToJson

public interface ToJson {
    static func fromJson(jv: JsonValue): DataModel
    func toJson(): JsonValue
}

功能:用于实现 JsonValueDataModel 的相互转换。

static func fromJson(JsonValue)

static func fromJson(jv: JsonValue): DataModel

功能:将 JsonValue 转化为对象 DataModel

参数:

返回值:

func toJson()

func toJson(): JsonValue

功能:将自身转化为 JsonValue

返回值:

异常:

extend DataModel <: ToJson

extend DataModel <: ToJson

功能:为 DataModel 类型实现 ToJson 接口。

父类型:

static func fromJson(JsonValue)

public static func fromJson(jv: JsonValue): DataModel

功能:将 JsonValue 转化为对象 DataModel

参数:

返回值:

示例:

import stdx.serialization.serialization.*
import stdx.encoding.json.*
import std.collection.*

main() {
    var fields = HashMap<String, JsonValue>()
    fields.add("name", JsonString("张三"))
    fields.add("tel", JsonString("10000000000"))

    // 使用HashMap创建新的JsonValue对象
    var jsonObject: JsonObject = JsonObject(fields)

    // JsonValue还原回DataModel
    let dataModel = DataModel.fromJson(jsonObject)
    let data = HashMap<String, String>.deserialize(dataModel)
    println("数据: ${data}")
    return 0
}

运行结果:

数据: [(name, 张三), (tel, 10000000000)]

func toJson()

public func toJson(): JsonValue

功能:将自身转化为 JsonValue

返回值:

异常:

示例:

import stdx.serialization.serialization.*
import std.collection.*
import stdx.encoding.json.*

main() {
    // 创建一个ArrayList并添加一些DataModel
    let list = ArrayList<DataModel>()
    list.add(DataModelString("元素1"))
    list.add(DataModelString("元素2"))

    // 使用ArrayList创建DataModelSeq实例
    let dataModel = DataModelSeq(list)

    // 将DataModelSeq转换为JsonValue
    let jsonValue = dataModel.toJson()

    let kind = jsonValue.kind()
    match (kind) {
        case JsonKind.JsArray => println("JsonValue的类型是JsArray")
        case _ => println("JsonValue的类型不是JsArray")
    }
    println("JsonValue: ${jsonValue.toJsonString()}")
    return 0
}

运行结果:

JsonValue的类型是JsArray
JsonValue: [
  "元素1",
  "元素2"
]

class JsonArray

public class JsonArray <: JsonValue {
    public init()
    public init(list: ArrayList<JsonValue>)
    public init(list: Array<JsonValue>)
}

功能:此类为 JsonValue 实现子类,主要用于封装数组类型的 JSON 数据。

父类型:

示例:

使用示例见 JsonArray 使用示例

init()

public init()

功能:创建空 JsonArray

示例:

import stdx.encoding.json.*

main() {
    let jsonArray: JsonArray = JsonArray()
    println(jsonArray)
    println("JsonValue的数量: ${jsonArray.size()}")
}

运行结果:

[]
JsonValue的数量: 0

init(Array<JsonValue>)

public init(list: Array<JsonValue>)

功能:将指定的 Array 类型实例封装成 JsonArray 实例。

参数:

示例:

import stdx.encoding.json.*
import std.collection.*

main() {
    let a: JsonValue = JsonNull()
    let b: JsonValue = JsonBool(true)
    let c: JsonValue = JsonInt(123)
    let d: JsonValue = JsonString("hello")
    let e: JsonValue = JsonObject(HashMap<String, JsonValue>([("hello", JsonString("world"))]))

    let array: Array<JsonValue> = [a, b, c, d, e]
    let jsonArray: JsonArray = JsonArray(array)

    println(jsonArray)
}

运行结果:

[null,true,123,"hello",{"hello":"world"}]

init(ArrayList<JsonValue>)

public init(list: ArrayList<JsonValue>)

功能:将指定的 ArrayList 类型实例封装成 JsonArray 实例。

参数:

示例:

import stdx.encoding.json.*
import std.collection.*

main() {
    var a: JsonValue = JsonNull()
    var b: JsonValue = JsonBool(true)
    var c: JsonValue = JsonInt(123)
    var d: JsonValue = JsonString("hello")
    var e: JsonValue = JsonObject(HashMap<String, JsonValue>([("hello", JsonString("world"))]))

    var list: ArrayList<JsonValue> = ArrayList<JsonValue>()
    list.add(a)
    list.add(b)
    list.add(c)
    list.add(d)
    list.add(e)

    let jsonArray: JsonArray = JsonArray(list)
    println(jsonArray)
}

运行结果:

[null,true,123,"hello",{"hello":"world"}]

func add(JsonValue)

public func add(jv: JsonValue): JsonArray

功能:向 JsonArray 中加入 JsonValue 数据。

参数:

返回值:

示例:

import std.collection.*
import stdx.encoding.json.*

main() {
    var jsonArray: JsonArray = JsonArray()
    println("初始 JsonArray: ${jsonArray}")
    println("初始数量: ${jsonArray.size()}")

    // 添加不同类型的 JsonValue
    jsonArray = jsonArray.add(JsonNull())
    println("添加 JsonNull 后: ${jsonArray}")
    println("数量: ${jsonArray.size()}")

    jsonArray = jsonArray.add(JsonBool(true))
    println("添加 JsonBool(true) 后: ${jsonArray}")
    println("数量: ${jsonArray.size()}")

    jsonArray = jsonArray.add(JsonString("hello"))
    println("添加 JsonString(\"hello\") 后: ${jsonArray}")
    println("数量: ${jsonArray.size()}")

    jsonArray = jsonArray.add(JsonObject(HashMap<String, JsonValue>([("hello", JsonString("world"))])))
    println("添加 JsonObject 后: ${jsonArray}")
    println("数量: ${jsonArray.size()}")
}

运行结果:

初始 JsonArray: []
初始数量: 0
添加 JsonNull 后: [null]
数量: 1
添加 JsonBool(true) 后: [null,true]
数量: 2
添加 JsonString("hello") 后: [null,true,"hello"]
数量: 3
添加 JsonObject 后: [null,true,"hello",{"hello":"world"}]
数量: 4

func get(Int64)

public func get(index: Int64): Option<JsonValue>

功能:获取 JsonArray 中指定索引的 JsonValue,并用 Option<JsonValue> 封装。

参数:

  • index: Int64 - 指定的索引。

返回值:

示例:

import std.collection.*
import stdx.encoding.json.*

main() {
    var jsonArray: JsonArray = JsonArray()
    jsonArray = jsonArray.add(JsonNull())
    jsonArray = jsonArray.add(JsonBool(true))
    jsonArray = jsonArray.add(JsonInt(100))
    jsonArray = jsonArray.add(JsonString("hello"))
    jsonArray = jsonArray.add(JsonObject(HashMap<String, JsonValue>([("hello", JsonString("world"))])))

    println("JsonArray 内容: ${jsonArray}")
    println("数量: ${jsonArray.size()}")

    // 测试获取不同索引的元素
    let opt1 = jsonArray.get(0)
    println("索引 0 的值: ${opt1.getOrThrow()}")

    let opt2 = jsonArray.get(2)
    println("索引 2 的值: ${opt2.getOrThrow()}")

    let opt3 = jsonArray.get(4)
    println("索引 4 的值: ${opt3.getOrThrow()}")

    // 测试超出范围的索引
    let opt4 = jsonArray.get(10)
    if (let Some(v) <- opt4) {
        println("索引 10 的值: ${v}")
    } else {
        println("索引 10 的值不存在")
    }
}

运行结果:

JsonArray 内容: [null,true,100,"hello",{"hello":"world"}]
数量: 5
索引 0 的值: null
索引 2 的值: 100
索引 4 的值: {"hello":"world"}
索引 10 的值不存在

func getItems()

public func getItems(): ArrayList<JsonValue>

功能:获取 JsonArray 中的 items 数据。

返回值:

示例:

import stdx.encoding.json.*
import std.collection.*

main() {
    var jsonArray: JsonArray = JsonArray()
    jsonArray = jsonArray.add(JsonNull())
    jsonArray = jsonArray.add(JsonBool(true))
    jsonArray = jsonArray.add(JsonInt(100))
    jsonArray = jsonArray.add(JsonString("hello"))
    jsonArray = jsonArray.add(JsonObject(HashMap<String, JsonValue>([("hello", JsonString("world"))])))

    println("JsonArray 内容: ${jsonArray}")
    println("数量: ${jsonArray.size()}")

    // 获取 items 列表
    let items = jsonArray.getItems()
    let itemsSize = items.size
    println("获取的 items 列表数量: ${itemsSize}")

    // 遍历 items 列表
    for (i in items) {
        println("值: ${i}")
    }
}

运行结果:

JsonArray 内容: [null,true,100,"hello",{"hello":"world"}]
数量: 5
获取的 items 列表数量: 5
值: null
值: true
值: 100
值: "hello"
值: {"hello":"world"}

func kind()

public func kind(): JsonKind

功能:返回当前 JsonArray 所属的 JsonKind 类型(JsArray)。

返回值:

示例:

import std.collection.*
import stdx.encoding.json.*

main() {
    var jsonArray: JsonArray = JsonArray()
    jsonArray = jsonArray.add(JsonNull())
    jsonArray = jsonArray.add(JsonBool(true))
    jsonArray = jsonArray.add(JsonInt(100))
    jsonArray = jsonArray.add(JsonObject(HashMap<String, JsonValue>([("hello", JsonString("world"))])))

    // 获取 JsonArray 的 kind
    let kind = jsonArray.kind()

    // 使用 match 语句来处理 JsonKind 枚举
    match (kind) {
        case JsonKind.JsArray => println("变量 jsonArray 的 kind 是 JsArray")
        case _ => println("变量 jsonArray 的 kind 不是 JsArray")
    }
}

运行结果:

变量 jsonArray 的 kind 是 JsArray

func size()

public func size(): Int64

功能:获取 JsonArrayJsonValue 的数量。

返回值:

示例:

import stdx.encoding.json.*

main() {
    var jsonArray: JsonArray = JsonArray()

    println("初始 JsonArray 数量: ${jsonArray.size()}")

    // 添加元素并检查数量变化
    jsonArray = jsonArray.add(JsonNull())
    println("添加 JsonNull 后的数量: ${jsonArray.size()}")

    jsonArray = jsonArray.add(JsonBool(true))
    println("添加 JsonBool 后的数量: ${jsonArray.size()}")
    // 验证最终内容
    println("最终 JsonArray 内容: ${jsonArray}")
}

运行结果:

初始 JsonArray 数量: 0
添加 JsonNull 后的数量: 1
添加 JsonBool 后的数量: 2
最终 JsonArray 内容: [null,true]

func toJsonString()

public func toJsonString(): String

功能:将 JsonArray 转换为 JSON 格式的 (带有空格换行符) 的字符串。

返回值:

  • String - 转换后的 JSON 格式字符串。

示例:

import stdx.encoding.json.*
import std.collection.*

main() {
    var jsonArray: JsonArray = JsonArray()
    jsonArray = jsonArray.add(JsonNull())
    jsonArray = jsonArray.add(JsonBool(true))
    jsonArray = jsonArray.add(JsonInt(123))
    jsonArray = jsonArray.add(JsonString("hello"))
    jsonArray = jsonArray.add(JsonObject(HashMap<String, JsonValue>([("hello", JsonString("world"))])))

    println("JsonArray 内容: ${jsonArray}")
    println("数量: ${jsonArray.size()}")

    // 使用 toJsonString 方法
    let jsonString = jsonArray.toJsonString()
    println("toJsonString 结果:")
    println(jsonString)

    // 对比 toString 方法
    let toStringResult = jsonArray
    println("toString 结果: ${toStringResult}")
}

运行结果:

JsonArray 内容: [null,true,123,"hello",{"hello":"world"}]
数量: 5
toJsonString 结果:
[
  null,
  true,
  123,
  "hello",
  {
    "hello": "world"
  }
]
toString 结果: [null,true,123,"hello",{"hello":"world"}]

func toJsonString(Int64, Bool, String)

public func toJsonString(depth: Int64, bracketInNewLine!: Bool = false, indent!: String = "  "): String

功能:将 JsonArray 转换为 JSON 格式的字符串。该函数将指定初始的缩进深度、第一个括号后是否换行以及缩进字符串。

参数:

  • depth: Int64 - 指定的缩进深度。
  • bracketInNewLine!: Bool - 第一个括号是否换行,如果为 true,第一个括号将另起一行并且按照指定的深度缩进。
  • indent!: String - 指定的缩进字符串,缩进字符串中只允许空格和制表符的组合,默认为两个空格。

返回值:

  • String - 转换后的 JSON 格式字符串。

异常:

  • IllegalArgumentException - 如果 depth 为负数,或 indent 中存在 ' ' 和 '\t' 以外的字符,则抛出异常。

示例:

import std.collection.*
import stdx.encoding.json.*

main() {
    var jsonArray: JsonArray = JsonArray()
    jsonArray = jsonArray.add(JsonNull())
    jsonArray = jsonArray.add(JsonBool(true))
    jsonArray = jsonArray.add(JsonInt(123))
    jsonArray = jsonArray.add(JsonString("hello"))
    jsonArray = jsonArray.add(JsonObject(HashMap<String, JsonValue>([("hello", JsonString("world"))])))

    println("=== 自定义参数toJsonString ===")
    let result = jsonArray.toJsonString(1, bracketInNewLine: true, indent: " ")
    println(result)
    println("=== 默认toJsonString ===")
    let result1 = jsonArray.toJsonString()
    println(result1)
}

运行结果:

=== 自定义参数toJsonString ===
 [
  null,
  true,
  123,
  "hello",
  {
   "hello": "world"
  }
 ]
=== 默认toJsonString ===
[
  null,
  true,
  123,
  "hello",
  {
    "hello": "world"
  }
]

func toJsonStringWithoutEscaping()

public func toJsonStringWithoutEscaping(): String

功能:将 JsonArray 转换为 JSON 格式的 (带有空格换行符) 的字符串,不对 html 特殊字符 & 转义。

返回值:

  • String - 转换后的 JSON 格式字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonArray: JsonArray = JsonArray()
    jsonArray = jsonArray.add(JsonString("~!@#$%^&*();':\"/.,<>?\\|"))

    // 使用 toJsonString 方法
    let jsonString = jsonArray.toJsonString()
    println("toJsonString 结果(仅&符号转义):")
    println(jsonString)

    // 使用 toJsonStringWithoutEscaping 方法
    let jsonStringWithoutEscaping = jsonArray.toJsonStringWithoutEscaping()
    println("toJsonStringWithoutEscaping 结果(无转义):")
    println(jsonStringWithoutEscaping)
}

运行结果:

toJsonString 结果(仅&符号转义):
[
  "~!@#$%^\u0026*();':\"/.,<>?\\|"
]
toJsonStringWithoutEscaping 结果(无转义):
[
  "~!@#$%^&*();':\"/.,<>?\\|"
]

func toJsonStringWithoutEscaping(Int64, Bool, String)

public func toJsonStringWithoutEscaping(depth: Int64, bracketInNewLine!: Bool = false, indent!: String = "  "): String

功能:将 JsonArray 转换为 JSON 格式的字符串。该函数将指定初始的缩进深度、第一个括号后是否换行以及缩进字符串,不对 html 特殊字符 & 转义。

参数:

  • depth: Int64 - 指定的缩进深度。
  • bracketInNewLine!: Bool - 第一个括号是否换行,如果为 true,第一个括号将另起一行并且按照指定的深度缩进。
  • indent!: String - 指定的缩进字符串,缩进字符串中只允许空格和制表符的组合,默认为两个空格。

返回值:

  • String - 转换后的 JSON 格式字符串。

异常:

  • IllegalArgumentException - 如果 depth 为负数,或 indent 中存在 ' ' 和 '\t' 以外的字符,则抛出异常。

示例:

import stdx.encoding.json.*

main() {
    var jsonArray: JsonArray = JsonArray()
    jsonArray = jsonArray.add(JsonString("~!@#$%^&*();':\"/.,<>?\\|"))

    // 使用 toJsonString 方法
    let jsonString = jsonArray.toJsonString(2, bracketInNewLine: true, indent: " ")
    println("toJsonString (带参数) 结果(仅&符号转义):")
    println(jsonString)

    // 使用 toJsonStringWithoutEscaping 方法
    let jsonStringWithoutEscaping = jsonArray.toJsonStringWithoutEscaping(2, bracketInNewLine: true, indent: " ")
    println("toJsonStringWithoutEscaping (带参数) 结果(无转义):")
    println(jsonStringWithoutEscaping)
}

运行结果:

toJsonString (带参数) 结果(仅&符号转义):
  [
   "~!@#$%^\u0026*();':\"/.,<>?\\|"
  ]
toJsonStringWithoutEscaping (带参数) 结果(无转义):
  [
   "~!@#$%^&*();':\"/.,<>?\\|"
  ]

func toString()

public func toString(): String

功能:将 JsonArray 转换为字符串。

返回值:

  • String - 转换后的字符串。

示例:

import std.collection.*
import stdx.encoding.json.*

main() {
    var jsonArray: JsonArray = JsonArray()
    jsonArray = jsonArray.add(JsonNull())
    jsonArray = jsonArray.add(JsonBool(true))
    jsonArray = jsonArray.add(JsonInt(123))
    jsonArray = jsonArray.add(JsonString("hello&world"))
    jsonArray = jsonArray.add(JsonObject(HashMap<String, JsonValue>([("hello", JsonString("world"))])))

    // 使用 toString 方法
    let stringResult = jsonArray
    println("toString 结果: ${stringResult}")
}

运行结果:

toString 结果: [null,true,123,"hello\u0026world",{"hello":"world"}]

func toStringWithoutEscaping()

public func toStringWithoutEscaping(): String

功能:将 JsonArray 转换为字符串,不对 html 特殊字符 & 转义。

返回值:

  • String - 转换后的字符串。

示例:

import std.collection.*
import stdx.encoding.json.*

main() {
    var jsonArray: JsonArray = JsonArray()
    jsonArray = jsonArray.add(JsonNull())
    jsonArray = jsonArray.add(JsonBool(true))
    jsonArray = jsonArray.add(JsonInt(123))
    jsonArray = jsonArray.add(JsonString("hello&world"))
    jsonArray = jsonArray.add(JsonObject(HashMap<String, JsonValue>([("hello", JsonString("world"))])))

    // 使用 toStringWithoutEscaping 方法
    let stringResult = jsonArray
    println("toString 结果: ${stringResult.toStringWithoutEscaping()}")
}

运行结果:

toString 结果: [null,true,123,"hello&world",{"hello":"world"}]

operator func [](Int64)

public operator func [](index: Int64): JsonValue

功能:获取 JsonArray 中指定索引的 JsonValue

参数:

  • index: Int64 - 指定的索引。

返回值:

异常:

示例:

import std.collection.*
import stdx.encoding.json.*

main() {
    var jsonArray: JsonArray = JsonArray()
    jsonArray = jsonArray.add(JsonNull())
    jsonArray = jsonArray.add(JsonBool(true))
    jsonArray = jsonArray.add(JsonInt(123))
    jsonArray = jsonArray.add(JsonString("hello&world"))
    jsonArray = jsonArray.add(JsonObject(HashMap<String, JsonValue>([("hello", JsonString("world"))])))

    println("JsonArray 内容: ${jsonArray}")

    // 使用下标操作符访问元素
    println("使用下标操作符访问元素:")
    let element0 = jsonArray[0]
    println("索引 0 的值: ${element0}")

    let element1 = jsonArray[1]
    println("索引 1 的值: ${element1}")

    let element3 = jsonArray[3]
    println("索引 3 的值: ${element3}")

    // 测试越界访问(应该会抛出异常)
    println("测试越界访问:")
    try {
        let elementOut = jsonArray[10]
        println("索引 10 的值: ${elementOut}")
    } catch (e: Exception) {
        println("捕获到异常: ${e.message}")
    }
}

运行结果:

JsonArray 内容: [null,true,123,"hello\u0026world",{"hello":"world"}]
使用下标操作符访问元素:
索引 0 的值: null
索引 1 的值: true
索引 3 的值: "hello\u0026world"
测试越界访问:
捕获到异常: The index 10 of JsonArray does not exist.

class JsonBool

public class JsonBool <: JsonValue {
    public init(bv: Bool)
}

功能:此类为 JsonValue 实现子类,主要用于封装 true 或者 false 的 JSON 数据。

父类型:

init(Bool)

public init(bv: Bool)

功能:将指定的 Bool 类型实例封装成 JsonBool 实例。

参数:

  • bv: Bool - Bool 类型。

示例:

import stdx.encoding.json.*

main() {
    var jsonTrue: JsonBool = JsonBool(true)

    println("JsonBool(true) 创建的对象: ${jsonTrue}")
}

运行结果:

JsonBool(true) 创建的对象: true

func getValue()

public func getValue(): Bool

功能:获取 JsonBool 中 value 的实际值。

返回值:

  • Bool - value 的实际值。

示例:

import stdx.encoding.json.*

main() {
    var jsonTrue: JsonBool = JsonBool(true)

    var trueValue = jsonTrue.getValue()

    println("JsonBool(true) 的值: ${trueValue}")
}

运行结果:

JsonBool(true) 的值: true

func kind()

public func kind(): JsonKind

功能:返回当前 JsonBool 所属的 JsonKind 类型(JsBool)。

返回值:

示例:

import stdx.encoding.json.*

main() {
    var jsonTrue: JsonBool = JsonBool(true)

    var trueKind = jsonTrue.kind()

    // 使用 match 语句处理类型
    match (trueKind) {
        case JsonKind.JsBool => println("变量jsonTrue的类型是JsBool")
        case _ => println("变量jsonTrue的类型不是JsBool")
    }
}

运行结果:

变量jsonTrue的类型是JsBool

func toJsonString()

public func toJsonString(): String

功能:将 JsonBool 转换为 JSON 格式的 (带有空格换行符) 字符串。

返回值:

  • String - 转换后的 JSON 格式字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonTrue: JsonBool = JsonBool(true)

    var trueJsonStr = jsonTrue.toJsonString()

    println("JsonBool(true) 的 JSON 字符串: ${trueJsonStr}")
}

运行结果:

JsonBool(true) 的 JSON 字符串: true

func toJsonStringWithoutEscaping()

public func toJsonStringWithoutEscaping(): String

功能:等同 toJsonString()。

返回值:

  • String - 转换后的 JSON 格式字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonTrue: JsonBool = JsonBool(true)

    var trueJsonStr = jsonTrue.toJsonStringWithoutEscaping()

    println("等同 toJsonString(): ${trueJsonStr}")
}

运行结果:

等同 toJsonString(): true

func toString()

public func toString(): String

功能:将 JsonBool 转换为字符串。

返回值:

  • String - 转换后的字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonTrue: JsonBool = JsonBool(true)

    var trueStr = jsonTrue.toString()

    println("JsonBool(true) 的字符串表示: ${trueStr}")
}

运行结果:

JsonBool(true) 的字符串表示: true

func toStringWithoutEscaping()

public func toStringWithoutEscaping(): String

功能:等同 toString()。

返回值:

  • String - 转换后的字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonTrue: JsonBool = JsonBool(true)

    var trueStr = jsonTrue.toStringWithoutEscaping()

    println("等同toString(): ${trueStr}")
}

运行结果:

等同toString(): true

class JsonFloat

public class JsonFloat <: JsonValue {
    public init(fv: Float64)
    public init(v: Int64)
}

功能:此类为 JsonValue 实现子类,主要用于封装浮点类型的 JSON 数据。

父类型:

init(Float64)

public init(fv: Float64)

功能:将指定的 Float64 类型实例封装成 JsonFloat 实例。

参数:

  • fv: Float64 - Float64 类型。

示例:

import stdx.encoding.json.*

main() {
    let jsonFloat: JsonFloat = JsonFloat(3.14159)

    println("JsonFloat(3.14159) 创建的对象: ${jsonFloat}")
}

运行结果:

JsonFloat(3.14159) 创建的对象: 3.141590

init(Int64)

public init(v: Int64)

功能:将指定的 Int64 类型实例封装成 JsonFloat 实例。

参数:

  • v: Int64 - Int64 类型。

示例:

import stdx.encoding.json.*

main() {
    let jsonFloat: JsonFloat = JsonFloat(42)

    println("JsonFloat(42) 创建的对象: ${jsonFloat}")
}

运行结果:

JsonFloat(42) 创建的对象: 42.000000

func getValue()

public func getValue(): Float64

功能:获取 JsonFloat 中 value 的实际值。

返回值:

  • Float64 - value 的实际值。

示例:

import stdx.encoding.json.*

main() {
    let jsonFloat: JsonFloat = JsonFloat(3.14159)

    let value = jsonFloat.getValue()

    println("JsonFloat(3.14159) 的值: ${value}")
}

运行结果:

JsonFloat(3.14159) 的值: 3.141590

func kind()

public func kind(): JsonKind

功能:返回当前 JsonFloat 所属的 JsonKind 类型(JsFloat)。

返回值:

示例:

import stdx.encoding.json.*

main() {
    let jsonFloat: JsonFloat = JsonFloat(3.14159)

    let kind = jsonFloat.kind()

    // 使用 match 语句处理类型
    match (kind) {
        case JsonKind.JsFloat => println("变量jsonFloat的类型是JsFloat")
        case _ => println("变量jsonFloat的类型不是JsFloat")
    }
}

运行结果:

变量jsonFloat的类型是JsFloat

func toJsonString()

public func toJsonString(): String

功能:将 JsonFloat 转换为 JSON 格式的 (带有空格换行符) 字符串。

返回值:

  • String - 转换后的 JSON 格式字符串。

示例:

import stdx.encoding.json.*

main() {
    let jsonFloat: JsonFloat = JsonFloat(3.14159)

    let jsonStr = jsonFloat.toJsonString()

    println("JsonFloat(3.14159) 的 JSON 字符串: ${jsonStr}")
}

运行结果:

JsonFloat(3.14159) 的 JSON 字符串: 3.141590

func toJsonStringWithoutEscaping()

public func toJsonStringWithoutEscaping(): String

功能:等同 toJsonString()。

返回值:

  • String - 转换后的 JSON 格式字符串。

示例:

import stdx.encoding.json.*

main() {
    let jsonFloat: JsonFloat = JsonFloat(3.14159)

    let jsonStr = jsonFloat.toJsonStringWithoutEscaping()

    println("等同 toJsonString(): ${jsonStr}")
}

运行结果:

等同 toJsonString(): 3.141590

func toString()

public func toString(): String

功能:将 JsonFloat 转换为字符串。

返回值:

  • String - 转换后的字符串。

示例:

import stdx.encoding.json.*

main() {
    let jsonFloat: JsonFloat = JsonFloat(3.14159)

    let str = jsonFloat.toString()

    println("JsonFloat(3.14159) 的字符串表示: ${str}")
}

运行结果:

JsonFloat(3.14159) 的字符串表示: 3.141590

func toStringWithoutEscaping()

public func toStringWithoutEscaping(): String

功能:等同 toString()。

返回值:

  • String - 转换后的字符串。

示例:

import stdx.encoding.json.*

main() {
    let jsonFloat: JsonFloat = JsonFloat(3.14159)

    let str = jsonFloat.toStringWithoutEscaping()

    println("等同toString(): ${str}")
}

运行结果:

等同toString(): 3.141590

class JsonInt

public class JsonInt <: JsonValue {
    public init(iv: Int64)
}

功能:此类为 JsonValue 实现子类,主要用于封装整数类型的 JSON 数据。

父类型:

init(Int64)

public init(iv: Int64)

功能:将指定的 Int64 类型实例封装成 JsonInt 实例。

参数:

  • iv: Int64 - 用于创建 JsonInt 的 Int64。

示例:

import stdx.encoding.json.*

main() {
    var jsonInt: JsonInt = JsonInt(42)

    println("JsonInt(42) 创建的对象: ${jsonInt}")
}

运行结果:

JsonInt(42) 创建的对象: 42

func getValue()

public func getValue(): Int64

功能:获取 JsonInt 中 value 的实际值。

返回值:

  • Int64 - value 的实际值。

示例:

import stdx.encoding.json.*

main() {
    var jsonInt: JsonInt = JsonInt(42)

    var value = jsonInt.getValue()

    println("JsonInt(42) 的值: ${value}")
}

运行结果:

JsonInt(42) 的值: 42

func kind()

public func kind(): JsonKind

功能:返回当前 JsonInt 所属的 JsonKind 类型(JsInt)。

返回值:

示例:

import stdx.encoding.json.*

main() {
    var jsonInt: JsonInt = JsonInt(42)

    var kind = jsonInt.kind()

    // 使用 match 语句处理类型
    match (kind) {
        case JsonKind.JsInt => println("变量jsonInt的类型是JsInt")
        case _ => println("变量jsonInt的类型不是JsInt")
    }
}

运行结果:

变量jsonInt的类型是JsInt

func toJsonString()

public func toJsonString(): String

功能:将 JsonInt 转换为 JSON 格式的 (带有空格换行符) 字符串。

返回值:

  • String - 转换后的 JSON 格式字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonInt: JsonInt = JsonInt(42)

    var jsonStr = jsonInt.toJsonString()

    println("JsonInt(42) 的 JSON 字符串: ${jsonStr}")
}

运行结果:

JsonInt(42) 的 JSON 字符串: 42

func toJsonStringWithoutEscaping()

public func toJsonStringWithoutEscaping(): String

功能:等同 toJsonString()。

返回值:

  • String - 转换后的 JSON 格式字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonInt: JsonInt = JsonInt(42)

    var jsonStr = jsonInt.toJsonStringWithoutEscaping()

    println("等同 toJsonString(): ${jsonStr}")
}

运行结果:

等同 toJsonString(): 42

func toString()

public func toString(): String

功能:将 JsonInt 转换为字符串。

返回值:

  • String - 转换后的字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonInt: JsonInt = JsonInt(42)

    var str = jsonInt.toString()

    println("JsonInt(42) 的字符串表示: ${str}")
}

运行结果:

JsonInt(42) 的字符串表示: 42

func toStringWithoutEscaping()

public func toStringWithoutEscaping(): String

功能:等同 toString()。

返回值:

  • String - 转换后的字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonInt: JsonInt = JsonInt(42)

    var str = jsonInt.toStringWithoutEscaping()

    println("等同toString(): ${str}")
}

运行结果:

等同toString(): 42

class JsonNull

public class JsonNull <: JsonValue

功能:此类为 JsonValue 实现子类,主要用于封装 null 的 JSON 数据。

父类型:

func kind()

public func kind(): JsonKind

功能:返回当前 JsonNull 所属的 JsonKind 类型(JsNull)。

返回值:

示例:

import stdx.encoding.json.*

main() {
    var jsonNull: JsonNull = JsonNull()

    let kind = jsonNull.kind()
    // 使用 match 语句处理类型
    match (kind) {
        case JsonKind.JsNull => println("变量jsonNull的类型是JsNull")
        case _ => println("变量jsonNull的类型不是JsNull")
    }
}

运行结果:

变量jsonNull的类型是JsNull

func toJsonString()

public func toJsonString(): String

功能:将 JsonNull 转换为 JSON 格式的 (带有空格换行符) 字符串。

返回值:

  • String - 转换后的 JSON 格式字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonNull: JsonNull = JsonNull()

    var jsonStr = jsonNull.toJsonString()
    println("JsonNull 的 JSON 字符串: ${jsonStr}")
}

运行结果:

JsonNull 的 JSON 字符串: null

func toJsonStringWithoutEscaping()

public func toJsonStringWithoutEscaping(): String

功能:等同 toJsonString()。

返回值:

  • String - 转换后的 JSON 格式字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonNull: JsonNull = JsonNull()

    var jsonStr = jsonNull.toJsonStringWithoutEscaping()

    println("等同 toJsonString(): ${jsonStr}")
}

运行结果:

等同 toJsonString(): null

func toString()

public func toString(): String

功能:将 JsonNull 转换为字符串。

返回值:

  • String - 转换后的字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonNull: JsonNull = JsonNull()

    var str = jsonNull.toString()
    println("JsonNull 的字符串表示: ${str}")
}

运行结果:

JsonNull 的字符串表示: null

func toStringWithoutEscaping()

public func toStringWithoutEscaping(): String

功能:等同 toString()。

返回值:

  • String - 转换后的字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonNull: JsonNull = JsonNull()

    var str = jsonNull.toStringWithoutEscaping()

    println("等同 toJsonString(): ${str}")
}

运行结果:

等同 toJsonString(): null

class JsonObject

public class JsonObject <: JsonValue {
    public init()
    public init(map: HashMap<String, JsonValue>)
}

功能:此类为 JsonValue 实现子类,主要用于封装 object 类型的 JSON 数据。

父类型:

init()

public init()

功能:创建空 JsonObject

示例:

import stdx.encoding.json.*

main() {
    var jsonObject: JsonObject = JsonObject()

    println("创建空JsonObject: ${jsonObject}")
}

运行结果:

创建空JsonObject: {}

init(HashMap<String, JsonValue>)

public init(map: HashMap<String, JsonValue>)

功能:将指定的 HashMap 类型实例封装成 JsonObject 实例。

参数:

  • map: HashMap<String, JsonValue> - data 数据。

示例:

import stdx.encoding.json.*
import std.collection.*

main() {
    var fields = HashMap<String, JsonValue>()
    fields.add("name", JsonString("张三"))
    fields.add("age", JsonInt(25))
    fields.add("student", JsonBool(true))

    // 使用HashMap创建新的JsonObject
    var jsonObject2: JsonObject = JsonObject(fields)

    println("使用HashMap创建JsonObject: ${jsonObject2}")
}

运行结果:

使用HashMap创建JsonObject: {"name":"张三","age":25,"student":true}

func containsKey(String)

public func containsKey(key: String): Bool

功能:判断 JsonObject 中是否存在 key。

参数:

  • key: String - 指定的 key。

返回值:

  • Bool - 存在返回 true,不存在返回 false。

示例:

import stdx.encoding.json.*

main() {
    var jsonObject: JsonObject = JsonObject()
    jsonObject.put("name", JsonString("张三"))
    jsonObject.put("age", JsonInt(25))

    var hasName = jsonObject.containsKey("name")
    var hasAddress = jsonObject.containsKey("address")

    println("JsonObject是否包含name键: ${hasName}")
    println("JsonObject是否包含address键: ${hasAddress}")
}

运行结果:

JsonObject是否包含name键: true
JsonObject是否包含address键: false

func get(String)

public func get(key: String): Option<JsonValue>

功能:获取 JsonObject 中 key 对应的 JsonValue,并用 Option<JsonValue> 封装。

参数:

  • key: String - 指定的 key。

返回值:

示例:

import stdx.encoding.json.*

main() {
    var jsonObject: JsonObject = JsonObject()
    jsonObject.put("name", JsonString("张三"))
    jsonObject.put("age", JsonInt(25))

    var nameValue = jsonObject.get("name")
    var ageValue = jsonObject.get("age")
    var addressValue = jsonObject.get("address") // 不存在的键

    // 使用match处理Option类型
    var nameStr = match (nameValue) {
        case Some(value) => value
        case None => "键不存在"
    }

    var ageStr = match (ageValue) {
        case Some(value) => value
        case None => "键不存在"
    }

    var addressStr = match (addressValue) {
        case Some(value) => value
        case None => "键不存在"
    }

    println("name的值: ${nameStr}")
    println("age的值: ${ageStr}")
    println("address的值: ${addressStr}")
}

运行结果:

name的值: "张三"
age的值: 25
address的值: 键不存在

func getFields()

public func getFields(): HashMap<String, JsonValue>

功能:获取 JsonObject 中的 fields 数据。

返回值:

示例:

import stdx.encoding.json.*
import std.collection.*

main() {
    var jsonObject: JsonObject = JsonObject()
    jsonObject.put("name", JsonString("张三"))
    jsonObject.put("age", JsonInt(25))
    jsonObject.put("student", JsonBool(true))

    var fields: HashMap<String, JsonValue> = jsonObject.getFields()

    println("JsonObject的字段数据: ${jsonObject}")
    println("获取到的字段HashMap: ${fields}")
}

运行结果:

JsonObject的字段数据: {"name":"张三","age":25,"student":true}
获取到的字段HashMap: [(name, "张三"), (age, 25), (student, true)]

func kind()

public func kind(): JsonKind

功能:返回当前 JsonObject 所属的 JsonKind 类型(JsObject)。

返回值:

示例:

import stdx.encoding.json.*

main() {
    var jsonObject: JsonObject = JsonObject()
    jsonObject.put("name", JsonString("张三"))

    var kind = jsonObject.kind()

    // 使用 match 语句处理类型
    match (kind) {
        case JsonKind.JsObject => println("变量jsonObject的类型是JsObject")
        case _ => println("变量jsonObject的类型不是JsObject")
    }
}

运行结果:

变量jsonObject的类型是JsObject

func put(String, JsonValue)

public func put(key: String, v: JsonValue): Unit

功能:向 JsonObject 中加入 key-JsonValue 数据。

参数:

示例:

import stdx.encoding.json.*

main() {
    var jsonObject: JsonObject = JsonObject()

    jsonObject.put("name", JsonString("张三"))
    jsonObject.put("age", JsonInt(25))
    jsonObject.put("student", JsonBool(true))

    println("添加键值对后的JsonObject: ${jsonObject}")
}

运行结果:

添加键值对后的JsonObject: {"name":"张三","age":25,"student":true}

func size()

public func size(): Int64

功能:获取 JsonObject 中 fields 存入 string-JsonValue 的数量。

返回值:

示例:

import stdx.encoding.json.*

main() {
    var jsonObject: JsonObject = JsonObject()

    var initialSize = jsonObject.size()
    println("初始JsonObject的大小: ${initialSize}")

    jsonObject.put("name", JsonString("张三"))
    var sizeAfterAdd1 = jsonObject.size()
    println("添加一个键值对后的大小: ${sizeAfterAdd1}")

    jsonObject.put("age", JsonInt(25))
    jsonObject.put("student", JsonBool(true))
    var finalSize = jsonObject.size()
    println("添加多个键值对后的最终大小: ${finalSize}")
}

运行结果:

初始JsonObject的大小: 0
添加一个键值对后的大小: 1
添加多个键值对后的最终大小: 3

func toJsonString()

public func toJsonString(): String

功能:将 JsonObject 转换为 JSON 格式的 (带有空格换行符) 字符串。

返回值:

  • String - 转换后的 JSON 格式字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonObject: JsonObject = JsonObject()
    jsonObject.put("name", JsonString("张三"))
    jsonObject.put("age", JsonInt(25))
    jsonObject.put("student", JsonBool(true))

    var jsonStr = jsonObject.toJsonString()

    println("JsonObject转换为JSON字符串:\n${jsonStr}")
}

运行结果:

JsonObject转换为JSON字符串:
{
  "name": "张三",
  "age": 25,
  "student": true
}

func toJsonString(Int64, Bool, String)

public func toJsonString(depth: Int64, bracketInNewLine!: Bool = false, indent!: String = "  "): String

功能:将 JsonObject 转换为 JSON 格式的字符串。该函数将指定初始的缩进深度、第一个括号后是否换行以及缩进字符串。

参数:

  • depth: Int64 - 缩进深度。
  • bracketInNewLine!: Bool - 第一个括号是否换行,如果为 true,第一个括号将另起一行并且按照指定的深度缩进。
  • indent!: String - 指定的缩进字符串,缩进字符串中只允许空格和制表符的组合,默认为两个空格。

返回值:

  • String - 转换后的 JSON 格式字符串。

异常:

  • IllegalArgumentException - 如果 depth 为负数,或 indent 中存在 ' ' 和 '\t' 以外的字符,则抛出异常。

示例:

import stdx.encoding.json.*

main() {
    var jsonObject: JsonObject = JsonObject()
    jsonObject.put("name", JsonString("张三"))
    jsonObject.put("age", JsonInt(25))
    jsonObject.put("student", JsonBool(true))

    // 使用参数的toJsonString方法,使用命名参数
    var jsonStr1 = jsonObject.toJsonString(0, bracketInNewLine: false, indent: "  ") // 默认缩进
    var jsonStr2 = jsonObject.toJsonString(1, bracketInNewLine: true, indent: "    ") // 深度1,第一个括号换行,4个空格缩进

    println("默认格式的JSON字符串:\n${jsonStr1}")
    println("指定参数的JSON字符串:\n${jsonStr2}")
}

运行结果:

默认格式的JSON字符串:
{
  "name": "张三",
  "age": 25,
  "student": true
}
指定参数的JSON字符串:
    {
        "name": "张三",
        "age": 25,
        "student": true
    }

func toJsonStringWithoutEscaping()

public func toJsonStringWithoutEscaping(): String

功能:将 JsonObject 转换为 JSON 格式的 (带有空格换行符) 字符串,不对 html 特殊字符 & 转义。

返回值:

  • String - 转换后的 JSON 格式字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonObject: JsonObject = JsonObject()
    jsonObject.put("name", JsonString("张三&李四")) // 包含&符号
    jsonObject.put("description", JsonString("学生<25岁"))

    var jsonStr = jsonObject.toJsonStringWithoutEscaping()
    var normalJsonStr = jsonObject.toJsonString() // 对比正常方法

    println("不转义HTML特殊字符的JSON字符串:\n${jsonStr}")
    println("正常转义的JSON字符串:\n${normalJsonStr}")
}

运行结果:

不转义HTML特殊字符的JSON字符串:
{
  "name": "张三&李四",
  "description": "学生<25岁"
}
正常转义的JSON字符串:
{
  "name": "张三\u0026李四",
  "description": "学生<25岁"
}

func toJsonStringWithoutEscaping(Int64, Bool, String)

public func toJsonStringWithoutEscaping(depth: Int64, bracketInNewLine!: Bool = false, indent!: String = "  "): String

功能:将 JsonObject 转换为 JSON 格式的字符串。该函数将指定初始的缩进深度、第一个括号后是否换行以及缩进字符串,不对 html 特殊字符 & 转义。

参数:

  • depth: Int64 - 缩进深度。
  • bracketInNewLine!: Bool - 第一个括号是否换行,如果为 true,第一个括号将另起一行并且按照指定的深度缩进。
  • indent!: String - 指定的缩进字符串,缩进字符串中只允许空格和制表符的组合,默认为两个空格。

返回值:

  • String - 转换后的 JSON 格式字符串。

异常:

  • IllegalArgumentException - 如果 depth 为负数,或 indent 中存在 ' ' 和 '\t' 以外的字符,则抛出异常。

示例:

import stdx.encoding.json.*

main() {
    var jsonObject: JsonObject = JsonObject()
    jsonObject.put("name", JsonString("张三&李四")) // 包含&符号
    jsonObject.put("description", JsonString("学生<25岁"))

    // 使用参数的toJsonStringWithoutEscaping方法
    var jsonStr1 = jsonObject.toJsonStringWithoutEscaping(0, bracketInNewLine: false, indent: "  ") // 默认缩进
    var jsonStr2 = jsonObject.toJsonStringWithoutEscaping(1, bracketInNewLine: true, indent: "    ") // 深度1,第一个括号换行,4个空格缩进

    println("不转义的默认格式JSON字符串:\n${jsonStr1}")
    println("不转义的指定参数JSON字符串:\n${jsonStr2}")
}

运行结果:

不转义的默认格式JSON字符串:
{
  "name": "张三&李四",
  "description": "学生<25岁"
}
不转义的指定参数JSON字符串:
    {
        "name": "张三&李四",
        "description": "学生<25岁"
    }

func toString()

public func toString(): String

功能:将 JsonObject 转换为字符串。

返回值:

  • String - 转换后的字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonObject: JsonObject = JsonObject()
    jsonObject.put("name", JsonString("张三"))
    jsonObject.put("age", JsonInt(25))
    jsonObject.put("student", JsonBool(true))

    var str = jsonObject.toString()

    println("JsonObject的字符串表示: ${str}")
}

运行结果:

JsonObject的字符串表示: {"name":"张三","age":25,"student":true}

func toStringWithoutEscaping()

public func toStringWithoutEscaping(): String

功能:将 JsonObject 转换为字符串,不对 html 特殊字符 & 转义。

返回值:

  • String - 转换后的字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonObject: JsonObject = JsonObject()
    jsonObject.put("name", JsonString("张三&李四")) // 包含&符号
    jsonObject.put("description", JsonString("学生<25岁"))

    var str = jsonObject.toStringWithoutEscaping()
    var normalStr = jsonObject.toString() // 对比正常方法

    println("不转义HTML特殊字符的字符串: ${str}")
    println("正常转义的字符串: ${normalStr}")
}

运行结果:

不转义HTML特殊字符的字符串: {"name":"张三&李四","description":"学生<25岁"}
正常转义的字符串: {"name":"张三\u0026李四","description":"学生<25岁"}

operator func [](String)

public operator func [](key: String): JsonValue

功能:获取 JsonObject 中 key 对应的 JsonValue

参数:

  • key: String - 指定的 key。

返回值:

异常:

示例:

import stdx.encoding.json.*

main() {
    var jsonObject: JsonObject = JsonObject()
    jsonObject.put("name", JsonString("张三"))
    jsonObject.put("age", JsonInt(25))

    // 使用索引操作符获取值
    var nameValue = jsonObject["name"]

    var ageValue = jsonObject["age"]

    println("通过索引操作符获取name: ${nameValue}")
    println("通过索引操作符获取age: ${ageValue}")
}

运行结果:

通过索引操作符获取name: "张三"
通过索引操作符获取age: 25

class JsonString

public class JsonString <: JsonValue {
    public init(sv: String)
}

功能:此类为 JsonValue 实现子类,主要用于封装字符串类型的 JSON 数据。

父类型:

init(String)

public init(sv: String)

功能:将指定的 String 类型实例封装成 JsonString 实例。

参数:

  • sv: String - String 类型。

示例:

import stdx.encoding.json.*

main() {
    var jsonString: JsonString = JsonString("Hello, 世界")

    println("JsonString(\"Hello, 世界\") 创建的对象: ${jsonString}")
}

运行结果:

JsonString("Hello, 世界") 创建的对象: "Hello, 世界"

func getValue()

public func getValue(): String

功能:获取 JsonString 中 value 的实际值。

返回值:

  • String - value 的实际值。

示例:

import stdx.encoding.json.*

main() {
    var jsonString: JsonString = JsonString("Hello, 世界")

    var value = jsonString.getValue()

    println("JsonString(\"Hello, 世界\") 的值: ${value}")
}

运行结果:

JsonString("Hello, 世界") 的值: Hello, 世界

func kind()

public func kind(): JsonKind

功能:返回当前 JsonString 所属的 JsonKind 类型(JsString)。

返回值:

示例:

import stdx.encoding.json.*

main() {
    var jsonString: JsonString = JsonString("Hello, 世界")

    var kind = jsonString.kind()

    // 使用 match 语句处理类型
    match (kind) {
        case JsonKind.JsString => println("变量jsonString的类型是JsString")
        case _ => println("变量jsonString的类型不是JsString")
    }
}

运行结果:

变量jsonString的类型是JsString

func toJsonString()

public func toJsonString(): String

功能:将 JsonString 转换为 JSON 格式的 (带有空格换行符) 字符串。

返回值:

  • String - 转换后的 JSON 格式字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonString: JsonString = JsonString("Hello, 世界")

    var jsonStr = jsonString.toJsonString()

    println("JsonString(\"Hello, 世界\") 的 JSON 字符串: ${jsonStr}")
}

运行结果:

JsonString("Hello, 世界") 的 JSON 字符串: "Hello, 世界"

func toJsonStringWithoutEscaping()

public func toJsonStringWithoutEscaping(): String

功能:将 JsonString 转换为 JSON 格式的 (带有空格换行符) 字符串,不对 html 特殊字符 & 转义。

返回值:

  • String - 转换后的 JSON 格式字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonString: JsonString = JsonString("Hello & World <测试>")

    var jsonStr = jsonString.toJsonStringWithoutEscaping()
    var normalJsonStr = jsonString.toJsonString() // 对比正常方法

    println("不转义HTML特殊字符的JSON字符串: ${jsonStr}")
    println("正常转义的JSON字符串: ${normalJsonStr}")
}

运行结果:

不转义HTML特殊字符的JSON字符串: "Hello & World <测试>"
正常转义的JSON字符串: "Hello \u0026 World <测试>"

func toString()

public func toString(): String

功能:将 JsonString 转换为字符串。

返回值:

  • String - 转换后的字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonString: JsonString = JsonString("Hello, 世界")

    var str = jsonString.toString()

    println("JsonString(\"Hello, 世界\") 的字符串表示: ${str}")
}

运行结果:

JsonString("Hello, 世界") 的字符串表示: "Hello, 世界"

func toStringWithoutEscaping()

public func toStringWithoutEscaping(): String

功能:将 JsonString 转换为字符串,不对 html 特殊字符 & 转义。

返回值:

  • String - 转换后的字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonString: JsonString = JsonString("Hello & World <测试>")

    var str = jsonString.toStringWithoutEscaping()
    var normalStr = jsonString.toString() // 对比正常方法

    println("不转义HTML特殊字符的字符串: ${str}")
    println("正常转义的字符串: ${normalStr}")
}

运行结果:

不转义HTML特殊字符的字符串: "Hello & World <测试>"
正常转义的字符串: "Hello \u0026 World <测试>"

class JsonValue

sealed abstract class JsonValue <: ToString

功能:此类为 JSON 数据层,主要用于 JsonValue 和 String 数据之间的互相转换。

抽象类 JsonValue 提供了 String 类型和具体的 JSON 类型相互转换的接口,以及具体的 JSON 类型判断功能。

父类型:

  • ToString

示例:

使用示例见JsonValue 和 String 互相转换

static func fromStr(String)

public static func fromStr(s: String): JsonValue

功能:将字符串数据解析为 JsonValue。对于整数,支持前导 '0b','0o','0x'(不区分大小写),分别表示二进制,八进制和十六进制。字符串解析失败时将打印错误字符及其行数和列数,其中列数从错误字符所在行的非空格字符起开始计算。

JSON 在解析 String 转换为 JsonValue 时,转义字符 \ 之后只能对应 JSON 支持的转义字符(b、f、n、r、t、u、\、"、/),其中 \u 的格式为:\uXXXX,X 为十六进制数,例:\u0041 代表字符 'A'。

参数:

  • s: String - 传入字符串,暂不支持 "?" 和特殊字符。

返回值:

异常:

  • JsonException - 如果内存分配失败,或解析字符串出错,抛出异常。

示例:

import stdx.encoding.json.*

main() {
    var jsonString = ##"{"name": "张三", "age": 25, "student": true}"##
    // JSON解析JsonObject
    var jsonValue: JsonValue = JsonValue.fromStr(jsonString)

    println("JsonValue 是 JsonString?: ${jsonValue is JsonString}")
    println("JsonValue 是 JsonObject?: ${jsonValue is JsonObject}")
    println("解析后的JsonValue: ${jsonValue}")

    // JSON解析JsonString合法的转义字符
    let str1 = ##""\n""##
    let jsonValue1 = JsonValue.fromStr(str1)
    println("解析JsonString: ${jsonValue1}")

    // JSON解析JsonString合法的转义字符
    let str2 = ##""\u0041""##
    let jsonValue2 = JsonValue.fromStr(str2)
    println("解析JsonString: ${jsonValue2}")

    // JSON解析JsonString不合法的转义字符
    try {
        let str3 = ##""\x1""##
        let jsonValue3 = JsonValue.fromStr(str3)
        println("解析JsonString: ${jsonValue3}")
    } catch (e: JsonException) {
        println("异常信息: ${e.message}")
    }
}

运行结果:

JsonValue 是 JsonString?: false
JsonValue 是 JsonObject?: true
解析后的JsonValue: {"name":"张三","age":25,"student":true}
解析JsonString: "\n"
解析JsonString: "A"
异常信息: the json data is Non-standard, please check:
Parse Error: [Line]: 1, [Pos]: 3, [Error]: Unexpected character: 'x'.

func asArray()

public func asArray(): JsonArray

功能:将 JsonValue 转换为 JsonArray 格式。

返回值:

异常:

示例:

import stdx.encoding.json.*

main() {
    var jsonString = ##"[1, 2, 3, "hello"]"##
    var jsonValue: JsonValue = JsonValue.fromStr(jsonString)

    var jsonArray = jsonValue.asArray()

    println("JsonValue转换为JsonArray: ${jsonArray}")
    println("数组大小: ${jsonArray.size()}")

    // 转换异常示例
    jsonString = ##"123"##
    jsonValue = JsonValue.fromStr(jsonString)
    try {
        jsonArray = jsonValue.asArray()
    } catch (e: JsonException) {
        println("转换异常: ${e.message}")
    }
}

运行结果:

JsonValue转换为JsonArray: [1,2,3,"hello"]
数组大小: 4
转换异常: Fail to convert to JsonArray

func asBool()

public func asBool(): JsonBool

功能:将 JsonValue 转换为 JsonBool 格式。

返回值:

异常:

示例:

import stdx.encoding.json.*

main() {
    var jsonString = ##"true"##
    var jsonValue: JsonValue = JsonValue.fromStr(jsonString)

    var jsonBool = jsonValue.asBool()

    println("JsonValue转换为JsonBool: ${jsonBool}")
    println("JsonBool的值: ${jsonBool.getValue()}")

    // 转换异常示例
    jsonString = ##"123"##
    jsonValue = JsonValue.fromStr(jsonString)
    try {
        jsonBool = jsonValue.asBool()
    } catch (e: Exception) {
        println("转换异常: ${e.message}")
    }
}

运行结果:

JsonValue转换为JsonBool: true
JsonBool的值: true
转换异常: Fail to convert to JsonBool

func asFloat()

public func asFloat(): JsonFloat

功能:将 JsonValue 转换为 JsonFloat 格式。

返回值:

异常:

示例:

import stdx.encoding.json.*

main() {
    var jsonString = ##"3.14159"##
    var jsonValue: JsonValue = JsonValue.fromStr(jsonString)

    var jsonFloat = jsonValue.asFloat()

    println("JsonValue转换为JsonFloat: ${jsonFloat}")
    println("JsonFloat的值: ${jsonFloat.getValue()}")

    // 转换异常示例
    jsonString = ##"null"##
    jsonValue = JsonValue.fromStr(jsonString)
    try {
        jsonFloat = jsonValue.asFloat()
    } catch (e: Exception) {
        println("转换异常: ${e.message}")
    }
}

运行结果:

JsonValue转换为JsonFloat: 3.141590
JsonFloat的值: 3.141590
转换异常: Fail to convert to JsonFloat

func asInt()

public func asInt(): JsonInt

功能:将 JsonValue 转换为 JsonInt 格式。

返回值:

异常:

示例:

import stdx.encoding.json.*

main() {
    var jsonString = ##"42"##
    var jsonValue: JsonValue = JsonValue.fromStr(jsonString)

    var jsonInt = jsonValue.asInt()

    println("JsonValue转换为JsonInt: ${jsonInt}")
    println("JsonInt的值: ${jsonInt.getValue()}")

    // 转换异常示例
    jsonString = ##"123.12"##
    jsonValue = JsonValue.fromStr(jsonString)
    try {
        jsonInt = jsonValue.asInt()
    } catch (e: Exception) {
        println("转换异常: ${e.message}")
    }
}

运行结果:

JsonValue转换为JsonInt: 42
JsonInt的值: 42
转换异常: Fail to convert to JsonInt

func asNull()

public func asNull(): JsonNull

功能:将 JsonValue 转换为 JsonNull 格式。

返回值:

异常:

示例:

import stdx.encoding.json.*

main() {
    var jsonString = ##"null"##
    var jsonValue: JsonValue = JsonValue.fromStr(jsonString)

    var jsonNull = jsonValue.asNull()

    println("JsonValue转换为JsonNull: ${jsonNull}")
}

运行结果:

JsonValue转换为JsonNull: null

func asObject()

public func asObject(): JsonObject

功能:将 JsonValue 转换为 JsonObject 格式。

返回值:

异常:

示例:

import stdx.encoding.json.*

main() {
    var jsonString = ##"{"name": "张三", "age": 25, "student": true}"##
    var jsonValue: JsonValue = JsonValue.fromStr(jsonString)

    var jsonObject = jsonValue.asObject()

    println("JsonValue转换为JsonObject: ${jsonObject}")
    println("JsonObject的大小: ${jsonObject.size()}")

    // 转换异常示例
    jsonString = ##"[1, 2, 3, "hello"]"##
    jsonValue = JsonValue.fromStr(jsonString)
    try {
        jsonObject = jsonValue.asObject()
    } catch (e: Exception) {
        println("转换异常: ${e.message}")
    }
}

运行结果:

JsonValue转换为JsonObject: {"name":"张三","age":25,"student":true}
JsonObject的大小: 3
转换异常: Fail to convert to JsonObject

func asString()

public func asString(): JsonString

功能:将 JsonValue 转换为 JsonString 格式。

返回值:

异常:

示例:

import stdx.encoding.json.*

main() {
    var jsonString = ##""Hello, 世界""##
    var jsonValue: JsonValue = JsonValue.fromStr(jsonString)

    var jsonStr = jsonValue.asString()

    println("JsonValue转换为JsonString: ${jsonStr}")
    println("JsonString的值: ${jsonStr.getValue()}")

    // 转换异常示例
    jsonString = ##"{"name": "张三", "age": 25, "student": true}"##
    jsonValue = JsonValue.fromStr(jsonString)
    try {
        jsonStr = jsonValue.asString()
    } catch (e: Exception) {
        println("转换异常: ${e.message}")
    }
}

运行结果:

JsonValue转换为JsonString: "Hello, 世界"
JsonString的值: Hello, 世界
转换异常: Fail to convert to JsonString

func kind()

public func kind(): JsonKind

功能:返回当前 JsonValue 所属的 JsonKind 类型。

返回值:

示例:

import stdx.encoding.json.*

main() {
    var jsonString = ##"{"name": "张三", "age": 25}"##
    var jsonValue: JsonValue = JsonValue.fromStr(jsonString)

    var kind = jsonValue.kind()

    // 使用 match 语句处理类型
    match (kind) {
        case JsonKind.JsArray => println("JsonValue的类型是JsArray")
        case JsonKind.JsString => println("JsonValue的类型是JsString")
        case JsonKind.JsInt => println("JsonValue的类型是JsInt")
        case JsonKind.JsObject => println("JsonValue的类型是JsObject")
        case JsonKind.JsFloat => println("JsonValue的类型是JsFloat")
        case JsonKind.JsBool => println("JsonValue的类型是JsBool")
        case JsonKind.JsNull => println("JsonValue的类型是JsNull")
    }
}

运行结果:

JsonValue的类型是JsObject

func toJsonString()

public func toJsonString(): String

功能:将 JsonValue 转换为 JSON 格式的 (带有空格换行符) 字符串。

返回值:

  • String - 转换后的 JSON 格式字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonString = ##"{"name": "张三", "age": 25, "hobbies": ["读书", "游泳"]}"##
    var jsonValue: JsonValue = JsonValue.fromStr(jsonString)

    var jsonStr = jsonValue.toJsonString()

    println("JsonValue转换为JSON字符串:\n${jsonStr}")
}

运行结果:

JsonValue转换为JSON字符串:
{
  "name": "张三",
  "age": 25,
  "hobbies": [
    "读书",
    "游泳"
  ]
}

func toJsonStringWithoutEscaping()

public func toJsonStringWithoutEscaping(): String

功能:将 JsonValue 转换为 JSON 格式的 (带有空格换行符) 字符串,不对 html 特殊字符 & 转义。

返回值:

  • String - 转换后的 JSON 格式字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonString = ##"{"description": "Hello & World <测试>"}"##
    var jsonValue: JsonValue = JsonValue.fromStr(jsonString)

    var jsonStr = jsonValue.toJsonStringWithoutEscaping()
    var normalJsonStr = jsonValue.toJsonString() // 对比正常方法

    println("不转义HTML特殊字符的JSON字符串:\n${jsonStr}")
    println("正常转义的JSON字符串:\n${normalJsonStr}")
}

运行结果:

不转义HTML特殊字符的JSON字符串:
{
  "description": "Hello & World <测试>"
}
正常转义的JSON字符串:
{
  "description": "Hello \u0026 World <测试>"
}

func toString()

public func toString(): String

功能:将 JsonValue 转换为字符串。

返回值:

  • String - 转换后的字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonString = ##"{"name": "张三", "age": 25}"##
    var jsonValue: JsonValue = JsonValue.fromStr(jsonString)

    var str = jsonValue.toString()

    println("JsonValue转换为字符串: ${str}")
}

运行结果:

JsonValue转换为字符串: {"name":"张三","age":25}

func toStringWithoutEscaping()

public func toStringWithoutEscaping(): String

功能:将 JsonValue 转换为字符串,不对 html 特殊字符 & 转义。

返回值:

  • String - 转换后的字符串。

示例:

import stdx.encoding.json.*

main() {
    var jsonString = ##"{"description": "Hello & World <测试>"}"##
    var jsonValue: JsonValue = JsonValue.fromStr(jsonString)

    var str = jsonValue.toStringWithoutEscaping()
    var normalStr = jsonValue.toString() // 对比正常方法

    println("不转义HTML特殊字符的字符串: ${str}")
    println("正常转义的字符串: ${normalStr}")
}

运行结果:

不转义HTML特殊字符的字符串: {"description":"Hello & World <测试>"}
正常转义的字符串: {"description":"Hello \u0026 World <测试>"}

枚举

enum JsonKind

public enum JsonKind {
    | JsNull
    | JsBool
    | JsInt
    | JsFloat
    | JsString
    | JsArray
    | JsObject
}

功能:表示 JsonValue 的具体类型。

JsArray

JsArray

功能:表示 JSON 类型中的数组类型。

JsBool

JsBool

功能:表示 true 或者 false 类型。

JsFloat

JsFloat

功能:表示值为浮点数的 number 类型。

JsInt

JsInt

功能:表示值为整数的 number 类型。

JsNull

JsNull

功能:表示 null 类型。

JsObject

JsObject

功能:表示 JSON 类型中的对象类型。

JsString

JsString

功能:表示 string 类型。

异常类

class JsonException

public class JsonException <: Exception {
    public init()
    public init(message: String)
}

功能:JSON 包的异常类,用于 JsonValue 类型使用时出现异常的场景。

父类型:

  • Exception

init()

public init()

功能:构造一个不包含任何异常提示信息的 JsonException 实例。

示例:

import stdx.encoding.json.*

main() {
    // 创建不带消息的JsonException
    try {
        throw JsonException()
    } catch (e: JsonException) {
        println("捕获到 JsonException: ${e.message}")
    }
}

运行结果:

捕获到 JsonException: 

init(String)

public init(message: String)

功能:根据指定的异常提示信息构造 JsonException 实例。

参数:

  • message: String - 指定的异常提示信息。

示例:

import stdx.encoding.json.*

main() {
    // 创建带消息的JsonException
    try {
        throw JsonException("JSON解析异常")
    } catch (e: JsonException) {
        println("捕获到 JsonException: ${e.message}")
    }
}

运行结果:

捕获到 JsonException: JSON解析异常

JsonArray 使用示例

下面是 JsonArray 使用示例。该示例构造了一个 JsonArray 对象,并向其中添加了一些 JsonValue,最后以两种格式打印了该 JsonArray 对象。

示例:

import stdx.encoding.json.*
import std.collection.*

main() {
    var a: JsonValue = JsonNull()
    var b: JsonValue = JsonBool(true)
    var c: JsonValue = JsonBool(false)
    var d: JsonValue = JsonInt(7363)
    var e: JsonValue = JsonFloat(736423.546)
    var list: ArrayList<JsonValue> = ArrayList<JsonValue>()
    var list2: ArrayList<JsonValue> = ArrayList<JsonValue>()
    var map = JsonObject()
    var map1 = JsonObject()
    map1.put("a", JsonString("jjjjjj"))
    map1.put("b", b)
    map1.put("c", JsonString("hhhhh"))
    list2.add(b)
    list2.add(JsonInt(3333333))
    list2.add(map1)
    list2.add(JsonString("sdfghgfasd"))
    list.add(b)
    list.add(a)
    list.add(map)
    list.add(c)
    list.add(JsonArray(list2))
    list.add(d)
    list.add(JsonString("ddddddd"))
    list.add(e)
    var result: JsonValue = JsonArray(list)
    println("func toString result is:")
    println(result.toString())
    println("func toJsonString result is:")
    println(result.toJsonString())
}

运行结果:

func toString result is:
[true,null,{},false,[true,3333333,{"a":"jjjjjj","b":true,"c":"hhhhh"},"sdfghgfasd"],7363,"ddddddd",736423.546]
func toJsonString result is:
[
  true,
  null,
  {},
  false,
  [
    true,
    3333333,
    {
      "a": "jjjjjj",
      "b": true,
      "c": "hhhhh"
    },
    "sdfghgfasd"
  ],
  7363,
  "ddddddd",
  736423.546
]

JsonValue 和 String 互相转换

下面是 JsonValue 和 String 互相转换的示例。该示例使用 JsonValue.fromStr 将一个 JSON 字符串转换为 JsonValue,随后以两种格式打印了该 JsonValue 对象。

示例:

import stdx.encoding.json.*

main() {
    var str = ##"[true,"kjjjke\"eed",{"sdfd":"ggggg","eeeee":[341,false,{"nnnn":55.87}]},3422,22.341,false,[22,22.22,true,"ddd"],43]"##
    var jv: JsonValue = JsonValue.fromStr(str)
    var res = jv.toString()
    var prettyres = jv.toJsonString()
    println(res)
    println(prettyres)
}

运行结果:

[true,"kjjjke\"eed",{"sdfd":"ggggg","eeeee":[341,false,{"nnnn":55.87}]},3422,22.341,false,[22,22.22,true,"ddd"],43]
[
  true,
  "kjjjke\"eed",
  {
    "sdfd": "ggggg",
    "eeeee": [
      341,
      false,
      {
        "nnnn": 55.87
      }
    ]
  },
  3422,
  22.341,
  false,
  [
    22,
    22.22,
    true,
    "ddd"
  ],
  43
]

JsonValue 与 DataModel 的转换

下面是 JSON 字符串与自定义类型间的转换的示例。该用例为 Person 类型实现了 Serializable 接口,随后进行了从 JSON 字符串到自定义类型的转换和从自定义类型到 JSON 字符串的转换。

示例:

import stdx.serialization.serialization.*
import stdx.encoding.json.*

class Person <: Serializable<Person> {
    var name: String = ""
    var age: Int64 = 0
    var loc: Option<Location> = Option<Location>.None

    public func serialize(): DataModel {
        return DataModelStruct()
            .add(field<String>("name", name))
            .add(field<Int64>("age", age))
            .add(field<Option<Location>>("loc", loc))
    }

    public static func deserialize(dm: DataModel): Person {
        var dms = match (dm) {
            case data: DataModelStruct => data
            case _ => throw Exception("this data is not DataModelStruct")
        }
        var result = Person()
        result.name = String.deserialize(dms.get("name"))
        result.age = Int64.deserialize(dms.get("age"))
        result.loc = Option<Location>.deserialize(dms.get("loc"))
        return result
    }
}

class Location <: Serializable<Location> {
    var country: String = ""
    var province: String = ""

    public func serialize(): DataModel {
        return DataModelStruct().add(field<String>("country", country)).add(field<String>("province", province))
    }

    public static func deserialize(dm: DataModel): Location {
        var dms = match (dm) {
            case data: DataModelStruct => data
            case _ => throw Exception("this data is not DataModelStruct")
        }
        var result = Location()
        result.country = String.deserialize(dms.get("country"))
        result.province = String.deserialize(dms.get("province"))
        return result
    }
}

main() {
    var js = ##"{
    "name": "A",
    "age": 30,
    "loc": {
        "country": "China",
        "province": "Beijing"
    }
}"##

    // 实现从 JSON 字符串到自定义类型的转换
    var jv = JsonValue.fromStr(js)
    var dm = DataModel.fromJson(jv)
    var A = Person.deserialize(dm)
    println("name == ${A.name}")
    println("age == ${A.age}")
    println("country == ${A.loc.getOrThrow().country}")
    println("province == ${A.loc.getOrThrow().province}")
    println("====================")

    // 实现从自定义类型到 JSON 字符串的转换
    dm = A.serialize()
    var jo = dm.toJson().asObject()
    println(jo.toJsonString())
}

运行结果:

name == A
age == 30
country == China
province == Beijing
====================
{
  "name": "A",
  "age": 30,
  "loc": {
    "country": "China",
    "province": "Beijing"
  }
}

stdx.encoding.json.stream

功能介绍

json.stream 包主要用于仓颉对象和 JSON 数据流之间的互相转换。

本包提供了 JsonWriter 和 JsonReader 类,JsonWriter 用于提供仓颉对象转 JSON 数据流的序列化能力;JsonReader 用于提供 JSON 数据流转仓颉对象的反序列化能力。

当前实现中支持和 JSON 数据流互转的类型有:

  • 基础数据类型:String、Int8、Int16、Int32、Int64、Float16、Float32、Float64、UInt8、UInt16、UInt32、UInt64。

  • 集合类型:Array<T>、ArrayList<T>、HashMap<String, T>、HashSet<T>、LinkedList<T>、ArrayQueue<T>、ArrayDeque<T>、ArrayStack<T>、TreeSet<T>、TreeMap<String, T>、ConcurrentHashMap<String, T>。

  • 其它类型:Option<T>、BigInt、Decimal。

API 列表

接口

接口名功能
JsonDeserializable<T>此接口用于实现从 JsonReader 中读取一个仓颉对象。
JsonSerializable为类型提供序列化到 JSON 数据流的接口。

类名功能
JsonReader此类提供 JSON 数据流转仓颉对象的反序列化能力。
JsonWriter构造函数,构造一个将数据写入 out 的实例。

枚举

枚举名功能
JsonToken表示 JSON 编码的字符串中的结构、名称或者值类型。

结构体

结构体名功能
WriteConfig用于表示 JsonWriter 的序列化格式配置。

接口

interface JsonDeserializable<T>

public interface JsonDeserializable<T> {
    static func fromJson(r: JsonReader): T
}

功能:此接口用于实现从 JsonReader 中读取一个仓颉对象。

支持的对象类型包括:

  • 基本数据类型:整数类型、浮点类型、布尔类型、字符串类型。

  • Collection 类型:Array、ArrayList、HashMap、Option。

  • BigInt、Decimal 类型。

  • DateTime 类型。

static func fromJson(JsonReader)

static func fromJson(r: JsonReader): T

功能:从参数 r 指定的 JsonReader 实例中读取一个 T 类型对象。

参数:

返回值:

  • T - T 类型的实例。

异常:

  • IllegalStateException - 如果输入流的 JSON 数据不符合格式,抛出异常。

extend BigInt <: JsonDeserializable<BigInt>

extend BigInt <: JsonDeserializable<BigInt>

功能:为 BigInt 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): BigInt

功能:从 JsonReader 中读取一个 BigInt。

参数:

返回值:

  • BigInt - BigInt 类型的实例。

示例:

import std.io.*
import std.math.numeric.*
import stdx.encoding.json.stream.*

main() {
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个BigInt值作为示例数据 
    let originalBigInt: BigInt = BigInt(1234567890123456789)
    originalBigInt.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取BigInt对象 
    let bigIntValue: BigInt = BigInt.fromJson(reader)

    println("BigInt反序列化结果: ${bigIntValue}")
}

运行结果:

BigInt反序列化结果: 1234567890123456789

extend Bool <: JsonDeserializable<Bool>

extend Bool <: JsonDeserializable<Bool>

功能:为 Bool 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): Bool

功能:从 JsonReader 中读取一个 Bool。

参数:

返回值:

  • Bool - Bool 类型的实例。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个Bool值作为示例数据 
    let originalBool: Bool = true
    originalBool.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取Bool对象 
    let boolValue: Bool = Bool.fromJson(reader)

    println("Bool反序列化结果: ${boolValue}")
}

运行结果:

Bool反序列化结果: true

extend DateTime <: JsonDeserializable<DateTime>

extend DateTime <: JsonDeserializable<DateTime>

功能:为 DateTime 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): DateTime

功能:从 JsonReader 中读取一个 DateTime 实例。

该函数将会把读取到的字符串按照 RFC3339 的规范解析,可包含小数秒格式,函数的行为参考 DateTime 的 func parse(String)。

参数:

返回值:

  • DateTime - DateTime 类型的实例。

异常:

  • TimeParseException - 无法正常解析时,抛出异常。

示例:

import std.io.*
import std.time.*
import stdx.encoding.json.stream.*

main() {
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个DateTime值作为示例数据 
    let originalDateTime: DateTime = DateTime.of(year: 2026, month: 1, dayOfMonth: 7)
    originalDateTime.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取DateTime对象 
    let dateTimeValue: DateTime = DateTime.fromJson(reader)

    println("DateTime反序列化结果: ${dateTimeValue}")
}

可能的运行结果:

DateTime反序列化结果: 2026-01-07T00:00:00+08:00

extend Decimal <: JsonDeserializable<Decimal>

extend Decimal <: JsonDeserializable<Decimal>

功能:为 Decimal 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): Decimal

功能:从 JsonReader 中读取一个 Decimal。

参数:

返回值:

  • Decimal - Decimal 类型的实例。

示例:

import std.io.*
import std.math.numeric.*
import stdx.encoding.json.stream.*

main() {
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个Decimal值作为示例数据 
    let originalDecimal: Decimal = Decimal.parse("123.456")
    originalDecimal.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取Decimal对象 
    let decimalValue: Decimal = Decimal.fromJson(reader)

    println("Decimal反序列化结果: ${decimalValue}")
}

运行结果:

Decimal反序列化结果: 123.456

extend Float16 <: JsonDeserializable<Float16>

extend Float16 <: JsonDeserializable<Float16>

功能:为 Float16 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): Float16

功能:从 JsonReader 中读取一个 Float16。

参数:

返回值:

  • Float16 - Float16 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个Float16值作为示例数据 
    let originalFloat16: Float16 = 123.45f16
    originalFloat16.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取Float16对象 
    let floatValue: Float16 = Float16.fromJson(reader)

    println("Float16反序列化结果: ${floatValue}")
}

运行结果:

Float16反序列化结果: 123.437500

extend Float32 <: JsonDeserializable<Float32>

extend Float32 <: JsonDeserializable<Float32>

功能:为 Float32 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): Float32

功能:从 JsonReader 中读取一个 Float32。

参数:

返回值:

  • Float32 - Float32 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个Float32值作为示例数据 
    let originalFloat32: Float32 = 123.45f32
    originalFloat32.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取Float32对象 
    let floatValue: Float32 = Float32.fromJson(reader)

    println("Float32反序列化结果: ${floatValue}")
}

运行结果:

Float32反序列化结果: 123.449997

extend Float64 <: JsonDeserializable<Float64>

extend Float64 <: JsonDeserializable<Float64>

功能:为 Float64 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): Float64

功能:从 JsonReader 中读取一个 Float64。

参数:

返回值:

  • Float64 - Float64 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个Float64值作为示例数据 
    let originalFloat64: Float64 = 123.45f64
    originalFloat64.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取Float64对象 
    let floatValue: Float64 = Float64.fromJson(reader)

    println("Float64反序列化结果: ${floatValue}")
}

运行结果:

Float64反序列化结果: 123.450000

extend Int16 <: JsonDeserializable<Int16>

extend Int16 <: JsonDeserializable<Int16>

功能:为 Int16 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): Int16

功能:从 JsonReader 中读取一个 Int16。

参数:

返回值:

  • Int16 - Int16 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个Int16值作为示例数据 
    let originalInt16: Int16 = 12345
    originalInt16.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取Int16对象 
    let intValue: Int16 = Int16.fromJson(reader)

    println("Int16反序列化结果: ${intValue}")
}

运行结果:

Int16反序列化结果: 12345

extend Int32 <: JsonDeserializable<Int32>

extend Int32 <: JsonDeserializable<Int32>

功能:为 Int32 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): Int32

功能:从 JsonReader 中读取一个 Int32。

参数:

返回值:

  • Int32 - Int32 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个Int32值作为示例数据 
    let originalInt32: Int32 = 1234567890
    originalInt32.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取Int32对象 
    let intValue: Int32 = Int32.fromJson(reader)

    println("Int32反序列化结果: ${intValue}")
}

运行结果:

Int32反序列化结果: 1234567890

extend Int64 <: JsonDeserializable<Int64>

extend Int64 <: JsonDeserializable<Int64>

功能:为 Int64 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): Int64

功能:从 JsonReader 中读取一个 Int64。

参数:

返回值:

  • Int64 - Int64 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个Int64值作为示例数据 
    let originalInt64: Int64 = 1234567890123456789
    originalInt64.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取Int64对象 
    let intValue: Int64 = Int64.fromJson(reader)

    println("Int64反序列化结果: ${intValue}")
}

运行结果:

Int64反序列化结果: 1234567890123456789

extend Int8 <: JsonDeserializable<Int8>

extend Int8 <: JsonDeserializable<Int8>

功能:为 Int8 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): Int8

功能:从 JsonReader 中读取一个 Int8。

参数:

返回值:

  • Int8 - Int8 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个Int8值作为示例数据 
    let originalInt8: Int8 = 123
    originalInt8.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取Int8对象 
    let intValue: Int8 = Int8.fromJson(reader)

    println("Int8反序列化结果: ${intValue}")
}

运行结果:

Int8反序列化结果: 123

extend IntNative <: JsonDeserializable<IntNative>

extend IntNative <: JsonDeserializable<IntNative>

功能:为 IntNative 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): IntNative

功能:从 JsonReader 中读取一个 IntNative。

参数:

返回值:

  • IntNative - IntNative 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个IntNative值作为示例数据 
    let originalIntNative: IntNative = 123456789
    originalIntNative.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取IntNative对象 
    let intValue: IntNative = IntNative.fromJson(reader)

    println("IntNative反序列化结果: ${intValue}")
}

运行结果:

IntNative反序列化结果: 123456789

extend String <: JsonDeserializable<String>

extend String <: JsonDeserializable<String>

功能:为 String 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): String

功能:从 JsonReader 中读取一个 String。

根据下一个 JsonToken 的不同,String 的反序列化结果将会不同:

  • 当下一个 JsonTokenJsonString 时, 反序列化过程会按照标准ECMA-404 The JSON Data Interchange Standard对读到的 String 进行转义。
  • 当下一个 JsonTokenJsonNumber JsonBool JsonNull 其中一个时,将会读取下一个 value 字段的原始字符串并返回。
  • 当下一个 JsonToken 是其它类型时,调用此接口会抛异常。

参数:

返回值:

  • String - String 类型的实例。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个String值作为示例数据 
    let originalString: String = "Hello, World!"
    originalString.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取String对象 
    let stringValue: String = String.fromJson(reader)

    println("String反序列化结果: ${stringValue}")
}

运行结果:

String反序列化结果: Hello, World!

extend UInt16 <: JsonDeserializable<UInt16>

extend UInt16 <: JsonDeserializable<UInt16>

功能:为 UInt16 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): UInt16

功能:从 JsonReader 中读取一个 UInt16。

参数:

返回值:

  • UInt16 - UInt16 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个UInt16值作为示例数据 
    let originalUInt16: UInt16 = 65432
    originalUInt16.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取UInt16对象 
    let uintValue: UInt16 = UInt16.fromJson(reader)

    println("UInt16反序列化结果: ${uintValue}")
}

运行结果:

UInt16反序列化结果: 65432

extend UInt32 <: JsonDeserializable<UInt32>

extend UInt32 <: JsonDeserializable<UInt32>

功能:为 UInt32 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): UInt32

功能:从 JsonReader 中读取一个 UInt32。

参数:

返回值:

  • UInt32 - UInt32 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个UInt32值作为示例数据 
    let originalUInt32: UInt32 = 3214567890
    originalUInt32.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取UInt32对象 
    let uintValue: UInt32 = UInt32.fromJson(reader)

    println("UInt32反序列化结果: ${uintValue}")
}

运行结果:

UInt32反序列化结果: 3214567890

extend UInt64 <: JsonDeserializable<UInt64 >

extend UInt64 <: JsonDeserializable<UInt64>

功能:为 UInt64 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): UInt64

功能:从 JsonReader 中读取一个 UInt64。

参数:

返回值:

  • UInt64 - UInt64 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个UInt64值作为示例数据 
    let originalUInt64: UInt64 = 1234567890123456789
    originalUInt64.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取UInt64对象 
    let uintValue: UInt64 = UInt64.fromJson(reader)

    println("UInt64反序列化结果: ${uintValue}")
}

运行结果:

UInt64反序列化结果: 1234567890123456789

extend UInt8 <: JsonDeserializable<UInt8>

extend UInt8 <: JsonDeserializable<UInt8>

功能:为 UInt8 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): UInt8

功能:从 JsonReader 中读取一个 UInt8。

参数:

返回值:

  • UInt8 - UInt8 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个UInt8值作为示例数据 
    let originalUInt8: UInt8 = 255
    originalUInt8.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取UInt8对象 
    let uintValue: UInt8 = UInt8.fromJson(reader)

    println("UInt8反序列化结果: ${uintValue}")
}

运行结果:

UInt8反序列化结果: 255

extend UIntNative <: JsonDeserializable<UIntNative>

extend UIntNative <: JsonDeserializable<UIntNative>

功能:为 UIntNative 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): UIntNative

功能:从 JsonReader 中读取一个 UIntNative。

参数:

返回值:

  • UIntNative - UIntNative 类型的实例。

异常:

  • OverflowException - 读取的数据超过范围时,抛出异常。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个UIntNative值作为示例数据 
    let originalUIntNative: UIntNative = 987654321
    originalUIntNative.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取UIntNative对象 
    let uintValue: UIntNative = UIntNative.fromJson(reader)

    println("UIntNative反序列化结果: ${uintValue}")
}

运行结果:

UIntNative反序列化结果: 987654321

extend<T> Array<T> <: JsonDeserializable<Array<T>> where T <: JsonDeserializable<T>

extend<T> Array<T> <: JsonDeserializable<Array<T>> where T <: JsonDeserializable<T>

功能:为 Array<T> 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): Array<T>

功能:从 JsonReader 中读取一个 Array。

参数:

返回值:

  • Array<T> - Array 类型的实例。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonReader 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个Array值作为示例数据 
    let originalArray: Array<Int64> = [1, 2, 3, 4, 5]
    originalArray.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取Array对象 
    let arrayValue: Array<Int64> = Array.fromJson(reader)

    println("Array反序列化结果: ${arrayValue}")
}

运行结果:

Array反序列化结果: [1, 2, 3, 4, 5]

extend<T> ArrayDeque<T> <: JsonDeserializable<ArrayDeque<T>> where T <: JsonDeserializable<T>

extend<T> ArrayDeque<T> <: JsonDeserializable<ArrayDeque<T>> where T <: JsonDeserializable<T>

功能:为 ArrayDeque 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): ArrayDeque<T>

功能:从 JsonReader 中读取一个 ArrayDeque。

参数:

返回值:

  • ArrayDeque<T> - ArrayDeque 类型的实例。

示例:

import std.io.*
import std.collection.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonReader 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个ArrayDeque值作为示例数据 
    let originalArrayDeque: ArrayDeque<Int64> = ArrayDeque<Int64>()
    originalArrayDeque.addFirst(1)
    originalArrayDeque.addFirst(2)
    originalArrayDeque.addFirst(3)
    originalArrayDeque.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取ArrayDeque对象 
    let arrayDequeValue: ArrayDeque<Int64> = ArrayDeque.fromJson(reader)

    println("ArrayDeque反序列化结果: ${arrayDequeValue}")
}

运行结果:

ArrayDeque反序列化结果: [3, 2, 1]

extend<T> ArrayList<T> <: JsonDeserializable<ArrayList<T>> where T <: JsonDeserializable<T>

extend<T> ArrayList<T> <: JsonDeserializable<ArrayList<T>> where T <: JsonDeserializable<T>

功能:为 ArrayList 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): ArrayList<T>

功能:从 JsonReader 中读取一个 ArrayList。

参数:

返回值:

  • ArrayList <T> - ArrayList 类型的实例。

示例:

import std.io.*
import std.collection.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonReader 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个ArrayList值作为示例数据 
    let originalArrayList: ArrayList<Int64> = ArrayList<Int64>([10, 20, 30])
    originalArrayList.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取ArrayList对象 
    let arrayListValue: ArrayList<Int64> = ArrayList.fromJson(reader)

    println("ArrayList反序列化结果: ${arrayListValue}")
}

运行结果:

ArrayList反序列化结果: [10, 20, 30]

extend<T> ArrayQueue<T> <: JsonDeserializable<ArrayQueue<T>> where T <: JsonDeserializable<T>

extend<T> ArrayQueue<T> <: JsonDeserializable<ArrayQueue<T>> where T <: JsonDeserializable<T>

功能:为 ArrayQueue 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): ArrayQueue<T>

功能:从 JsonReader 中读取一个 ArrayQueue。

参数:

返回值:

  • ArrayQueue<T> - ArrayQueue 类型的实例。

示例:

import std.io.*
import std.collection.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonReader 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个ArrayQueue值作为示例数据 
    let originalArrayQueue: ArrayQueue<Int64> = ArrayQueue<Int64>()
    originalArrayQueue.add(10)
    originalArrayQueue.add(20)
    originalArrayQueue.add(30)
    originalArrayQueue.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取ArrayQueue对象 
    let arrayQueueValue: ArrayQueue<Int64> = ArrayQueue.fromJson(reader)

    println("ArrayQueue反序列化结果: ${arrayQueueValue}")
}

运行结果:

ArrayQueue反序列化结果: [10, 20, 30]

extend<T> ArrayStack<T> <: JsonDeserializable<ArrayStack<T>> where T <: JsonDeserializable<T>

extend<T> ArrayStack<T> <: JsonDeserializable<ArrayStack<T>> where T <: JsonDeserializable<T>

功能:为 ArrayStack 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): ArrayStack<T>

功能:从 JsonReader 中读取一个 ArrayStack。

参数:

返回值:

  • ArrayStack<T> - ArrayStack 类型的实例。

示例:

import std.io.*
import std.collection.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonReader 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个ArrayStack值作为示例数据 
    let originalArrayStack: ArrayStack<Int64> = ArrayStack<Int64>()
    originalArrayStack.add(10)
    originalArrayStack.add(20)
    originalArrayStack.add(30)
    originalArrayStack.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取ArrayStack对象 
    let arrayStackValue: ArrayStack<Int64> = ArrayStack.fromJson(reader)

    println("ArrayStack反序列化结果: ${arrayStackValue}")
}

运行结果:

ArrayStack反序列化结果: [30, 20, 10]

extend<T> ConcurrentHashMap<String, T> <: JsonDeserializable<ConcurrentHashMap<String, T>> where T <: JsonDeserializable<T>

extend<T> ConcurrentHashMap<String, T> <: JsonDeserializable<ConcurrentHashMap<String, T>> where T <: JsonDeserializable<T>

功能:为 ConcurrentHashMap 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): ConcurrentHashMap<String, T>

功能:从 JsonReader 中读取一个 ConcurrentHashMap。

参数:

返回值:

  • ConcurrentHashMap<String, T> - ConcurrentHashMap<String, T> 类型的实例。

示例:

import std.io.*
import std.collection.concurrent.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonReader 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个ConcurrentHashMap值作为示例数据 
    let originalConcurrentHashMap: ConcurrentHashMap<String, Int64> = ConcurrentHashMap<String, Int64>()
    originalConcurrentHashMap.add("key1", 10)
    originalConcurrentHashMap.add("key2", 20)
    originalConcurrentHashMap.add("key3", 30)
    originalConcurrentHashMap.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取ConcurrentHashMap对象 
    let concurrentHashMapValue: ConcurrentHashMap<String, Int64> = ConcurrentHashMap.fromJson(reader)

    println("ConcurrentHashMap反序列化结果的大小: ${concurrentHashMapValue.size}")
}

运行结果:

ConcurrentHashMap反序列化结果的大小: 3

extend<T> HashMap<String, T> <: JsonDeserializable<HashMap<String, T>> where T <: JsonDeserializable<T>

extend<T> HashMap<String, T> <: JsonDeserializable<HashMap<String, T>> where T <: JsonDeserializable<T>

功能:为 HashMap 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): HashMap<String, T>

功能:从 JsonReader 中读取一个 HashMap。

参数:

返回值:

  • HashMap<String, T> - HashMap<String, T> 类型的实例。

示例:

import std.io.*
import std.collection.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonReader 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个HashMap值作为示例数据 
    let originalHashMap: HashMap<String, Int64> = HashMap<String, Int64>()
    originalHashMap.add("first", 10)
    originalHashMap.add("second", 20)
    originalHashMap.add("third", 30)
    originalHashMap.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取HashMap对象 
    let hashMapValue: HashMap<String, Int64> = HashMap.fromJson(reader)

    println("HashMap反序列化结果: ${hashMapValue}")
}

运行结果:

HashMap反序列化结果: [(first, 10), (second, 20), (third, 30)]

extend<T> HashSet<T> <: JsonDeserializable<HashSet<T>> where T <: JsonDeserializable<T>

extend<T> HashSet<T> <: JsonDeserializable<HashSet<T>> where T <: JsonDeserializable<T>

功能:为 HashSet 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): HashSet<T>

功能:从 JsonReader 中读取一个 HashSet。

参数:

返回值:

  • HashSet<T> - HashSet 类型的实例。

示例:

import std.io.*
import std.collection.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonReader 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个HashSet值作为示例数据 
    let originalHashSet: HashSet<Int64> = HashSet<Int64>([10, 20, 30])
    originalHashSet.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取HashSet对象 
    let hashSetValue: HashSet<Int64> = HashSet.fromJson(reader)

    println("HashSet反序列化结果: ${hashSetValue}")
}

运行结果:

HashSet反序列化结果: [10, 20, 30]

extend<T> LinkedList<T> <: JsonDeserializable<LinkedList<T>> where T <: JsonDeserializable<T>

extend<T> LinkedList<T> <: JsonDeserializable<LinkedList<T>> where T <: JsonDeserializable<T>

功能:为 LinkedList 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): LinkedList<T>

功能:从 JsonReader 中读取一个 LinkedList。

参数:

返回值:

  • LinkedList<T> - LinkedList 类型的实例。

示例:

import std.io.*
import std.collection.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonReader 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个LinkedList值作为示例数据 
    let originalLinkedList: LinkedList<Int64> = LinkedList<Int64>([50, 60, 70])
    originalLinkedList.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取LinkedList对象 
    let linkedListValue: LinkedList<Int64> = LinkedList.fromJson(reader)

    println("LinkedList反序列化结果: ${linkedListValue}")
}

运行结果:

LinkedList反序列化结果: [50, 60, 70]

extend<T> Option <T> <: JsonDeserializable<Option<T>> where T <: JsonDeserializable<T>

extend<T> Option<T> <: JsonDeserializable<Option<T>> where T <: JsonDeserializable<T>

功能:为 Option 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): Option<T>

功能:从 JsonReader 中读取一个 Option。

参数:

返回值:

  • Option<T> - Option 类型的实例。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonReader 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个Option值作为示例数据 
    let originalOption: Option<Int32> = Some(99)
    originalOption.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取Option对象 
    let optionValue: Option<Int32> = Option.fromJson(reader)

    println("Option反序列化结果: ${optionValue}")
}

运行结果:

Option反序列化结果: Some(99)

extend<T> TreeMap<String, T> <: JsonDeserializable<TreeMap<String, T>> where T <: JsonDeserializable<T>

extend<T> TreeMap<String, T> <: JsonDeserializable<TreeMap<String, T>> where T <: JsonDeserializable<T>

功能:为 TreeMap 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): TreeMap<String, T>

功能:从 JsonReader 中读取一个 TreeMap。

参数:

返回值:

  • TreeMap<String, T> - TreeMap<String, T> 类型的实例。

示例:

import std.io.*
import std.collection.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonReader 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个TreeMap值作为示例数据 
    let originalTreeMap: TreeMap<String, Int64> = TreeMap<String, Int64>()
    originalTreeMap.add("first", 10)
    originalTreeMap.add("second", 20)
    originalTreeMap.add("third", 30)
    originalTreeMap.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取TreeMap对象 
    let treeMapValue: TreeMap<String, Int64> = TreeMap.fromJson(reader)

    println("TreeMap反序列化结果: ${treeMapValue}")
}

运行结果:

TreeMap反序列化结果: [(first, 10), (second, 20), (third, 30)]

extend<T> TreeSet<T> <: JsonDeserializable<TreeSet<T>> where T <: JsonDeserializable<T>

extend<T> TreeSet<T> <: JsonDeserializable<TreeSet<T>> where T <: JsonDeserializable<T>

功能:为 TreeSet 类型实现 JsonDeserializable 接口。

父类型:

static func fromJson(JsonReader)

public static func fromJson(r: JsonReader): TreeSet<T>

功能:从 JsonReader 中读取一个 TreeSet。

参数:

返回值:

  • TreeSet<T> - TreeSet 类型的实例。

示例:

import std.io.*
import std.collection.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonReader 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 先写入一个TreeSet值作为示例数据 
    let originalTreeSet: TreeSet<Int64> = TreeSet<Int64>([10, 20, 30])
    originalTreeSet.toJson(writer)
    writer.flush()

    // 从ByteBuffer创建JsonReader 
    let reader = JsonReader(buffer)

    // 从JsonReader读取TreeSet对象 
    let treeSetValue: TreeSet<Int64> = TreeSet.fromJson(reader)

    println("TreeSet反序列化结果: ${treeSetValue}")
}

运行结果:

TreeSet反序列化结果: [10, 20, 30]

interface JsonSerializable

public interface JsonSerializable {
    func toJson(w: JsonWriter): Unit
}

功能:为类型提供序列化到 JSON 数据流的接口。

JsonWriter 搭配使用,JsonWriter 可以将实现了 JsonSerializable 接口的类型写入到 Stream 中。

func toJson(JsonWriter)

func toJson(w: JsonWriter): Unit

功能:将实现了 JsonSerializable 接口的类型写入参数 w 指定的 JsonWriter 实例中。

参数:

extend BigInt <: JsonSerializable

extend BigInt <: JsonSerializable

功能:为 BigInt 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 BigInt 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import std.math.numeric.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入BigInt对象 
    let bigIntValue: BigInt = BigInt(1234567890123456789)
    bigIntValue.toJson(writer)
    writer.flush()

    println("BigInt序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

BigInt序列化结果: 1234567890123456789

extend Bool <: JsonSerializable

extend Bool <: JsonSerializable

功能:为 Bool 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 Bool 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入Bool对象 
    let boolValue: Bool = true
    boolValue.toJson(writer)
    writer.flush()

    println("Bool序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

Bool序列化结果: true

extend DateTime <: JsonSerializable

extend DateTime <: JsonSerializable

功能:为 DateTime 类型实现 JsonSerializable 接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:提供 DateTime 类型序列化到流的功能。

该接口的功能与 JsonWriterwriteConfig中的属性 dateTimeFormat有关联,将会把 DateTime 按照dateTimeFormat中的格式输出到目标流中,可以通过修改dateTimeFormat实现不同的格式控制。

参数:

示例:

import std.io.*
import std.time.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入DateTime对象 
    let dateTimeValue = DateTime.of(year: 2026, month: 1, dayOfMonth: 7)
    dateTimeValue.toJson(writer)
    writer.flush()

    println("DateTime序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

可能的运行结果:

DateTime序列化结果: "2026-01-07T00:00:00+08:00"

extend Decimal <: JsonSerializable

extend Decimal <: JsonSerializable

功能:为 Decimal 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 Decimal 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import std.math.numeric.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入Decimal对象 
    let decimalValue: Decimal = Decimal(123.456)
    decimalValue.toJson(writer)
    writer.flush()

    println("Decimal序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

Decimal序列化结果: 123.4560000000000030695446184836328029632568359375

extend Float16 <: JsonSerializable

extend Float16 <: JsonSerializable

功能:为 Float16 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 Float16 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入Float16对象 
    let floatValue: Float16 = 123.45f16
    floatValue.toJson(writer)
    writer.flush()

    println("Float16序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

Float16序列化结果: 123.4375

extend Float32 <: JsonSerializable

extend Float32 <: JsonSerializable

功能:为 Float32 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 Float32 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入Float32对象 
    let floatValue: Float32 = 123.45f32
    floatValue.toJson(writer)
    writer.flush()

    println("Float32序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

Float32序列化结果: 123.449997

extend Float64 <: JsonSerializable

extend Float64 <: JsonSerializable

功能:为 Float64 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 Float64 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入Float64对象 
    let floatValue: Float64 = 123.456
    floatValue.toJson(writer)
    writer.flush()

    println("Float64序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

Float64序列化结果: 123.456

extend Int16 <: JsonSerializable

extend Int16 <: JsonSerializable

功能:为 Int16 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 Int16 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入Int16对象 
    let intValue: Int16 = 12345
    intValue.toJson(writer)
    writer.flush()

    println("Int16序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

Int16序列化结果: 12345

extend Int32 <: JsonSerializable

extend Int32 <: JsonSerializable

功能:为 Int32 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 Int32 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入Int32对象 
    let intValue: Int32 = 1234567
    intValue.toJson(writer)
    writer.flush()

    println("Int32序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

Int32序列化结果: 1234567

extend Int64 <: JsonSerializable

extend Int64 <: JsonSerializable

功能:为 Int64 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 Int64 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入Int64对象 
    let intValue: Int64 = 1234567890123
    intValue.toJson(writer)
    writer.flush()

    println("Int64序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

Int64序列化结果: 1234567890123

extend Int8 <: JsonSerializable

extend Int8 <: JsonSerializable

功能:为 Int8 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 Int8 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入Int8对象 
    let intValue: Int8 = 123
    intValue.toJson(writer)
    writer.flush()

    println("Int8序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

Int8序列化结果: 123

extend IntNative <: JsonSerializable

extend IntNative <: JsonSerializable

功能:为 IntNative 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 IntNative 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入IntNative对象 
    let intValue: IntNative = 987654
    intValue.toJson(writer)
    writer.flush()

    println("IntNative序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

IntNative序列化结果: 987654

extend String <: JsonSerializable

extend String <: JsonSerializable

功能:为 String 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 String 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入String对象 
    let strValue: String = "Hello, World!"
    strValue.toJson(writer)
    writer.flush()

    println("String序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

String序列化结果: "Hello, World!"

extend UInt16 <: JsonSerializable

extend UInt16 <: JsonSerializable

功能:为 UInt16 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 UInt16 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入UInt16对象 
    let uintValue: UInt16 = 45678
    uintValue.toJson(writer)
    writer.flush()

    println("UInt16序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

UInt16序列化结果: 45678

extend UInt32 <: JsonSerializable

extend UInt32 <: JsonSerializable

功能:为 UInt32 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 UInt32 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入UInt32对象 
    let uintValue: UInt32 = 3245678901
    uintValue.toJson(writer)
    writer.flush()

    println("UInt32序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

UInt32序列化结果: 3245678901

extend UInt64 <: JsonSerializable

extend UInt64 <: JsonSerializable

功能:为 UInt64 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 UInt64 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入UInt64对象 
    let uintValue: UInt64 = 12345678901234567890
    uintValue.toJson(writer)
    writer.flush()

    println("UInt64序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

UInt64序列化结果: 12345678901234567890

extend UInt8 <: JsonSerializable

extend UInt8 <: JsonSerializable

功能:为 UInt8 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 UInt8 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入UInt8对象 
    let uintValue: UInt8 = 200
    uintValue.toJson(writer)
    writer.flush()

    println("UInt8序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

UInt8序列化结果: 200

extend UIntNative <: JsonSerializable

extend UIntNative <: JsonSerializable

功能:为 UIntNative 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 UIntNative 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入UIntNative对象 
    let uintValue: UIntNative = 2147483648
    uintValue.toJson(writer)
    writer.flush()

    println("UIntNative序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

UIntNative序列化结果: 2147483648

extend<T> Array<T> <: JsonSerializable where T <: JsonSerializable

extend<T> Array<T> <: JsonSerializable where T <: JsonSerializable

功能:为 Array<T> 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 Array<T> 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入Array对象 
    let arrayValue: Array<Int32> = [1, 2, 3, 4, 5]
    arrayValue.toJson(writer)
    writer.flush()

    println("Array序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

Array序列化结果: [1,2,3,4,5]

extend<T> ArrayDeque<T> <: JsonSerializable where T <: JsonSerializable

extend<T> ArrayDeque<T> <: JsonSerializable where T <: JsonSerializable

功能:为 ArrayDeque<T> 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 ArrayDeque<T> 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import std.collection.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入ArrayDeque对象 
    let arrayDequeValue: ArrayDeque<Int64> = ArrayDeque<Int64>()
    arrayDequeValue.addFirst(10)
    arrayDequeValue.addFirst(20)
    arrayDequeValue.addFirst(30)
    arrayDequeValue.toJson(writer)
    writer.flush()

    println("ArrayDeque序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

ArrayDeque序列化结果: [30,20,10]

extend<T> ArrayList<T> <: JsonSerializable where T <: JsonSerializable

extend<T> ArrayList<T> <: JsonSerializable where T <: JsonSerializable

功能:为 ArrayList<T> 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 ArrayList<T> 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import std.collection.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入ArrayList对象 
    let arrayListValue: ArrayList<Int64> = ArrayList<Int64>([100, 200, 300])
    arrayListValue.toJson(writer)
    writer.flush()

    println("ArrayList序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

ArrayList序列化结果: [100,200,300]

extend<T> ArrayQueue<T> <: JsonSerializable where T <: JsonSerializable

extend<T> ArrayQueue<T> <: JsonSerializable where T <: JsonSerializable

功能:为 ArrayQueue<T> 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 ArrayQueue<T> 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import std.collection.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入ArrayQueue对象 
    let arrayQueueValue: ArrayQueue<Int64> = ArrayQueue<Int64>()
    arrayQueueValue.add(100)
    arrayQueueValue.add(200)
    arrayQueueValue.add(300)
    arrayQueueValue.toJson(writer)
    writer.flush()

    println("ArrayQueue序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

ArrayQueue序列化结果: [100,200,300]

extend<T> ArrayStack<T> <: JsonSerializable where T <: JsonSerializable

extend<T> ArrayStack<T> <: JsonSerializable where T <: JsonSerializable

功能:为 ArrayStack<T> 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 ArrayStack<T> 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import std.collection.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入ArrayStack对象 
    let arrayStackValue: ArrayStack<Int64> = ArrayStack<Int64>()
    arrayStackValue.add(111)
    arrayStackValue.add(222)
    arrayStackValue.add(333)
    arrayStackValue.toJson(writer)
    writer.flush()

    println("ArrayStack序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

ArrayStack序列化结果: [111,222,333]

extend<T> HashSet<T> <: JsonSerializable where T <: JsonSerializable

extend<T> HashSet<T> <: JsonSerializable where T <: JsonSerializable

功能:为 HashSet<T> 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 HashSet<T> 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import std.collection.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入HashSet对象 
    let hashSetValue: HashSet<Int64> = HashSet<Int64>([100, 200, 300])
    hashSetValue.toJson(writer)
    writer.flush()

    println("HashSet序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

HashSet序列化结果: [100,200,300]

extend<T> LinkedList<T> <: JsonSerializable where T <: JsonSerializable

extend<T> LinkedList<T> <: JsonSerializable where T <: JsonSerializable

功能:为 LinkedList<T> 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 LinkedList<T> 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import std.collection.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入LinkedList对象 
    let linkedListValue: LinkedList<Int64> = LinkedList<Int64>()
    linkedListValue.addFirst(111)
    linkedListValue.addFirst(222)
    linkedListValue.addFirst(333)
    linkedListValue.toJson(writer)
    writer.flush()

    println("LinkedList序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

LinkedList序列化结果: [333,222,111]

extend<T> Option<T> <: JsonSerializable where T <: JsonSerializable

extend<T> Option<T> <: JsonSerializable where T <: JsonSerializable

功能:为 Option<T> 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 Option<T> 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入Option对象 
    let optionValue: Option<Int64> = Some(999)
    optionValue.toJson(writer)
    writer.flush()

    println("Option序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

Option序列化结果: 999

extend<T> TreeSet<T> <: JsonSerializable where T <: JsonSerializable

extend<T> TreeSet<T> <: JsonSerializable where T <: JsonSerializable

功能:为 TreeSet<T> 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 TreeSet<T> 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import std.collection.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入TreeSet对象 
    let treeSetValue: TreeSet<Int64> = TreeSet<Int64>([333, 111, 222])
    treeSetValue.toJson(writer)
    writer.flush()

    println("TreeSet序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

TreeSet序列化结果: [111,222,333]

extend<V> ConcurrentHashMap<String, V> <: JsonSerializable where V <: JsonSerializable

extend<V> ConcurrentHashMap<String, V> <: JsonSerializable where V <: JsonSerializable

功能:为 ConcurrentHashMap<String, T> 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 ConcurrentHashMap<String, T> 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import std.collection.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入ConcurrentHashMap对象 
    let concurrentHashMapValue = HashMap<String, Int64>([("key1", 100), ("key2", 200), ("key3", 300)])
    concurrentHashMapValue.toJson(writer)
    writer.flush()

    println("ConcurrentHashMap序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

ConcurrentHashMap序列化结果: {"key1":100,"key2":200,"key3":300}

extend<V> HashMap<String, V> <: JsonSerializable where V <: JsonSerializable

extend<V> HashMap<String, V> <: JsonSerializable where V <: JsonSerializable

功能:为 HashMap<String, T> 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 HashMap<String, T> 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import std.collection.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入HashMap对象 
    let hashMapValue = HashMap<String, Int64>([("first", 100), ("second", 200), ("third", 300)])
    hashMapValue.toJson(writer)
    writer.flush()

    println("HashMap序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

HashMap序列化结果: {"first":100,"second":200,"third":300}

extend<V> TreeMap<String, V> <: JsonSerializable where V <: JsonSerializable

extend<V> TreeMap<String, V> <: JsonSerializable where V <: JsonSerializable

功能:为 TreeMap<String, T> 类型提供序列化到 JSON 数据流的接口。

父类型:

func toJson(JsonWriter)

public func toJson(w: JsonWriter): Unit

功能:将 TreeMap<String, T> 类型写入参数 w 指定的 JsonWriter 实例中。

参数:

示例:

import std.io.*
import std.collection.*
import stdx.encoding.json.stream.*

main() {
    // 创建JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 写入TreeMap对象 
    let treeMapValue = TreeMap<String, Int64>([("apple", 100), ("banana", 200), ("cherry", 300)])
    treeMapValue.toJson(writer)
    writer.flush()

    println("TreeMap序列化结果: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

TreeMap序列化结果: {"apple":100,"banana":200,"cherry":300}

class JsonReader

public class JsonReader {
    public init(inputStream: InputStream)
}

功能:此类提供 JSON 数据流转仓颉对象的反序列化能力。

使用示例见使用 Json Stream 进行反序列化

init(InputStream)

public init(inputStream: InputStream)

功能:根据输入流创建一个 JsonReaderJsonReader 从输入流中读取数据时,将跳过非 JsonString 中的空字符('\0', '\t', '\n', '\r')。

参数:

  • inputStream: InputStream - 输入的 JSON 数据流。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建一个包含JSON数据的输入流 
    let jsonStr = ##"{"name":"John","age":30}"##
    let buffer = ByteBuffer()
    buffer.write(jsonStr.toArray())

    // 使用构造函数创建JsonReader 
    let reader = JsonReader(buffer)

    // 读取数据验证构造函数 
    reader.startObject()
    let name = reader.readName()
    let nameValue = reader.readValue<String>()
    let age = reader.readName()
    let ageValue = reader.readValue<Int64>()
    reader.endObject()

    println("JsonReader构造函数示例: ${name}=${nameValue}, ${age}=${ageValue}")
}

运行结果:

JsonReader构造函数示例: name=John, age=30

func endArray()

public func endArray(): Unit

功能:从输入流的当前位置跳过空白字符后消耗一个 ']' 字符,endArray 必须有一个 startArray 与之对应。

异常:

  • IllegalStateException - 如果输入流的 JSON 数据不符合格式,抛出异常。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建一个包含JSON数组的输入流 
    let jsonStr = ##"[1, "Two", 3.14, true]"##
    let buffer = ByteBuffer()
    buffer.write(jsonStr.toArray())

    // 创建JsonReader 
    let reader = JsonReader(buffer)

    // 开始数组 
    reader.startArray()

    // 读取数组元素 
    let first = reader.readValue<Int64>()
    let second = reader.readValue<String>()
    let third = reader.readValue<Float64>()
    let fourth = reader.readValue<Bool>()

    // 结束数组 
    reader.endArray()

    println("读取到的内容: ${first}, ${second}, ${third}, ${fourth}")
}

运行结果:

读取到的内容: 1, Two, 3.140000, true

func endObject()

public func endObject(): Unit

功能:从输入流的当前位置跳过空白字符后消耗一个 '}' 字符,endObject 必须有一个 startObject 与之对应。

异常:

  • IllegalStateException - 如果输入流的 JSON 数据不符合格式,抛出异常。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建一个包含JSON对象的输入流 
    let jsonStr = ##"{"name":"zhangsan","age":25,"city":"Beijing"}"##
    let buffer = ByteBuffer()
    buffer.write(jsonStr.toArray())

    // 创建JsonReader 
    let reader = JsonReader(buffer)

    // 开始对象 
    reader.startObject()

    // 读取对象属性 
    let nameKey = reader.readName()
    let nameValue = reader.readValue<String>()
    let ageKey = reader.readName()
    let ageValue = reader.readValue<Int64>()
    let cityKey = reader.readName()
    let cityValue = reader.readValue<String>()

    // 结束对象 
    reader.endObject()

    println("读取到的内容: ${nameKey}=${nameValue}, ${ageKey}=${ageValue}, ${cityKey}=${cityValue}")
}

运行结果:

读取到的内容: name=zhangsan, age=25, city=Beijing

func peek()

public func peek(): Option<JsonToken>

功能:获取输入流的下一个 JsonToken 的类型,不保证下一个 JsonToken 的格式一定正确。

例:如果输入流中的下一个字符为 't',获取的 JsonToken 将为 JsonToken.Bool,但调用 readValue<Bool>() 不一定成功。

返回值:

  • Option<JsonToken> - 获取到的下一个 JsonToken 的类型,如果到了输入流的结尾返回 None。

异常:

  • IllegalStateException - 如果输入流的下一个字符不在以下范围内:(n, t, f, ", 0~9, -, {, }, [, ])。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建一个包含JSON数据的输入流 
    let jsonStr = ##""Hello, World!""##
    let buffer = ByteBuffer()
    buffer.write(jsonStr.toArray())

    // 创建JsonReader 
    let reader = JsonReader(buffer)

    // 使用peek查看下一个token类型 
    let tokenOption = reader.peek()

    // 检查token类型 
    if (let Some(token) <- tokenOption) {
        match (token) {
            case JsonToken.JsonString => println("下一个token是字符串类型")
            case _ => println("下一个token是其他类型")
        }
    } else {
        println("没有更多数据")
    }
}

运行结果:

下一个token是字符串类型

func readName()

public func readName(): String

功能:从输入流的当前位置读取一个 name。

返回值:

  • String - 读取出的 name 值。

异常:

  • IllegalStateException - 如果输入流的 JSON 数据不符合格式,抛出异常。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建一个包含JSON对象的输入流 
    let jsonStr = ##"{"key1":"value1","key2":5}"##
    let buffer = ByteBuffer()
    buffer.write(jsonStr.toArray())

    // 创建JsonReader 
    let reader = JsonReader(buffer)

    // 开始对象 
    reader.startObject()

    // 读取名称和值 
    let firstKey = reader.readName()
    let firstValue = reader.readValue<String>()
    let secondKey = reader.readName()
    let secondValue = reader.readValue<Int64>()

    // 结束对象 
    reader.endObject()

    println("读取到的内容: ${firstKey}=${firstValue}, ${secondKey}=${secondValue}")
}

运行结果:

读取到的内容: key1=value1, key2=5

func readValue<T>() where T <: JsonDeserializable<T>

public func readValue<T>(): T where T <: JsonDeserializable<T>

功能:从输入流的当前位置读取一个 value。

注意:

当泛型 T 是 String 类型时,根据下一个 JsonToken 的不同,该函数的返回值将会不同:

返回值:

  • T - 读取出的 value 值。

异常:

  • IllegalStateException - 如果输入流的 JSON 数据不符合格式,抛出异常。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建一个包含多种类型JSON值的输入流 
    let jsonStr = ##"["Hello", 123, true, null, 45.67, {"key":"value"}]"##
    let buffer = ByteBuffer()
    buffer.write(jsonStr.toArray())

    // 创建JsonReader 
    let reader = JsonReader(buffer)

    // 开始数组 
    reader.startArray()

    // 读取不同类型的值 
    let strValue = reader.readValue<String>()
    let intValue = reader.readValue<Int64>()
    let boolValue = reader.readValue<Bool>()
    let nullValue = reader.readValue<Option<String>>()
    let floatValue = reader.readValue<Float64>()

    // 数组内对象
    reader.startObject()
    let key = reader.readName()
    let value = reader.readValue<String>()
    reader.endObject()

    // 结束数组 
    reader.endArray()

    println(
        "读取到的内容: 字符串: ${strValue}, 整数: ${intValue}, 布尔: ${boolValue}, 空值: ${nullValue}, 浮点: ${floatValue}, 对象: ${key}=${value}")
}

运行结果:

读取到的内容: 字符串: Hello, 整数: 123, 布尔: true, 空值: None, 浮点: 45.670000, 对象: key=value

func readValueBytes()

public func readValueBytes(): Array<Byte>

功能:读取输入流的下一组原始数据(字节数组),不进行转义等操作。

说明:

readValueBytes 的规则如下:

  • 如果 next token 是 value,则读取这个 value 的所有原始字节,直到读取到代表结束的符号,如 ',' '}' ']'。

  • 如果 next token 是 Name,读取 (name + value) 这一个组合的原始字节数组。

  • 如果 next token 是 BeginArray,读取 Array 内的内的所有原始字节。

  • 如果 next token 是 BeginObject,读取 Object 内的内的所有原始字节。

  • 如果 next token 是 EndArray 或者 EndObject 或者 None,不做任何操作,返回空的数组,再次执行 peek() 仍返回 EndArray 或者 EndObject 或者 None。

返回值:

  • Array<Byte> - 下一组数据对应的原始字节数据。

异常:

  • IllegalStateException - 如果输入流的 JSON 数据不符合格式,抛出异常。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建一个包含JSON数据的输入流 
    let jsonStr = ##"{"key1":"value1","key2":"value2"}"##
    let buffer = ByteBuffer()
    buffer.write(jsonStr.toArray())

    // 创建JsonReader 
    let reader = JsonReader(buffer)

    // 开始对象 
    reader.startObject()

    // 读取原始字节数据,此处 next token 是 name,读取 (name + value) 这一个组合的原始字节数组 
    let valueBytes = reader.readValueBytes()

    // 跳过一个 name
    reader.readName()
    // 读取原始字节数据,此处 next token 是 value,读取 value 原始字节数组
    let valueBytes1 = reader.readValueBytes()

    // 结束对象 
    reader.endObject()

    println("第一个读取的字节数组(转字符串表示)=${String.fromUtf8(valueBytes)}")
    println("第二个读取的字节数组(转字符串表示)=${String.fromUtf8(valueBytes1)}")
}

运行结果:

第一个读取的字节数组(转字符串表示)="key1":"value1"
第二个读取的字节数组(转字符串表示)="value2"

func skip()

public func skip(): Unit

功能:从输入流的当前位置跳过一组数据。

说明:

Skip 的规则如下:

  • 如果 next token 是 value,跳过这个 value, 跳过 value 时不检查该 value 格式是否正确。

  • 如果 next token 是 Name,跳过 (name + value) 这一个组合。

  • 如果 next token 是 BeginArray,跳过这个 array。

  • 如果 next token 是 BeginObject,跳过这个 object。

  • 如果 next token 是 EndArray 或者 EndObject 或者 None,不做任何操作,peek 仍返回 EndArray 或者 EndObject 或者 None。

异常:

  • IllegalStateException - 如果输入流的 JSON 数据不符合格式,抛出异常。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建一个包含JSON对象的输入流 
    let jsonStr = ##"[100, {"key1":"value1"}, {"key2":"value2"}, [1, "Two", 3.14, true]]"##
    let buffer = ByteBuffer()
    buffer.write(jsonStr.toArray())

    // 创建JsonReader 
    let reader = JsonReader(buffer)

    // 开始数组
    reader.startArray()

    // 读取第一个内容 
    let firstValue = reader.readValue<Int64>()

    // 跳过了一个对象
    reader.skip()

    // 读取第二个对象的name 
    reader.startObject()
    let secondValue = reader.readName()

    // 跳过了一个value
    reader.skip()

    // 结束了对象
    reader.endObject()

    // 跳过了一个数组
    reader.skip()

    // 可以正确执行,如果没有跳过一个数组,这里会报错
    reader.endArray()
    println("读取到的第一个内容: ${firstValue}")
    println("读取到的第二个内容: ${secondValue}")
}

运行结果:

读取到的第一个内容: 100
读取到的第二个内容: key2

func startArray()

public func startArray(): Unit

功能:从输入流的当前位置跳过空白字符后消耗一个 '[' 字符。

异常:

  • IllegalStateException - 如果输入流的 JSON 数据不符合格式,抛出异常。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建一个包含JSON数组的输入流 
    let jsonStr = ##"[1, "Two", 3.14, true]"##
    let buffer = ByteBuffer()
    buffer.write(jsonStr.toArray())

    // 创建JsonReader 
    let reader = JsonReader(buffer)

    // 开始数组 
    reader.startArray()

    // 读取数组元素 
    let first = reader.readValue<Int64>()
    let second = reader.readValue<String>()
    let third = reader.readValue<Float64>()
    let fourth = reader.readValue<Bool>()

    // 结束数组 
    reader.endArray()

    println("读取到的内容: ${first}, ${second}, ${third}, ${fourth}")
}

运行结果:

读取到的内容: 1, Two, 3.140000, true

func startObject()

public func startObject(): Unit

功能:从输入流的当前位置跳过空白字符后消耗一个 '{' 字符。

异常:

  • IllegalStateException - 如果输入流的 JSON 数据不符合格式,抛出异常。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建一个包含JSON对象的输入流 
    let jsonStr = ##"{"name":"zhangsan","age":25,"city":"Beijing"}"##
    let buffer = ByteBuffer()
    buffer.write(jsonStr.toArray())

    // 创建JsonReader 
    let reader = JsonReader(buffer)

    // 开始对象 
    reader.startObject()

    // 读取对象属性 
    let nameKey = reader.readName()
    let nameValue = reader.readValue<String>()
    let ageKey = reader.readName()
    let ageValue = reader.readValue<Int64>()
    let cityKey = reader.readName()
    let cityValue = reader.readValue<String>()

    // 结束对象 
    reader.endObject()

    println("读取到的内容: ${nameKey}=${nameValue}, ${ageKey}=${ageValue}, ${cityKey}=${cityValue}")
}

运行结果:

读取到的内容: name=zhangsan, age=25, city=Beijing

class JsonWriter

public class JsonWriter {
    public var writeConfig: WriteConfig = WriteConfig.compact
    public init(out: OutputStream)
}

功能:JsonWriter 提供了将仓颉对象序列化到 OutputStream 的能力。

JsonWriter 需要和 interface JsonSerializable 搭配使用,JsonWriter 可以通过 writeValue 来将实现了 JsonSerializable 接口的类型写入到 Stream 中。

注意:

JsonWriter 中使用缓存来减少写入 Stream 时的 IO 次数,在结束使用 JsonWriter 之前需要调用 flush 函数来确保缓存中的数据全部写入 Stream。

示例:

使用示例见使用 Json Stream 进行序列化

var writeConfig

public var writeConfig: WriteConfig = WriteConfig.compact

功能:序列化格式配置。详见 WriteConfig

类型:WriteConfig

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建使用pretty配置的JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)
    var config = WriteConfig.pretty // 使用美化格式

    writer.writeConfig = config

    // 写入简单对象 
    writer.startObject()
    writer.writeName("Name").writeValue("zhangsan")
    writer.writeName("Age").writeValue(18)
    writer.endObject()

    writer.flush()

    // 打印结果 
    println("使用pretty配置的JSON输出:\n${String.fromUtf8(buffer.bytes())}")
}

运行结果:

使用pretty配置的JSON输出:
{
    "Name": "zhangsan",
    "Age": 18
}

init(OutputStream)

public init(out: OutputStream)

功能:构造函数,构造一个将数据写入 out 的实例。

参数:

  • out: OutputStream - 目标流

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建一个输出流 
    let outputStream = ByteBuffer()

    // 使用构造函数创建JsonWriter 
    let writer = JsonWriter(outputStream)

    // 使用writeValue写入一些数据 
    writer.writeValue("Hello, World!")
    writer.flush()

    println("JsonWriter构造函数示例: ${String.fromUtf8(outputStream.bytes())}")
}

运行结果:

JsonWriter构造函数示例: "Hello, World!"

func endArray()

public func endArray(): Unit

功能:结束序列化当前的 JSON 数组。

异常:

  • IllegalStateException - 当前 writer 没有匹配的 startArray 时。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建一个输出流 
    let outputStream = ByteBuffer()

    // 创建JsonWriter 
    let writer = JsonWriter(outputStream)

    // 开始数组 
    writer.startArray()

    // 写入数组元素 
    writer.writeValue(1)
    writer.writeValue("hello world")
    writer.writeValue(3.14)

    // 结束数组 
    writer.endArray()
    writer.flush()

    println("转字符串表示: ${String.fromUtf8(outputStream.bytes())}")
}

运行结果:

转字符串表示: [1,"hello world",3.14]

func endObject()

public func endObject(): Unit

功能:结束序列化当前的 JSON object。

异常:

  • IllegalStateException - 当前 writer 的状态不应该结束一个 JSON object 时。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建一个输出流 
    let outputStream = ByteBuffer()

    // 创建JsonWriter 
    let writer = JsonWriter(outputStream)

    // 开始对象 
    writer.startObject()

    // 写入对象属性 
    writer.writeName("property1").writeValue("value1")
    writer.writeName("property2").writeValue(42)

    // 结束对象 
    writer.endObject()
    writer.flush()

    println("转字符串表示: ${String.fromUtf8(outputStream.bytes())}")
}

运行结果:

转字符串表示: {"property1":"value1","property2":42}

func flush()

public func flush(): Unit

功能:将缓存中的数据写入 out,并且调用 out 的 flush 方法。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建一个输出流 
    let outputStream = ByteBuffer()

    // 创建JsonWriter 
    let writer = JsonWriter(outputStream)

    // 写入一些数据 
    writer.writeValue("test data")

    // 调用flush方法确保数据写入流 
    writer.flush()
}

func jsonValue(String)

public func jsonValue(value: String): JsonWriter

功能:将符合 JSON value 规范的原始字符串写入 stream。

注意:

此函数不会对值 value 进行转义,也不会为入参添加双引号。如果使用者能够保证输入的值 value 符合数据转换标准ECMA-404 The JSON Data Interchange Standard, 建议使用该函数。

参数:

  • value: String - 待写入的字符串。

返回值:

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 value 时。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建一个输出流 
    let outputStream = ByteBuffer()

    // 创建JsonWriter 
    let writer = JsonWriter(outputStream)

    // 使用jsonValue写入原始JSON字符串 
    writer.jsonValue(##"{"property1":"value1","property2":42}"##)

    writer.flush()

    println("转字符串表示: ${String.fromUtf8(outputStream.bytes())}")
}

运行结果:

转字符串表示: {"property1":"value1","property2":42}

func startArray()

public func startArray(): Unit

功能:开始序列化一个新的 JSON 数组,每一个 startArray 都必须有一个 endArray 对应。

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 JSON array 时。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建一个输出流 
    let outputStream = ByteBuffer()

    // 创建JsonWriter 
    let writer = JsonWriter(outputStream)

    // 开始数组 
    writer.startArray()

    // 写入数组元素 
    writer.writeValue(1)
    writer.writeValue("hello world")
    writer.writeValue(3.14)

    // 结束数组 
    writer.endArray()
    writer.flush()

    println("转字符串表示: ${String.fromUtf8(outputStream.bytes())}")
}

运行结果:

转字符串表示: [1,"hello world",3.14]

func startObject()

public func startObject(): Unit

功能:开始序列化一个新的 JSON object,每一个 startObject 都必须有一个 endObject 对应。

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 JSON object 时。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建一个输出流 
    let outputStream = ByteBuffer()

    // 创建JsonWriter 
    let writer = JsonWriter(outputStream)

    // 开始对象 
    writer.startObject()

    // 写入对象属性 
    writer.writeName("name").writeValue("zhangsan")
    writer.writeName("age").writeValue(30)

    // 结束对象 
    writer.endObject()
    writer.flush()

    println("转字符串表示: ${String.fromUtf8(outputStream.bytes())}")
}

运行结果:

转字符串表示: {"name":"zhangsan","age":30}

func writeName(String)

public func writeName(name: String): JsonWriter

功能:在 object 结构中写入 name。

参数:

  • name: String - 待写入的字符串。

返回值:

异常:

  • IllegalStateException - 当前 JsonWriter 的状态不应写入参数 name 指定字符串时。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建一个输出流 
    let outputStream = ByteBuffer()

    // 创建JsonWriter 
    let writer = JsonWriter(outputStream)

    // 开始对象 
    writer.startObject()

    // 使用writeName写入名称 
    writer.writeName("key").writeValue("value")
    writer.writeName("count").writeValue(100)

    // 结束对象 
    writer.endObject()
    writer.flush()

    println("转字符串表示: ${String.fromUtf8(outputStream.bytes())}")
}

运行结果:

转字符串表示: {"key":"value","count":100}

func writeNullValue()

public func writeNullValue(): JsonWriter

功能:向流中写入 JSON value null。

返回值:

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 value 时

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建一个输出流 
    let outputStream = ByteBuffer()

    // 创建JsonWriter 
    let writer = JsonWriter(outputStream)

    // 开始对象 
    writer.startObject()

    // 写入名称和null值 
    writer.writeName("nullField").writeNullValue()
    writer.writeName("anotherField").writeValue("someValue")

    // 结束对象 
    writer.endObject()
    writer.flush()

    println("转字符串表示: ${String.fromUtf8(outputStream.bytes())}")
}

运行结果:

转字符串表示: {"nullField":null,"anotherField":"someValue"}

func writeValue<T>(T) where T <: JsonSerializable

public func writeValue<T>(v: T): JsonWriter where T <: JsonSerializable

功能:将实现了 JsonSerializable 接口的类型写入到 Stream 中。该接口会调用泛型 T 的 toJson 方法向输出流中写入数据。

json.stream 包已经为基础类型 Int64、UInt64、Float64、Bool、String 类型扩展实现了 JsonSerializable,并且为 Collection 类型 Array、ArrayList 和 HashMap 扩展实现了 JsonSerializable

参数:

  • v: T - 待写入的对象,类型为 T。

返回值:

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 value 时。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建一个输出流 
    let outputStream = ByteBuffer()

    // 创建JsonWriter 
    let writer = JsonWriter(outputStream)

    // 使用writeValue写入各种类型的数据 
    writer.writeValue("Hello")
    writer.flush()

    println("转字符串表示(字符串): ${String.fromUtf8(outputStream.bytes())}")

    // 重新创建流和写入器以写入其他值 
    let outputStream2 = ByteBuffer()
    let writer2 = JsonWriter(outputStream2)

    // 写入对象
    writer2.startObject()
    writer2.writeName("key")
    writer2.writeValue("value")
    writer2.endObject()

    writer2.flush()

    println("转字符串表示(对象): ${String.fromUtf8(outputStream2.bytes())}")

    // 写入数组 
    let outputStream3 = ByteBuffer()
    let writer3 = JsonWriter(outputStream3)

    writer3.writeValue([1, 2, 3, 4])
    writer3.flush()

    println("转字符串表示(数组): ${String.fromUtf8(outputStream3.bytes())}")
}

运行结果:

转字符串表示(字符串): "Hello"
转字符串表示(对象): {"key":"value"}
转字符串表示(数组): [1,2,3,4]

枚举

enum JsonToken

public enum JsonToken <: Equatable<JsonToken> & Hashable {
    | JsonNull
    | JsonBool
    | JsonNumber
    | JsonString
    | BeginArray
    | EndArray
    | BeginObject
    | EndObject
    | Name
}

功能:表示 JSON 编码的字符串中的结构、名称或者值类型。

JsonToken 通常和 JsonReader.peek()搭配使用,通过对返回值的判断来决定具体的处理方式。

父类型:

BeginArray

BeginArray

功能:表示 JSON 中 array 的开始。如果 JsonReader.peek() 返回的是该类型,可以使用 JsonReader.startArray() 读取。

BeginObject

BeginObject

功能:表示 JSON 中 object 的开始。如果 JsonReader.peek() 返回的是该类型,可以使用 JsonReader.startObject() 读取。

EndArray

EndArray

功能:表示 JSON 中 array 的结束。如果 JsonReader.peek() 返回的是该类型,可以使用 JsonReader.endArray() 读取。

EndObject

EndObject

功能:表示 JSON 中 object 的结束。如果 JsonReader.peek() 返回的是该类型,可以使用 JsonReader.endObject() 读取。

JsonBool

JsonBool

功能:表示 JSON 的 bool 类型。如果 JsonReader.peek() 返回的是该类型,可以使用 JsonReader.readValue<Bool>() 读取。

JsonNull

JsonNull

功能:表示 JSON 的 null 类型。如果 JsonReader.peek() 返回的是该类型,可以使用 JsonReader.readValue<Option<T>>() 读取。

JsonNumber

JsonNumber

功能:表示 JSON 的 number 类型。如果 JsonReader.peek() 返回的是该类型,可以使用 JsonReader.readValue<Float64>() 读取。

JsonString

JsonString

功能:表示 JSON 的 string 类型。如果 JsonReader.peek() 返回的是该类型,可以使用 JsonReader.readValue<String>() 读取。

Name

Name

功能:表示 object 中的 name。如果 JsonReader.peek() 返回的是该类型,可以使用 JsonReader.readName() 读取。

func hashCode()

public func hashCode(): Int64

功能:获取 JsonToken 对象的 hashCode 值。

返回值:

  • Int64 - hashCode 值。

示例:

import stdx.encoding.json.stream.*

main() {
    // 创建一个JsonToken枚举对象 
    let token = JsonToken.BeginArray

    // 调用hashCode方法 
    let hashCodeValue = token.hashCode()

    println("JsonToken的hashCode值: ${hashCodeValue}")
}

运行结果:

JsonToken的hashCode值: 4

operator func !=(JsonToken)

public operator func !=(that: JsonToken): Bool

功能:判不等。

参数:

返回值:

  • Bool - 当前实例与 that 不相等返回 true,否则返回 false

示例:

import stdx.encoding.json.stream.*

main() {
    // 创建两个不同的JsonToken对象 
    let token1 = JsonToken.BeginArray
    let token2 = JsonToken.EndArray

    // 调用!=操作符 
    let isNotEqual = token1 != token2

    println("两个JsonToken不相等的结果: ${isNotEqual}")

    // 创建两个相同的JsonToken对象 
    let token3 = JsonToken.JsonString
    let token4 = JsonToken.JsonString

    // 调用!=操作符 
    let isNotEqual2 = token3 != token4

    println("两个相同JsonToken不相等的结果: ${isNotEqual2}")
}

运行结果:

两个JsonToken不相等的结果: true
两个相同JsonToken不相等的结果: false

operator func ==(JsonToken)

public operator func ==(that: JsonToken): Bool

功能:判等。

参数:

返回值:

  • Bool - 当前实例与 that 相等返回 true,否则返回 false

示例:

import stdx.encoding.json.stream.*

main() {
    // 创建两个相同的JsonToken对象 
    let token1 = JsonToken.BeginObject
    let token2 = JsonToken.BeginObject

    // 调用==操作符 
    let isEqual = token1 == token2

    println("两个相同JsonToken相等的结果: ${isEqual}")

    // 创建两个不同的JsonToken对象 
    let token3 = JsonToken.JsonString
    let token4 = JsonToken.JsonNumber

    // 调用==操作符 
    let isEqual2 = token3 == token4

    println("两个不同JsonToken相等的结果: ${isEqual2}")
}

运行结果:

两个相同JsonToken相等的结果: true
两个不同JsonToken相等的结果: false

结构体

struct WriteConfig

public struct WriteConfig {
    public static let compact: WriteConfig
    public static let pretty: WriteConfig
}

功能:用于表示 JsonWriter 的序列化格式配置。

示例:

使用示例见 WriteConfig 使用示例

static let compact

public static let compact: WriteConfig

功能:提供紧凑的序列化格式。

说明:

compact 的各属性值为:

  • newline: "",空字符串。
  • indent: "",空字符串。
  • useSpaceAfterSeparators: false。
  • htmlSafe: false。
  • dateTimeFormat: DateTimeFormat.RFC3339。

类型:WriteConfig

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建使用compact配置的JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)
    var config = WriteConfig.compact // 使用紧凑格式

    writer.writeConfig = config

    // 写入简单对象 
    writer.startObject()
    writer.writeName("Name").writeValue("zhangsan")
    writer.writeName("Age").writeValue(18)
    writer.endObject()

    writer.flush()

    // 打印结果 
    println("使用compact配置的JSON输出: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

使用compact配置的JSON输出: {"Name":"zhangsan","Age":18}

static let pretty

public static let pretty: WriteConfig

功能:提供整洁的序列化格式。

说明:

pretty 的各属性值为:

  • newline: "\n"。
  • indent: "    ",包含 4 个空格的字符串。
  • useSpaceAfterSeparators: true。
  • htmlSafe: false。
  • dateTimeFormat: DateTimeFormat.RFC3339。

类型:WriteConfig

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建使用pretty配置的JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)
    var config = WriteConfig.pretty // 使用美化格式

    writer.writeConfig = config

    // 写入简单对象 
    writer.startObject()
    writer.writeName("Name").writeValue("zhangsan")
    writer.writeName("Age").writeValue(18)
    writer.endObject()

    writer.flush()

    // 打印结果 
    println("使用pretty配置的JSON输出:\n${String.fromUtf8(buffer.bytes())}")
}

运行结果:

使用pretty配置的JSON输出:
{
    "Name": "zhangsan",
    "Age": 18
}

prop dateTimeFormat

public mut prop dateTimeFormat: String

功能:用于序列化 DateTime 类型时的格式控制,功能与 DateTime 的 func toString(DateTimeFormat) 一致。

类型:String

示例:

import std.io.*
import std.time.*
import stdx.encoding.json.stream.*

main() {
    // 创建使用pretty配置的JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)
    var config = WriteConfig.pretty // 使用美化格式

    config.dateTimeFormat = "yyyy-MM-dd"
    writer.writeConfig = config

    // 写入简单对象 
    writer.startObject()
    writer.writeName("Name").writeValue("zhangsan")
    writer.writeName("DOB").writeValue(DateTime.of(year: 2026, month: 1, dayOfMonth: 7))
    writer.endObject()

    writer.flush()

    // 打印结果 
    println("修改DateTime格式的JSON输出:\n${String.fromUtf8(buffer.bytes())}")
}

运行结果:

修改DateTime格式的JSON输出:
{
    "Name": "zhangsan",
    "DOB": "2026-01-07"
}

prop htmlSafe

public mut prop htmlSafe: Bool

功能:用于表示是否转义 HTML 字符 <>&='

该值为 true 时,会将 HTML 字符转义为对应的 Unicode 编码的字符串。

该选项只对 json value 中的字符串字面量有效。

类型:Bool

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建使用pretty配置的JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)
    var config = WriteConfig.pretty // 使用美化格式

    config.htmlSafe = true
    writer.writeConfig = config

    // 写入包含HTML字符的对象 
    writer.startObject()
    writer.writeName("Content").writeValue("<script>alert('XSS')</script>")
    writer.writeName("Title").writeValue("Hello & Welcome")
    writer.endObject()

    writer.flush()

    // 打印结果 
    println("启用htmlSafe的JSON输出:\n${String.fromUtf8(buffer.bytes())}")
}

运行结果:

启用htmlSafe的JSON输出:
{
    "Content": "\u003cscript\u003ealert(\u0027XSS\u0027)\u003c/script\u003e",
    "Title": "Hello \u0026 Welcome"
}

prop indent

public mut prop indent: String

功能:序列化过程中,为每个缩进级别填充的缩进字符串,用于定义序列化输出内容的缩进格式。

取值必须匹配正则表达式:^[ \t]*$,即字符串仅可包含空格、制表符,或为空字符串。

无换行行为时,该属性不生效。

类型:String

异常:

  • IllegalArgumentException - 设置的字符串包含 ' ' 或者 '\t' 以外的字符。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建使用compact配置的JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)
    var config = WriteConfig.pretty

    config.indent = " " // 1个空格对应的输出1个缩进
    writer.writeConfig = config

    // 写入简单对象 
    writer.startObject()
    writer.writeName("Name").writeValue("zhangsan")
    writer.writeName("Age").writeValue(18)
    writer.endObject()

    writer.flush()

    // 打印结果 
    println("使用indent格式的JSON输出:\n${String.fromUtf8(buffer.bytes())}")
}

运行结果:

使用indent格式的JSON输出:
{
 "Name": "zhangsan",
 "Age": 18
}

prop newline

public mut prop newline: String

功能:用于表示序列化时填入的换行符。取值应匹配正则 ^[\r\n]*$

当该值不为空字符串且合法时,JsonWriter 调用 startObject 和 startArray 操作、插入元素、以及它们的结束操作会产生新的换行。

当该值为空字符串时,不会触发换行。

类型:String

异常:

  • IllegalArgumentException - 设置的字符串包含 '\r' 或者 '\n' 以外的字符。

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建使用compact配置的JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)
    var config = WriteConfig.pretty // 使用美化格式

    config.newline = "\n\n" // 换行符
    writer.writeConfig = config

    // 写入简单对象 
    writer.startObject()
    writer.writeName("Name").writeValue("zhangsan")
    writer.writeName("Age").writeValue(18)
    writer.endObject()

    writer.flush()

    // 打印结果 
    println("使用newline格式的JSON输出:\n${String.fromUtf8(buffer.bytes())}")
}

运行结果:

使用newline格式的JSON输出:
{

    "Name": "zhangsan",

    "Age": 18

}

prop useSpaceAfterSeparators

public mut prop useSpaceAfterSeparators: Bool

功能:用于表示序列化时在 ':' 和 ',' 后是否加一个空格。

该值为 true 时,每插入一个 field name 或者 array 元素后会自动写入一个空格。

该选项只对 json Object 中的 field 以及 json Array 中的元素有效。

类型:Bool

示例:

import std.io.*
import stdx.encoding.json.stream.*

main() {
    // 创建使用compact配置的JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)
    var config = WriteConfig.compact // 使用紧凑格式

    config.useSpaceAfterSeparators = true // 启用在分隔符后添加空格
    writer.writeConfig = config

    // 写入简单对象 
    writer.startObject()
    writer.writeName("Name").writeValue("zhangsan")
    writer.writeName("Age").writeValue(18)
    writer.endObject()

    writer.flush()

    // 打印结果 
    println("启用useSpaceAfterSeparators的JSON输出: ${String.fromUtf8(buffer.bytes())}")
}

运行结果:

启用useSpaceAfterSeparators的JSON输出: {"Name": "zhangsan","Age": 18}

使用 Json Stream 进行反序列化

示例:

import stdx.encoding.json.stream.*
import std.io.*
import std.collection.*

class A <: JsonDeserializable<A> {
    var key1: Option<String> = None
    var key2: Bool = false
    var key3: Float64 = 0.0
    var key4: String = ""
    var key5: Array<Int64> = Array<Int64>()
    var key6: HashMap<String, String> = HashMap<String, String>()

    public static func fromJson(r: JsonReader): A {
        var res = A()
        while (let Some(v) <- r.peek()) {
            match (v) {
                case BeginObject =>
                    r.startObject()
                    while (r.peek() != EndObject) {
                        let n = r.readName()
                        match (n) {
                            case "key1" => res.key1 = r.readValue<Option<String>>()
                            case "key2" => res.key2 = r.readValue<Bool>()
                            case "key3" => res.key3 = r.readValue<Float64>()
                            case "key4" => res.key4 = r.readValue<String>()
                            case "key5" => res.key5 = r.readValue<Array<Int64>>()
                            case "key6" => res.key6 = r.readValue<HashMap<String, String>>()
                            case _ => ()
                        }
                    }
                    r.endObject()
                    break
                case _ => throw Exception()
            }
        }
        return res
    }

    func toString(): String {
        return "${key1}\n${key2}\n${key3}\n${key4}\n${key5}\n${key6}"
    }
}

main() {
    let jsonStr = ##"{"key1": null, "key2": true, "key3": 123.456, "key4": "string", "key5": [123, 456], "key6": {"key7": " ", "key8": "\\a"}}"##
    var bas = ByteBuffer()
    unsafe { bas.write(jsonStr.rawData()) }
    var reader = JsonReader(bas)
    var obj = A.fromJson(reader)
    println(obj.toString())
}

运行结果:

None
true
123.456000
string
[123, 456]
[(key7,  ), (key8, \a)]

使用 Json Stream 进行序列化

示例:

import stdx.encoding.json.stream.*
import std.io.{ByteBuffer, readToEnd}

class Image <: JsonSerializable {
    var width: Int64
    var height: Int64
    var title: String
    var ids: Array<Int64>

    public init() {
        width = 0
        height = 0
        title = ""
        ids = Array<Int64>()
    }

    public func toJson(w: JsonWriter): Unit {
        w.startObject()
        w.writeName("Width").writeValue(width)
        w.writeName("Height").writeValue(height)
        w.writeName("Title").writeValue(title)
        w.writeName("Ids").writeValue<Array<Int64>>(ids)
        w.endObject()
    }
}

main() {
    let image = Image()
    image.width = 800
    image.height = 600
    image.title = "View from 15th Floor"
    image.ids = [116, 943, 234, 38793]

    let stream = ByteBuffer()
    let writer = JsonWriter(stream)

    // 将图片序列化 
    writer.writeValue(image)
    writer.flush()
    println(String.fromUtf8(readToEnd(stream)))
}

运行结果:

{"Width":800,"Height":600,"Title":"View from 15th Floor","Ids":[116,943,234,38793]}

WriteConfig 使用示例

示例:

import stdx.encoding.json.stream.{JsonWriter, WriteConfig, JsonSerializable}
import std.io.ByteBuffer

main() {
    // 构造 JsonWriter 
    let buffer = ByteBuffer()
    let writer = JsonWriter(buffer)

    // 设置 JSON 写格式配置 
    let fmtCfg = WriteConfig.pretty
    writer.writeConfig = fmtCfg

    // 写 JSON  
    writer.writeValue(MyObj())

    // 打印 JSON 序列化字符串 
    println(String.fromUtf8(buffer.bytes()))
}

class MyObj <: JsonSerializable {
    public func toJson(w: JsonWriter): Unit {
        w.startObject()
        w.writeName("Name").writeValue("zhangsan")
        w.writeName("Age").writeValue(18)
        w.writeName("Scores").writeValue([88.8, 99.9])
        w.writeName("Class")
        w.startObject()
        w.writeName("Name").writeValue("Class A")
        w.writeName("Students Number").writeValue(33)
        w.endObject()
        w.endObject()
        w.flush()
    }
}

运行结果:

{
    "Name": "zhangsan",
    "Age": 18,
    "Scores": [
        88.8,
        99.9
    ],
    "Class": {
        "Name": "Class A",
        "Students Number": 33
    }
}

stdx.encoding.url

功能介绍

url 包提供了 URL 相关的能力,包括解析 URL 的各个组件,对 URL 进行编解码,合并 URL 或路径等。

URL(Uniform Resource Locator)是统一资源定位符的缩写,它是用来标识互联网上资源位置的一种地址。通常包含协议、主机名、路径和查询参数等信息,其中协议是指访问资源所使用的协议(如 HTTP、FTP 等),主机名是指资源所在的服务器的域名或 IP 地址,路径是指资源所在的具体位置,查询参数是指用于传递参数的字符串。URL 是互联网上标识资源的唯一方式,通过 URL 可以访问网页、图片、视频等各种类型的资源。

URL 一般是以下格式:

scheme://host[:port]/path[?query][#fragment]

其中:

  • scheme:协议,例如 httphttpsftp 等;
  • host:主机名或 IP 地址;
  • port:端口号,可选,默认为协议默认端口;
  • path:资源路径,例如 /index.html/blog/post/123 等;
  • query:查询参数,例如 ?page=2&sort=desc 等,可选;
  • fragment:文档片段标识符,例如 #section-1,可选。

例如,网址 https://www.example.com/blog/post/123?page=2&sort=desc#section-1 的 URL 格式为:

  • scheme: https
  • host: www.example.com
  • path: /blog/post/123
  • query: ?page=2&sort=desc
  • fragment: #section-1

URL 编码的原因和基本过程:

URL 编码是将 URL 中的非 ASCII 字符转换为一种可读性更好的 ASCII 字符的过程。这是因为 URL 中只允许包含 ASCII 字符,而非 ASCII 字符可能会导致 URL 解析错误或传输失败。

URL 编码的基本过程如下:

  1. 将 URL 字符串转换为字节数组。
  2. 对于每个非 ASCII 字符,将其转换为 UTF-8 编码的字节序列。
  3. 对于每个字节,将其转换为两个十六进制数字。
  4. 在每个十六进制数字前添加一个百分号(%)。
  5. 将所有编码后的字符连接起来形成编码后的 URL 字符串。

例如,将字符串“你好,世界!”进行 URL 编码,结果为“%E4%BD%A0%E5%A5%BD%EF%BC%8C%E4%B8%96%E7%95%8C%EF%BC%81”。

API 列表

类名功能
FormForm 以 key-value 键值对形式存储 http 请求的参数,同一个 key 可以对应多个 value,value 以数组形式存储。
URL该类提供解析 URL 的函数以及其他相关函数。
UserInfoUserInfo 表示 URL 中用户名和密码信息。

异常类

异常类名功能
UrlSyntaxExceptionurl 解析异常类。

class Form

public class Form {
    public init()
    public init(queryComponent: String)
}

功能:Form 以 key-value 键值对形式存储 http 请求的表单信息,通常为请求 URL 中的 query 部分。

同一个 key 可以对应多个 value,value 以数组形式存储。& 符号分隔多个键值对;= 分隔的左侧作为 key 值,右侧作为 value 值(没有 = 或者 value 为空,均是允许的)。使用示例见 Form 的构造使用

init()

public init()

功能:构造一个默认的 Form 实例。

示例:

import stdx.encoding.url.*

main() {
    // 使用无参构造函数创建Form实例 
    let form = Form()
}

init(String)

public init(queryComponent: String)

功能:根据 URL 编码的查询字符串,即 URL 实例的 query 部分构造 Form 实例。

解析 URL 编码的查询字符串,得到若干键值对,并将其添加到新构造的 Form 实例中。

参数:

  • queryComponent: String - URL 的 query 组件部分的字符串,但是不包括组件前面的 ? 符号。

异常:

  • IllegalArgumentException - 当URL 字符串中包含不符合 utf8 编码规则的字节时,抛出异常。
  • UrlSyntaxException - 当 URL 字符串中包含非法转义字符时,抛出异常。

示例:

import stdx.encoding.url.*

main() {
    // 使用带参构造函数创建Form实例 
    let form = Form("name=Zhangsan&age=30&city=Nanjing")
}

func add(String, String)

public func add(key: String, value: String): Unit

功能:新增 key-value 映射,如果 key 已存在,则将 value 添加到原来 value 数组的最后面。

参数:

  • key: String - 指定键,可以是新增的。
  • value: String - 将该值添加到指定键对应的值数组中。

示例:

import stdx.encoding.url.*

main() {
    // 创建一个Form实例 
    let form = Form()

    // 添加键值对 
    form.add("username", "admin")
    form.add("password", "123456")

    println("toEncodeString: ${form.toEncodeString()}")
}

运行结果:

toEncodeString: username=admin&password=123456

func clone()

public func clone(): Form

功能:克隆 Form

返回值:

  • Form - 克隆得到的新 Form 实例。

示例:

import stdx.encoding.url.*

main() {
    // 创建一个Form实例并添加一些键值对 
    let originalForm = Form("item1=value1&item2=value2")

    // 克隆Form实例 
    let clonedForm = originalForm.clone()

    println("克隆的是否是 Form: ${clonedForm is Form}")
    println("toEncodeString: ${clonedForm.toEncodeString()}")
}

运行结果:

克隆的是否是 Form: true
toEncodeString: item1=value1&item2=value2

func get(String)

public func get(key: String): Option<String>

功能:根据 key 获取第一个对应的 value 值。

情况举例:

  • 当 query 组件部分是 a=b 时,form.get("a")获得 Some(b)
  • 当 query 组件部分是 a= 时,form.get("a")获得 Some()
  • 当 query 组件部分是 a 时,form.get("a")获得 Some()
  • 当 query 组件部分是 a 时,form.get("c")获得 None

参数:

  • key: String - 指定键。

返回值:

  • Option<String> - 根据指定键获取的第一个值,用 Option<String> 类型表示。

示例:

import stdx.encoding.url.*

main() {
    // 创建一个Form实例并添加一些键值对 
    let form = Form()
    form.add("username", "admin")
    form.add("email", "admin@example.com")

    // 获取指定键的值 
    let usernameResult = form.get("username")
    let emailResult = form.get("email")
    let nonexistentResult = form.get("nonexistent")

    println("username: ${usernameResult}")
    println("email: ${emailResult}")
    println("nonexistent: ${nonexistentResult}")
}

运行结果:

username: Some(admin)
email: Some(admin@example.com)
nonexistent: None

func getAll(String)

public func getAll(key: String): ArrayList<String>

功能:根据指定的键(key)获取该键(key)对应的所有 value 值。

参数:

  • key: String - 用户指定的键(key),用于获取对应的 value 值。

返回值:

  • ArrayList<String> - 根据指定键(key)获取的全部 value 值对应的数组。当指定键(key)不存在时,返回空数组。

示例:

import stdx.encoding.url.*

main() {
    // 创建一个Form实例并添加一些键值对 
    let form = Form()
    form.add("tag", "red")
    form.add("tag", "blue")
    form.add("tag", "green")
    form.add("name", "myForm")

    // 获取指定键的所有值 
    let tagValues = form.getAll("tag")
    let nameValues = form.getAll("name")
    let nonexistentValues = form.getAll("nonexistent")

    println("tagValues: ${tagValues}")
    println("nameValues: ${nameValues}")
    println("nonexistentValues: ${nonexistentValues}")
}

运行结果:

tagValues: [red, blue, green]
nameValues: [myForm]
nonexistentValues: []

func isEmpty()

public func isEmpty(): Bool

功能:判断 Form 是否为空。

返回值:

  • Bool - 如果为空,则返回 true;否则,返回 false。

示例:

import stdx.encoding.url.*

main() {
    // 创建一个空Form实例 
    let emptyForm = Form()

    // 检查Form是否为空 
    let isEmpty = emptyForm.isEmpty()

    // 添加一些数据后再检查 
    emptyForm.add("key", "value")
    let isNotEmpty = emptyForm.isEmpty()

    println("是否为空: ${isEmpty}")
    println("添加数据后是否为空: ${isNotEmpty}")
}

运行结果:

是否为空: true
添加数据后是否为空: false

func remove(String)

public func remove(key: String): Unit

功能:删除 key 及其对应 value。

参数:

  • key: String - 需要删除的键。

示例:

import stdx.encoding.url.*

main() {
    // 创建一个Form实例并添加一些键值对 
    let form = Form()
    form.add("username", "admin")
    form.add("password", "secret")

    // 移除指定的键值对 
    form.remove("password")
    // 移除不存在的键值对,无异常
    form.remove("nonexistent")

    println("toEncodeString: ${form.toEncodeString()}")
}

运行结果:

toEncodeString: username=admin

func set(String, String)

public func set(key: String, value: String): Unit

功能:重置指定 key 对应的 value。

参数:

  • key: String - 指定键。
  • value: String - 将指定键的值设置为 value。

示例:

import stdx.encoding.url.*

main() {
    // 创建一个Form实例并添加一些键值对 
    let form = Form()
    form.add("key1", "value1")

    // 重置指定键的值 
    form.set("key1", "newvalue1")
    // 重置不存在的键的值,会创建新的键值对
    form.set("key2", "value2")

    println("toEncodeString: ${form.toEncodeString()}")
}

运行结果:

toEncodeString: key1=newvalue1&key2=value2

func toEncodeString()

public func toEncodeString(): String

功能:对表单中的键值对进行编码,编码采用百分号编码。

未保留字符不会被编码,空格将编码为 '+'。

说明:

RFC 3986 协议中对未保留字符定义如下: unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"

返回值:

  • String - 编码后的字符串。

示例:

import stdx.encoding.url.*

main() {
    // 创建一个Form实例并添加一些键值对 
    let form = Form()
    // 存在空格
    form.add("name", "Zhang san")
    // 存在保留字符‘-’,不会进行编码
    form.add("生日", "2026-1-8")
    // 存在特殊字符,会进行编码
    form.add("email", "zhangsan@example.com")

    // 将表单转换为编码字符串 
    let encodedString = form.toEncodeString()

    println("toEncodeString: ${encodedString}")
}

运行结果:

toEncodeString: name=Zhang+san&%E7%94%9F%E6%97%A5=2026-1-8&email=zhangsan%40example.com

class URL

public class URL <: ToString {
    public init(scheme!: String, hostName!: String, path!: String)
}

功能:该类提供解析 URL 的函数以及其他相关函数。

字符串中被百分号%编码的内容会被解码,保存在相应的组件之中,而初始值保存在相应的 raw 属性之中。URL 中的用户名和密码部分(如果存在的话)也会按照 RFC 3986 协议的说明被解析。

注意:

RFC 3986 明确说明在任何场景下,明文保存用户信息存在被泄露风险,所以建议不要在 URL 中明文保存用户信息。

父类型:

  • ToString

prop fragment

public prop fragment: ?String

功能:获取解码后的锚点组件,用字符串表示。

类型:?String

示例:

import stdx.encoding.url.*

main() {
    // 解析URL
    let url = URL.parse("https://admin:password123@example.com/path?k=v#fragment%20with%20space")

    println("URL fragment: ${url.fragment}")
}

运行结果:

URL fragment: Some(fragment with space)

prop host

public prop host: String

功能:获取解码后的主机名和端口部分,用字符串表示。

类型:String

示例:

import stdx.encoding.url.*

main() {
    // 解析URL
    let url = URL.parse("https://admin:password123@example.com:8080/path?k=v#fragment")

    println("URL host: ${url.host}")
}

运行结果:

URL host: example.com:8080

prop hostName

public prop hostName: String

功能:获取解码后的主机名,用字符串表示。

类型:String

示例:

import stdx.encoding.url.*

main() {
    // 解析URL
    let url = URL.parse("https://admin:password123@example.com:8080/path?k=v#fragment")

    println("URL hostName: ${url.hostName}")
}

运行结果:

URL hostName: example.com

prop opaque

public prop opaque: String

功能:获取 URL 中未被解析的部分,用字符串表示。

类型:String

示例:

import stdx.encoding.url.*

main() {
    let url = URL.parse("https:\\\\/example.com/foo/bar") // '\' 不是协议规定的分割符,无法被解析。
    println("url.scheme=${url.scheme}")
    println("url.host=${url.host}")
    println("url.opaque=${url.opaque}")
}

运行结果:

url.scheme=https
url.host=
url.opaque=\\/example.com/foo/bar

prop path

public prop path: String

功能:获取解码后的路径,用字符串表示。

类型:String

示例:

import stdx.encoding.url.*

main() {
    // 解析URL
    let url = URL.parse("https://example.com:8080/api/v1/users?k=v#fragment")

    println("URL path: ${url.path}")
}

运行结果:

URL path: /api/v1/users

prop port

public prop port: String

功能:获取端口号,用字符串表示,空字符串表示无端口号。

类型:String

示例:

import stdx.encoding.url.*

main() {
    // 解析URL
    let url = URL.parse("https://example.com:8080/api/v1/users?k=v#fragment")

    println("URL port: ${url.port}")
}

运行结果:

URL port: 8080

prop query

public prop query: ?String

功能:获取解码后的查询组件,用字符串表示。

类型:?String

示例:

import stdx.encoding.url.*

main() {
    // 解析URL
    let url = URL.parse("https://example.com:8080/api/v1/users?name=%E5%BC%A0%E4%B8%89&age=30#fragment")

    println("URL query: ${url.query}")
}

运行结果:

URL query: Some(name=张三&age=30)

prop queryForm

public prop queryForm: Form

功能:获取解码后的查询组件,用 Form 实例表示。

类型:Form

示例:

import stdx.encoding.url.*

main() {
    // 解析URL
    let url = URL.parse("https://example.com:8080/api/v1/users?name=%E5%BC%A0%E4%B8%89&age=30#fragment")

    // 获取查询组件
    let queryForm = url.queryForm
    // 获取查询组件中的 name 值
    let name = queryForm.get("name")
    println("URL queryForm: ${name}")
}

运行结果:

URL queryForm: Some(张三)

prop rawFragment

public prop rawFragment: ?String

功能:获取解码前的锚点组件,用字符串表示。

类型:?String

示例:

import stdx.encoding.url.*

main() {
    // 解析URL
    let url = URL.parse("https://example.com:8080/path?k=v#fragment%20with%20space")

    println("URL rawFragment: ${url.rawFragment}")
}

运行结果:

URL rawFragment: Some(fragment%20with%20space)

prop rawPath

public prop rawPath: String

功能:获取解码前的路径,用字符串表示。

类型:String

示例:

import stdx.encoding.url.*

main() {
    // 解析URL
    let url = URL.parse("https://example.com:8080/path%20with%20space?k=v#fragment")

    println("URL rawPath: ${url.rawPath}")
}

运行结果:

URL rawPath: /path%20with%20space

prop rawQuery

public prop rawQuery: ?String

功能:获取解码前的查询组件,用字符串表示。

类型:?String

示例:

import stdx.encoding.url.*

main() {
    // 解析URL
    let url = URL.parse("https://example.com:8080/path?name%3Djohn%26age%3D30#fragment")

    println("URL rawQuery: ${url.rawQuery}")
}

运行结果:

URL rawQuery: Some(name%3Djohn%26age%3D30)

prop rawUserInfo

public prop rawUserInfo: UserInfo

功能:获取解码前的用户名和密码信息,用 UserInfo 实例表示。

类型:UserInfo

示例:

import stdx.encoding.url.*

main() {
    // 解析URL
    let url = URL.parse("https://admin%40company:password123@example.com:8080/path?k=v#fragment")

    println("URL rawUserInfo: ${url.rawUserInfo}")
}

运行结果:

URL rawUserInfo: admin%40company:password123

prop scheme

public prop scheme: String

功能:获取 URL 中协议部分,用字符串表示。

类型:String

示例:

import stdx.encoding.url.*

main() {
    // 解析URL
    let url = URL.parse("https://example.com:8080/path?k=v#fragment")

    println("URL scheme: ${url.scheme}")
}

运行结果:

URL scheme: https

prop userInfo

public prop userInfo: UserInfo

功能:获取解码后的用户名和密码信息,用 UserInfo 实例表示。

类型:UserInfo

示例:

import stdx.encoding.url.*

main() {
    // 解析URL
    let url = URL.parse("https://admin:password123@example.com:8080/path?k=v#fragment")

    println("URL userInfo: ${url.userInfo}")
}

运行结果:

URL userInfo: admin:password123

init(String, String, String)

public init(scheme!: String, hostName!: String, path!: String)

功能:构造一个 URL 实例。

构造实例时需要满足要求:

  • 拥有主机名 hostName 时,需要有协议 scheme。
  • 不能只存在协议 scheme。
  • 存在协议和路径的情况下,路径 path 必须是绝对路径。

参数:

  • scheme!: String - 协议类型。
  • hostName!: String - 不包含端口号的主机名。
  • path!: String - 请求资源的路径。

异常:

示例:

import stdx.encoding.url.*

main() {
    // 创建URL实例
    let url = URL(scheme: "https", hostName: "example.com", path: "/path")

    println("URL created: ${url}")
}

运行结果:

URL created: https://example.com/path

static func decode(String)

static func decode(url: String): String

功能:对经过 URL 编码(也就是 % 编码)的字符串进行解码操作,将编码后的字符串还原成原始的字符串。

注意:

该函数解码所有被编码的字符,但部分字符是 URL 语法的一部分,所以以下字符将保留在输出字符串中:

# $ & + , / : ; = ? @

参数:

  • url: String - 待解码的字符串。

返回值:

  • String - 解码后的字符串。

示例:

import stdx.encoding.url.*

main() {
    // 解码URL编码的字符串‘Hello & World! %’
    let encoded = "Hello%20%26%20World! %25"

    // 解码URL编码的字符串,部分字符是保留字符,如 '&'
    let decoded = URL.decode(encoded)

    println("URL decode: ${decoded}")
}

运行结果:

URL decode: Hello %26 World! %

static func decodeComponent(String)

static func decodeComponent(component: String): String

功能:对经过 URL 编码(也就是 % 编码)的字符串进行解码操作,将编码后的字符串还原成原始的字符串。

参数:

  • component: String - 待解码的字符串。

返回值:

  • String - 解码后的字符串。

示例:

import stdx.encoding.url.*

main() {
    let encoded = "Hello%20%26%20World! %25"

    // 全部解码,无保留字符
    let decoded = URL.decodeComponent(encoded)

    println("URL decodeComponent: ${decoded}")
}

运行结果:

URL decodeComponent: Hello & World! %

static func encode(String)

static func encode(url: String): String

功能:对普通字符串进行 URL 编码(也称为 % 编码)。URL 编码的目的是将字符串中的特殊字符、非 ASCII 字符等转换为符合 URL 规范的格式,以确保这些字符串能在 URL 中安全地传输和使用。

注意:

该函数编码所有字符,但部分字符被 URL 语法所保留,所以以下字符将不会被编码:

0-9 A-Z a-z

! ' - . * ( ) _ ~

# $ & + , / : ; = ? @

参数:

  • url: String - 待编码的字符串。

返回值:

  • String - 编码后的字符串。

示例:

import stdx.encoding.url.*

main() {
    // 编码URL字符串
    let original = "Hello & World!"

    // 编码URL字符串,保留字符如 '&' 不会被编码
    let encoded = URL.encode(original)

    println("URL encode: ${encoded}")
}

运行结果:

URL encode: Hello%20&%20World!

static func encodeComponent(String)

static func encodeComponent(component: String): String

功能:对普通字符串进行 URL 编码(也称为 % 编码)。URL 编码的目的是将字符串中的特殊字符、非 ASCII 字符等转换为符合 URL 规范的格式,以确保这些字符串能在 URL 中安全地传输和使用。

注意:

该函数编码所有字符,包括 URL 语法的字符,但部分字符被 URL 语法所保留,所以以下字符将不会被编码:

0-9 A-Z a-z

! ' - . * ( ) _ ~

参数:

  • component: String - 待编码的字符串。

返回值:

  • String - 编码后的字符串。

示例:

import stdx.encoding.url.*

main() {
    // 编码URL字符串
    let original = "key & value!"

    // 编码URL字符串,保留字符如 '!' 不会被编码
    let encodeComponent = URL.encodeComponent(original)

    println("URL encodeComponent: ${encodeComponent}")
}

运行结果:

URL encodeComponent: key%20%26%20value!

static func mergePaths(String, String)

public static func mergePaths(basePath: String, refPath: String): String

功能:合并两个路径。

合并规则:将引用路径 refPath 追加到基础路径 basePath 的最后一段。如果 refPath 是绝对路径,结果就是 refPath 原本的值。如果 refPath 不是绝对路径,则将自身拼接至 basePath 最后一个 / 后,所有结果最终都会进行标准化(路径中的.字符,..字符,以及多个连续的 / 字符都会被优化)。具体行为可以参照下面示例。更详细行为参考 RFC 3986 协议。

如需合并 URL 请使用 resolveURL

例如:

  • /a/b/c 合并 /d 输出 /d
  • /a/b/c 合并 d 输出 /a/b/d
  • /a/b/ 合并 d/e/../f 输出 /a/b/d/f
  • /a/b/c/ 合并 ./../../g 输出 /a/g

参数:

  • basePath: String - 基础路径。
  • refPath: String - 引用路径。

返回值:

  • String - 合并且标准化后的路径。

示例:

import stdx.encoding.url.*

main() {
    // 合并路径
    let basePath = "/a/b/c"
    let refPath = "d"
    let mergedPath = URL.mergePaths(basePath, refPath)

    println("URL mergePaths: ${mergedPath}")
}

运行结果:

URL mergePaths: /a/b/d

static func parse(String)

public static func parse(rawUrl: String): URL

功能:将原始 URL 字符串解析成 URL 对象。

这个函数会将 URL 按照组件分解,然后分别进行解码并存储在相应的组件属性中,而 rawXXX (此处泛指前缀是 raw 的 URL 属性)属性部分存储的是原始值,不做编解码处理。

使用示例请参见URL 解析函数 parse 的使用

注意:

该函数可以解析 URL 中的用户名和密码(如果存在),这是符合 RFC 3986 协议的解析功能的,但是 RFC 3986 也明确指出,任何场景下,明文保存用户信息存在被泄露风险,所以建议不要在 URL 中明文保存用户信息。

参数:

  • rawUrl: String - URL 字符串。

返回值:

  • URL - 解析字符串得到的 URL 实例。

异常:

  • UrlSyntaxException - 当 URL 字符串中包含非法字符时,抛出异常。
  • IllegalArgumentException - 当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常。

示例:

import stdx.encoding.url.*

main() {
    // 解析URL字符串
    let url = URL.parse("https://example.com:8080/path?query=value#fragment")

    println("URL parsed: ${url}")
}

运行结果:

URL parsed: https://example.com:8080/path?query=value#fragment

func isAbsoluteURL()

public func isAbsoluteURL(): Bool

功能:判断 URL 是否为绝对 URL(scheme 存在时,URL 是绝对 URL)。

返回值:

  • Bool - scheme 存在时返回 true,不存在时返回 false。

示例:

import stdx.encoding.url.*

main() {
    // 解析URL字符串
    let url = URL.parse("https://example.com:8080/path?query=value#fragment")
    let isAbsolute = url.isAbsoluteURL()
    println("isAbsolute isAbsoluteURL: ${isAbsolute}")

    let url1 = URL.parse("/path?query=value#fragment")
    let notAbsolute = url1.isAbsoluteURL()
    println("notAbsolute isAbsoluteURL: ${notAbsolute}")
}

运行结果:

isAbsolute isAbsoluteURL: true
notAbsolute isAbsoluteURL: false

func replace(Option<String>, Option<String>, Option<String>, Option<String>, Option<String>, Option<String>, Option<String>)

public func replace(scheme!: Option<String> = None, userInfo!: Option<String> = None,
 hostName!: Option<String> = None, port!: Option<String> = None, path!: Option<String> = None, 
 query!: Option<String> = None, fragment!: Option<String> = None): URL

功能:替换 URL 对象的各组件,并且返回一个新的 URL 对象。

替换时需要满足以下要求:

  • 方案 scheme 为空时,主机名必须为空。
  • 主机名为空时,用户信息或端口号必须为空。
  • 方案 scheme 不为空时,主机名和路径不能同时为空。
  • 方案 scheme 不为空时,路径必须是绝对路径。
  • 任意组件均为合法字符。

参数:

  • scheme!: Option<String> - 协议组件。
  • userInfo!: Option<String> - 用户信息。
  • hostName!: Option<String> - 主机名。
  • port!: Option<String> - 端口号。
  • path!: Option<String> - 资源路径。
  • query!: Option<String> - 查询组件。
  • fragment!: Option<String> - 锚点组件。

返回值:

异常:

示例:

import stdx.encoding.url.*

main() {
    // 解析URL字符串
    let url = URL.parse("https://example.com:8080/path?query=value#fragment")

    // 替换URL组件
    let newUrl = url.replace(path: Some("/newpath"))

    println("URL replace: ${newUrl}")
}

运行结果:

URL replace: https://example.com:8080/newpath?query=value#fragment

func resolveURL(URL)

public func resolveURL(ref: URL): URL

功能:以当前 URL 实例为基础 URL,以传入的 URL 为参考 URL,根据 RFC 3986 协议生成一个新的 URL 实例。

例如:http://a/b/c/d;p?q 为基础 URL,以下 = 左边为参考 URL,右边为生成的新 URL

更多详细的 URL 生成规则,请参见 RFC 3968 协议。

参数:

  • ref: URL - 参考 URL 对象。

返回值:

示例:

import stdx.encoding.url.*

main() {
    // 解析基础URL
    let baseUrl = URL.parse("http://a/b/c/d;p?q")
    // 解析参考URL
    let refUrl = URL.parse("g")

    // 解析URL
    let resolvedUrl = baseUrl.resolveURL(refUrl)

    println("URL resolveURL: ${resolvedUrl}")
}

运行结果:

URL resolveURL: http://a/b/c/g

func toString()

public func toString(): String

功能:获取当前 URL 实例的字符串值。

会把 hostName 编码,其余部分取 rawXXX (此处泛指前缀是 raw 的 URL 属性)属性值,按照 URL 组件构成顺序进行拼接而获得该函数返回值。

返回值:

  • String - 当前 URL 实例的字符串值。

示例:

import stdx.encoding.url.*

main() {
    // 解析URL字符串
    let url = URL.parse("https://example.com:8080/path?query=value#fragment")

    // 获取URL字符串表示
    let urlString = url.toString()

    println("URL toString: ${urlString}")
}

运行结果:

URL toString: https://example.com:8080/path?query=value#fragment

class UserInfo

public class UserInfo <: ToString {
    public init()
    public init(userName: String)
    public init(userName: String, passWord: String)
    public init(userName: String, passWord: Option<String>)
}

功能:UserInfo 表示 URL 中用户名和密码信息。

注意:

RFC 3986 明确指出,任何场景下,明文保存用户信息存在被泄露风险,所以建议不要在 URL 中明文保存用户信息。

父类型:

  • ToString

init()

public init()

功能:创建 UserInfo 实例。

示例:

import stdx.encoding.url.*

main() {
    // 使用无参构造函数创建UserInfo实例 
    let userInfo = UserInfo()
}

init(String)

public init(userName: String)

功能:根据用户名创建 UserInfo 实例。

参数:

  • userName: String - 用户名。

示例:

import stdx.encoding.url.*

main() {
    // 使用用户名参数创建UserInfo实例 
    let userInfo = UserInfo("Zhangsan")

    println("UserInfo: ${userInfo}")
}

运行结果:

UserInfo: Zhangsan

init(String, Option<String>)

public init(userName: String, passWord: Option<String>)

功能:根据用户名和密码创建 UserInfo 实例。 参数:

  • userName: String - 用户名。
  • passWord: Option<String> - 密码,用 Option<String> 类型表示。

示例:

import stdx.encoding.url.*

main() {
    // 使用用户名和密码创建UserInfo实例 
    let userInfo = UserInfo("admin", Some("password123"))

    println("UserInfo带用户名和密码: ${userInfo}")
}

运行结果:

UserInfo带用户名和密码: admin:password123

init(String, String)

public init(userName: String, passWord: String)

功能:根据用户名和密码创建 UserInfo 实例。 参数:

  • userName: String - 用户名。
  • passWord: String - 密码。

示例:

import stdx.encoding.url.*

main() {
    // 使用用户名和密码创建UserInfo实例 
    let userInfo = UserInfo("admin", "password123")

    println("UserInfo带用户名和密码: ${userInfo}")
}

运行结果:

UserInfo带用户名和密码: admin:password123

func password()

public func password(): Option<String>

功能:获取密码信息。

注意:

RFC 3986 明确指出,任何场景下,明文保存用户信息存在被泄露风险,所以建议不要在 URL 中明文保存用户信息。

返回值:

  • Option<String> - 将密码以 Option<String> 形式返回。

示例:

import stdx.encoding.url.*

main() {
    // 创建UserInfo实例 
    let userInfo = UserInfo("admin", "password123")

    // 获取密码信息 
    let passwordOption = userInfo.password()

    println("UserInfo password: ${passwordOption}")
}

运行结果:

UserInfo password: Some(password123)

func toString()

public func toString(): String

功能:将当前 UserInfo 实例转换为字符串。

返回值:

  • String - 当前 UserInfo 实例的字符串表示。

示例:

import stdx.encoding.url.*

main() {
    // 创建UserInfo实例 
    let userInfo = UserInfo("admin", "password123")

    // 获取字符串表示 
    let userInfoString = userInfo.toString()

    println("UserInfo toString方法示例: ${userInfoString}")
}

运行结果:

UserInfo toString方法示例: admin:password123

func username()

public func username(): String

功能:获取用户名信息。

返回值:

  • String - 字符串类型的用户名。

示例:

import stdx.encoding.url.*

main() {
    // 创建UserInfo实例 
    let userInfo = UserInfo("admin", "password123")

    // 获取用户名信息 
    let username = userInfo.username()

    println("UserInfo username: ${username}")
}

运行结果:

UserInfo username: admin

异常类

class UrlSyntaxException

public class UrlSyntaxException <: Exception {
    public init(reason: String)
    public init(input: String, reason: String)
    public init(input: String, reason: String, pos: String)
}

功能:URL 解析异常类。

父类型:

  • Exception

init(String)

public init(reason: String)

功能:根据错误原因构造 UrlSyntaxException 实例。

参数:

  • reason: String - 解析错误的原因。

示例:

import stdx.encoding.url.*

main() {
    try {
        throw UrlSyntaxException("URL格式错误")
    } catch (e: UrlSyntaxException) {
        println("异常信息: ${e.message}")
    }
}

运行结果:

异常信息: URL格式错误

init(String, String)

public init(input: String, reason: String)

功能:根据 URL 及错误原因构造 UrlSyntaxException 实例。

参数:

  • input: String - 原生 URL 或其片段。
  • reason: String - 解析错误的原因。

示例:

import stdx.encoding.url.*

main() {
    try {
        throw UrlSyntaxException("https://example.com%", "URL格式错误")
    } catch (e: UrlSyntaxException) {
        println("异常信息: ${e.message}")
    }
}

运行结果:

异常信息: URL格式错误 Input = https://example.com%.

init(String, String, String)

public init(input: String, reason: String, pos: String)

功能:根据 URL 字符串,错误原因以及解析失败的部分,构造 UrlSyntaxException 实例。

参数:

  • input: String - 原生 URL 或其片段。
  • reason: String - 解析错误的原因。
  • pos: String - 给定 URL 字符串中解析失败的部分。

示例:

import stdx.encoding.url.*

main() {
    try {
        let url = "https://example.com%"
        throw UrlSyntaxException(url, "URL格式错误", url[8..])
    } catch (e: UrlSyntaxException) {
        println("异常信息: ${e.message}")
    }
}

运行结果:

异常信息: URL格式错误 Input = https://example.com% (at 'example.com%').

Form 的构造使用

Form 的构造与其函数 get 的使用

创建 Form 类,并通过 get 获取 key 对应映射的 value。示例中使用 Form 类的函数 get 获取指定 key = 1 的 value 值 2 。

示例:

import stdx.encoding.url.*

main(): Int64 {
    var s = Form("1=2&2=3&1=2&&")
    print(s.get("1").getOrThrow())
    return 0
}

运行结果:

2

Form 的构造与重复 key 情况下函数 get 的使用

创建 Form 类,并通过 get 获取 key 对应映射的 value。示例中使用 Form 类的函数 get 获取指定 key = 1 的第一个 value 值 %6AD。value 中的 %6A 被解码为 j,因此得到 value 值 jD 。

示例:

import stdx.encoding.url.*

main(): Int64 {
    var s = Form("2=3&1=%6AD&1=2")
    // 对于 %6A 解码成 j,重复的 key 调用 get 获取第一个 value 值 jD 
    print(s.get("1").getOrThrow())
    return 0
}

运行结果如下:

jD

Form 的构造与其他函数使用

分别调用 add,set,clone,打印输出前后变化。

示例:

import stdx.encoding.url.*

main(): Int64 {
    var f = Form()

    // 给键 k 增加值 v1 和 v2 
    f.add("k", "v1")
    f.add("k", "v2")

    // 调用 get 方法时,获取的是第一个值 
    println(f.get("k").getOrThrow())

    // 设定键 k 的值为 v 
    f.set("k", "v")
    println(f.get("k").getOrThrow())
    let clone_f = f.clone()

    // 给克隆出来的 clone_f 增加键值对 
    clone_f.add("k1", "v1")

    // 通过 get 获得值 v1 
    println(clone_f.get("k1").getOrThrow())

    // 原来的 f 并没有键 k1,所以值是给的默认值 kkk 
    println(f.get("k1") ?? "kkk")
    return 0
}

运行结果如下:

v1
v
v1
kkk

URL 解析函数 parse 的使用

使用 parse 函数解析 URL 字符串,生成 URL 对象。示例中对一个地址进行了解析并获得了 URL 对象,并且打印该对象的各个属性。

示例:

import stdx.encoding.url.*

main(): Int64 {
    // 调用 URL 静态函数 parse 解析网址获得名为 url 的对象 
    var url = URL.parse(
        "http://www.example.com:80/path%E4%BB%93%E9%A2%89?key=value%E4%BB%93%E9%A2%89#%E4%BD%A0%E5%A5%BD")

    // 打印 url 的组件属性 
    println("url.scheme = ${url.scheme}")
    println("url.opaque = ${url.opaque}")
    println("url.userInfo = ${url.userInfo}")
    println("url.rawUserInfo = ${url.rawUserInfo}")
    println("url.host = ${url.host}")
    println("url.hostName = ${url.hostName}")
    println("url.port = ${url.port}")
    println("url.path = ${url.path}")
    println("url.rawPath = ${url.rawPath}")
    println("url.query = ${url.query.getOrThrow()}")
    println("url.rawQuery = ${url.rawQuery.getOrThrow()}")
    println("url.fragment = ${url.fragment.getOrThrow()}")
    println("url.rawfragment = ${url.rawFragment.getOrThrow()}")
    println("url = ${url}")
    return 0
}

运行结果:

url.scheme = http
url.opaque = 
url.userInfo = 
url.rawUserInfo = 
url.host = www.example.com:80
url.hostName = www.example.com
url.port = 80
url.path = /path仓颉
url.rawPath = /path%E4%BB%93%E9%A2%89
url.query = key=value仓颉
url.rawQuery = key=value%E4%BB%93%E9%A2%89
url.fragment = 你好
url.rawfragment = %E4%BD%A0%E5%A5%BD
url = http://www.example.com:80/path%E4%BB%93%E9%A2%89?key=value%E4%BB%93%E9%A2%89#%E4%BD%A0%E5%A5%BD

stdx.fuzz.fuzz

功能介绍

Fuzz 技术是一种自动化软件测试方法,旨在发现软件中的漏洞和错误。它通过持续输入随机的或经过变异的测试用例来执行软件程序,并根据程序的覆盖率信息来指导测试的方向。

fuzz 包为开发者提供基于覆盖率反馈的仓颉 fuzz 引擎及对应的接口,开发者可以编写代码对 API 进行测试。当前支持通过传入 fuzz 引擎变异的字节流 (Array<UInt8>) 或符合仓颉的标准数据类型(FuzzDataProvider)进行 fuzz 测试。

使用此包需要配合覆盖率反馈插桩(SanitizerCoverage)功能使用,需要开发者对 fuzz 测试有一定的了解,初学者建议先学习 C 语言的 Fuzz 工具。

使用本包需要外部依赖 LLVM 套件 compiler-rt 提供的 libclang_rt.fuzzer_no_main.a 静态库。

通常使用包管理工具即可完成安装,例如 Ubuntu 22.04 系统上可使用 sudo apt install clang 进行安装,安装后可以在 clang -print-runtime-dir 指向的目录下找到对应的 libclang_rt.fuzzer_no_main.a 文件,例如 /usr/lib/llvm-14/lib/clang/14.0.0/lib/linux/libclang_rt.fuzzer_no_main-x86_64.a,将来在链接时会用到它。

注意:

不支持平台:Windows。

API 列表

类名功能
FuzzerFuzzer 类提供了 fuzz 工具的创建。
FuzzerBuilder此类用于 Fuzzer 类的构建。
FuzzDataProviderFuzzDataProvider 是一个工具类,目的是将变异数据的字节流转化为标准的仓颉基本数据。
DebugDataProvider此类继承了 FuzzDataProvider 类型,额外增加了调试信息。

异常类

异常类名功能
ExhaustedException此异常为转换数据时,剩余数据不足以转换时抛出的异常。

常量&变量

let FUZZ_VERSION

public let FUZZ_VERSION: String = "1.0.0"

功能:Fuzz 版本。

注意:

不支持平台:Windows。

类型:String

示例:

import stdx.fuzz.fuzz.*

main() {
    println("Fuzz 版本: ${FUZZ_VERSION}")
    return 0
}

运行结果:

Fuzz 版本: 1.0.0

class DebugDataProvider

public class DebugDataProvider <: FuzzDataProvider

功能:此类继承了 FuzzDataProvider 类型,额外增加了调试信息。

注意:

不支持平台:Windows。

父类型:

func consumeAll()

public override func consumeAll(): Array<UInt8>

功能:将所有数据转换成 UInt8 类型数组。

注意:

不支持平台:Windows。

返回值:

  • Array<UInt8> - UInt8 类型数组。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68])
    let ddp = DebugDataProvider.wrap(fdp)
    // 将所有数据转换成 UInt8 类型数组
    let allData = ddp.consumeAll()
    return 0
}

运行结果:

[DEBUG] consumeAll return [65, 66, 67, 68]

func consumeAllAsAscii()

public override func consumeAllAsAscii(): String

功能:将所有数据转换成 Ascii String 类型。

注意:

不支持平台:Windows。

返回值:

  • String - Ascii String 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([72, 101, 108, 108, 111]) // "Hello" in ASCII
    let ddp = DebugDataProvider.wrap(fdp)
    // 将所有数据转换成 Ascii String 类型
    let asciiStr = ddp.consumeAllAsAscii()
    return 0
}

运行结果:

[DEBUG] consumeAllAsAscii return Hello

func consumeAllAsString()

public override func consumeAllAsString(): String

功能:将所有数据转换成 utf8 String 类型。

注意:

不支持平台:Windows。

返回值:

  • String - utf8 String 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([72, 101, 108, 108, 111]) // "Hello" in ASCII
    let ddp = DebugDataProvider.wrap(fdp)
    // 将所有数据转换成 utf8 String 类型
    let utf8Str = ddp.consumeAllAsString()
    return 0
}

运行结果:

[DEBUG] consumeAllAsString return Hello

func consumeAsciiString(Int64)

public override func consumeAsciiString(maxLength: Int64): String

功能:将数据转换成 Ascii String 类型实例。

注意:

不支持平台:Windows。

参数:

  • maxLength: Int64 - String 类型的最大长度。

返回值:

  • String - String 类型实例。

异常:

  • IllegalArgumentException - 如果 maxLength 为负数,则抛出异常。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([72, 101, 108, 108, 111]) // "Hello" in ASCII
    let ddp = DebugDataProvider.wrap(fdp)
    // 将数据转换成 Ascii String 类型实例,最大长度为3
    let asciiStr = ddp.consumeAsciiString(3)
    return 0
}

运行结果:

[DEBUG] consumeAsciiString return Hel

func consumeBool()

public override func consumeBool(): Bool

功能:将数据转换成 Bool 类型实例。

注意:

不支持平台:Windows。

返回值:

  • Bool - Bool 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65])
    let ddp = DebugDataProvider.wrap(fdp)
    // 将数据转换成 Bool 类型实例
    let boolVal = ddp.consumeBool()
    return 0
}

运行结果:

[DEBUG] consumeBool return true

func consumeBools(Int64)

public override func consumeBools(count: Int64): Array<Bool>

功能:将指定数量的数据转换成 Bool 类型数组。

注意:

不支持平台:Windows。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<Bool> - Bool 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67])
    let ddp = DebugDataProvider.wrap(fdp)
    // 将指定数量的数据转换成 Bool 类型数组
    let bools = ddp.consumeBools(3)
    return 0
}

运行结果:

[DEBUG] consumeBools return [true, false, true]

func consumeByte()

public override func consumeByte(): Byte

功能:将数据转换成 Byte 类型实例。

注意:

不支持平台:Windows。

返回值:

  • Byte - Byte 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66])
    let ddp = DebugDataProvider.wrap(fdp)
    // 将数据转换成 Byte 类型实例
    let byteVal = ddp.consumeByte()
    return 0
}

运行结果:

[DEBUG] consumeByte return 65

func consumeBytes(Int64)

public override func consumeBytes(count: Int64): Array<Byte>

功能:将指定数量的数据转换成 Byte 类型数组。

注意:

不支持平台:Windows。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<Byte> - Byte 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67])
    let ddp = DebugDataProvider.wrap(fdp)
    // 将指定数量的数据转换成 Byte 类型数组
    let bytes = ddp.consumeBytes(2)
    return 0
}

运行结果:

[DEBUG] consumeBytes return [65, 66]

func consumeFloat32()

public override func consumeFloat32(): Float32

功能:将数据转换成 Float32 类型实例。

注意:

不支持平台:Windows。

返回值:

  • Float32 - Float32 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68])
    let ddp = DebugDataProvider.wrap(fdp)
    // 将数据转换成 Float32 类型实例
    let float32Val = ddp.consumeFloat32()
    return 0
}

运行结果:

[DEBUG] consumeFloat32 return 781.035217

func consumeFloat64()

public override func consumeFloat64(): Float64

功能:将数据转换成 Float64 类型实例。

注意:

不支持平台:Windows。

返回值:

  • Float64 - Float64 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68, 69, 70, 71, 72])
    let ddp = DebugDataProvider.wrap(fdp)
    // 将数据转换成 Float64 类型实例
    let float64Val = ddp.consumeFloat64()
    return 0
}

运行结果:

[DEBUG] consumeFloat64 return 15839800103804824402926068484019465486336.000000

func consumeInt16()

public override func consumeInt16(): Int16

功能:将数据转换成 Int16 类型实例。

注意:

不支持平台:Windows。

返回值:

  • Int16 - Int16 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66])
    let ddp = DebugDataProvider.wrap(fdp)
    // 将数据转换成 Int16 类型实例
    let int16Val = ddp.consumeInt16()
    return 0
}

运行结果:

[DEBUG] consumeInt16 return 16961

func consumeInt16s(Int64)

public override func consumeInt16s(count: Int64): Array<Int16>

功能:将指定数量的数据转换成 Int16 类型数组。

注意:

不支持平台:Windows。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<Int16> - Int16 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68, 69, 70])
    let ddp = DebugDataProvider.wrap(fdp)
    // 将指定数量的数据转换成 Int16 类型数组
    let int16s = ddp.consumeInt16s(2)
    return 0
}

运行结果:

[DEBUG] consumeInt16s return [16961, 17475]

func consumeInt32()

public override func consumeInt32(): Int32

功能:将数据转换成 Int32 类型实例。

注意:

不支持平台:Windows。

返回值:

  • Int32 - Int32 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68])
    let ddp = DebugDataProvider.wrap(fdp)
    // 将数据转换成 Int32 类型实例
    let int32Val = ddp.consumeInt32()
    return 0
}

运行结果:

[DEBUG] consumeInt32 return 1145258561

func consumeInt32s(Int64)

public override func consumeInt32s(count: Int64): Array<Int32>

功能:将指定数量的数据转换成 Int32 类型数组。

注意:

不支持平台:Windows。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<Int32> - Int32 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68, 69, 70, 71, 72, 73, 74])
    let ddp = DebugDataProvider.wrap(fdp)
    // 将指定数量的数据转换成 Int32 类型数组
    let int32s = ddp.consumeInt32s(2)
    return 0
}

运行结果:

[DEBUG] consumeInt32s return [1145258561, 1212630597]

func consumeInt64()

public override func consumeInt64(): Int64

功能:将数据转换成 Int64 类型实例。

注意:

不支持平台:Windows。

返回值:

  • Int64 - Int64 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68, 65, 66, 67, 68])
    let ddp = DebugDataProvider.wrap(fdp)
    // 将数据转换成 Int64 类型实例
    let int64Val = ddp.consumeInt64()
    return 0
}

运行结果:

[DEBUG] consumeInt64 return 4918848066104279617

func consumeInt64s(Int64)

public override func consumeInt64s(count: Int64): Array<Int64>

功能:将指定数量的数据转换成 Int64 类型数组。

注意:

不支持平台:Windows。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<Int64> - Int64 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68, 65, 66, 67, 68, 65, 66, 67, 68, 65, 66, 67, 68])
    let ddp = DebugDataProvider.wrap(fdp)
    // 将指定数量的数据转换成 Int64 类型数组
    let int64s = ddp.consumeInt64s(2)
    return 0
}

运行结果:

[DEBUG] consumeInt64s return [4918848066104279617, 4918848066104279617]

func consumeInt8()

public override func consumeInt8(): Int8

功能:将数据转换成 Int8 类型实例。

注意:

不支持平台:Windows。

返回值:

  • Int8 - Int8 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65])
    let ddp = DebugDataProvider.wrap(fdp)
    // 将数据转换成 Int8 类型实例
    let int8Val = ddp.consumeInt8()
    return 0
}

运行结果:

[DEBUG] consumeInt8 return 65

func consumeInt8s(Int64)

public override func consumeInt8s(count: Int64): Array<Int8>

功能:将指定数量的数据转换成 Int8 类型数组。

注意:

不支持平台:Windows。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<Int8> - Int8 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67])
    let ddp = DebugDataProvider.wrap(fdp)
    // 将指定数量的数据转换成 Int8 类型数组
    let int8s = ddp.consumeInt8s(2)
    return 0
}

运行结果:

[DEBUG] consumeInt8s return [65, 66]

func consumeRune()

public override func consumeRune(): Rune

功能:将数据转换成 Rune 类型实例。

注意:

不支持平台:Windows。

返回值:

  • Rune - Rune 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([72, 101, 108, 108, 111]) // "Hello" string
    let ddp = DebugDataProvider.wrap(fdp)
    // 将数据转换成 Rune 类型实例
    let runeVal = ddp.consumeRune()
    return 0
}

运行结果:

[DEBUG] consumeRune return 󆕈

func consumeString(Int64)

public override func consumeString(maxLength: Int64): String

功能:将数据转换成 utf8 String 类型实例。

注意:

不支持平台:Windows。

参数:

  • maxLength: Int64 - String 类型的最大长度。

返回值:

  • String - String 类型实例。

异常:

  • IllegalArgumentException - 如果 maxLength 为负数,则抛出异常。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([228, 189, 160, 229, 165, 189]) // "你好" string
    let ddp = DebugDataProvider.wrap(fdp)
    // 将指定长度的数据转换成 String 类型实例
    let str = ddp.consumeString(1)
    return 0
}

运行结果:

[DEBUG] consumeString return 你

func consumeUInt16()

public override func consumeUInt16(): UInt16

功能:将数据转换成 UInt16 类型实例。

注意:

不支持平台:Windows。

返回值:

  • UInt16 - UInt16 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66])
    let ddp = DebugDataProvider.wrap(fdp)
    // 将数据转换成 UInt16 类型实例
    let uint16Val = ddp.consumeUInt16()
    return 0
}

运行结果:

[DEBUG] consumeUInt16 return 16961

func consumeUInt16s(Int64)

public override func consumeUInt16s(count: Int64): Array<UInt16>

功能:将指定数量的数据转换成 UInt16 类型数组。

注意:

不支持平台:Windows。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<UInt16> - UInt16 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68])
    let ddp = DebugDataProvider.wrap(fdp)
    // 将指定数量的数据转换成 UInt16 类型数组
    let uint16s = ddp.consumeUInt16s(2)
    return 0
}

运行结果:

[DEBUG] consumeUInt16s return [16961, 17475]

func consumeUInt32()

public override func consumeUInt32(): UInt32

功能:将数据转换成 UInt32 类型实例。

注意:

不支持平台:Windows。

返回值:

  • UInt32 - UInt32 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68])
    let ddp = DebugDataProvider.wrap(fdp)
    // 将数据转换成 UInt32 类型实例
    let uint32Val = ddp.consumeUInt32()
    return 0
}

运行结果:

[DEBUG] consumeUInt32 return 1145258561

func consumeUInt32s(Int64)

public override func consumeUInt32s(count: Int64): Array<UInt32>

功能:将指定数量的数据转换成 UInt32 类型数组。

注意:

不支持平台:Windows。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<UInt32> - UInt32 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68, 69, 70, 71, 72])
    let ddp = DebugDataProvider.wrap(fdp)
    // 将指定数量的数据转换成 UInt32 类型数组
    let uint32s = ddp.consumeUInt32s(2)
    return 0
}

运行结果:

[DEBUG] consumeUInt32s return [1145258561, 1212630597]

func consumeUInt64()

public override func consumeUInt64(): UInt64

功能:将数据转换成 UInt64 类型实例。

注意:

不支持平台:Windows。

返回值:

  • UInt64 - UInt64 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68, 69, 70, 71, 72])
    let ddp = DebugDataProvider.wrap(fdp)
    // 将数据转换成 UInt64 类型实例
    let uint64Val = ddp.consumeUInt64()
    return 0
}

运行结果:

[DEBUG] consumeUInt64 return 5208208757389214273

func consumeUInt64s(Int64)

public override func consumeUInt64s(count: Int64): Array<UInt64>

功能:将指定数量的数据转换成 UInt64 类型数组。

注意:

不支持平台:Windows。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<UInt64> - UInt64 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80])
    let ddp = DebugDataProvider.wrap(fdp)
    // 将指定数量的数据转换成 UInt64 类型数组
    let uint64s = ddp.consumeUInt64s(2)
    return 0
}

运行结果:

[DEBUG] consumeUInt64s return [5208208757389214273, 5786930140093827657]

func consumeUInt8()

public override func consumeUInt8(): UInt8

功能:将数据转换成 UInt8 类型实例。

注意:

不支持平台:Windows。

返回值:

  • UInt8 - UInt8 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65])
    let ddp = DebugDataProvider.wrap(fdp)
    // 将数据转换成 UInt8 类型实例
    let uint8Val = ddp.consumeUInt8()
    return 0
}

运行结果:

[DEBUG] consumeUInt8 return 65

func consumeUInt8s(Int64)

public override func consumeUInt8s(count: Int64): Array<UInt8>

功能:将指定数量的数据转换成 UInt8 类型数组。

注意:

不支持平台:Windows。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<UInt8> - UInt8 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67])
    let ddp = DebugDataProvider.wrap(fdp)
    // 将指定数量的数据转换成 UInt8 类型数组
    let uint8s = ddp.consumeUInt8s(2)
    return 0
}

运行结果:

[DEBUG] consumeUInt8s return [65, 66]

func wrap(FuzzDataProvider)

public static func wrap(dp: FuzzDataProvider): DebugDataProvider

功能:根据 FuzzDataProvider 实例创建 DebugDataProvider 实例。

注意:

不支持平台:Windows。

参数:

返回值:

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67])

    // 通过FuzzDataProvider创建DebugDataProvider
    let ddp = DebugDataProvider.wrap(fdp)
    // 将指定数量的数据转换成 UInt8 类型数组
    let uint8s = ddp.consumeUInt8s(2)
    return 0
}

运行结果:

[DEBUG] consumeUInt8s return [65, 66]

class FuzzDataProvider

public open class FuzzDataProvider {
    public let data: Array<UInt8>
    public var remainingBytes: Int64
    public var offset: Int64
}

功能:FuzzDataProvider 是一个工具类,目的是将变异数据的字节流转化为标准的仓颉基本数据。

注意:

不支持平台:Windows。

当前支持的数据结构如下:

目标类型API说明
BoolconsumeBool()获取 1 个 Bool,变异数据长度不足时,抛出 ExhaustedException
Array<Bool>consumeBools(count: Int64)获取 N 个 Bool,变异数据长度不足时,抛出 ExhaustedException
ByteconsumeByte()获取 1 个 Byte,变异数据长度不足时,抛出 ExhaustedException
Array<Byte>consumeBytes(count: Int64)获取 N 个 Byte,变异数据长度不足时,抛出 ExhaustedException
UInt8consumeUInt8()获取 1 个 UInt8,变异数据长度不足时,抛出 ExhaustedException
UInt16consumeUInt16()获取 1 个 UInt16,变异数据长度不足时,抛出 ExhaustedException
UInt32consumeUInt32()获取 1 个 UInt32,变异数据长度不足时,抛出 ExhaustedException
UInt64consumeUInt64()获取 1 个 UInt64,变异数据长度不足时,抛出 ExhaustedException
Int8consumeInt8()获取 1 个 Int8,变异数据长度不足时,抛出 ExhaustedException
Int16consumeInt16()获取 1 个 Int16,变异数据长度不足时,抛出 ExhaustedException
Int32consumeInt32()获取 1 个 Int32,变异数据长度不足时,抛出 ExhaustedException
Int64consumeInt64()获取 1 个 Int64,变异数据长度不足时,抛出 ExhaustedException
Float32consumeFloat32()获取 1 个 Float32,变异数据长度不足时,抛出 ExhaustedException
Float64consumeFloat64()获取 1 个 Float64,变异数据长度不足时,抛出 ExhaustedException
Array<UInt8>consumeUInt8s(count: Int64)获取 N 个 UInt8,变异数据长度不足时,抛出 ExhaustedException
Array<UInt16>consumeUInt16s(count: Int64)获取 N 个 UInt16,变异数据长度不足时,抛出 ExhaustedException
Array<UInt32>consumeUInt32s(count: Int64)获取 N 个 UInt32,变异数据长度不足时,抛出 ExhaustedException
Array<UInt64>consumeUInt64s(count: Int64)获取 N 个 UInt64,变异数据长度不足时,抛出 ExhaustedException
Array<Int8>consumeInt8s(count: Int64)获取 N 个 Int8,变异数据长度不足时,抛出 ExhaustedException
Array<Int16>consumeInt16s(count: Int64)获取 N 个 Int16,变异数据长度不足时,抛出 ExhaustedException
Array<Int32>consumeInt32s(count: Int64)获取 N 个 Int32,变异数据长度不足时,抛出 ExhaustedException
Array<Int64>consumeInt64s(count: Int64)获取 N 个 Int64,变异数据长度不足时,抛出 ExhaustedException
RuneconsumeRune()获取 1 个 Rune,变异数据长度不足时,抛出 ExhaustedException
StringconsumeAsciiString(maxLength: Int64)获取 1 个纯 ASCII 的 String,长度为 0 到 maxLength,可以为 0。
StringconsumeString(maxLength: Int64)获取 1 个 UTF8 String,长度为 0 到 maxLength,可以为 0。
Array<UInt8>consumeAll()FuzzDataProvider 中的剩余内容全部转化为字节数组。
StringconsumeAllAsAscii()FuzzDataProvider 中的剩余内容全部转化为纯 ASCII 的 String。
StringconsumeAllAsString()FuzzDataProvider 中的剩余内容全部转化为 UTF8 String,末尾多余的字符不会被消耗。

在数据长度不足时,调用上述大部分虽然会抛出 ExhaustedException,但编写 fuzz 函数时通常并不需要对它进行处理,ExhaustedException 默认会被 fuzz 框架捕获,告诉 libfuzzer 该次运行无效,请继续下一轮变异。随着执行时间的变长,变异数据也会逐渐变长,直到满足 FuzzDataProvider 的需求。

如果达到了 max_len 仍无法满足 FuzzDataProvider 的需求,则进程退出,请修改 fuzz 测试用例(推荐) 或 增大 max_len(不推荐)。

let data

public let data: Array<UInt8>

功能:变异数据。

注意:

不支持平台:Windows。

类型:Array<UInt8>

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let inputData: Array<UInt8> = [65, 66, 67]
    // 使用withCangjieData创建FuzzDataProvider实例
    let fdp = FuzzDataProvider.withCangjieData(inputData)
    println("数据: ${fdp.data}")
    return 0
}

运行结果:

数据: [65, 66, 67]

var offset

public var offset: Int64

功能:已转化的字节数。

注意:

不支持平台:Windows。

类型:Int64

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68, 69, 70, 71, 72])
    // 访问offset属性
    println("当前消耗量: ${fdp.offset}")
    // 消费一些数据后再次查看offset
    let _ = fdp.consumeByte()
    let _ = fdp.consumeByte()
    let _ = fdp.consumeByte()
    println("消费数据后: ${fdp.offset}")
    return 0
}

运行结果:

当前消耗量: 0
消费数据后: 3

var remainingBytes

public var remainingBytes: Int64

功能:剩余字节数。

注意:

不支持平台:Windows。

类型:Int64

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68, 69, 70, 71, 72])
    // 访问remainingBytes属性
    println("当前剩余量: ${fdp.remainingBytes}")
    // 消费一些数据后再次查看remainingBytes
    let _ = fdp.consumeByte()
    let _ = fdp.consumeByte()
    let _ = fdp.consumeByte()
    println("消费数据后: ${fdp.remainingBytes}")
    return 0
}

运行结果:

当前剩余量: 8
消费数据后: 5

static func withCangjieData(Array<UInt8>)

public static func withCangjieData(data: Array<UInt8>): FuzzDataProvider

功能:使用 Array<UInt8> 类型的数据生成 FuzzDataProvider 类型实例。

注意:

不支持平台:Windows。

参数:

  • data: Array<UInt8> - 输入的外部数据。

返回值:

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let inputData: Array<UInt8> = [65, 66, 67, 68, 69, 70]
    // 使用withCangjieData创建FuzzDataProvider实例
    let fdp = FuzzDataProvider.withCangjieData(inputData)
    println("FuzzDataProvider创建成功,数据长度: ${fdp.data.size}")
    return 0
}

运行结果:

FuzzDataProvider创建成功,数据长度: 6

static func withNativeData(CPointer<UInt8>, Int64)

public static unsafe func withNativeData(data: CPointer<UInt8>, length: Int64): FuzzDataProvider

功能:使用 C 指针数据生成 FuzzDataProvider 类型实例。

注意:

不支持平台:Windows。

参数:

  • data: CPointer<UInt8> - 输入的外部数据。
  • length: Int64 - 数据长度。

返回值:

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let arr: Array<UInt8> = [65, 66, 67, 68]
    // 获取CPointerHandle
    let cptrHandle: CPointerHandle<UInt8> = unsafe { acquireArrayRawData(arr) }
    // 获取pointer
    let cptr: CPointer<UInt8> = cptrHandle.pointer

    // 模拟外部数据指针创建FuzzDataProvider实例
    let fdp = unsafe { FuzzDataProvider.withNativeData(cptr, arr.size) }
    println("数据: ${fdp.data}")

    // 释放CPointerHandle
    unsafe { releaseArrayRawData<UInt8>(cptrHandle) }
    return 0
}

运行结果:

数据: [65, 66, 67, 68]

func consumeAll()

public open func consumeAll(): Array<UInt8>

功能:将所有数据转换成 UInt8 类型数组。

注意:

不支持平台:Windows。

返回值:

  • Array<UInt8> - UInt8 类型数组。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68])
    // 将所有数据转换成 UInt8 类型数组
    let allData = fdp.consumeAll()
    println("转换后的UInt8数组: ${allData}")
    return 0
}

运行结果:

转换后的UInt8数组: [65, 66, 67, 68]

func consumeAllAsAscii()

public open func consumeAllAsAscii(): String

功能:将所有数据转换成 Ascii String 类型。

注意:

不支持平台:Windows。

返回值:

  • String - Ascii String 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([72, 101, 108, 108, 111]) // "Hello" in ASCII

    // 将所有数据转换成 Ascii String 类型
    let asciiStr = fdp.consumeAllAsAscii()
    println("转换后的Ascii字符串: ${asciiStr}")
    return 0
}

运行结果:

转换后的Ascii字符串: Hello

func consumeAllAsString()

public open func consumeAllAsString(): String

功能:将所有数据转换成 utf8 String 类型。

注意:

不支持平台:Windows。

返回值:

  • String - utf8 String 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([72, 101, 108, 108, 111]) // "Hello" in ASCII

    // 将所有数据转换成 utf8 String 类型
    let utf8Str = fdp.consumeAllAsString()
    println("转换后的utf8字符串: ${utf8Str}")
    return 0
}

运行结果:

转换后的utf8字符串: Hello

func consumeAsciiString(Int64)

public open func consumeAsciiString(maxLength: Int64): String

功能:将数据转换成 Ascii String 类型实例。

注意:

不支持平台:Windows。

参数:

  • maxLength: Int64 - String 类型的最大长度。

返回值:

  • String - String 类型实例。

异常:

  • IllegalArgumentException - 如果 maxLength 为负数,则抛出异常。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([72, 101, 108, 108, 111]) // "Hello" in ASCII

    // 将数据转换成 Ascii String 类型实例,最大长度为3
    let asciiStr = fdp.consumeAsciiString(3)
    println("转换后的Ascii字符串: ${asciiStr}")
    return 0
}

运行结果:

转换后的Ascii字符串: Hel

func consumeBool()

public open func consumeBool(): Bool

功能:将数据转换成 Bool 类型实例。

注意:

不支持平台:Windows。

返回值:

  • Bool - Bool 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65])
    // 将数据转换成 Bool 类型实例
    let boolVal = fdp.consumeBool()
    println("转换后的Bool值: ${boolVal}")
    return 0
}

运行结果:

转换后的Bool值: true

func consumeBools(Int64)

public open func consumeBools(count: Int64): Array<Bool>

功能:将指定数量的数据转换成 Bool 类型数组。

注意:

不支持平台:Windows。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<Bool> - Bool 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67])
    // 将指定数量的数据转换成 Bool 类型数组
    let bools = fdp.consumeBools(3)
    println("转换后的Bool数组: ${bools}")
    return 0
}

运行结果:

转换后的Bool数组: [true, false, true]

func consumeByte()

public open func consumeByte(): Byte

功能:将数据转换成 Byte 类型实例。

注意:

不支持平台:Windows。

返回值:

  • Byte - Byte 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66])
    // 将数据转换成 Byte 类型实例
    let byteVal = fdp.consumeByte()
    println("转换后的Byte值: ${byteVal}")
    return 0
}

运行结果:

转换后的Byte值: 65

func consumeBytes(Int64)

public open func consumeBytes(count: Int64): Array<Byte>

功能:将指定数量的数据转换成 Byte 类型数组。

注意:

不支持平台:Windows。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<Byte> - Byte 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67])
    // 将指定数量的数据转换成 Byte 类型数组
    let bytes = fdp.consumeBytes(2)
    println("转换后的Byte数组: ${bytes}")
    return 0
}

运行结果:

转换后的Byte数组: [65, 66]

func consumeFloat32()

public open func consumeFloat32(): Float32

功能:将数据转换成 Float32 类型实例。

注意:

不支持平台:Windows。

返回值:

  • Float32 - Float32 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68])
    // 将数据转换成 Float32 类型实例
    let float32Val = fdp.consumeFloat32()
    println("转换后的Float32值: ${float32Val}")
    return 0
}

运行结果:

转换后的Float32值: 781.035217

func consumeFloat64()

public open func consumeFloat64(): Float64

功能:将数据转换成 Float64 类型实例。

注意:

不支持平台:Windows。

返回值:

  • Float64 - Float64 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68, 69, 70, 71, 72])
    // 将数据转换成 Float64 类型实例
    let float64Val = fdp.consumeFloat64()
    println("转换后的Float64值: ${float64Val}")
    return 0
}

运行结果:

转换后的Float64值: 15839800103804824402926068484019465486336.000000

func consumeInt16()

public open func consumeInt16(): Int16

功能:将数据转换成 Int16 类型实例。

注意:

不支持平台:Windows。

返回值:

  • Int16 - Int16 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66])
    // 将数据转换成 Int16 类型实例
    let int16Val = fdp.consumeInt16()
    println("转换后的Int16值: ${int16Val}")
    return 0
}

运行结果:

转换后的Int16值: 16961

func consumeInt16s(Int64)

public open func consumeInt16s(count: Int64): Array<Int16>

功能:将指定数量的数据转换成 Int16 类型数组。

注意:

不支持平台:Windows。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<Int16> - Int16 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68, 69, 70])
    // 将指定数量的数据转换成 Int16 类型数组
    let int16s = fdp.consumeInt16s(2)
    println("Int16数组: ${int16s}")
    return 0
}

运行结果:

Int16数组: [16961, 17475]

func consumeInt32()

public open func consumeInt32(): Int32

功能:将数据转换成 Int32 类型实例。

注意:

不支持平台:Windows。

返回值:

  • Int32 - Int32 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68])
    // 将数据转换成 Int32 类型实例
    let int32Val = fdp.consumeInt32()
    println("转换后的Int32值: ${int32Val}")
    return 0
}

运行结果:

转换后的Int32值: 1145258561

func consumeInt32s(Int64)

public open func consumeInt32s(count: Int64): Array<Int32>

功能:将指定数量的数据转换成 Int32 类型数组。

注意:

不支持平台:Windows。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<Int32> - Int32 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68, 69, 70, 71, 72, 73, 74])
    // 将指定数量的数据转换成 Int32 类型数组
    let int32s = fdp.consumeInt32s(2)
    println("转换后的Int32数组: ${int32s}")
    return 0
}

运行结果:

转换后的Int32数组: [1145258561, 1212630597]

func consumeInt64()

public open func consumeInt64(): Int64

功能:将数据转换成 Int64 类型实例。

注意:

不支持平台:Windows。

返回值:

  • Int64 - Int64 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68, 65, 66, 67, 68])
    // 将数据转换成 Int64 类型实例
    let int64Val = fdp.consumeInt64()
    println("转换后的Int64值: ${int64Val}")
    return 0
}

运行结果:

转换后的Int64值: 4918848066104279617

func consumeInt64s(Int64)

public open func consumeInt64s(count: Int64): Array<Int64>

功能:将指定数量的数据转换成 Int64 类型数组。

注意:

不支持平台:Windows。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<Int64> - Int64 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68, 65, 66, 67, 68, 65, 66, 67, 68, 65, 66, 67, 68])
    // 将指定数量的数据转换成 Int64 类型数组
    let int64s = fdp.consumeInt64s(2)
    println("转换后的Int64数组: ${int64s}")
    return 0
}

运行结果:

转换后的Int64数组: [4918848066104279617, 4918848066104279617]

func consumeInt8()

public open func consumeInt8(): Int8

功能:将数据转换成 Int8 类型实例。

注意:

不支持平台:Windows。

返回值:

  • Int8 - Int8 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65])
    // 将数据转换成 Int8 类型实例
    let int8Val = fdp.consumeInt8()
    println("转换后的Int8值: ${int8Val}")
    return 0
}

运行结果:

转换后的Int8值: 65

func consumeInt8s(Int64)

public open func consumeInt8s(count: Int64): Array<Int8>

功能:将指定数量的数据转换成 Int8 类型数组。

注意:

不支持平台:Windows。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<Int8> - Int8 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67])
    // 将指定数量的数据转换成 Int8 类型数组
    let int8s = fdp.consumeInt8s(2)
    println("转换后的Int8数组: ${int8s}")
    return 0
}

运行结果:

转换后的Int8数组: [65, 66]

func consumeRune()

public open func consumeRune(): Rune

功能:将数据转换成 Rune 类型实例。

注意:

不支持平台:Windows。

返回值:

  • Rune - Rune 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([72, 101, 108, 108, 111]) // "Hello" string

    // 将数据转换成 Rune 类型实例
    let runeVal = fdp.consumeRune()
    println("转换后的Rune值: ${runeVal}")
    return 0
}

运行结果:

转换后的Rune值: 󆕈

func consumeString(Int64)

public open func consumeString(maxLength: Int64): String

功能:将数据转换成 utf8 String 类型实例。

注意:

不支持平台:Windows。

参数:

  • maxLength: Int64 - String 类型的最大长度。

返回值:

  • String - String 类型实例。

异常:

  • IllegalArgumentException - 如果 maxLength 为负数,则抛出异常。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([228, 189, 160, 229, 165, 189]) // "你好" string

    // 将指定长度的数据转换成 String 类型实例
    let str = fdp.consumeString(1)
    println("转换后的String值: ${str}")
    return 0
}

运行结果:

转换后的String值: 你

func consumeUInt16()

public open func consumeUInt16(): UInt16

功能:将数据转换成 UInt16 类型实例。

注意:

不支持平台:Windows。

返回值:

  • UInt16 - UInt16 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66])
    // 将数据转换成 UInt16 类型实例
    let uint16Val = fdp.consumeUInt16()
    println("转换后的UInt16值: ${uint16Val}")
    return 0
}

运行结果:

转换后的UInt16值: 16961

func consumeUInt16s(Int64)

public open func consumeUInt16s(count: Int64): Array<UInt16>

功能:将指定数量的数据转换成 UInt16 类型数组。

注意:

不支持平台:Windows。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<UInt16> - UInt16 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68])
    // 将指定数量的数据转换成 UInt16 类型数组
    let uint16s = fdp.consumeUInt16s(2)
    println("转换后的UInt16数组: ${uint16s}")
    return 0
}

运行结果:

转换后的UInt16数组: [16961, 17475]

func consumeUInt32()

public open func consumeUInt32(): UInt32

功能:将数据转换成 UInt32 类型实例。

注意:

不支持平台:Windows。

返回值:

  • UInt32 - UInt32 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68])
    // 将数据转换成 UInt32 类型实例
    let uint32Val = fdp.consumeUInt32()
    println("转换后的UInt32值: ${uint32Val}")
    return 0
}

运行结果:

转换后的UInt32值: 1145258561

func consumeUInt32s(Int64)

public open func consumeUInt32s(count: Int64): Array<UInt32>

功能:将指定数量的数据转换成 UInt32 类型数组。

注意:

不支持平台:Windows。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<UInt32> - UInt32 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68, 69, 70, 71, 72])
    // 将指定数量的数据转换成 UInt32 类型数组
    let uint32s = fdp.consumeUInt32s(2)
    println("转换后的UInt32数组: ${uint32s}")
    return 0
}

运行结果:

转换后的UInt32数组: [1145258561, 1212630597]

func consumeUInt64()

public open func consumeUInt64(): UInt64

功能:将数据转换成 UInt64 类型实例。

注意:

不支持平台:Windows。

返回值:

  • UInt64 - UInt64 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68, 69, 70, 71, 72])
    // 将数据转换成 UInt64 类型实例
    let uint64Val = fdp.consumeUInt64()
    println("转换后的UInt64值: ${uint64Val}")
    return 0
}

运行结果:

转换后的UInt64值: 5208208757389214273

func consumeUInt64s(Int64)

public open func consumeUInt64s(count: Int64): Array<UInt64>

功能:将指定数量的数据转换成 UInt64 类型数组。

注意:

不支持平台:Windows。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<UInt64> - UInt64 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80])
    // 将指定数量的数据转换成 UInt64 类型数组
    let uint64s = fdp.consumeUInt64s(2)
    println("转换后的UInt64数组: ${uint64s}")
    return 0
}

运行结果:

转换后的UInt64数组: [5208208757389214273, 5786930140093827657]

func consumeUInt8()

public open func consumeUInt8(): UInt8

功能:将数据转换成 UInt8 类型实例。

注意:

不支持平台:Windows。

返回值:

  • UInt8 - UInt8 类型实例。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65])
    // 将数据转换成 UInt8 类型实例
    let uint8Val = fdp.consumeUInt8()
    println("转换后的UInt8值: ${uint8Val}")
    return 0
}

运行结果:

转换后的UInt8值: 65

func consumeUInt8s(Int64)

public open func consumeUInt8s(count: Int64): Array<UInt8>

功能:将指定数量的数据转换成 UInt8 类型数组。

注意:

不支持平台:Windows。

参数:

  • count: Int64 - 指定转换的数据量。

返回值:

  • Array<UInt8> - UInt8 类型数组。

异常:

  • IllegalArgumentException - 如果 count 为负数,则抛出异常。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 通过手动传入数据创建FuzzDataProvider(真实模糊测试自动、持续生成海量随机初始数据)
    let fdp = FuzzDataProvider.withCangjieData([65, 66, 67])
    // 将指定数量的数据转换成 UInt8 类型数组
    let uint8s = fdp.consumeUInt8s(2)
    println("转换后的UInt8数组: ${uint8s}")
    return 0
}

运行结果:

转换后的UInt8数组: [65, 66]

class Fuzzer

public class Fuzzer {
    public init(targetFunction: (Array<UInt8>) -> Int32)
    public init(targetFunction: (Array<UInt8>) -> Int32, args: Array<String>)
    public init(targetFunction: (FuzzDataProvider) -> Int32)
    public init(targetFunction: (FuzzDataProvider) -> Int32, args: Array<String>)
}

功能:Fuzzer 类提供了 fuzz 工具的创建。用户提供需要进行 fuzz 测试的函数 targetFunction,以及设置特定的 fuzz 运行参数 args 比如 fuzz 执行次数、初始种子、生成数据最大长度等,可创建相应类型的 Fuzzer

注意:

不支持平台:Windows。

init((Array<UInt8>) -> Int32)

public init(targetFunction: (Array<UInt8>) -> Int32)

功能:根据以 UInt8 数组为参数,以 Int32 为返回值的目标函数,创建 Fuzzer 实例。

注意:

不支持平台:Windows。

参数:

  • targetFunction: (Array<UInt8>) ->Int32 - 以 UInt8 数组为参数,以 Int32 为返回值的目标函数。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 创建Fuzzer
    let fuzzer = Fuzzer(testApi)

    // 启动Fuzz,解除注释有临时文件和输出
    // fuzzer.startFuzz()
    return 0
}

// 被测函数,在满足特定条件会抛出异常,该异常会被 Fuzzer 捕获
public func testApi(data: Array<UInt8>): Int32 {
    if (data.size == 8 && data[0] == b'C' && data[1] == b'a' && data[2] == b'n' && data[3] == b'g' && data[4] == b'j' &&
        data[5] == b'i' && data[6] == b'e' && data[7] == b'!') {
        throw Exception("TRAP")
    }
    return 0
}

init((Array<UInt8>) -> Int32, Array<String>)

public init(targetFunction: (Array<UInt8>) -> Int32, args: Array<String>)

功能:根据以 UInt8 数组为参数,以 Int32 为返回值的目标函数,以及 Fuzz 运行参数,创建 Fuzzer 实例。

注意:

不支持平台:Windows。

参数:

  • targetFunction: (Array<UInt8>) ->Int32 - 以 UInt8 数组为参数,以 Int32 为返回值的目标函数。
  • args: Array<String> - Fuzz 运行参数。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 此示例因为有运行参数的原因而输出帮助信息
    let fuzzer = Fuzzer(testApi, ["-help=1"])
    fuzzer.startFuzz()
    return 0
}

public func testApi(data: Array<UInt8>): Int32 {
    throw Exception("TRAP")
    return 0
}

init((FuzzDataProvider) -> Int32)

public init(targetFunction: (FuzzDataProvider) -> Int32)

功能:根据以 FuzzDataProvider 为参数,以 Int32 为返回值的目标函数,创建 Fuzzer 实例。

注意:

不支持平台:Windows。

参数:

示例:

import stdx.fuzz.fuzz.*

main() {
    // 创建Fuzzer
    let fuzzer = Fuzzer(testApi)

    // 启动Fuzz,解除注释有临时文件和输出
    // fuzzer.startFuzz()
    return 0
}

public func testApi(dp: FuzzDataProvider): Int32 {
    if (dp.consumeBool() && dp.consumeByte() == b'A' && dp.consumeUInt32() == 0xdeadbeef) {
        throw Exception("TRAP")
    }
    return 0
}

init((FuzzDataProvider) -> Int32, Array<String>)

public init(targetFunction: (FuzzDataProvider) -> Int32, args: Array<String>)

功能:根据以 FuzzDataProvider 为参数,以 Int32 为返回值的目标函数,以及 Fuzz 运行参数,创建 Fuzzer 实例。

注意:

不支持平台:Windows。

参数:

  • targetFunction: (FuzzDataProvider) ->Int32 - 以 FuzzDataProvider 为参数,以 Int32 为返回值的目标函数。
  • args: Array<String> - Fuzz 运行参数。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 此示例因为有运行参数的原因而输出帮助信息
    let fuzzer = Fuzzer(testApi, ["-help=1"])
    fuzzer.startFuzz()
    return 0
}

public func testApi(dp: FuzzDataProvider): Int32 {
    throw Exception("TRAP")
    return 0
}

func disableDebugDataProvider()

public func disableDebugDataProvider(): Unit

功能:关闭调试信息打印功能,当 FuzzDataProvider.consumeXXX 被调用时,返回值将不被打印到 stdout

注意:

不支持平台:Windows。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 创建Fuzzer
    let fuzzer = Fuzzer(testApi)

    // 关闭调试信息打印功能
    fuzzer.disableDebugDataProvider()

    // 启动Fuzz,解除注释有临时文件和输出
    // fuzzer.startFuzz()
    return 0
}

public func testApi(dp: FuzzDataProvider): Int32 {
    if (dp.consumeBool() && dp.consumeByte() == b'A' && dp.consumeUInt32() == 0xdeadbeef) {
        throw Exception("TRAP")
    }
    return 0
}

func disableFakeCoverage()

public func disableFakeCoverage(): Unit

功能:关闭调用 enableFakeCoverage 对 Fuzz 的影响。

注意:

不支持平台:Windows。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 创建Fuzzer
    let fuzzer = Fuzzer(testApi)

    // 关闭调用 `enableFakeCoverage` 对 Fuzz 的影响
    fuzzer.disableFakeCoverage()

    // 启动Fuzz,解除注释有临时文件和输出
    // fuzzer.startFuzz()
    return 0
}

public func testApi(dp: FuzzDataProvider): Int32 {
    if (dp.consumeBool() && dp.consumeByte() == b'A' && dp.consumeUInt32() == 0xdeadbeef) {
        throw Exception("TRAP")
    }
    return 0
}

func enableDebugDataProvider()

public func enableDebugDataProvider(): Unit

功能:启用调试信息打印功能,当 FuzzDataProvider.consumeXXX 被调用时,返回值将被打印到 stdout。该功能默认为关闭。

注意:

不支持平台:Windows。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 创建Fuzzer
    let fuzzer = Fuzzer(testApi)

    // 启用调试信息打印功能
    fuzzer.enableDebugDataProvider()

    // 启动Fuzz,解除注释有临时文件和输出
    // fuzzer.startFuzz()
    return 0
}

public func testApi(dp: FuzzDataProvider): Int32 {
    if (dp.consumeBool() && dp.consumeByte() == b'A' && dp.consumeUInt32() == 0xdeadbeef) {
        throw Exception("TRAP")
    }
    return 0
}

func enableFakeCoverage()

public func enableFakeCoverage(): Unit

功能:创建一块虚假的覆盖率反馈区域,保持 Fuzz 持续进行。在 FuzzDataProvider 模式下,前几轮运行时可能由于数据不足而导致没有覆盖率,libfuzzer 会退出。该功能默认为关闭。

注意:

不支持平台:Windows。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 创建Fuzzer
    let fuzzer = Fuzzer(testApi)

    fuzzer.enableFakeCoverage()

    // 启动Fuzz,解除注释有临时文件和输出
    // fuzzer.startFuzz()
    return 0
}

public func testApi(dp: FuzzDataProvider): Int32 {
    if (dp.consumeBool() && dp.consumeByte() == b'A' && dp.consumeUInt32() == 0xdeadbeef) {
        throw Exception("TRAP")
    }
    return 0
}

func getArgs()

public func getArgs(): Array<String>

功能:获取 Fuzz 运行参数。

注意:

不支持平台:Windows。

返回值:

  • Array<String> - 当前 Fuzz 运行参数。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 创建有运行参数的Fuzzer
    let fuzzer = Fuzzer(testApi, ["-help=1"])

    // 获取运行参数
    let args = fuzzer.getArgs()

    println("运行参数: ${args}")
    return 0
}

public func testApi(data: Array<UInt8>): Int32 {
    throw Exception("TRAP")
    return 0
}

运行结果:

运行参数: [-help=1]

func setArgs(Array<String>)

public func setArgs(args: Array<String>): Unit

功能:设置 Fuzz 运行参数。

注意:

不支持平台:Windows。

参数:

  • args: Array<String> - Fuzz 运行参数。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 创建Fuzzer
    let fuzzer = Fuzzer(testApi)

    // 设置运行参数
    fuzzer.setArgs(["-help=1"])

    // 获取运行参数
    let args = fuzzer.getArgs()

    println("运行参数: ${args}")
    return 0
}

public func testApi(data: Array<UInt8>): Int32 {
    throw Exception("TRAP")
    return 0
}

运行结果:

运行参数: [-help=1]

func setTargetFunction((Array<UInt8>) -> Int32)

public func setTargetFunction(targetFunction: (Array<UInt8>) -> Int32): Unit

功能:设置 Fuzz 目标函数。

注意:

不支持平台:Windows。

参数:

  • targetFunction: (Array<UInt8>) ->Int32 - 以 UInt8 数组为参数,以 Int32 为返回值的目标函数。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 创建Fuzzer
    let fuzzer = Fuzzer(testApi)

    // 设置被测函数,原本的 testApi 函数将被 testApi1 替代
    fuzzer.setTargetFunction(testApi1)

    // 启动Fuzz,解除注释有临时文件和输出
    // fuzzer.startFuzz()
    return 0
}

// 被测函数,在满足特定条件会抛出异常,该异常会被 Fuzzer 捕获
public func testApi(dp: FuzzDataProvider): Int32 {
    if (dp.consumeBool() && dp.consumeByte() == b'A' && dp.consumeUInt32() == 0xdeadbeef) {
        throw Exception("TRAP")
    }
    return 0
}

// 被测函数,在满足特定条件会抛出异常,该异常会被 Fuzzer 捕获
public func testApi1(data: Array<UInt8>): Int32 {
    if (data.size == 8 && data[0] == b'C' && data[1] == b'a' && data[2] == b'n' && data[3] == b'g' && data[4] == b'j' &&
        data[5] == b'i' && data[6] == b'e' && data[7] == b'!') {
        throw Exception("TRAP")
    }
    return 0
}

func setTargetFunction((FuzzDataProvider) -> Int32)

public func setTargetFunction(targetFunction: (FuzzDataProvider) -> Int32): Unit

功能:设置 Fuzz 目标函数。

注意:

不支持平台:Windows。

参数:

示例:

import stdx.fuzz.fuzz.*

main() {
    // 创建Fuzzer
    let fuzzer = Fuzzer(testApi)

    // 设置被测函数,原本的 testApi 函数将被 testApi1 替代
    fuzzer.setTargetFunction(testApi1)

    // 启动Fuzz,解除注释有临时文件和输出
    // fuzzer.startFuzz()
    return 0
}

// 被测函数,在满足特定条件会抛出异常,该异常会被 Fuzzer 捕获
public func testApi(data: Array<UInt8>): Int32 {
    if (data.size == 8 && data[0] == b'C' && data[1] == b'a' && data[2] == b'n' && data[3] == b'g' && data[4] == b'j' &&
        data[5] == b'i' && data[6] == b'e' && data[7] == b'!') {
        throw Exception("TRAP")
    }
    return 0
}

// 被测函数,在满足特定条件会抛出异常,该异常会被 Fuzzer 捕获
public func testApi1(dp: FuzzDataProvider): Int32 {
    if (dp.consumeBool() && dp.consumeByte() == b'A' && dp.consumeUInt32() == 0xdeadbeef) {
        throw Exception("TRAP")
    }
    return 0
}

func startFuzz()

public func startFuzz(): Unit

功能:执行 Fuzz。

注意:

不支持平台:Windows。

示例:

import stdx.fuzz.fuzz.*

main() {
    // 创建Fuzzer
    let fuzzer = Fuzzer(testApi)

    // 启动Fuzz,解除注释有临时文件和输出
    // fuzzer.startFuzz()
    return 0
}

// 被测函数,在满足特定条件会抛出异常,该异常会被 Fuzzer 捕获
public func testApi(data: Array<UInt8>): Int32 {
    if (data.size == 8 && data[0] == b'C' && data[1] == b'a' && data[2] == b'n' && data[3] == b'g' && data[4] == b'j' &&
        data[5] == b'i' && data[6] == b'e' && data[7] == b'!') {
        throw Exception("TRAP")
    }
    return 0
}

class FuzzerBuilder

public class FuzzerBuilder {
    public init(targetFunction: (Array<UInt8>) -> Int32)
    public init(targetFunction: (FuzzDataProvider) -> Int32)
}

功能:此类用于 Fuzzer 类的构建。

注意:

不支持平台:Windows。

init((Array<UInt8>) -> Int32)

public init(targetFunction: (Array<UInt8>) -> Int32)

功能:根据以 UInt8 数组为参数,以 Int32 为返回值的目标函数,创建 FuzzerBuilder 实例。

注意:

不支持平台:Windows。

参数:

  • targetFunction: (Array<UInt8>) ->Int32 - 以 UInt8 数组为参数,以 Int32 为返回值的目标函数。

示例:

import stdx.fuzz.fuzz.*

func myFuzzFunction(data: Array<UInt8>): Int32 {
    // 简单的模糊测试函数,检查数据长度
    if (data.size > 3) {
        println("数据长度大于3")
        return 0
    }
    return -1
}

main() {
    // 使用以UInt8数组为目标函数的FuzzerBuilder
    let builder = FuzzerBuilder(myFuzzFunction)
    println("FuzzerBuilder创建成功")
    return 0
}

运行结果:

FuzzerBuilder创建成功

init((FuzzDataProvider) -> Int32)

public init(targetFunction: (FuzzDataProvider) -> Int32)

功能:根据以 FuzzDataProvider 为参数,以 Int32 为返回值的目标函数,创建 FuzzerBuilder 实例。

注意:

不支持平台:Windows。

参数:

示例:

import stdx.fuzz.fuzz.*

func myFuzzFunctionWithProvider(fdp: FuzzDataProvider): Int32 {
    // 使用FuzzDataProvider的简单模糊测试函数
    try {
        let byte = fdp.consumeByte()
        println("消耗了一个字节: ${byte}")
        return 0
    } catch (ex: ExhaustedException) {
        println("数据耗尽")
        return -1
    }
}

main() {
    // 使用以FuzzDataProvider为目标函数的FuzzerBuilder
    let builder = FuzzerBuilder(myFuzzFunctionWithProvider)
    println("FuzzerBuilder创建成功")
    return 0
}

运行结果:

FuzzerBuilder创建成功

func build()

public func build(): Fuzzer

功能:生成一个 Fuzzer 实例。

注意:

不支持平台:Windows。

返回值:

示例:

import stdx.fuzz.fuzz.*

func myFuzzFunction(data: Array<UInt8>): Int32 {
    // 简单的模糊测试函数
    if (data.size >= 1) {
        let value = data[0]
        println("第一个字节值: ${value}")
        return 0
    }
    return -1
}

main() {
    // 创建FuzzerBuilder并构建Fuzzer实例
    let builder = FuzzerBuilder(myFuzzFunction)
    let fuzzer = builder.build()
    println("Fuzzer构建成功")
    return 0
}

运行结果:

Fuzzer构建成功

func setArgs(Array<String>)

public func setArgs(args: Array<String>): FuzzerBuilder

功能:设置 Fuzz 运行参数。

注意:

不支持平台:Windows。

参数:

  • args: Array<String> - Fuzz 运行参数。

返回值:

示例:

import stdx.fuzz.fuzz.*

func myFuzzFunction(data: Array<UInt8>): Int32 {
    // 简单的模糊测试函数
    return 0
}

main() {
    // 创建FuzzerBuilder并设置参数
    let builder = FuzzerBuilder(myFuzzFunction)
    let args = ["-max_len=1024", "-timeout=10"]
    builder.setArgs(args)
    return 0
}

func setTargetFunction((Array<UInt8>) -> Int32)

public func setTargetFunction(targetFunction: (Array<UInt8>) -> Int32): FuzzerBuilder

功能:设置 Fuzz 目标函数。

注意:

不支持平台:Windows。

参数:

  • targetFunction: (Array<UInt8>) ->Int32 - 以 UInt8 数组为参数,以 Int32 为返回值的目标函数。

返回值:

示例:

import stdx.fuzz.fuzz.*

func myFirstFuzzFunction(data: Array<UInt8>): Int32 {
    // 第一个模糊测试函数
    return 0
}

func mySecondFuzzFunction(data: Array<UInt8>): Int32 {
    // 第二个模糊测试函数
    if (data.size > 5) {
        return 1
    }
    return 0
}

main() {
    // 创建FuzzerBuilder并设置目标函数
    let builder = FuzzerBuilder(myFirstFuzzFunction)
    let updatedBuilder = builder.setTargetFunction(mySecondFuzzFunction)
    println("目标函数更新成功")
    return 0
}

运行结果:

目标函数更新成功

func setTargetFunction((FuzzDataProvider) -> Int32)

public func setTargetFunction(targetFunction: (FuzzDataProvider) -> Int32): FuzzerBuilder

功能:设置 Fuzz 目标函数。

注意:

不支持平台:Windows。

参数:

返回值:

示例:

import stdx.fuzz.fuzz.*

func myFirstFuzzFunctionWithProvider(fdp: FuzzDataProvider): Int32 {
    // 第一个使用FuzzDataProvider的模糊测试函数
    return 0
}

func mySecondFuzzFunctionWithProvider(fdp: FuzzDataProvider): Int32 {
    // 第二个使用FuzzDataProvider的模糊测试函数
    try {
        let intVal = fdp.consumeInt32()
        println("消耗了一个Int32值: ${intVal}")
        return 0
    } catch (ex: ExhaustedException) {
        println("数据耗尽")
        return -1
    }
}

main() {
    // 创建FuzzerBuilder并设置FuzzDataProvider目标函数
    let builder = FuzzerBuilder(myFirstFuzzFunctionWithProvider)
    let updatedBuilder = builder.setTargetFunction(mySecondFuzzFunctionWithProvider)
    println("FuzzDataProvider目标函数更新成功")
    return 0
}

运行结果:

FuzzDataProvider目标函数更新成功

异常类

class ExhaustedException

public class ExhaustedException <: Exception {
    public init()
    public init(message: String)
}

功能:此异常为转换数据时,剩余数据不足以转换时抛出的异常。

注意:

不支持平台:Windows。

父类型:

  • Exception

init()

public init()

功能:创建 ExhaustedException 实例。

注意:

不支持平台:Windows。

示例:

import stdx.fuzz.fuzz.*

main(): Unit {
    try {
        throw ExhaustedException()
    } catch (e: ExhaustedException) {
        println("捕获到无参构造的 ExhaustedException: ${e.message}")
    }
}

运行结果:

捕获到无参构造的 ExhaustedException:

init(String)

public init(message: String)

功能:创建 ExhaustedException 实例。

注意:

不支持平台:Windows。

参数:

  • message: String - 异常提示信息。

示例:

import stdx.fuzz.fuzz.*

main(): Unit {
    try {
        throw ExhaustedException("剩余数据不足")
    } catch (e: ExhaustedException) {
        println("捕获到 ExhaustedException: ${e.message}")
    }
}

运行结果:

捕获到 ExhaustedException: 剩余数据不足

测试猜测字符功能

  • 编写被测 API,当且仅当输入数组长度是 8、内容是 "Cangjie!" 对应的 ASCII 时抛出异常,纯随机的情况下最差需要 264 次猜测才会触发异常。
  • 创建 Fuzzer 并且调用待测 API,进入主流程。
// 导入依赖的类
import stdx.fuzz.fuzz.Fuzzer

main() {
    // 创建 Fuzzer 并启动 fuzz 流程
    Fuzzer(api).startFuzz()
    return 0
}

// 被测函数,在满足特定条件会抛出异常,该异常会被 Fuzzer 捕获
public func api(data: Array<UInt8>): Int32 {
    if (data.size == 8 && data[0] == b'C' && data[1] == b'a' && data[2] == b'n' && data[3] == b'g' && data[4] == b'j' &&
        data[5] == b'i' && data[6] == b'e' && data[7] == b'!') {
        throw Exception("TRAP")
    }
    return 0
}

下方的命令中的 CANGJIE_STDX_PATH 指向存放 stdx 系列的路径,例如 "./static/stdx"

Linux 的编译命令是:cjc fuzz_main.cj -L $CANGJIE_STDX_PATH -lstdx.fuzz.fuzz --import-path $CANGJIE_STDX_PATH --link-options="--whole-archive $CANGJIE_HOME/lib/linux_x86_64_cjnative/libclang_rt.fuzzer_no_main.a -no-whole-archive -lstdc++" --sanitizer-coverage-inline-8bit-counters -lpthread

macOS 的编译命令是:cjc fuzz_main.cj -L $CANGJIE_STDX_PATH -lstdx.fuzz.fuzz --import-path $CANGJIE_STDX_PATH --link-options="$CANGJIE_HOME/lib/linux_x86_64_cjnative/libclang_rt.fuzzer_no_main.a -lc++" --sanitizer-coverage-inline-8bit-counters -lpthread

释义:

  • link-options 是链接时选项,fuzz 库本身依赖符号 LLVMFuzzerRunDriver,该符号需要开发者自行解决。
    • 仓颉语言在 $CANGJIE_HOME/lib/linux_x86_64_cjnative/libclang_rt.fuzzer_no_main.a 存放一份 修改过 的 libfuzzer,对标准的 libfuzzer 进行了增强,见 实验性特性-覆盖率信息打印
    • 可以使用 find $(clang -print-runtime-dir) -name "libclang_rt.fuzzer_no_main*.a" 寻找本地安装好的静态库文件。
  • 向 Linux 编译需要使用 whole-archive libfuzzer.a 是因为 cjc 调用 ld 后端时,从左到右顺序是 libfuzzer.alibcangjie-fuzz-fuzz.a、 libc 等基础库,该顺序会导致 libcangjie-fuzz-fuzz.a 依赖的 LLVMFuzzerRunDriver 符号未被找到。解决方案有:
    • libfuzzer.a 放到 libcangjie-fuzz-fuzz.a 后面;
    • 使用 whole-archive libfuzzer.a 来规避符号找不到的问题。
  • -lstdc++ (Linux) / -lc++ (macOS) 用于链接 libfuzzer 依赖的 std 库。
  • --sanitizer-coverage-inline-8bit-counterscjc 的编译选项,它会对当前 package 执行覆盖率反馈插桩,详见 cjc 编译器使用手册。
    • 其他高级的参数有:--sanitizer-coverage-trace-compares(提高 Fuzz 变异的效率)、--sanitizer-coverage-pc-table(Fuzz 结束后打印覆盖率信息)。

注意:

如果您使用的 Linux 系统版本较低,可能出现 GLIBC 版本过低的链接器报错,请在 link-options 参数中添加 -lpthread 来解决此问题。

libfuzzer 体验类似,可以直接运行,数秒后(取决于 CPU 性能)可获得 crash,且输入的数据是 "Cangjie!"

运行结果如下:

$ ./main
INFO: Seed: 246468919
INFO: Loaded 1 modules   (15 inline 8-bit counters): 15 [0x55bb7c76dcb0, 0x55bb7c76dcbf),
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: A corpus is not provided, starting from an empty corpus
#2      INITED ft: 4 corp: 1/1b exec/s: 0 rss: 28Mb
#420    NEW    ft: 5 corp: 2/9b lim: 8 exec/s: 0 rss: 28Mb L: 8/8 MS: 3 CrossOver-InsertByte-InsertRepeatedBytes-
#1323   NEW    ft: 6 corp: 3/17b lim: 14 exec/s: 0 rss: 28Mb L: 8/8 MS: 3 InsertByte-InsertByte-CrossOver-
#131072 pulse  ft: 6 corp: 3/17b lim: 1300 exec/s: 65536 rss: 35Mb
#262144 pulse  ft: 6 corp: 3/17b lim: 2600 exec/s: 65536 rss: 41Mb
#295225 NEW    ft: 7 corp: 4/25b lim: 2930 exec/s: 73806 rss: 43Mb L: 8/8 MS: 2 ShuffleBytes-ChangeByte-
#514006 NEW    ft: 8 corp: 5/33b lim: 4096 exec/s: 73429 rss: 53Mb L: 8/8 MS: 1 ChangeByte-
#524288 pulse  ft: 8 corp: 5/33b lim: 4096 exec/s: 74898 rss: 53Mb
#1048576        pulse  ft: 8 corp: 5/33b lim: 4096 exec/s: 61680 rss: 78Mb
#1064377        NEW    ft: 9 corp: 6/41b lim: 4096 exec/s: 62610 rss: 79Mb L: 8/8 MS: 1 ChangeByte-
#1287268        NEW    ft: 10 corp: 7/49b lim: 4096 exec/s: 61298 rss: 90Mb L: 8/8 MS: 1 ChangeByte-
#2097152        pulse  ft: 10 corp: 7/49b lim: 4096 exec/s: 59918 rss: 128Mb
#2875430        NEW    ft: 11 corp: 8/57b lim: 4096 exec/s: 61179 rss: 165Mb L: 8/8 MS: 2 ChangeBinInt-ChangeByte-
#4194304        pulse  ft: 11 corp: 8/57b lim: 4096 exec/s: 59918 rss: 227Mb
#4208258        NEW    ft: 12 corp: 9/65b lim: 4096 exec/s: 60117 rss: 228Mb L: 8/8 MS: 3 CrossOver-CrossOver-ChangeBit-
[WARNING]: Detect uncatched exception, maybe caused by bugs, exit now
An exception has occurred:
Exception: TRAP
         at default.api(std/core::Array<...>)(/data/Cangjie/fuzz_main.cj:14)
         at _ZN7default3apiER_ZN8std$core5ArrayIhE_cc_wrapper(/data/Cangjie/fuzz_main.cj:0)
         at libfuzzerCallback(fuzz/fuzz/callback.cj:20)
[INFO]: data is: [67, 97, 110, 103, 106, 105, 101, 33]
[INFO]: crash file will stored with libfuzzer
==899957== ERROR: libFuzzer: fuzz target exited
SUMMARY: libFuzzer: fuzz target exited
MS: 1 ChangeByte-; base unit: 7d8b0108ce76a937161065eafcde95bbf3d47dbf
0x43,0x61,0x6e,0x67,0x6a,0x69,0x65,0x21,
Cangjie!
artifact_prefix='./'; Test unit written to ./crash-555e7af32a2ceb585cdd9ce810c4804e65d41cea
Base64: Q2FuZ2ppZSE=

使用 DataProvider 功能进行测试

除了使用字节流对 API 进行测试的方法之外,fuzz 包提供了 FuzzDataProvider 类,用于更友好地从变异的数据源产生仓颉的标准数据类型,方便对 API 进行测试。

public func api2(dp: FuzzDataProvider): Int32 {
    if(dp.consumeBool() && dp.consumeByte() == b'A' && dp.consumeUInt32() == 0xdeadbeef){
        throw Exception("TRAP")
    }
    return 0
}

此案例中,开启 --sanitizer-coverage-trace-compares 可有效提高 fuzz 效率。

DataProvider 模式下,无法直观地判断各个 API 返回值分别是什么,因此提供了 Fuzzer.enableDebugDataProvider() 和 DebugDataProvider,在 startFuzz 前调用 enableDebugDataProvider() 即可令本次 fuzz 每次调用 consumeXXX 时打印日志。

例如,上文代码触发异常后,添加 enableDebugDataProvider 重新编译,效果如下。

import stdx.fuzz.fuzz.*

main() {
    let fuzzer = Fuzzer(api2)
    fuzzer.enableDebugDataProvider()
    fuzzer.startFuzz()
    return 0
}

运行结果如下:

./main crash-d7ece8e77ff25769a5d55eb8d3093d4bace78e1b
Running: crash-d7ece8e77ff25769a5d55eb8d3093d4bace78e1b
[DEBUG] consumeBool return true
[DEBUG] consumeByte return 65
[DEBUG] consumeUInt32 return 3735928559
[WARNING]: Detect uncatched exception, maybe caused by bugs, exit now
An exception has occurred:
Exception: TRAP
         at default.api2(fuzz/fuzz::FuzzDataProvider)(/tmp/test.cj:12)
         at _ZN7default4api2EC_ZN9fuzz$fuzz16FuzzDataProviderE_cc_wrapper(/tmp/test.cj:0)
         at libfuzzerCallback(fuzz/fuzz/callback.cj:0)
[INFO]: data is: [191, 65, 239, 190, 173, 222]

使用 FakeCoverage 避免 DataProvider 模式下 Fuzz 异常终止

在链接了 libfuzzer <= 14 的情况下,且处于 DataProvider 模式下,遇到了类似如下的错误,可能需要阅读此章节:

ERROR: no interesting inputs were found. Is the code instrumented for coverage? Exiting.

libfuzzer 15 起,修复了该 feature,即使初始化时拒绝了输入,也不会停止执行。

注意:请确认被测试的库确实被插入了覆盖率反馈,因为在没有覆盖率反馈插桩的情况下,也会出现该错误!

当前 fuzz 后端对接到了 libfuzzer,而 libfuzzer 在启动时会先输入空字节流、再输入仅包含一个 '\n' 的字节流对待测函数进行试探,在两轮结束后检测覆盖率是否新增。在 DataProvider 模式下,如果先消耗数据,再调用待测库的 API,会导致消耗数据时长度不足而提前返回,从而 libfuzzer 认为覆盖率信息为零。

例如下方代码,会触发该错误

触发的代码:

// main.cj
import stdx.fuzz.fuzz.*

main() {
    let f = Fuzzer(api)
    f.disableFakeCoverage()
    f.startFuzz()
    return 0
}

// fuzz_target.cj, with sancov
public func api(dp: FuzzDataProvider): Int32 {
    if (dp.consumeBool() && dp.consumeBool()) {
        throw Exception("TRAP!")
    }
    return 0
}

运行结果如下:

...
ERROR: no interesting inputs were found. Is the code instrumented for coverage? Exiting.
...

因此,需要使用 Fake Coverage 创建虚假的覆盖率信息,让 libfuzzer 在初始化期间认为待测模块确实被插桩,等到 DataProvider 收集到足够数据后,再进行有效的 fuzz 测试。该模式被称为 Fake Coverage 模式。

将上文的 disableFakeCoverage() 替换为 enableFakeCoverage() 即可继续运行,最终触发 TRAP。

此外,除了使用 Fake Coverage 模式,还可以在测试用例中主动调用待测函数的某些不重要的 API 来将覆盖率信息传递给 libfuzzer,也能起到让 fuzz 继续下去的作用。

// main.cj
import stdx.fuzz.fuzz.*

main() {
    let f = Fuzzer(api)
    f.enableFakeCoverage()
    f.startFuzz()
    return 0
}

// fuzz_target.cj, with sancov
public func api(dp: FuzzDataProvider): Int32 {
    if (dp.consumeBool() && dp.consumeBool()) {
        throw Exception("TRAP!")
    }
    return 0
}

运行结果如下:

INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 3187548846
INFO: Loaded 2 modules   (8 inline 8-bit counters): 7 [0x55bf83ea8790, 0x55bf83ea8797), 1 [0x55bf83e97b00, 0x55bf83e97b01),
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: A corpus is not provided, starting from an empty corpus
#2      INITED ft: 5 corp: 1/1b exec/s: 0 rss: 33Mb
#9      NEW    ft: 6 corp: 2/2b lim: 4 exec/s: 0 rss: 33Mb L: 1/1 MS: 2 CopyPart-ChangeByte-
[WARNING]: Detect uncatched exception, maybe caused by bugs, exit now
An exception has occurred:
Exception: TRAP!
...
...

打印 fuzz 使用方法

可以使用 -help=1 打印帮助,-seed=246468919 指定随机数的种子。

运行结果如下:

$ ./main -help=1

Usage:
To run fuzzing pass 0 or more directories.
program_name [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]
To run individual tests without fuzzing pass 1 or more files:
program_name [-flag1=val1 [-flag2=val2 ...] ] file1 [file2 ...]

实验性特性-覆盖率信息打印

仓颉 fuzzer 支持使用 -print_coverage=1 作为启动参数运行 fuzzer,用于统计各函数的测试情况,该特性在持续完善中,只与输出覆盖率报告有关,不影响 fuzz 过程。

由于该功能需要对 libfuzzer 进行侵入式修改,使用该功能需要链接仓颉自带的 libfuzzer,路径是:$CANGJIE_HOME/lib/{linux_x86_64_cjnative, linux_aarch64_cjnative}/libclang_rt-fuzzer_no_main.a。

编译时需要同时启用--sanitizer-coverage-inline-8bit-counters--sanitizer-coverage-pc-table

C 语言 libfuzzer 输出举例

./a.out -print_coverage=1
COVERAGE:
COVERED_FUNC: hits: 5 edges: 6/8 LLVMFuzzerTestOneInput /tmp/test.cpp:5
  UNCOVERED_PC: /tmp/test.cpp:6
  UNCOVERED_PC: /tmp/test.cpp:9

仓颉语言 cj-fuzz 输出举例

./main -print_coverage=1 -runs=100
Done 100 runs in 0 second(s)
COVERAGE:
COVERED_FUNC: hits: 1 edges: 3/12 ttt <unknown cj filename>:<unknown cj line number>
  UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
  UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
  UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
  UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
  UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
  UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
  UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
  UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
  UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
UNCOVERED_FUNC: hits: 0 edges: 0/2 main <unknown cj filename>:<unknown cj line number>
COVERED_FUNC: hits: 1 edges: 1/1 ttt_cc_wrapper <unknown cj filename>:<unknown cj line number>

栈回溯缺失的处理方案

当前在启动 fuzz 时默认会有这三条 WARNING,因为当前 cj-fuzz 没有对它们进行实现。

WARNING: Failed to find function "__sanitizer_acquire_crash_state".
WARNING: Failed to find function "__sanitizer_print_stack_trace".
WARNING: Failed to find function "__sanitizer_set_death_callback".

在 fuzz 过程中,可能会因为以下 3 种情况而结束 fuzz 流程:

  1. 抛出异常
  2. 超时
  3. 在 C 代码中 crash

其中“抛出异常”的情况,fuzz 框架对异常进行捕获后会打印栈回溯,不会造成栈回溯缺失的现象。

“超时”和“在 C 代码中 crash”实际是在 native 代码中触发了 SIGNAL,不属于仓颉异常,因此会造成栈回溯的缺失。

libfuzzer 会尝试使用 __sanitizer_acquire_crash_state__sanitizer_print_stack_trace__sanitizer_set_death_callback 等函数处理异常情况,其中 __sanitizer_print_stack_trace 会打印栈回溯,目前成熟的实现在 llvm compiler-rt 中的 asan 等模块中。

因此,建议的解决方案是在链接时额外加入如下的静态库文件和链接选项,释义如下:

/usr/lib/llvm-14/lib/clang/14.0.0/lib/linux/libclang_rt.asan-x86_64.a -lgcc_s --eh-frame-hdr

  • /usr/lib/llvm-14/lib/clang/14.0.0/lib/linux/libclang_rt.asan-x86_64.a 因为该 .a 文件实现了 __sanitizer_print_stack_trace,出于方便就直接用它;
  • -lgcc_s 栈回溯依赖 gcc_s;
  • --eh-frame-hdr ld 链接时生成 eh_frame_hdr 节,帮助完成栈回溯。

可选的环境变量:ASAN_SYMBOLIZER_PATH=$CANGJIE_HOME/third_party/llvm/bin/llvm-symbolizer,可能在某些情况下有用。

最终会得到两套栈回溯,一套是 Exception.printStackTrace,一套是 __sanitizer_print_stack_trace,内容如下:

[WARNING]: Detect uncatched exception, maybe caused by bugs, exit now
An exception has occurred:
Exception: TRAP!
         at default.ttt(std/core::Array<...>)(/data/cangjie/libs/fuzz/ci_fuzzer0.cj:11)
         at _ZN7default3tttER_ZN8std$core5ArrayIhE_cc_wrapper(/data/cangjie/libs/fuzz/ci_fuzzer0.cj:0)
         at libfuzzerCallback(/data/cangjie/libs/fuzz/fuzz/callback.cj:34)
[INFO]: data is: [0, 202, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]
[INFO]: crash file will stored with libfuzzer
==425243== ERROR: libFuzzer: fuzz target exited
    #0 0x563a233fadf1 in __sanitizer_print_stack_trace (/data/cangjie/libs/fuzz/main+0x280df1)
    #1 0x563a2337c0b8 in fuzzer::PrintStackTrace() (/data/cangjie/libs/fuzz/main+0x2020b8)
    #2 0x563a2338726c in fuzzer::Fuzzer::ExitCallback() (/data/cangjie/libs/fuzz/main+0x20d26c)
    #3 0x7f485cf36494 in __run_exit_handlers stdlib/exit.c:113:8
    #4 0x7f485cf3660f in exit stdlib/exit.c:143:3
    #5 0x563a23224e68 in libfuzzerCallback$real /data/cangjie/libs/fuzz/fuzz/callback.cj:62:18
    #6 0x7f485d22718b in CJ_MCC_N2CStub (/data/cangjie/output/runtime/lib/linux_x86_64_cjnative/libcangjie-runtime.so+0x2718b)
    #7 0x563a2322fc26 in libfuzzerCallback /data/cangjie/libs/fuzz/fuzz/callback.cj:20
    #8 0x563a23387883 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/data/cangjie/libs/fuzz/main+0x20d883)
    #9 0x563a2338a3f9 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) (/data/cangjie/libs/fuzz/main+0x2103f9)
    #10 0x563a23387e49 in fuzzer::Fuzzer::MutateAndTestOne() (/data/cangjie/libs/fuzz/main+0x20de49)
    #11 0x563a2338a2b5 in fuzzer::Fuzzer::Loop(std::vector<fuzzer::SizedFile, std::allocator<fuzzer::SizedFile>>&) (/data/cangjie/libs/fuzz/main+0x2102b5)
    #12 0x563a23377a12 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/data/cangjie/libs/fuzz/main+0x1fda12)
    #13 0x563a231ad2b6 in fuzz_fake$fuzz::Fuzzer::startFuzz() /data/cangjie/libs/fuzz/fuzz/fuzzer.cj:200:13
    #14 0x563a23405fad in default::main() /data/cangjie/libs/fuzz/ci_fuzzer0.cj:5:5
    #15 0x563a23405fe7 in user.main /data/cangjie/libs/fuzz/<stdin>
    #16 0x563a234060e1 in cj_entry$ (/data/cangjie/libs/fuzz/main+0x28c0e1)
    #17 0x7f485d227220  (/data/cangjie/output/runtime/lib/linux_x86_64_cjnative/libcangjie-runtime.so+0x27220)
    #18 0x7f485d223898  (/data/cangjie/output/runtime/lib/linux_x86_64_cjnative/libcangjie-runtime.so+0x23898)
    #19 0x7f485d2607b9 in CJ_CJThreadEntry (/data/cangjie/output/runtime/lib/linux_x86_64_cjnative/libcangjie-runtime.so+0x607b9)

stdx.log

功能介绍

log 包提供了一个单一的日志 API,它抽象了实际的日志实现。

API 列表

函数

函数名功能
getGlobalLogger(Array<Attr>)获取全局 Logger 对象。
setGlobalLogger(Logger)设置全局 Logger 对象。

类型别名

类型别名功能
Attr日志消息的键值对类型,是 (String, LogValue) 的类型别名。

接口

接口名功能
LogValue为仓颉数据类型提供序列化到日志输出目标的接口。

类名功能
Logger此抽象类提供基础的日志打印和管理功能。
LogRecord日志消息的“负载”。
LogWriterLogWriter 提供了将仓颉数据类型序列化到日志输出目标的能力。
NoopLoggerLogger 的 NO-OP(无操作)实现。

结构体

结构体名功能
LogLevelLogLevel 为日志级别结构体。

异常类

异常类名功能
LogException用于处理 log 相关的异常。

类型别名

type Attr

public type Attr = (String, LogValue)

功能:日志消息的键值对类型,是 (String, LogValue) 的类型别名。

示例:

import stdx.log.*
import std.time.*

main() {
    // 创建一个LogRecord实例
    let logRecord = LogRecord(DateTime.now(), LogLevel.INFO, "测试消息")

    // 获取当前的attrs属性
    println("原始attrs长度: ${logRecord.attrs.size}")

    // 指定attrs属性
    let attr: Attr = ("key", "value")
    let attr1: Attr = ("key1", 123)
    let attr2: (String, LogValue) = ("key2", true)

    // 检查attr2的类型
    println("attr2类型是 Attr: ${attr2 is Attr}")

    logRecord.attrs = [attr, attr1, attr2]
    println("修改后attrs长度: ${logRecord.attrs.size}")

    return 0
}

运行结果:

原始attrs长度: 0
attr2类型是 Attr: true
修改后attrs长度: 3

函数

func getGlobalLogger(Array<Attr>)

public func getGlobalLogger(attrs: Array<Attr>): Logger

功能:获取 Logger 对象。

说明:

如果未传入 attrs 参数,那么获取的是同一个 Logger 对象,传入了 attrs 参数,则创建一个包含指定的属性的 Logger 对象副本。

参数:

  • attrs: Array<Attr> - 日志数据键值对属性,获取的 Logger 对象会包含这些属性。

返回值:

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*

main() {
    // 创建一个SimpleLogger(抽象类Logger的实现类)实例
    let logger = SimpleLogger(getStdOut())

    // 设置全局日志记录器
    println("提示:未设置全局日志记录器之前所有的日志事件都将被忽略")
    setGlobalLogger(logger)

    // 获取全局日志记录器(不带属性)
    let globalLogger = getGlobalLogger()
    globalLogger.warn("无属性日志打印")

    // 获取带属性的全局日志记录器
    let attrLogger = getGlobalLogger([("module", "main"), ("version", "1.0")])
    attrLogger.warn("带属性日志打印")

    return 0
}

可能的运行结果:

提示:未设置全局日志记录器之前所有的日志事件都将被忽略
2026-01-14T10:16:02.144486114+08:00 WARN 无属性日志打印 
2026-01-14T10:16:02.144587908+08:00 WARN 带属性日志打印 module="main" version="1.0"

func setGlobalLogger(Logger)

public func setGlobalLogger(logger: Logger): Unit

功能:设置全局 Logger 对象。

注意:

  • 此函数在程序的生命周期中只应该被调用一次。对 setGlobalLogger 的调用完成之前发生的任何日志事件都将被忽略。
  • 此函数通常不需要手动调用。日志实现提供者应提供包含了调用本方法的的初始化方法。

参数:

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*

main() {
    // 获取全局日志记录器(未设置)
    let globalLogger = getGlobalLogger()
    globalLogger.warn("不会被打印!!")

    // 创建一个SimpleLogger(抽象类Logger的实现类)实例
    let logger = SimpleLogger(getStdOut())

    // 设置全局日志记录器
    println("提示:未设置全局日志记录器之前所有的日志事件都将被忽略")
    setGlobalLogger(logger)

    // 获取无属性的全局日志记录器
    let attrLogger = getGlobalLogger()
    attrLogger.warn("日志打印")

    return 0
}

可能的运行结果:

提示:未设置全局日志记录器之前所有的日志事件都将被忽略
2026-01-14T10:18:57.993352204+08:00 WARN 日志打印

接口

interface LogValue

public interface LogValue {
    func writeTo(w: LogWriter): Unit
}

功能:为类型提供序列化到日志输出目标的接口。

LogWriter 搭配使用, LogWriter 可以通过 writeValue 将实现了 LogValue 接口的类型写入到日志输出目标中。

func writeTo(LogWriter)

func writeTo(w: LogWriter): Unit

功能:将实现了 LogValue 接口的类型写入参数 w 指定的 LogWriter 实例中。

参数:

extend Bool <: LogValue

extend Bool <: LogValue

功能:为 Bool 类型实现 LogValue 接口。

父类型:

func writeTo(LogWriter)

public func writeTo(w: LogWriter): Unit

功能:提供 Bool 类型序列化到流的功能。

参数:

示例:

import stdx.log.*
import std.time.*

// 定义一个简单自定义的LogWriter实现用于演示,实际开发中请参考 samples 中示例
public class SimpleLogWriter <: LogWriter {
    var buffer = ""

    // 写入空值时,添加自定义内容
    public func writeNone(): Unit {
        buffer += " NONE "
    }
    // 写入整数时,添加自定义内容
    public func writeInt(v: Int64): Unit {
        buffer += "INT: ${v} "
    }
    // 写入布尔值时,添加自定义内容
    public func writeBool(v: Bool): Unit {
        buffer += "BOOL: ${v} "
    }
    // 写入浮点数时,添加自定义内容
    public func writeFloat(v: Float64): Unit {
        buffer += " FLOAT: ${v} "
    }
    // 写入字符串时,添加自定义内容
    public func writeString(v: String): Unit {
        buffer += " STRING: ${v} "
    }
    // 写入日期时间时,添加自定义内容
    public func writeDateTime(v: DateTime): Unit {
        buffer += " DATETIME: ${v} "
    }
    // 写入间隔时间时,添加自定义内容
    public func writeDuration(v: Duration): Unit {
        buffer += " DURATION: ${v} "
    }
    // 写入异常时,添加自定义内容
    public func writeException(v: Exception): Unit {
        buffer += " EXCEPTION: ${v.message} "
    }
    // 写入键时,添加自定义内容
    public func writeKey(v: String): Unit {
        buffer += " KEY: ${v} = "
    }
    // 写入值时,添加自定义内容
    public func writeValue(v: LogValue): Unit {
        v.writeTo(this)
    }
    // 写入数组时,添加自定义内容
    public func startArray(): Unit {
        buffer += "["
    }
    public func endArray(): Unit {
        buffer += "]"
    }
    // 写入对象时,添加自定义内容
    public func startObject(): Unit {
        buffer += "{"
    }
    public func endObject(): Unit {
        buffer += "}"
    }
}

main() {
    // 创建一个LogWriter实例
    let writer = SimpleLogWriter()

    Option<String>.Some("hello").writeTo(writer)
    123.writeTo(writer)
    true.writeTo(writer)
    3.14.writeTo(writer)
    "hello".writeTo(writer)
    DateTime.of(year: 2026, month: 1, dayOfMonth: 1, timeZone: TimeZone.UTC).writeTo(writer)
    Duration.second.writeTo(writer)
    Exception("异常信息").writeTo(writer)

    println("输出样式: ${writer.buffer}")

    return 0
}

运行结果:

输出样式:  STRING: hello INT: 123 BOOL: true  FLOAT: 3.140000  STRING: hello  DATETIME: 2026-01-01T00:00:00Z  DURATION: 1s  EXCEPTION: 异常信息

extend DateTime <: LogValue

extend DateTime <: LogValue

功能:为 DateTime 类型实现 LogValue 接口。

父类型:

func writeTo(LogWriter)

public func writeTo(w: LogWriter): Unit

功能:提供 DateTime 类型序列化到流的功能。

参数:

示例:

参见 extend Bool 示例。

extend Duration <: LogValue

extend Duration <: LogValue

功能:为 Duration 类型实现 LogValue 接口。

父类型:

func writeTo(LogWriter)

public func writeTo(w: LogWriter): Unit

功能:提供 Duration 类型序列化到流的功能。

参数:

示例:

参见 extend Bool 示例。

extend Exception <: LogValue

extend Exception <: LogValue

功能:为 Exception 类型实现 LogValue 接口。

父类型:

func writeTo(LogWriter)

public func writeTo(w: LogWriter): Unit

功能:提供 Exception 类型序列化到流的功能。

参数:

示例:

参见 extend Bool 示例。

extend Float64 <: LogValue

extend Float64 <: LogValue

功能:为 Float64 类型实现 LogValue 接口。

父类型:

func writeTo(LogWriter)

public func writeTo(w: LogWriter): Unit

功能:提供 Float64 类型序列化到流的功能。

参数:

示例:

参见 extend Bool 示例。

extend Int64 <: LogValue

extend Int64 <: LogValue

功能:为 Int64 类型实现 LogValue 接口。

父类型:

func writeTo(LogWriter)

public func writeTo(w: LogWriter): Unit

功能:提供 Int64 类型序列化到流的功能。

参数:

示例:

参见 extend Bool 示例。

extend String <: LogValue

extend String <: LogValue

功能:为 String 类型实现 LogValue 接口。

父类型:

func writeTo(LogWriter)

public func writeTo(w: LogWriter): Unit

功能:提供 String 类型序列化到流的功能。

参数:

示例:

参见 extend Bool 示例。

extend<T> Array<T> <: LogValue where T <: LogValue

extend<T> Array<T> <: LogValue where T <: LogValue

功能:为 Array<T> 类型实现 LogValue 接口。

父类型:

func writeTo(LogWriter)

public func writeTo(w: LogWriter): Unit

功能:提供 Array<T> 类型序列化到流的功能。

参数:

示例:

import stdx.log.*
import std.time.*

// 定义一个简单自定义的LogWriter实现用于演示,实际开发中请参考 samples 中示例
public class SimpleLogWriter <: LogWriter {
    var buffer = ""

    // 写入空值时,添加自定义内容
    public func writeNone(): Unit {
        buffer += " NONE "
    }
    // 写入整数时,添加自定义内容
    public func writeInt(v: Int64): Unit {
        buffer += "INT: ${v} "
    }
    // 写入布尔值时,添加自定义内容
    public func writeBool(v: Bool): Unit {
        buffer += "BOOL: ${v} "
    }
    // 写入浮点数时,添加自定义内容
    public func writeFloat(v: Float64): Unit {
        buffer += " FLOAT: ${v} "
    }
    // 写入字符串时,添加自定义内容
    public func writeString(v: String): Unit {
        buffer += " STRING: ${v} "
    }
    // 写入日期时间时,添加自定义内容
    public func writeDateTime(v: DateTime): Unit {
        buffer += " DATETIME: ${v} "
    }
    // 写入间隔时间时,添加自定义内容
    public func writeDuration(v: Duration): Unit {
        buffer += " DURATION: ${v} "
    }
    // 写入异常时,添加自定义内容
    public func writeException(v: Exception): Unit {
        buffer += " EXCEPTION: ${v.message} "
    }
    // 写入键时,添加自定义内容
    public func writeKey(v: String): Unit {
        buffer += " KEY: ${v} = "
    }
    // 写入值时,添加自定义内容
    public func writeValue(v: LogValue): Unit {
        v.writeTo(this)
    }
    // 写入数组时,添加自定义内容
    public func startArray(): Unit {
        buffer += "["
    }
    public func endArray(): Unit {
        buffer += "]"
    }
    // 写入对象时,添加自定义内容
    public func startObject(): Unit {
        buffer += "{"
    }
    public func endObject(): Unit {
        buffer += "}"
    }
}

main() {
    // 创建一个LogWriter实例
    let writer = SimpleLogWriter()

    // 创建一个Array实例
    let array: Array<LogValue> = [
        3.14,
        "hello",
        DateTime.of(year: 2026, month: 1, dayOfMonth: 1, timeZone: TimeZone.UTC),
        Duration.second,
        Exception("error"),
        Option<String>.None
    ]

    array.writeTo(writer)

    println("输出样式: ${writer.buffer}")

    return 0
}

运行结果:

输出样式: [ FLOAT: 3.140000  STRING: hello  DATETIME: 2026-01-01T00:00:00Z  DURATION: 1s  EXCEPTION: error  NONE ]

extend<T> Option<T> <: LogValue where T <: LogValue

extend<T> Option<T> <: LogValue where T <: LogValue

功能:为 Option<T> 类型实现 LogValue 接口。

父类型:

func writeTo(LogWriter)

public func writeTo(w: LogWriter): Unit

功能:提供 Option<T> 类型序列化到流的功能。

参数:

示例:

参见 extend Bool 示例。

extend<V> HashMap<String, V> <: LogValue where V <: LogValue

extend<V> HashMap<String, V> <: LogValue where V <: LogValue

功能:为 HashMap<K, V> 类型实现 LogValue 接口。

父类型:

func writeTo(LogWriter)

public func writeTo(w: LogWriter): Unit

功能:提供 HashMap<K, V> 类型序列化到流的功能。

参数:

示例:

import stdx.log.*
import std.collection.*
import std.time.*

// 定义一个简单自定义的LogWriter实现用于演示,实际开发中请参考 samples 中示例
public class SimpleLogWriter <: LogWriter {
    var buffer = ""

    public func writeNone(): Unit {}

    // 写入整数时,添加自定义内容
    public func writeInt(v: Int64): Unit {
        buffer += "INT: ${v} "
    }
    public func writeBool(v: Bool): Unit {}
    public func writeFloat(v: Float64): Unit {}
    // 写入字符串时,添加自定义内容
    public func writeString(v: String): Unit {
        buffer += " STRING: ${v} "
    }
    public func writeDateTime(v: DateTime): Unit {}
    public func writeDuration(v: Duration): Unit {}
    public func writeException(v: Exception): Unit {}
    // 写入键时,添加自定义内容
    public func writeKey(v: String): Unit {
        buffer += " KEY: ${v} = "
    }
    // 写入值时,添加自定义内容
    public func writeValue(v: LogValue): Unit {
        v.writeTo(this)
    }
    public func startArray(): Unit {}
    public func endArray(): Unit {}
    // 写入对象时,添加自定义内容
    public func startObject(): Unit {
        buffer += "{"
    }
    public func endObject(): Unit {
        buffer += "}"
    }
}

main() {
    // 创建一个LogWriter实例
    let writer = SimpleLogWriter()

    // 创建一个HashMap实例
    let hashMap = HashMap<String, LogValue>([("HashMapKey", 123)])
    // 创建一个TreeMap实例
    let treeMap = TreeMap<String, LogValue>([("TreeMapKey", "TreeMapValue")])

    // 写入LogWriter
    hashMap.writeTo(writer)
    treeMap.writeTo(writer)

    println("输出样式: ${writer.buffer}")

    return 0
}

运行结果:

输出样式: { KEY: HashMapKey = INT: 123 }{ KEY: TreeMapKey =  STRING: TreeMapValue }

extend<V> TreeMap<String, V> <: LogValue where V <: LogValue

extend<V> TreeMap<String, V> <: LogValue where V <: LogValue

功能:为 TreeMap<K, V> 类型实现 LogValue 接口。

父类型:

func writeTo(LogWriter)

public func writeTo(w: LogWriter): Unit

功能:提供 TreeMap<K, V> 类型序列化到流的功能。

参数:

示例:

参见 extend<V> HashMap 示例。

class Logger

public abstract class Logger <: Resource {
}

功能:此抽象类提供基础的日志打印和管理功能。

父类型:

  • Resource

prop level

public open mut prop level: LogLevel

功能:获取和修改日志打印级别。

类型:LogLevel

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*

main() {
    // 创建一个SimpleLogger(抽象类Logger的实现类)实例
    let logger = SimpleLogger(getStdOut())

    // 获取当前日志级别
    let currentLevel = logger.level
    println("当前日志级别: ${currentLevel}")
    logger.debug({=> "级别较低,本调试日志不被打印"}, [("type", "debug")])

    // 修改日志级别
    logger.level = LogLevel.DEBUG
    println("修改后的日志级别: ${logger.level}")
    logger.debug({=> "这是一个调试信息"}, [("type", "debug")])
    return 0
}

可能的运行结果:

当前日志级别: INFO
修改后的日志级别: DEBUG
2026-01-19T06:41:10.610312112Z DEBUG 这是一个调试信息 type="debug"

func debug(() -> String, Array<Attr>)

public func debug(message: () -> String, attrs: Array<Attr>): Unit

功能:打印 DEBUG 级别的日志的便捷函数。

参数:

  • message: () -> String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*

main() {
    // 创建一个SimpleLogger(抽象类Logger的实现类)实例并设置为DEBUG级别
    let logger = SimpleLogger(getStdOut())
    logger.level = LogLevel.DEBUG

    // 使用lambda表达式作为消息函数记录DEBUG日志
    logger.debug({=> "这是一个调试信息"}, [("type", "debug"), ("id", 123)])
    return 0
}

可能的运行结果:

2026-01-12T11:07:09.245444333+08:00 DEBUG 这是一个调试信息 type="debug" id=123

func debug(String, Array<Attr>)

public func debug(message: String, attrs: Array<Attr>): Unit

功能:打印 DEBUG 级别的日志的便捷函数。

参数:

  • message: String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*

main() {
    // 创建一个SimpleLogger(抽象类Logger的实现类)实例并设置为DEBUG级别
    let logger = SimpleLogger(getStdOut())
    logger.level = LogLevel.DEBUG

    // 使用字符串消息记录DEBUG日志(变长参数语法糖)
    logger.debug("这是一个调试信息")
    return 0
}

可能的运行结果:

2026-01-12T11:08:03.320265151+08:00 DEBUG 这是一个调试信息

func enabled(LogLevel)

public func enabled(level: LogLevel): Bool

功能:确定是否记录指定日志级别的日志消息。

这个函数允许调用者提前判断日志是否会被丢弃,以避免耗时的日志消息参数计算。

参数:

返回值:

  • Bool - 如果指定的日志级别处于使能状态,则返回 true;否则,返回 false

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*

main() {
    // 创建一个SimpleLogger(抽象类Logger的实现类)实例
    let logger = SimpleLogger(getStdOut())
    logger.level = LogLevel.INFO

    // 检查DEBUG级别是否启用(当前为INFO级别,所以DEBUG不会启用)
    let isDebugEnabled = logger.enabled(LogLevel.DEBUG)
    println("DEBUG级别是否启用: ${isDebugEnabled}")

    // 检查INFO级别是否启用
    let isInfoEnabled = logger.enabled(LogLevel.INFO)
    println("INFO级别是否启用: ${isInfoEnabled}")
    return 0
}

运行结果:

DEBUG级别是否启用: false
INFO级别是否启用: true

func error(() -> String, Array<Attr>)

public func error(message: () -> String, attrs: Array<Attr>): Unit

功能:打印 ERROR 级别的日志的便捷函数。

参数:

  • message: () -> String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*

main() {
    // 创建一个SimpleLogger(抽象类Logger的实现类)实例
    let logger = SimpleLogger(getStdOut())

    // 使用lambda表达式作为消息函数记录ERROR日志(变长参数语法糖)
    logger.error({=> "这是一个错误信息"})
    return 0
}

可能的运行结果:

2026-01-12T11:09:56.446050589+08:00 ERROR 这是一个错误信息

func error(String, Array<Attr>)

public func error(message: String, attrs: Array<Attr>): Unit

功能:打印 ERROR 级别的日志的便捷函数。

参数:

  • message: String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*

main() {
    // 创建一个SimpleLogger(抽象类Logger的实现类)实例
    let logger = SimpleLogger(getStdOut())

    // 使用字符串消息记录ERROR日志
    logger.error("这是一个错误信息", [("type", "error"), ("code", 404)])
    return 0
}

可能的运行结果:

2026-01-12T11:11:52.781377362+08:00 ERROR 这是一个错误信息 type="error" code=404

func fatal(() -> String, Array<Attr>)

public func fatal(message: () -> String, attrs: Array<Attr>): Unit

功能:打印 FATAL 级别的日志的便捷函数。

参数:

  • message: () -> String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*

main() {
    // 创建一个SimpleLogger(抽象类Logger的实现类)实例
    let logger = SimpleLogger(getStdOut())

    // 使用lambda表达式作为消息函数记录FATAL日志
    logger.fatal({=> "这是一个严重错误信息"}, [("type", Exception("fatal exception")), ("code", 600)])
    return 0
}

可能的运行结果:

2026-01-13T02:16:08.051647994Z FATAL 这是一个严重错误信息 type=["Exception: fatal exception","default.main()(test.cj:10)"] code=600

func fatal(String, Array<Attr>)

public func fatal(message: String, attrs: Array<Attr>): Unit

功能:打印 FATAL 级别的日志的便捷函数。

参数:

  • message: String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*

main() {
    // 创建一个SimpleLogger(抽象类Logger的实现类)实例
    let logger = SimpleLogger(getStdOut())

    // 使用字符串消息记录FATAL日志(变长参数语法糖)
    logger.fatal("这是一个严重错误信息")
    return 0
}

可能的运行结果:

2026-01-12T11:14:45.193240448+08:00 FATAL 这是一个严重错误信息

func info(() -> String, Array<Attr>)

public func info(message: () -> String, attrs: Array<Attr>): Unit

功能:打印 INFO 级别的日志的便捷函数。

参数:

  • message: () -> String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*

main() {
    // 创建一个SimpleLogger(抽象类Logger的实现类)实例
    let logger = SimpleLogger(getStdOut())

    // 使用lambda表达式作为消息函数记录INFO日志(变长参数语法糖)
    logger.info({=> "这是一个信息"})
    return 0
}

可能的运行结果:

2026-01-12T11:15:48.641498023+08:00 INFO 这是一个信息

func info(String, Array<Attr>)

public func info(message: String, attrs: Array<Attr>): Unit

功能:打印 INFO 级别的日志的便捷函数。

参数:

  • message: String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*

main() {
    // 创建一个SimpleLogger(抽象类Logger的实现类)实例
    let logger = SimpleLogger(getStdOut())

    // 使用字符串消息记录INFO日志(变长参数语法糖)
    logger.info("这是一个信息")
    return 0
}

可能的运行结果:

2026-01-12T11:16:15.123456789+08:00 INFO 这是一个信息

func log(LogLevel, () -> String, Array<Attr>)

public open func log(level: LogLevel, message: () -> String, attrs: Array<Attr>): Unit

功能:打印日志的通用函数,需指定日志级别。

参数:

  • level: LogLevel - 日志级别。
  • message: () -> String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*

main() {
    // 创建一个SimpleLogger(抽象类Logger的实现类)实例
    let logger = SimpleLogger(getStdOut())

    // 使用通用log函数记录不同级别的日志
    logger.log(LogLevel.WARN, {=> "这是一个警告信息"}, [("bool", true), ("array", [1, 2, 3])])
    return 0
}

可能的运行结果:

2026-01-13T02:18:14.81202694Z WARN 这是一个警告信息 bool=true array=[1,2,3]

func log(LogLevel, String, Array<Attr>)

public open func log(level: LogLevel, message: String, attrs: Array<Attr>): Unit

功能:打印日志的通用函数,需指定日志级别。

参数:

  • level: LogLevel - 日志级别。
  • message: String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*

main() {
    // 创建一个SimpleLogger(抽象类Logger的实现类)实例
    let logger = SimpleLogger(getStdOut())

    // 使用通用log函数记录不同级别的日志(变长参数语法糖)
    logger.log(LogLevel.INFO, "这是一个信息日志")
    return 0
}

可能的运行结果:

2026-01-12T11:18:05.493054545+08:00 INFO 这是一个信息日志

func log(LogRecord)

public open func log(record: LogRecord): Unit

功能:打印日志的通用函数。

参数:

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*
import std.time.*

main() {
    // 创建一个SimpleLogger(抽象类Logger的实现类)实例
    let logger = SimpleLogger(getStdOut())

    // 创建一个LogRecord实例
    let logRecord = LogRecord(DateTime.of(year: 2026, month: 1, dayOfMonth: 1), LogLevel.INFO, "通过LogRecord记录的信息")

    // 使用log函数记录LogRecord
    logger.log(logRecord)
    return 0
}

可能的运行结果:

2026-01-01T00:00:00Z INFO 通过LogRecord记录的信息

func trace(() -> String, Array<Attr>)

public func trace(message: () -> String, attrs: Array<Attr>): Unit

功能:打印 TRACE 级别的日志的便捷函数。

参数:

  • message: () -> String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*

main() {
    // 创建一个SimpleLogger(抽象类Logger的实现类)实例
    let logger = SimpleLogger(getStdOut())
    logger.level = LogLevel.TRACE

    // 使用lambda表达式作为消息函数记录TRACE日志(变长参数语法糖)
    logger.trace({=> "这是一个追踪信息"})
    return 0
}

可能的运行结果:

2026-01-12T11:20:02.668866491+08:00 TRACE 这是一个追踪信息

func trace(String, Array<Attr>)

public func trace(message: String, attrs: Array<Attr>): Unit

功能:打印 TRACE 级别的日志的便捷函数。

参数:

  • message: String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*
import std.collection.*

main() {
    // 创建一个SimpleLogger(抽象类Logger的实现类)实例
    let logger = SimpleLogger(getStdOut())
    logger.level = LogLevel.TRACE

    // 使用字符串消息记录TRACE日志
    logger.trace("这是一个追踪信息",
        [("type", "trace"), ("module", HashMap<String, String>([("name", "test01"), ("version", "1.0")]))])
    return 0
}

可能的运行结果:

2026-01-13T02:21:10.752213995Z TRACE 这是一个追踪信息 type="trace" module={name:"test01",version:"1.0"}

func warn(() -> String, Array<Attr>)

public func warn(message: () -> String, attrs: Array<Attr>): Unit

功能:打印 WARN 级别的日志的便捷函数。

参数:

  • message: () -> String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*

main() {
    // 创建一个SimpleLogger(抽象类Logger的实现类)实例
    let logger = SimpleLogger(getStdOut())

    // 使用lambda表达式作为消息函数记录WARN日志
    logger.warn({=> "这是一个警告信息"}, [("type", "warn"), ("module", "security")])
    return 0
}

可能的运行结果:

2026-01-12T11:23:11.841638679+08:00 WARN 这是一个警告信息 type="warn" module="security"

func warn(String, Array<Attr>)

public func warn(message: String, attrs: Array<Attr>): Unit

功能:打印 WARN 级别的日志的便捷函数。

参数:

  • message: String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*

main() {
    // 创建一个SimpleLogger(抽象类Logger的实现类)实例
    let logger = SimpleLogger(getStdOut())

    // 使用字符串消息记录WARN日志(变长参数语法糖)
    logger.warn("这是一个警告信息")
    return 0
}

可能的运行结果:

2026-01-12T11:23:45.818200702+08:00 WARN 这是一个警告信息

func withAttrs(Array<Attr>)

public open func withAttrs(attrs: Array<Attr>): Logger

功能:创建当前对象的副本,新的副本会包含指定的属性。

参数:

  • attrs: Array<Attr> - 日志数据键值对属性。

返回值:

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*

main() {
    // 创建一个SimpleLogger(抽象类Logger的实现类)实例
    let baseLogger = SimpleLogger(getStdOut())

    // 使用withAttrs方法创建一个新的Logger实例,带有预设属性
    let enhancedLogger = baseLogger.withAttrs([("service", "user-service"), ("version", "1.0")])

    // 使用增强的logger记录信息
    enhancedLogger.info("服务启动成功")
    enhancedLogger.info("服务接收请求")
    return 0
}

可能的运行结果:

2026-01-13T09:53:31.949826556+08:00 INFO 服务启动成功 service="user-service" version="1.0"
2026-01-13T09:53:31.949907056+08:00 INFO 服务接收请求 service="user-service" version="1.0"

class LogRecord

public class LogRecord {
    public init(time: DateTime, level: LogLevel, msg: String, attrs: Array<Attr>)
}

功能:日志消息的“负载”。

记录结构作为参数传递给 Logger 类的 log方法。日志提供者处理这些结构以显示日志消息。记录是由日志对象自动创建,因此日志用户看不到。

prop attrs

public mut prop attrs: Array<Attr>

功能:获取或设置日志数据键值对。

类型:Array<Attr>

示例:

import stdx.log.*
import std.time.*

main() {
    // 创建一个LogRecord实例
    let logRecord = LogRecord(DateTime.now(), LogLevel.INFO, "测试消息", [("type", "test")])

    // 获取当前的attrs属性
    println("原始attrs长度: ${logRecord.attrs.size}")

    // 修改attrs属性
    logRecord.attrs = [("type", "modified"), ("newAttr", "value")]
    println("修改后attrs长度: ${logRecord.attrs.size}")

    return 0
}

运行结果:

原始attrs长度: 1
修改后attrs长度: 2

prop level

public prop level: LogLevel

功能:获取日志打印级别,只有级别小于等于该值的日志会被打印。

类型:LogLevel

示例:

import stdx.log.*
import std.time.*

main() {
    // 创建一个LogRecord实例
    let logRecord = LogRecord(DateTime.now(), LogLevel.INFO, "测试消息", [("type", "test")])

    // 获取当前的level属性
    println("日志级别: ${logRecord.level}")

    return 0
}

运行结果:

日志级别: INFO

prop message

public mut prop message: String

功能:获取或设置日志消息。

类型:String

示例:

import stdx.log.*
import std.time.*

main() {
    // 创建一个LogRecord实例
    let logRecord = LogRecord(DateTime.now(), LogLevel.INFO, "测试消息")

    // 获取当前的消息内容
    println("原始消息: ${logRecord.message}")

    // 修改消息内容
    logRecord.message = "修改后的消息"
    println("修改后消息: ${logRecord.message}")

    return 0
}

运行结果:

原始消息: 测试消息
修改后消息: 修改后的消息

prop time

public prop time: DateTime

功能:获取日志打印时的时间戳。

类型:DateTime

示例:

import stdx.log.*
import std.time.*

main() {
    // 创建一个LogRecord实例
    let logRecord = LogRecord(DateTime.now(), LogLevel.INFO, "测试消息")

    // 获取当前的时间戳
    println("日志时间戳: ${logRecord.time}")

    return 0
}

可能的运行结果:

日志时间戳: 2026-01-13T10:04:57.582847051+08:00

init(DateTime, LogLevel, String, Array<Attr>)

public init(time: DateTime, level: LogLevel, msg: String, attrs: Array<Attr>)

功能:创建一个 LogRecord 实例,指定时间戳,日志打印级别,日志消息和日志数据键值对。

参数:

  • time: DateTime - 记录日志时的时间戳
  • level: LogLevel - 日志级别。
  • msg: String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

示例:

import stdx.log.*
import std.time.*

main() {
    // 创建一个LogRecord实例
    var logRecord = LogRecord(DateTime.now(), LogLevel.WARN, "警告消息", [("type", "warning"), ("module", "auth")])

    // 输出创建的LogRecord信息
    println("创建的LogRecord消息: ${logRecord.message}")
    println("日志级别: ${logRecord.level}")
    println("属性数量: ${logRecord.attrs.size}")

    // 创建一个没有属性的LogRecord实例(变长参数语法糖)
    logRecord = LogRecord(DateTime.now(), LogLevel.INFO, "通知消息")

    // 输出创建的LogRecord信息
    println("创建的LogRecord消息: ${logRecord.message}")
    println("日志级别: ${logRecord.level}")
    println("属性数量: ${logRecord.attrs.size}")
}

运行结果:

创建的LogRecord消息: 警告消息
日志级别: WARN
属性数量: 2
创建的LogRecord消息: 通知消息
日志级别: INFO
属性数量: 0

func clone()

public func clone(): LogRecord

功能:创建当前对象的副本。

返回值:

示例:

import stdx.log.*
import std.time.*

main() {
    // 创建一个LogRecord实例
    let originalRecord = LogRecord(DateTime.now(), LogLevel.INFO, "原始消息", [("type", "original"), ("id", 1)])

    // 克隆LogRecord对象
    let clonedRecord = originalRecord.clone()

    // 验证克隆的对象
    println("原始消息: ${originalRecord.message}")
    println("克隆消息: ${clonedRecord.message}")

    return 0
}

运行结果:

原始消息: 原始消息
克隆消息: 原始消息

class LogWriter

public abstract class LogWriter {
}

功能:LogWriter 提供了将仓颉对象序列化成日志输出目标的能力。

LogWriter 需要和 interface LogValue 搭配使用,LogWriter 可以通过 writeValue 系列方法来将实现了 LogValue 接口的类型写入到日志输出目标中。

func endArray()

public func endArray(): Unit

功能:结束序列化当前的 LogValue 数组。

异常:

  • IllegalStateException - 当前 writer 没有匹配的 startArray 时。

示例:

import stdx.log.*
import std.collection.*
import std.time.*

// 定义一个简单自定义的LogWriter实现用于演示,实际开发中请参考 samples 中示例
public class SimpleLogWriter <: LogWriter {
    var buffer = ""

    // 写入空值时,添加自定义内容
    public func writeNone(): Unit {
        buffer += " NONE"
    }
    // 写入整数时,添加自定义内容
    public func writeInt(v: Int64): Unit {
        buffer += "INT: ${v}"
    }
    // 写入布尔值时,添加自定义内容
    public func writeBool(v: Bool): Unit {
        buffer += "BOOL: ${v}"
    }
    // 写入浮点数时,添加自定义内容
    public func writeFloat(v: Float64): Unit {
        buffer += " FLOAT: ${v}"
    }
    // 写入字符串时,添加自定义内容
    public func writeString(v: String): Unit {
        buffer += " STRING: ${v}"
    }
    // 写入日期时间时,添加自定义内容
    public func writeDateTime(v: DateTime): Unit {
        buffer += " DATETIME: ${v}"
    }
    // 写入间隔时间时,添加自定义内容
    public func writeDuration(v: Duration): Unit {
        buffer += " DURATION: ${v}"
    }
    // 写入异常时,添加自定义内容
    public func writeException(v: Exception): Unit {
        buffer += " EXCEPTION: ${v.message}"
    }
    // 写入键时,添加自定义内容
    public func writeKey(v: String): Unit {
        buffer += " KEY: ${v} = "
    }
    // 写入值时,添加自定义内容
    public func writeValue(v: LogValue): Unit {
        v.writeTo(this)
    }
    // 写入数组时,添加自定义内容
    public func startArray(): Unit {
        buffer += "["
    }
    public func endArray(): Unit {
        buffer += "]"
    }
    // 写入对象时,添加自定义内容
    public func startObject(): Unit {
        buffer += "{"
    }
    public func endObject(): Unit {
        buffer += "}"
    }
}

main() {
    // 创建一个LogWriter实例
    let writer = SimpleLogWriter()

    // 创建一个HashMap实例
    let hashMap = HashMap<String, LogValue>([("myKey", 123)])
    // 创建一个Array实例
    let array: Array<LogValue> = [
        1,
        true,
        3.14,
        "hello",
        DateTime.of(
            year: 2024,
            month: May,
            dayOfMonth: 22,
            timeZone: TimeZone.UTC
        ),
        Duration.second,
        Exception("error"),
        Option<String>.None
    ]

    // 写入LogWriter
    hashMap.writeTo(writer)
    array.writeTo(writer)

    println("输出样式: ${writer.buffer}")

    return 0
}

运行结果:

输出样式: { KEY: myKey = INT: 123}[INT: 1BOOL: true FLOAT: 3.140000 STRING: hello DATETIME: 2024-05-22T00:00:00Z DURATION: 1s EXCEPTION: error NONE]

func endObject()

public func endObject(): Unit

功能:结束序列化当前的 LogValue object。

异常:

  • IllegalStateException - 当前 writer 的状态不应该结束一个 LogValue object 时。

示例:

参见 func endArray 示例。

func startArray()

public func startArray(): Unit

功能:开始序列化一个新的 LogValue 数组,每一个 startArray 都必须有一个 endArray 对应。

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 LogValue array 时。

示例:

参见 func endArray 示例。

func startObject()

public func startObject(): Unit

功能:开始序列化一个新的 LogValue object,每一个 startObject 都必须有一个 endObject 对应。

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 LogValue object 时。

示例:

参见 func endArray 示例。

func writeBool(Bool)

public func writeBool(v: Bool): Unit

功能:向日志输出目标中写入 Bool 值。

参数:

  • v: Bool - 待写入的 Bool 值。

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 value 时。

示例:

参见 func endArray 示例。

func writeDateTime(DateTime)

public func writeDateTime(v: DateTime): Unit

功能:向日志输出目标中写入 DateTime 值。

参数:

  • v: DateTime - 待写入的 DateTime 值。

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 value 时。

示例:

参见 func endArray 示例。

func writeDuration(Duration)

public func writeDuration(v: Duration): Unit

功能:向日志输出目标中写入 Duration 值。

参数:

  • v: Duration - 待写入的 Duration 值。

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 value 时。

示例:

参见 func endArray 示例。

func writeException(Exception)

public func writeException(v: Exception): Unit

功能:向日志输出目标中写入 Exception 值。

参数:

  • v: Exception - 待写入的 Exception 值。

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 value 时,抛出该异常。

示例:

参见 func endArray 示例。

func writeFloat(Float64)

public func writeFloat(v: Float64): Unit

功能:向日志输出目标中写入 Float64 值。

参数:

  • v: Float64 - 待写入的 Float64 值。

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 value 时。

示例:

参见 func endArray 示例。

func writeInt(Int64)

public func writeInt(v: Int64): Unit

功能:向日志输出目标中写入 Int64 值。

参数:

  • v: Int64 - 待写入的 Int64 值。

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 value 时。

示例:

参见 func endArray 示例。

func writeKey(String)

public func writeKey(v: String): Unit

功能:向日志输出目标中写入 name。

参数:

  • v: String - 待写入的 Key 值。

异常:

  • IllegalStateException - 当前 writer 的状态不应写入参数 name 指定字符串时。

示例:

参见 func endArray 示例。

func writeNone()

public func writeNone(): Unit

功能:向日志输出目标中写入 None,具体写成什么格式由 Logger 的提供者自行决定。

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 value 时。

示例:

参见 func endArray 示例。

func writeString(String)

public func writeString(v: String): Unit

功能:向日志输出目标中写入 String 值。

参数:

  • v: String - 待写入的 String 值。

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 value 时。

示例:

参见 func endArray 示例。

func writeValue(LogValue)

public func writeValue(v: LogValue): Unit

功能:将实现了 LogValue 接口的类型写入到日志输出目标中。该接口会调用 LogValuewriteTo 方法向日志输出目标中写入数据。

log 包已经为基础类型 Int64、Float64、Bool、String 类型扩展实现了 LogValue,并且为 DateTime、Duration、 Collection 类型 Array、HashMap 和 TreeMap 以及 Option<T> 扩展实现了 LogValue

参数:

异常:

  • IllegalStateException - 当前 writer 的状态不应该写入 value 时。

示例:

参见 func endArray 示例。

class NoopLogger

public class NoopLogger <: Logger {
    public init()
}

功能:Logger 的 NO-OP(无操作)实现,会丢弃所有的日志。

父类型:

prop level

public mut prop level: LogLevel

功能:永远只能获取到 OFF 日志打印级别,设置日志打印级别不会生效。

类型:LogLevel

示例:

import stdx.log.*

main() {
    // 创建一个NoopLogger实例
    let logger = NoopLogger()

    // 获取当前日志级别
    let currentLevel = logger.level
    println("初始日志级别: ${currentLevel}")

    // 尝试设置日志级别(不会生效)
    logger.level = LogLevel.DEBUG
    let newLevel = logger.level
    println("设置后的日志级别: ${newLevel}")

    return 0
}

运行结果:

初始日志级别: OFF
设置后的日志级别: OFF

init()

public init()

功能:创建一个 NoopLogger 实例。

示例:

import stdx.log.*

main() {
    // 创建一个NoopLogger实例
    let logger = NoopLogger()
    return 0
}

func close()

public func close(): Unit

功能:NOOP 实现。

示例:

import stdx.log.*

main() {
    // 创建一个NoopLogger实例
    let logger = NoopLogger()

    // 调用close方法
    logger.close()

    println("close方法调用完成(无操作,空实现)")

    return 0
}

运行结果:

close方法调用完成(无操作,空实现)

func isClosed()

public func isClosed(): Bool

功能:NOOP 实现。

返回值:

  • Bool - 是否关闭。

示例:

import stdx.log.*

main() {
    // 创建一个NoopLogger实例
    let logger = NoopLogger()

    // 检查是否关闭
    let isClosed = logger.isClosed()
    println("日志记录器是否关闭(无操作,空实现): ${isClosed}")

    return 0
}

运行结果:

日志记录器是否关闭(无操作,空实现): false

func log(LogLevel, () -> String, Array<Attr>)

public func log(level: LogLevel, message: () -> String, attrs: Array<Attr>): Unit

功能:NOOP 实现。

参数:

  • level: LogLevel - 日志级别。
  • message: () -> String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

示例:

import stdx.log.*

main() {
    // 创建一个NoopLogger实例
    let logger = NoopLogger()

    // 调用log方法(使用lambda表达式)
    logger.log(LogLevel.INFO, {=> "这是一条信息日志"}, [("type", "info"), ("id", 123)])

    println("log方法调用完成(无操作,空实现)")

    return 0
}

运行结果:

log方法调用完成(无操作,空实现)

func log(LogLevel, String, Array<Attr>)

public func log(level: LogLevel, message: String, attrs: Array<Attr>): Unit

功能:NOOP 实现。

参数:

  • level: LogLevel - 日志级别。
  • message: String - 日志消息。
  • attrs: Array<Attr> - 日志数据键值对。

示例:

import stdx.log.*

main() {
    // 创建一个NoopLogger实例
    let logger = NoopLogger()

    // 调用log方法(使用字符串消息)
    logger.log(LogLevel.WARN, "这是一条警告日志", [("type", "warn"), ("id", 456)])

    println("log方法调用完成(无操作,空实现)")

    return 0
}

运行结果:

log方法调用完成(无操作,空实现)

func log(LogRecord)

public func log(record: LogRecord): Unit

功能:NOOP 实现。

参数:

示例:

import stdx.log.*
import std.time.*

main() {
    // 创建一个NoopLogger实例
    let logger = NoopLogger()

    // 创建一个LogRecord实例
    let record = LogRecord(DateTime.now(), LogLevel.ERROR, "这是一条错误日志", [("type", "error"), ("id", 789)])

    // 调用log方法(使用LogRecord)
    logger.log(record)

    println("log方法调用完成(无操作,空实现)")

    return 0
}

运行结果:

log方法调用完成(无操作,空实现)

func withAttrs(Array<Attr>)

public func withAttrs(attrs: Array<Attr>): Logger

功能:NOOP 实现。

参数:

  • attrs: Array<Attr> - 日志数据键值对。

返回值:

示例:

import stdx.log.*

main() {
    // 创建一个NoopLogger实例
    let logger = NoopLogger()

    // 调用withAttrs方法
    let newLogger = logger.withAttrs([("user", "admin"), ("session", "12345")])

    println("withAttrs方法调用完成(无操作,空实现)")

    return 0
}

运行结果:

withAttrs方法调用完成(无操作,空实现)

结构体

struct LogLevel

public struct LogLevel <: ToString & Comparable<LogLevel> {
    public static const OFF: LogLevel = LogLevel("OFF", 0x7FFF_FFFF)
    public static const FATAL: LogLevel = LogLevel("FATAL", 6000)
    public static const ERROR: LogLevel = LogLevel("ERROR", 5000)
    public static const WARN: LogLevel = LogLevel("WARN", 4000)
    public static const INFO: LogLevel = LogLevel("INFO", 3000)
    public static const DEBUG: LogLevel = LogLevel("DEBUG", 2000)
    public static const TRACE: LogLevel = LogLevel("TRACE", 1000)
    public static const ALL: LogLevel = LogLevel("ALL", -0x8000_0000)
    public let name: String
    public let value: Int32
    public const init(name: String, value: Int32)
}

功能:LogLevel 为日志级别结构体。

定义了日志打印的七个级别,级别从高到低分别为 OFFFATALERRORWARNINFODEBUGTRACEALL

我们期望只有级别大于等于指定打印级别的日志条目会被打印到输出流中。

父类型:

static const ALL

public static const ALL: LogLevel = LogLevel("ALL", -0x8000_0000)

功能:获取一个日志打印级别的静态常量实例,等级为所有。

类型:LogLevel

示例:

import stdx.log.*

main() {
    // 获取ALL日志级别常量
    let allLevel = LogLevel.ALL

    println("ALL日志级别名称: ${allLevel.name}")
    println("ALL日志级别值: ${allLevel.value}")

    return 0
}

运行结果:

ALL日志级别名称: ALL
ALL日志级别值: -2147483648

static const DEBUG

public static const DEBUG: LogLevel = LogLevel("DEBUG", 2000)

功能:获取一个日志打印级别的静态常量实例,等级为调试。

类型:LogLevel

示例:

import stdx.log.*

main() {
    // 获取DEBUG日志级别常量
    let debugLevel = LogLevel.DEBUG

    println("DEBUG日志级别名称: ${debugLevel.name}")
    println("DEBUG日志级别值: ${debugLevel.value}")

    return 0
}

运行结果:

DEBUG日志级别名称: DEBUG
DEBUG日志级别值: 2000

static const ERROR

public static const ERROR: LogLevel = LogLevel("ERROR", 5000)

功能:获取一个日志打印级别的静态常量实例,等级为错误。

类型:LogLevel

示例:

import stdx.log.*

main() {
    // 获取ERROR日志级别常量
    let errorLevel = LogLevel.ERROR

    println("ERROR日志级别名称: ${errorLevel.name}")
    println("ERROR日志级别值: ${errorLevel.value}")

    return 0
}

运行结果:

ERROR日志级别名称: ERROR
ERROR日志级别值: 5000

static const FATAL

public static const FATAL: LogLevel = LogLevel("FATAL", 6000)

功能:获取一个日志打印级别的静态常量实例,等级为严重错误。

类型:LogLevel

示例:

import stdx.log.*

main() {
    // 获取FATAL日志级别常量
    let fatalLevel = LogLevel.FATAL

    println("FATAL日志级别名称: ${fatalLevel.name}")
    println("FATAL日志级别值: ${fatalLevel.value}")

    return 0
}

运行结果:

FATAL日志级别名称: FATAL
FATAL日志级别值: 6000

static const INFO

public static const INFO: LogLevel = LogLevel("INFO", 3000)

功能:获取一个日志打印级别的静态常量实例,等级为通知。

类型:LogLevel

示例:

import stdx.log.*

main() {
    // 获取INFO日志级别常量
    let infoLevel = LogLevel.INFO

    println("INFO日志级别名称: ${infoLevel.name}")
    println("INFO日志级别值: ${infoLevel.value}")

    return 0
}

运行结果:

INFO日志级别名称: INFO
INFO日志级别值: 3000

static const OFF

public static const OFF: LogLevel = LogLevel("OFF", 0x7FFF_FFFF)

功能:获取一个日志打印级别的静态常量实例,等级为禁用。

类型:LogLevel

示例:

import stdx.log.*

main() {
    // 获取OFF日志级别常量
    let offLevel = LogLevel.OFF

    println("OFF日志级别名称: ${offLevel.name}")
    println("OFF日志级别值: ${offLevel.value}")

    return 0
}

运行结果:

OFF日志级别名称: OFF
OFF日志级别值: 2147483647

static const TRACE

public static const TRACE: LogLevel = LogLevel("TRACE", 1000)

功能:获取一个日志打印级别的静态常量实例,等级为跟踪。

类型:LogLevel

示例:

import stdx.log.*

main() {
    // 获取TRACE日志级别常量
    let traceLevel = LogLevel.TRACE

    println("TRACE日志级别名称: ${traceLevel.name}")
    println("TRACE日志级别值: ${traceLevel.value}")

    return 0
}

运行结果:

TRACE日志级别名称: TRACE
TRACE日志级别值: 1000

static const WARN

public static const WARN: LogLevel = LogLevel("WARN", 4000)

功能:获取一个日志打印级别的静态常量实例,等级为警告。

类型:LogLevel

示例:

import stdx.log.*

main() {
    // 获取WARN日志级别常量
    let warnLevel = LogLevel.WARN

    println("WARN日志级别名称: ${warnLevel.name}")
    println("WARN日志级别值: ${warnLevel.value}")

    return 0
}

运行结果:

WARN日志级别名称: WARN
WARN日志级别值: 4000

let name

public let name: String

功能:日志级别名。

类型:String

示例:

import stdx.log.*

main() {
    // 获取一个日志级别常量
    let level = LogLevel.INFO

    // 访问name属性
    let name = level.name

    println("日志级别名称: ${name}")

    return 0
}

运行结果:

日志级别名称: INFO

let value

public let value: Int32

功能:日志级别值。

类型:Int32

示例:

import stdx.log.*

main() {
    // 获取一个日志级别常量
    let level = LogLevel.WARN

    // 访问value属性
    let value = level.value

    println("日志级别值: ${value}")

    return 0
}

运行结果:

日志级别值: 4000

const init(String, Int32)

public const init(name: String, value: Int32)

功能:常量构造函数,创建 LogLevel 对象。

参数:

  • name: String - 日志级别名。
  • value: Int32 - 日志级别值。

示例:

import stdx.log.*

main() {
    // 使用构造函数创建自定义LogLevel
    let customLevel = LogLevel("CUSTOM", 1500)

    println("自定义日志级别名称: ${customLevel.name}")
    println("自定义日志级别值: ${customLevel.value}")

    return 0
}

运行结果:

自定义日志级别名称: CUSTOM
自定义日志级别值: 1500

func compare(LogLevel)

public func compare(rhs: LogLevel): Ordering

功能:判断当前 LogLevel 类型实例与参数指向的 LogLevel 类型实例的大小关系。

参数:

  • rhs: LogLevel - 待与当前实例比较的另一个实例。

返回值:

  • Ordering - 如果大于,返回 Ordering.GT,如果等于,返回 Ordering.EQ,如果小于,返回 Ordering.LT。

示例:

import stdx.log.*

main() {
    // 创建两个日志级别实例
    let level1 = LogLevel.INFO
    let level2 = LogLevel.WARN

    // 比较两个日志级别
    let comparison = level1.compare(level2)

    println("INFO与WARN的比较结果: ${comparison}")

    return 0
}

运行结果:

INFO与WARN的比较结果: Ordering.LT

func toString()

public func toString(): String

功能:获取日志级别对应的名称。

返回值:

  • String - 当前的日志级别的名称。

示例:

import stdx.log.*

main() {
    // 获取一个日志级别常量
    let level = LogLevel.ERROR

    // 调用toString方法获取名称
    let name = level.toString()

    println("ERROR日志级别的字符串表示: ${name}")

    return 0
}

运行结果:

ERROR日志级别的字符串表示: ERROR

operator func !=(LogLevel)

public operator func !=(rhs: LogLevel): Bool

功能:比较日志级别高低。

参数:

  • rhs: LogLevel - 将当前日志级别和 target 进行比较。

返回值:

  • Bool - 如果当前日志级别不等于 target,返回 true,否则返回 false

示例:

import stdx.log.*

main() {
    // 创建两个不同的日志级别
    let level1 = LogLevel.INFO
    let level2 = LogLevel.WARN

    // 使用!=操作符比较
    let notEqual = level1 != level2

    println("INFO不等于WARN: ${notEqual}")

    // 创建两个相同的日志级别
    let level3 = LogLevel.INFO
    let level4 = LogLevel.INFO

    // 使用!=操作符比较
    let equalNot = level3 != level4

    println("INFO不等于INFO: ${equalNot}")

    return 0
}

运行结果:

INFO不等于WARN: true
INFO不等于INFO: false

operator func <(LogLevel)

public operator func <(rhs: LogLevel): Bool

功能:比较日志级别高低。

参数:

  • rhs: LogLevel - 将当前日志级别和 target 进行比较。

返回值:

  • Bool - 如果当前日志级别小于 target,返回 true,否则返回 false

示例:

import stdx.log.*

main() {
    // 创建两个日志级别
    let level1 = LogLevel.INFO
    let level2 = LogLevel.WARN

    // 使用<操作符比较
    let lessThan = level1 < level2

    println("INFO小于WARN: ${lessThan}")

    // 再次比较
    let greaterOrEqual = level2 < level1

    println("WARN小于INFO: ${greaterOrEqual}")

    return 0
}

运行结果:

INFO小于WARN: true
WARN小于INFO: false

operator func <=(LogLevel)

public operator func <=(rhs: LogLevel): Bool

功能:比较日志级别高低。

参数:

  • rhs: LogLevel - 将当前日志级别和 target 进行比较。

返回值:

  • Bool - 如果当前日志级别小于等于 target,返回 true,否则返回 false

示例:

import stdx.log.*

main() {
    // 创建两个日志级别
    let level1 = LogLevel.INFO
    let level2 = LogLevel.WARN

    // 使用<=操作符比较
    let lessThanOrEqual = level1 <= level2

    println("INFO小于等于WARN: ${lessThanOrEqual}")

    // 比较相同级别
    let level3 = LogLevel.INFO
    let level4 = LogLevel.INFO

    // 使用<=操作符比较相同级别
    let sameLevel = level3 <= level4

    println("INFO小于等于INFO: ${sameLevel}")

    return 0
}

运行结果:

INFO小于等于WARN: true
INFO小于等于INFO: true

operator func ==(LogLevel)

public operator func ==(rhs: LogLevel): Bool

功能:比较日志级别高低。

参数:

  • rhs: LogLevel - 将当前日志级别和 target 进行比较。

返回值:

  • Bool - 如果当前日志级别等于 target,返回 true,否则返回 false

示例:

import stdx.log.*

main() {
    // 创建两个相同的日志级别
    let level1 = LogLevel.INFO
    let level2 = LogLevel.INFO

    // 使用==操作符比较
    let isEqual = level1 == level2

    println("INFO等于INFO: ${isEqual}")

    // 创建两个不同的日志级别
    let level3 = LogLevel.INFO
    let level4 = LogLevel.WARN

    // 使用==操作符比较
    let notEqual = level3 == level4

    println("INFO等于WARN: ${notEqual}")

    return 0
}

运行结果:

INFO等于INFO: true
INFO等于WARN: false

operator func >(LogLevel)

public operator func >(rhs: LogLevel): Bool

功能:比较日志级别高低。

参数:

  • rhs: LogLevel - 将当前日志级别和 target 进行比较。

返回值:

  • Bool - 如果当前日志级别大于 target,返回 true,否则返回 false

示例:

import stdx.log.*

main() {
    // 创建两个日志级别
    let level1 = LogLevel.WARN
    let level2 = LogLevel.INFO

    // 使用>操作符比较
    let greaterThan = level1 > level2

    println("WARN大于INFO: ${greaterThan}")

    // 再次比较
    let lessOrEqual = level2 > level1

    println("INFO大于WARN: ${lessOrEqual}")

    return 0
}

运行结果:

WARN大于INFO: true
INFO大于WARN: false

operator func >=(LogLevel)

public operator func >=(rhs: LogLevel): Bool

功能:比较日志级别高低。

参数:

  • rhs: LogLevel - 将当前日志级别和 target 进行比较。

返回值:

  • Bool - 如果当前日志级别大于等于 target,返回 true,否则返回 false

示例:

import stdx.log.*

main() {
    // 创建两个日志级别
    let level1 = LogLevel.WARN
    let level2 = LogLevel.INFO

    // 使用>=操作符比较
    let greaterThanOrEqual = level1 >= level2

    println("WARN大于等于INFO: ${greaterThanOrEqual}")

    // 比较相同级别
    let level3 = LogLevel.INFO
    let level4 = LogLevel.INFO

    // 使用>=操作符比较相同级别
    let sameLevel = level3 >= level4

    println("INFO大于等于INFO: ${sameLevel}")

    return 0
}

运行结果:

WARN大于等于INFO: true
INFO大于等于INFO: true

异常类

class LogException

public open class LogException <: Exception {
    public init()
    public init(message: String)
}

功能:用于处理 log 相关的异常。

父类型:

  • Exception

init()

public init()

功能:无参构造函数。

示例:

import stdx.log.*

main(): Unit {
    try {
        // 抛出一个无参的LogException异常
        throw LogException()
    } catch (e: LogException) {
        println("异常信息:${e.message}")
    }
}

运行结果:

异常信息:

init(String)

public init(message: String)

功能:根据异常信息创建 LogException 实例。

参数:

  • message: String - 异常信息。

示例:

import stdx.log.*

main(): Unit {
    try {
        // 抛出一个带消息的LogException异常
        throw LogException("日志异常")
    } catch (e: LogException) {
        println("异常信息: ${e.message}")
    }
}

运行结果:

异常信息: 日志异常

func getClassName()

protected override func getClassName(): String

功能:获得类名。

返回值:

  • String - 类名。

示例:

import stdx.log.*

main() {
    // 创建一个MyException实例
    let exception = MyException()

    // 调用getClassName函数获取类名
    let className = exception.myGetClassName()
    println("类名: ${className}")
}

// 子类可以调用父类的保护方法
class MyException <: LogException {
    func myGetClassName(): String {
        return getClassName()
    }
}

运行结果:

类名: LogException

日志打印示例

库开发场景记录日志

下面是开发仓颉库时,打印日志的示例。

代码如下:

import stdx.log.*
import stdx.logger.*
import std.env.*

public class PGConnection {
    let objId: Int64 = 1
    let logger = getGlobalLogger(("name", "PGConnection"))

    public func close(): Unit {
        logger.trace("driver conn closed", ("id", objId))
    }
}

main(): Unit {
    let tl = SimpleLogger(getStdOut())
    tl.level = LogLevel.TRACE
    setGlobalLogger(tl)
    var conn = PGConnection()
    conn.close()
}

运行结果可能如下:

2024-11-21T20:16:43.33200773+08:00 TRACE driver conn closed name="PGConnection" id=1

应用程序开发场景日志打印

下面是 自定义 PasswordFilter 和 TextLogger 日志打印示例。

代码如下:

import std.time.*
import std.io.{OutputStream, ByteBuffer, BufferedOutputStream}
import std.env.*
import std.fs.*
import std.collection.{ArrayList, Map, HashMap}
import std.collection.concurrent.*
import std.sync.AtomicBool
import std.time.DateTime
import stdx.log.*

public class PasswordFilter <: Logger {
    var _level = LogLevel.INFO
    let processor: Logger
    public init(logger: Logger) {
        processor = logger
    }
    public mut prop level: LogLevel {
        get() {
            _level
        }
        set(v) {
            _level = v
        }
    }
    public func withAttrs(attrs: Array<Attr>): Logger {
        this
    }
    // log
    public func log(level: LogLevel, message: String, attrs: Array<Attr>): Unit {
        let record: LogRecord = LogRecord(DateTime.now(), level, message, attrs)
        log(record)
    }
    // lazy
    public func log(level: LogLevel, message: () -> String, attrs: Array<Attr>): Unit {
        let record: LogRecord = LogRecord(DateTime.now(), level, message(), attrs)
        log(record)
    }
    // 根据键值对的名字过滤,将密码值换成 "***"
    public func log(record: LogRecord): Unit {
        var attrs = record.attrs.clone()
        for (i in 0..attrs.size) {
            var attr = attrs[i]
            if (attr[0] == "password") {
                attrs[i] = (attr[0], "***")
            }
        }
        let r = LogRecord(record.time, record.level, record.message, attrs)
        processor.log(r)
    }
    public func isClosed(): Bool {
        false
    }
    public func close(): Unit {
    }
}

main() {
    let o = ByteBuffer()
    let tl = TextLogger(getStdOut())
    tl.level = LogLevel.TRACE
    let l = PasswordFilter(tl)
    setGlobalLogger(l)
    let logger = getGlobalLogger([("name", "main")])
    let user = User()
    // 普通记录信息日志
    logger.info("Hello, World!", ("k1", [[1, 4], [2, 5], [3]]), ("password", "v22222"))
    // 记录诊断日志,如果 DEBUG 级别未开启,直接返回,几乎无cost
    logger.debug("Logging in user ${user.name} with birthday ${user.birthdayCalendar}")

    // lazy 方式记录耗时日志数据
    logger.log(LogLevel.ERROR, "long-running operation msg", ("k1", 100), ("k2", user.birthdayCalendar),
        ("oper", ToStringWrapper({=> "Some long-running operation returned"})))

    logger.log(LogLevel.ERROR, "long-running operation msg", ("sourcePackage", @sourcePackage()),
        ("sourceFile", @sourceFile()), ("sourceLine", @sourceLine()), ("birthdayCalendar", user.birthdayCalendar),
        ("oper", ToStringWrapper({=> "Some long-running operation returned"})))

    let m = HashMap<String, String>()
    m.add("k1", "1")
    m.add("k2", "2")
    m.add("k3", "3")
    logger.trace({=> "Some long-running operation returned"}, ("k1", m))
    let m2 = HashMap<String, LogValue>()
    m2.add("g1", m)

    // 如果TRACE 级别没有开启,那么lambda表达式不会被执行
    logger.trace({=> "Some long-running operation returned"}, ("k2", m2))

    // Console.stdOut.write(o.bytes())
    // Console.stdOut.flush()
}

public class User {
    public prop name: String {
        get() {
            "foo"
        }
    }
    public prop birthdayCalendar: DateTime {
        get() {
            DateTime.now()
        }
    }
}

public class ToStringWrapper <: ToString & LogValue {
    let _fn: () -> String
    public init(fn: () -> String) {
        _fn = fn
    }
    public func toString(): String {
        return _fn()
    }
    public func writeTo(w: LogWriter): Unit {
        w.writeValue(_fn())
    }
}

public class TextLogger <: Logger {
    let w: TextLogWriter
    let opts = HashMap<String, String>()
    let _closed = AtomicBool(false)
    let queue = ConcurrentLinkedQueue<LogRecord>()
    let bo: BufferedOutputStream<OutputStream>
    let _attrs = ArrayList<Attr>()
    var _level = LogLevel.INFO
    public init(output: OutputStream) {
        bo = BufferedOutputStream<OutputStream>(output)
        w = TextLogWriter(bo)
    }

    public mut prop level: LogLevel {
        get() {
            _level
        }
        set(v) {
            _level = v
        }
    }
    public func withAttrs(attrs: Array<Attr>): Logger {
        if (attrs.size > 0) {
            let nl = TextLogger(w.out)
            nl._attrs.add(all: attrs)
            return nl
        }
        return this
    }
    // log
    public func log(level: LogLevel, message: String, attrs: Array<Attr>): Unit {
        if (this.enabled(level)) {
            let record: LogRecord = LogRecord(DateTime.now(), level, message, attrs)
            log(record)
        }
    }
    // lazy
    public func log(level: LogLevel, message: () -> String, attrs: Array<Attr>): Unit {
        if (this.enabled(level)) {
            let record: LogRecord = LogRecord(DateTime.now(), level, message(), attrs)
            log(record)
        }
    }
    public func log(record: LogRecord): Unit {
        // write time
        w.writeKey("time")
        w.writeValue(record.time)
        w.writeString(" ")
        // write level
        w.writeKey("level")
        w.writeString(record.level.toString())
        w.writeString(" ")
        // write message
        w.writeKey("msg")
        w.writeValue(record.message)
        w.writeString(" ")
        // write source

        // write attrs
        for (i in 0..record.attrs.size) {
            let attr = record.attrs[i]
            w.writeKey(attr[0])
            w.writeValue(attr[1])
            if (i < record.attrs.size - 1) {
                w.writeString(" ")
            }
        }
        w.writeString("\n")
        bo.flush()
    }
    public func isClosed(): Bool {
        _closed.load()
    }
    public func close(): Unit {
        if (isClosed()) {
            return
        }
        _closed.store(true)
    }
}

class TextLogWriter <: LogWriter {
    var out: OutputStream
    init(out: OutputStream) {
        this.out = out
    }
    public func writeNone(): Unit {
        out.write("None".toArray())
    }
    public func writeInt(v: Int64): Unit {
        out.write(v.toString().toArray())
    }
    public func writeUInt(v: UInt64): Unit {
        out.write(v.toString().toArray())
    }
    public func writeBool(v: Bool): Unit {
        out.write(v.toString().toArray())
    }
    public func writeFloat(v: Float64): Unit {
        out.write(v.toString().toArray())
    }
    public func writeString(v: String): Unit {
        out.write(v.toArray())
    }
    public func writeDateTime(v: DateTime): Unit {
        out.write(v.toString().toArray())
    }
    public func writeDuration(v: Duration): Unit {
        out.write(v.toString().toArray())
    }
    public func writeException(v: Exception): Unit {
        out.write(v.toString().toArray())
    }
    public func writeKey(v: String): Unit {
        out.write(v.toString().toArray())
        out.write("=".toArray())
    }
    public func writeValue(v: LogValue): Unit {
        match (v) {
            case vv: String =>
                out.write("\"".toArray())
                out.write(vv.toArray())
                out.write("\"".toArray())
            case vv: ToString =>
                out.write("\"".toArray())
                out.write(vv.toString().toArray())
                out.write("\"".toArray())
            case _ =>
                out.write("\"".toArray())
                v.writeTo(this)
                out.write("\"".toArray())
        }
    }
    public func startArray(): Unit {
        out.write("[".toArray())
    }
    public func endArray(): Unit {
        out.write("]".toArray())
    }
    public func startObject(): Unit {
        out.write("{".toArray())
    }
    public func endObject(): Unit {
        out.write("}".toArray())
    }
}

运行结果可能如下:

time="2024-06-17T14:10:07.1861349Z" level=INFO msg="Hello, World!" k1="[[1, 4], [2, 5], [3]]" password="***"
time="2024-06-17T14:10:07.1864929Z" level=DEBUG msg="Logging in user foo with birthday 2024-06-17T14:10:07.1864802Z"
time="2024-06-17T14:10:07.1869579Z" level=ERROR msg="long-running operation msg" k1="100" k2="2024-06-17T14:10:07.186957Z" oper="Some long-running operation returned"
time="2024-06-17T14:10:07.18742Z" level=ERROR msg="long-running operation msg" sourcePackage="log" sourceFile="main.cj" sourceLine="77" birthdayCalendar="2024-06-17T14:10:07.1874188Z" oper="Some long-running operation returned"
time="2024-06-17T14:10:07.1879195Z" level=TRACE msg="Some long-running operation returned" k1="[(k1, 1), (k2, 2), (k3, 3)]"
time="2024-06-17T14:10:07.1881599Z" level=TRACE msg="Some long-running operation returned" k2="{g1="[(k1, 1), (k2, 2), (k3, 3)]"}"

stdx.logger

功能介绍

logger 包提供文本格式和 JSON 格式日志打印功能。

API 列表

类名功能
JsonLogger输出 JSON 格式的 Logger 类实现。
SimpleLogger输出传统文本格式的 Logger 类实现。
TextLogger输出文本 KV 格式的 Logger 类实现。

class JsonLogger

public class JsonLogger <: Logger {
    public init(output: OutputStream)
}

功能:此类实现了输出 JSON 格式的日志打印功能,形如 {"time":"2024-07-27T11:51:59+08:00","level":"INFO","msg":"foo","name":"bar"}

父类型:

prop level

public mut prop level: LogLevel

功能:获取和修改日志打印级别。

类型:LogLevel

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*

main() {
    // 创建JsonLogger实例,使用标准输出流
    let logger = JsonLogger(getStdOut())

    // 获取当前的日志级别
    let currentLevel = logger.level
    println("默认日志级别: ${currentLevel}")

    // 设置一个新的日志级别
    logger.level = LogLevel.DEBUG

    // 再次获取日志级别以确认更改
    let updatedLevel = logger.level
    println("更新后的日志级别: ${updatedLevel}")

    return 0
}

运行结果:

默认日志级别: INFO
更新后的日志级别: DEBUG

init(OutputStream)

public init(output: OutputStream)

功能:创建 JsonLogger 对象。

参数:

  • output: OutputStream - 绑定的输出流,日志格式化后将写入该输出流。

示例:

import stdx.logger.*
import std.env.*

main() {
    // 使用标准输出流创建JsonLogger实例
    let logger = JsonLogger(getStdOut())
    return 0
}

func close()

public func close(): Unit

功能:关闭 Logger。

示例:

import stdx.logger.*
import std.env.*

main() {
    // 创建JsonLogger实例
    let logger = JsonLogger(getStdOut())

    // 检查logger是否关闭
    let isClosedBefore = logger.isClosed()
    println("关闭前状态: ${isClosedBefore}")

    // 关闭logger
    logger.close()

    // 再次检查是否关闭
    let isClosedAfter = logger.isClosed()
    println("关闭后状态: ${isClosedAfter}")

    return 0
}

运行结果:

关闭前状态: false
关闭后状态: true

func isClosed()

public func isClosed(): Bool

功能:判断当前 Logger 是否关闭。

返回值:

  • Bool - 是否关闭。

示例:

参见 func close 示例。

func log(LogRecord)

public func log(record: LogRecord): Unit

功能:打印日志的通用函数。

参数:

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*
import std.time.*

main() {
    // 创建JsonLogger实例
    let logger = JsonLogger(getStdOut())

    // 创建一个LogRecord实例
    let dateTime = DateTime.of(year: 2026, month: 1, dayOfMonth: 1, timeZone: TimeZone.UTC)
    let logRecord = LogRecord(dateTime, LogLevel.INFO, "这是一个测试消息")

    // 使用log方法记录日志
    logger.log(logRecord)
    return 0
}

运行结果:

{"time":"2026-01-01T00:00:00Z","level":"INFO","msg":"这是一个测试消息"}

func withAttrs(Array<Attr>)

public func withAttrs(attrs: Array<Attr>): Logger

功能:创建当前对象的副本,新的副本会包含指定的属性。

参数:

  • attrs: Array<Attr> - 日志数据键值对属性。

返回值:

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*
import std.time.*

main() {
    // 创建JsonLogger实例
    let logger = JsonLogger(getStdOut())

    // 创建一个LogRecord实例
    let dateTime = DateTime.of(year: 2026, month: 1, dayOfMonth: 1, timeZone: TimeZone.UTC)
    let logRecord = LogRecord(dateTime, LogLevel.INFO, "这是一个测试消息")

    // 使用log方法记录日志,发现日志中不包含属性
    logger.log(logRecord)

    // 创建属性数组
    let attr1: (String, LogValue) = ("key1", "value1")
    let attr2: (String, LogValue) = ("key2", 123)
    let attrs = [attr1, attr2]

    // 使用withAttrs方法创建带属性的logger副本
    let loggerWithAttrs = logger.withAttrs(attrs)

    // 再次使用log方法记录日志,发现日志中包含属性
    loggerWithAttrs.log(logRecord)
    return 0
}

运行结果:

{"time":"2026-01-01T00:00:00Z","level":"INFO","msg":"这是一个测试消息"}
{"time":"2026-01-01T00:00:00Z","level":"INFO","msg":"这是一个测试消息","key1":"value1","key2":123}

class SimpleLogger

public class SimpleLogger <: Logger {
    public init(output: OutputStream)
}

功能:此类实现了输出文本格式的日志打印功能,形如 2024-07-27T11:50:47.6616733+08:00 INFO foo name="bar"

父类型:

prop level

public mut prop level: LogLevel

功能:获取和修改日志打印级别。

类型:LogLevel

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*

main() {
    // 创建SimpleLogger实例,使用标准输出流
    let logger = SimpleLogger(getStdOut())

    // 获取当前的日志级别
    let currentLevel = logger.level
    println("默认日志级别: ${currentLevel}")

    // 设置一个新的日志级别
    logger.level = LogLevel.DEBUG

    // 再次获取日志级别以确认更改
    let updatedLevel = logger.level
    println("更新后的日志级别: ${updatedLevel}")

    return 0
}

运行结果:

默认日志级别: INFO
更新后的日志级别: DEBUG

init(OutputStream)

public init(output: OutputStream)

功能:创建 SimpleLogger 对象。

参数:

  • output: OutputStream - 绑定的输出流,日志格式化后将写入该输出流。

示例:

import stdx.logger.*
import std.env.*

main() {
    // 使用标准输出流创建SimpleLogger实例
    let logger = SimpleLogger(getStdOut())
    return 0
}

func close()

public func close(): Unit

功能:关闭 Logger。

示例:

import stdx.logger.*
import std.env.*

main() {
    // 创建SimpleLogger实例
    let logger = SimpleLogger(getStdOut())

    // 检查logger是否关闭
    let isClosedBefore = logger.isClosed()
    println("关闭前状态: ${isClosedBefore}")

    // 关闭logger
    logger.close()

    // 再次检查是否关闭
    let isClosedAfter = logger.isClosed()
    println("关闭后状态: ${isClosedAfter}")

    return 0
}

运行结果:

关闭前状态: false
关闭后状态: true

func isClosed()

public func isClosed(): Bool

功能:判断当前 Logger 是否关闭。

返回值:

  • Bool - 是否关闭。

示例:

参见 func close 示例。

func log(LogRecord)

public func log(record: LogRecord): Unit

功能:打印日志的通用函数。

参数:

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*
import std.time.*

main() {
    // 创建SimpleLogger实例
    let logger = SimpleLogger(getStdOut())

    // 创建一个LogRecord实例
    let dateTime = DateTime.of(year: 2026, month: 1, dayOfMonth: 1, timeZone: TimeZone.UTC)
    let logRecord = LogRecord(dateTime, LogLevel.INFO, "这是一个测试消息")

    // 使用log方法记录日志
    logger.log(logRecord)
    return 0
}

运行结果:

2026-01-01T00:00:00Z INFO 这是一个测试消息

func withAttrs(Array<Attr>)

public func withAttrs(attrs: Array<Attr>): Logger

功能:创建当前对象的副本,新的副本会包含指定的属性。

参数:

  • attrs: Array<Attr> - 日志数据键值对属性。

返回值:

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*
import std.time.*

main() {
    // 创建SimpleLogger实例
    let logger = SimpleLogger(getStdOut())

    // 创建一个LogRecord实例
    let dateTime = DateTime.of(year: 2026, month: 1, dayOfMonth: 1, timeZone: TimeZone.UTC)
    let logRecord = LogRecord(dateTime, LogLevel.INFO, "这是一个测试消息")

    // 使用log方法记录日志,发现日志中不包含属性
    logger.log(logRecord)

    // 创建属性数组
    let attr1: (String, LogValue) = ("key1", "value1")
    let attr2: (String, LogValue) = ("key2", 123)
    let attrs = [attr1, attr2]

    // 使用withAttrs方法创建带属性的logger副本
    let loggerWithAttrs = logger.withAttrs(attrs)

    // 再次使用log方法记录日志,发现日志中包含属性
    loggerWithAttrs.log(logRecord)
    return 0
}

运行结果:

2026-01-01T00:00:00Z INFO 这是一个测试消息 
2026-01-01T00:00:00Z INFO 这是一个测试消息 key1="value1" key2=123

class TextLogger

public class TextLogger <: Logger {
    public init(output: OutputStream)
}

功能:此类实现了输出文本格式的日志打印功能,形如 time=2024-07-27T11:52:40.3226881+08:00 level="INFO" msg="foo" name="bar"

父类型:

prop level

public mut prop level: LogLevel

功能:获取和修改日志打印级别。

类型:LogLevel

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*

main() {
    // 创建TextLogger实例,使用标准输出流
    let logger = TextLogger(getStdOut())

    // 获取当前的日志级别
    let currentLevel = logger.level
    println("默认日志级别: ${currentLevel}")

    // 设置一个新的日志级别
    logger.level = LogLevel.DEBUG

    // 再次获取日志级别以确认更改
    let updatedLevel = logger.level
    println("更新后的日志级别: ${updatedLevel}")

    return 0
}

运行结果:

默认日志级别: INFO
更新后的日志级别: DEBUG

init(OutputStream)

public init(output: OutputStream)

功能:创建 TextLogger 对象。

参数:

  • output: OutputStream - 绑定的输出流,日志格式化后将写入该输出流。

示例:

import stdx.logger.*
import std.env.*

main() {
    // 使用标准输出流创建TextLogger实例
    let logger = TextLogger(getStdOut())
    return 0
}

func close()

public func close(): Unit

功能:关闭 Logger。

示例:

import stdx.logger.*
import std.env.*

main() {
    // 创建TextLogger实例
    let logger = TextLogger(getStdOut())

    // 检查logger是否关闭
    let isClosedBefore = logger.isClosed()
    println("关闭前状态: ${isClosedBefore}")

    // 关闭logger
    logger.close()

    // 再次检查是否关闭
    let isClosedAfter = logger.isClosed()
    println("关闭后状态: ${isClosedAfter}")

    return 0
}

运行结果:

关闭前状态: false
关闭后状态: true

func isClosed()

public func isClosed(): Bool

功能:判断当前 Logger 是否关闭。

返回值:

  • Bool - 是否关闭。

示例:

参见 func close 示例。

func log(LogRecord)

public func log(record: LogRecord): Unit

功能:打印日志的通用函数。

参数:

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*
import std.time.*

main() {
    // 创建TextLogger实例
    let logger = TextLogger(getStdOut())

    // 创建一个LogRecord实例
    let dateTime = DateTime.of(year: 2026, month: 1, dayOfMonth: 1, timeZone: TimeZone.UTC)
    let logRecord = LogRecord(dateTime, LogLevel.INFO, "这是一个测试消息")

    // 使用log方法记录日志
    logger.log(logRecord)
    return 0
}

运行结果:

time=2026-01-01T00:00:00Z level="INFO" msg="这是一个测试消息"

func withAttrs(Array<Attr>)

public func withAttrs(attrs: Array<Attr>): Logger

功能:创建当前对象的副本,新的副本会包含指定的属性。

参数:

  • attrs: Array<Attr> - 日志数据键值对属性。

返回值:

示例:

import stdx.log.*
import stdx.logger.*
import std.env.*
import std.time.*

main() {
    // 创建TextLogger实例
    let logger = TextLogger(getStdOut())

    // 创建一个LogRecord实例
    let dateTime = DateTime.of(year: 2026, month: 1, dayOfMonth: 1, timeZone: TimeZone.UTC)
    let logRecord = LogRecord(dateTime, LogLevel.INFO, "这是一个测试消息")

    // 使用log方法记录日志,发现日志中不包含属性
    logger.log(logRecord)

    // 创建属性数组
    let attr1: (String, LogValue) = ("key1", "value1")
    let attr2: (String, LogValue) = ("key2", 123)
    let attrs = [attr1, attr2]

    // 使用withAttrs方法创建带属性的logger副本
    let loggerWithAttrs = logger.withAttrs(attrs)

    // 再次使用log方法记录日志,发现日志中包含属性
    loggerWithAttrs.log(logRecord)
    return 0
}

运行结果:

time=2026-01-01T00:00:00Z level="INFO" msg="这是一个测试消息"
time=2026-01-01T00:00:00Z level="INFO" msg="这是一个测试消息" key1="value1" key2=123

日志打印示例

下面是使用 JsonLogger 日志打印示例代码:

import std.time.*
import std.io.{OutputStream, ByteBuffer, BufferedOutputStream}
import std.env.*
import std.fs.*
import std.collection.{HashMap, ArrayList}
import stdx.encoding.json.stream.*
import stdx.log.*
import stdx.logger.*

main() {
    let o = ByteBuffer()
    let bo = BufferedOutputStream<OutputStream>(getStdOut())
    let tl = JsonLogger(bo)
    tl.level = LogLevel.TRACE
    setGlobalLogger(tl)
    let logger = getGlobalLogger([("name", "main")])
    let futs = ArrayList<Future<Unit>>()

    for (_ in 0..1) {
        let f = spawn {
            =>
            logger.info("abc", ("age", 2))
            let user = User()
            // 记录诊断日志,如果 DEBUG 级别未开启,直接返回,几乎无cost
            logger.debug("Logging in user ${user.name} with birthday ${user.birthdayCalendar}")
            // 普通记录信息日志
            logger.info("Hello, World!", ("k1", [[1, 4], [2, 5], [3]]), ("password", "v22222"))

            // lazy 方式记录耗时日志数据
            logger.log(LogLevel.ERROR, "long-running operation msg", ("k1", 100), ("k2", user.birthdayCalendar),
                ("oper", ToStringWrapper({=> "Some long-running operation returned"})))

            logger.log(LogLevel.ERROR, "long-running operation msg", ("sourcePackage", @sourcePackage()),
                ("sourceFile", @sourceFile()), ("sourceLine", @sourceLine()), ("birthdayCalendar", user.birthdayCalendar),
                ("oper", ToStringWrapper({=> "Some long-running operation returned"})))

            let m = HashMap<String, String>()
            m.add("k1", "1\n")
            m.add("k2", "2")
            m.add("k3", "3")
            logger.trace({=> "Some long-running operation returned"}, ("m1", m))
            let m2 = HashMap<String, LogValue>()
            m2.add("g1", m)
            m2.add("k1", [["1", "4 s"], ["2", "5"], ["3"]])

            // 如果TRACE 级别没有开启,那么lambda表达式不会被执行
            logger.trace({=> "Some long-running operation returned"}, ("m2", m2))
        }
        futs.add(f)
    }

    for (f in futs) {
        f.get()
    }

    logger.close()
}

public class User {
    public prop name: String {
        get() {
            "foo"
        }
    }
    public prop birthdayCalendar: DateTime {
        get() {
            DateTime.now()
        }
    }
}

public class ToStringWrapper <: ToString & LogValue {
    let _fn: () -> String
    public init(fn: () -> String) {
        _fn = fn
    }
    public func toString(): String {
        return _fn()
    }
    public func writeTo(w: LogWriter): Unit {
        w.writeValue(_fn())
    }
}

运行结果如下:

{"time":"2024-07-18T07:57:45Z","level":"INFO","msg":"abc","name":"main","age":2}
{"time":"2024-07-18T07:57:45Z","level":"DEBUG","msg":"Logging in user foo with birthday 2024-07-18T07:57:45.9912185Z","name":"main"}
{"time":"2024-07-18T07:57:45Z","level":"INFO","msg":"Hello, World!","name":"main","k1":[[1,4],[2,5],[3]],"password":"v22222"}
{"time":"2024-07-18T07:57:45Z","level":"ERROR","msg":"long-running operation msg","name":"main","k1":100,"k2":"2024-07-18T07:57:45Z","oper":"Some long-running operation returned"}
{"time":"2024-07-18T07:57:45Z","level":"ERROR","msg":"long-running operation msg","name":"main","sourcePackage":"mylog","sourceFile":"main.cj","sourceLine":52,"birthdayCalendar":"2024-07-18T07:57:45Z","oper":"Some long-running operation returned"}
{"time":"2024-07-18T07:57:45Z","level":"TRACE","msg":"Some long-running operation returned","name":"main","m1":{"k1":"1\n","k2":"2","k3":"3"}}
{"time":"2024-07-18T07:57:45Z","level":"TRACE","msg":"Some long-running operation returned","name":"main","m2":{"g1":{"k1":"1\n","k2":"2","k3":"3"},"k1":[["1","4 s"],["2","5"],["3"]]}}

下面是使用 SimpleLogger 日志打印示例代码:

import std.time.*
import std.io.{OutputStream, ByteBuffer, BufferedOutputStream}
import std.env.*
import std.fs.*
import std.collection.{HashMap, ArrayList}
import stdx.log.*
import stdx.logger.*

main() {
    let o = ByteBuffer()
    let bo = BufferedOutputStream<OutputStream>(getStdOut())
    let tl = SimpleLogger(bo)
    tl.level = LogLevel.TRACE
    setGlobalLogger(tl)
    let logger = getGlobalLogger([("name", "main")])
    let futs = ArrayList<Future<Unit>>()

    // let f = File("log/a.log", Append)
    // let h = TextHandler(f)
    for (_ in 0..1) {
        let f = spawn {
            =>
            logger.info("abc", ("age", 2))
            let user = User()
            // 记录诊断日志,如果 DEBUG 级别未开启,直接返回,几乎无cost
            logger.debug("Logging in user ${user.name} with birthday ${user.birthdayCalendar}")
            // 普通记录信息日志
            logger.info("Hello, World!", ("k1", [[1, 4], [2, 5], [3]]), ("password", "v22222"))

            // lazy 方式记录耗时日志数据
            logger.log(LogLevel.ERROR, "long-running operation msg", ("k1", 100), ("k2", user.birthdayCalendar),
                ("oper", ToStringWrapper({=> "Some long-running operation returned"})))

            logger.log(LogLevel.ERROR, "long-running operation msg", ("sourcePackage", @sourcePackage()),
                ("sourceFile", @sourceFile()), ("sourceLine", @sourceLine()), ("birthdayCalendar", user.birthdayCalendar),
                ("oper", ToStringWrapper({=> "Some long-running operation returned"})))

            let m = HashMap<String, String>()
            m.add("k1", "1\n")
            m.add("k2", "2")
            m.add("k3", "3")
            logger.trace({=> "Some long-running operation returned"}, ("m1", m))
            let m2 = HashMap<String, LogValue>()
            m2.add("g1", m)
            m2.add("k1", [["1", "4 s"], ["2", "5"], ["3"]])

            // 如果TRACE 级别没有开启,那么lambda表达式不会被执行
            logger.trace({=> "Some long-running operation returned"}, ("m2", m2))
        }
        futs.add(f)
    }

    for (f in futs) {
        f.get()
    }

    logger.close()
}

public class User {
    public prop name: String {
        get() {
            "foo"
        }
    }
    public prop birthdayCalendar: DateTime {
        get() {
            DateTime.now()
        }
    }
}

public class ToStringWrapper <: ToString & LogValue {
    let _fn: () -> String
    public init(fn: () -> String) {
        _fn = fn
    }
    public func toString(): String {
        return _fn()
    }
    public func writeTo(w: LogWriter): Unit {
        w.writeValue(_fn())
    }
}

运行结果如下:

2025-04-15T15:06:54.7371418+08:00 INFO abc name="main" age=2
2025-04-15T15:06:54.737251+08:00 DEBUG Logging in user foo with birthday 2025-04-15T15:06:54.7372416+08:00 name="main"
2025-04-15T15:06:54.7376041+08:00 INFO Hello, World! name="main" k1=[[1,4],[2,5],[3]] password="v22222"
2025-04-15T15:06:54.7379054+08:00 ERROR long-running operation msg name="main" k1=100 k2=2025-04-15T15:06:54.7379047+08:00 oper="Some long-running operation returned"
2025-04-15T15:06:54.7381296+08:00 ERROR long-running operation msg name="main" sourcePackage="mylog" sourceFile="main.cj" sourceLine=37 birthdayCalendar=2025-04-15T15:06:54.7381291+08:00 oper="Some long-running operation returned"
2025-04-15T15:06:54.7385818+08:00 TRACE Some long-running operation returned name="main" m1={k1:"1\n",k2:"2",k3:"3"}
2025-04-15T15:06:54.7387716+08:00 TRACE Some long-running operation returned name="main" m2={g1:{k1:"1\n",k2:"2",k3:"3"},k1:[["1","4 s"],["2","5"],["3"]]}

下面是使用 TextLogger 日志打印示例代码:

import std.time.*
import std.io.{OutputStream, ByteBuffer, BufferedOutputStream}
import std.env.*
import std.fs.*
import std.collection.{HashMap, ArrayList}
import stdx.log.*
import stdx.logger.*

main() {
    let o = ByteBuffer()
    let bo = BufferedOutputStream<OutputStream>(getStdOut())
    let tl = TextLogger(bo)
    tl.level = LogLevel.TRACE
    setGlobalLogger(tl)
    let logger = getGlobalLogger([("name", "main")])
    let futs = ArrayList<Future<Unit>>()

    // let f = File("log/a.log", Append)
    // let h = TextHandler(f)
    for (_ in 0..1) {
        let f = spawn {
            =>
            logger.info("abc", ("age", 2))
            let user = User()
            // 记录诊断日志,如果 DEBUG 级别未开启,直接返回,几乎无cost
            logger.debug("Logging in user ${user.name} with birthday ${user.birthdayCalendar}")
            // 普通记录信息日志
            logger.info("Hello, World!", ("k1", [[1, 4], [2, 5], [3]]), ("password", "v22222"))

            // lazy 方式记录耗时日志数据
            logger.log(LogLevel.ERROR, "long-running operation msg", ("k1", 100), ("k2", user.birthdayCalendar),
                ("oper", ToStringWrapper({=> "Some long-running operation returned"})))

            logger.log(LogLevel.ERROR, "long-running operation msg", ("sourcePackage", @sourcePackage()),
                ("sourceFile", @sourceFile()), ("sourceLine", @sourceLine()), ("birthdayCalendar", user.birthdayCalendar),
                ("oper", ToStringWrapper({=> "Some long-running operation returned"})))

            let m = HashMap<String, String>()
            m.add("k1", "1\n")
            m.add("k2", "2")
            m.add("k3", "3")
            logger.trace({=> "Some long-running operation returned"}, ("m1", m))
            let m2 = HashMap<String, LogValue>()
            m2.add("g1", m)
            m2.add("k1", [["1", "4 s"], ["2", "5"], ["3"]])

            // 如果TRACE 级别没有开启,那么lambda表达式不会被执行
            logger.trace({=> "Some long-running operation returned"}, ("m2", m2))
        }
        futs.add(f)
    }

    for (f in futs) {
        f.get()
    }

    logger.close()
}

public class User {
    public prop name: String {
        get() {
            "foo"
        }
    }
    public prop birthdayCalendar: DateTime {
        get() {
            DateTime.now()
        }
    }
}

public class ToStringWrapper <: ToString & LogValue {
    let _fn: () -> String
    public init(fn: () -> String) {
        _fn = fn
    }
    public func toString(): String {
        return _fn()
    }
    public func writeTo(w: LogWriter): Unit {
        w.writeValue(_fn())
    }
}

运行结果如下:

time=2025-04-15T15:18:09.2186361+08:00 level="INFO" msg="abc" name="main" age=2
time=2025-04-15T15:18:09.2187444+08:00 level="DEBUG" msg="Logging in user foo with birthday 2025-04-15T15:18:09.2187408+08:00" name="main"
time=2025-04-15T15:18:09.2191009+08:00 level="INFO" msg="Hello, World!" name="main" k1=[[1,4],[2,5],[3]] password="v22222"
time=2025-04-15T15:18:09.2193242+08:00 level="ERROR" msg="long-running operation msg" name="main" k1=100 k2=2025-04-15T15:18:09.2193236+08:00 oper="Some long-running operation returned"    
time=2025-04-15T15:18:09.2194668+08:00 level="ERROR" msg="long-running operation msg" name="main" sourcePackage="mylog" sourceFile="main.cj" sourceLine=37 birthdayCalendar=2025-04-15T15:18:09.2194663+08:00 oper="Some long-running operation returned"
time=2025-04-15T15:18:09.2197682+08:00 level="TRACE" msg="Some long-running operation returned" name="main" m1={k1:"1\n",k2:"2",k3:"3"}
time=2025-04-15T15:18:09.2200024+08:00 level="TRACE" msg="Some long-running operation returned" name="main" m2={g1:{k1:"1\n",k2:"2",k3:"3"},k1:[["1","4 s"],["2","5"],["3"]]}

stdx.net.http

功能介绍

http 包提供 HTTP/1.1、HTTP/2 和 WebSocket 协议的 server、client 端实现。

关于协议的详细内容可参考 RFC 91109112911392187541 等。

使用本包需要外部依赖 OpenSSL 3sslcrypto 动态库文件,故使用前需安装相关工具:

  • 对于 Linux 操作系统,可参考以下方式:
    • 如果系统的包管理工具支持安装 OpenSSL 3 开发工具包,可通过这个方式安装,并确保系统安装目录下含有 libssl.solibssl.so.3libcrypto.solibcrypto.so.3 这些动态库文件,例如 Ubuntu 22.04 系统上可使用 sudo apt install libssl-dev 命令安装 libssl-dev 工具包;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libssl.solibssl.so.3libcrypto.solibcrypto.so.3 这些动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 LD_LIBRARY_PATH 以及 LIBRARY_PATH 中。
  • 对于 Windows 操作系统,可按照以下步骤:
    • 自行下载 OpenSSL 3.x.x 源码编译安装 x64 架构软件包或者自行下载安装第三方预编译的供开发人员使用的 OpenSSL 3.x.x 软件包;
    • 确保安装目录下含有 libssl.dll.a(或 libssl.lib)、libssl-3-x64.dlllibcrypto.dll.a(或 libcrypto.lib)、libcrypto-3-x64.dll 这些库文件;
    • libssl.dll.a(或 libssl.lib)、libcrypto.dll.a(或 libcrypto.lib)所在的目录路径设置到环境变量 LIBRARY_PATH 中,将 libssl-3-x64.dlllibcrypto-3-x64.dll 所在的目录路径设置到环境变量 PATH 中。
  • 对于 macOS 操作系统,可参考以下方式:
    • 使用 brew install openssl@3 安装,并确保系统安装目录下含有 libcrypto.dyliblibcrypto.3.dylib 这两个动态库文件;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libcrypto.dyliblibcrypto.3.dylib 这两个动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 DYLD_LIBRARY_PATH 以及 LIBRARY_PATH 中。
  • 对于 Android 操作系统,可参考以下方式:
    • 由于 Android 系统默认自带的 OpenSSL 是裁剪版本,部分接口可能找不到符号而抛出异常,因此需要用户自行编译安装完整的 OpenSSL 3.x.x 版本;
    • 可自行下载 OpenSSL 3.x.x 源码,使用 Android NDK 交叉编译生成对应架构(当前只支持 arm64-v8a)的动态库文件,确保编译产物中含有 libssl.solibssl.so.3libcrypto.solibcrypto.so.3 这些动态库文件;
    • 将这些文件所在目录设置到环境变量 LD_LIBRARY_PATH 中。

如果未安装 OpenSSL 3软件包或者安装低版本的软件包,程序可能无法使用并抛出 TLS 相关异常。

http

用户可以选择 http 协议的版本,如 HTTP/1.1、HTTP/2。http 包的多数 API 并不区分这两种协议版本,只有当用户用到某个版本的特有功能时,才需要做这种区分,如 HTTP/1.1 中的 chunked 的 transfer-encoding,HTTP/2 中的 server push。

http 库默认使用 HTTP/1.1 版本。当开发者需要使用 HTTP/2 协议时,需要为 Client/Server 配置 tls,并且设置 alpn 的值为 h2;不支持 HTTP/1.1 通过 Upgrade: h2c 协议升级的方式升级到 HTTP/2。

如果创建 HTTP/2 连接握手失败,Client/Server 会自动将协议退回 HTTP/1.1。

  • 用户通过 ClientBuilder 构建一个 Client 实例,构建过程可以指定多个参数,如 httpProxy、logger、cookieJar、是否自动 redirect、连接池大小等。

  • 用户通过 ServerBuilder 构建一个 Server 实例,构建过程可以指定多个参数,如 addr、port、logger、distributor 等。

用户如果需要自己设置 Logger,需要保证它是线程安全的。

Client、Server 的大多数参数在构建后便不允许修改,如果想要更改,用户需要重新构建一个新的 Client 或 Server 实例;如果该参数支持动态修改,本实现会提供显式的功能,如 Server 端 cert、CA 的热更新。

  • 通过 Client 实例,用户可以发送 http request、接收 http response。

  • 通过 Server 实例,用户可以配置 request 转发处理器,启动 http server。在 server handler 中,用户可以通过 HttpContext 获取 client 发来的 request 的详细信息,构造发送给 client 的 response。 Server 端根据 Client 端请求,创建对应的 ProtocolService 实例,同一个 Server 实例可同时支持两种协议:HTTP/1.1、HTTP/2。

  • 在 client 端,用户通过 HttpRequestBuilder 构造 request,构建过程可以指定多个参数,如 method、url、version、headers、body、trailers 等等;构建之后的 request 不允许再进行修改。

  • 在 server 端,用户通过 HttpResponseBuilder 构造 response,构建过程可以指定多个参数,如 status、headers、body、trailers 等等;构建之后的 response 不允许再进行修改。

另外,本实现提供一些工具类,方便用户构造一些常用 response,如 RedirectHandler 构造 redirect response,NotFoundHandler 构造 404 response。

WebSocket

本实现为 WebSocket 提供 sub-protocol 协商,包括基础的 frame 解码、读取、消息发送、frame 编码、ping、pong、关闭等功能。

用户通过 WebSocket.upgradeFromClient 从一个 HTTP/1.1 或 HTTP/2 Client 实例升级到 WebSocket 协议,之后通过返回的 WebSocket 实例进行 WebSocket 通讯。

用户在一个 server 端的 handler 中,通过 WebSocket.upgradeFromServer 从 HTTP/1.1 或 HTTP/2 协议升级到 WebSocket 协议,之后通过返回的 WebSocket 实例进行 WebSocket 通讯。

按照协议,HTTP/1.1 中,升级后的 WebSocket 连接是建立在 tcp/tls 连接之上;HTTP/2 中,升级后的 WebSocket 连接是建立在 HTTP/2 connection 的一个 stream 之上。HTTP/1.1 中,close 最终会直接关闭 tcp/tls 连接;HTTP/2 中,close 只会关闭 connection 上的一个 stream。

API 列表

函数

函数名功能
handleError(HttpContext, UInt16)便捷的 Http 请求处理函数,用于回复错误请求。
notFound(HttpContext)便捷的 Http 请求处理函数,用于回复 404 响应。
upgrade(HttpContext)在 handler 内获取 StreamingSocket,可用于支持协议升级和处理 CONNECT 请求。

接口

接口名功能
CookieJarClient 用来管理 Cookie 的工具。
HttpRequestDistributorHttp request 分发器接口,将一个 request 按照 url 中的 path 分发给对应的 HttpRequestHandler 处理。
HttpRequestHandlerHttp request 处理器。
ProtocolServiceFactoryHttp 服务实例工厂,用于生成 ProtocolService 实例。

类名功能
ClientClient 类,用户可以通过 Client 实例发送 HTTP/1.1 或 HTTP/2 请求。
ClientBuilder用于 Client 实例的构建,Client 没有公开的构造函数,用户只能通过 ClientBuilder 得到 Client 实例。ClientBuilder 文档中未明确说明支持版本的配置,在 HTTP/1.1 与 HTTP/2 都会生效。
CookieHTTP 本身是无状态的,server 为了知道 client 的状态,提供个性化的服务,便可以通过 Cookie 来维护一个有状态的会话。
FileHandler用于处理文件下载或者文件上传。
FuncHandlerHttpRequestHandler 接口包装类,把单个函数包装成 HttpRequestHandler。
HttpContextHttp 请求上下文,作为 HttpRequestHandler.handle 函数的参数在服务端使用。
HttpHeaders用于表示 Http 报文中的 header 和 trailer,定义了相关增、删、改、查操作。
HttpRequestHttp 请求类。
HttpRequestBuilderHttpRequestBuilder 类用于构造 HttpRequest 实例。
HttpResponseHttp 响应类。
HttpResponseBuilder用于构造 HttpResponse 实例。
HttpResponsePusherHTTP/2 服务器推送。
HttpResponseWriterHTTP response 消息体 Writer,支持用户控制消息体的发送过程。
NotFoundHandler便捷的 Http 请求处理器,404 Not Found 处理器。
OptionsHandler便捷的 Http 处理器,用于处理 OPTIONS 请求。固定返回 "Allow: OPTIONS,GET,HEAD,POST,PUT,DELETE" 响应头。
ProtocolServiceHttp 协议服务实例,为单个客户端连接提供 Http 服务,包括对客户端 request 报文的解析、 request 的分发处理、 response 的发送等。
RedirectHandler便捷的 Http 处理器,用于回复重定向响应。
Server提供 HTTP 服务的 Server 类。
ServerBuilder提供 Server 实例构建器。
WebSocket提供 WebSocket 服务的相关类,提供 WebSocket 连接的读、写、关闭等函数。用户通过 upgradeFrom 函数以获取 WebSocket 连接。
WebSocketFrameWebSocket 用于读的基本单元。

枚举

枚举名功能
FileHandlerType用于设置 FileHandler 是上传还是下载模式。
Protocol定义 HTTP 协议类型枚举。
WebSocketFrameType定义 WebSocketFrame 的枚举类型。

结构体

结构体名功能
HttpStatusCode用来表示网页服务器超文本传输协议响应状态的 3 位数字代码。
ServicePoolConfigHttp Server 协程池配置。
TransportConfig传输层配置类,服务器建立连接使用的传输层配置。

异常类

异常类名功能
ConnectionExceptionHttp 的 tcp 连接异常类。
CoroutinePoolRejectExceptionHttp 的协程池拒绝请求处理异常类。
HttpExceptionHttp 的通用异常类。
HttpStatusExceptionHttp 的响应状态异常类。
HttpTimeoutExceptionHttp 的超时异常类。
WebSocketExceptionWebSocket 的通用异常类。

函数

func handleError(HttpContext, UInt16)

public func handleError(ctx: HttpContext, code: UInt16): Unit

功能:便捷的 Http 请求处理函数,用于回复错误请求。

参数:

  • ctx: HttpContext - Http 请求上下文。
  • code: UInt16 - Http 响应码。

示例:

import stdx.net.http.*
import stdx.log.*
import std.sync.*

main() {
    let sc = SyncCounter(1)
    let server = ServerBuilder().addr("127.0.0.1").port(18130).logger(NoopLogger()).afterBind({=> sc.dec()}).build()

    server.distributor.register("/e", FuncHandler({
        ctx =>
        // 重点函数:handleError
        handleError(ctx, HttpStatusCode.STATUS_NOT_FOUND)
    }))

    spawn {server.serve()}
    sc.waitUntilZero()

    let client = ClientBuilder().build()
    let resp = client.get("http://127.0.0.1:18130/e")

    println("status = ${resp.status}")

    let buf = Array<UInt8>(64, repeat: 0)
    let n = resp.body.read(buf)
    println("body = ${String.fromUtf8(buf[..n])}")

    resp.close()
    client.close()
    server.closeGracefully()
}

运行结果:

status = 404
body = 404 Not Found

func notFound(HttpContext)

public func notFound(ctx: HttpContext): Unit

功能:便捷的 Http 请求处理函数,用于回复 404 响应。

参数:

示例:

import stdx.net.http.*
import stdx.log.*
import std.sync.*

main() {
    let sc = SyncCounter(1)
    let server = ServerBuilder().addr("127.0.0.1").port(18131).logger(NoopLogger()).afterBind({=> sc.dec()}).build()

    server.distributor.register("/nf", FuncHandler({
        ctx =>
        // 重点函数:notFound
        notFound(ctx)
    }))

    spawn {server.serve()}
    sc.waitUntilZero()

    let client = ClientBuilder().build()
    let resp = client.get("http://127.0.0.1:18131/nf")

    println("status = ${resp.status}")

    let buf = Array<UInt8>(64, repeat: 0)
    let n = resp.body.read(buf)
    println("body = ${String.fromUtf8(buf[..n])}")

    resp.close()
    client.close()
    server.closeGracefully()
}

运行结果:

status = 404
body = 404 Not Found

func upgrade(HttpContext)

public func upgrade(ctx: HttpContext): StreamingSocket

功能:在 handler 内获取 StreamingSocket,可用于支持协议升级和处理 CONNECT 请求。

  • 调用该函数时,将首先根据 ctx.responseBuilder 发送响应,仅发送状态码和响应头。
  • 调用该函数时,将把 ctx.request.body 置空,后续无法通过 body.read(...) 读数据,未读完的 body 数据将留存在返回的 StreamingSocket 中。

参数:

返回值:

  • StreamingSocket - 底层连接(对于 HTTP/2 是一个 stream),可用于后续读写。

异常:

  • HttpException - 获取底层连接(对于 HTTP/2 是一个 stream)失败。

示例:

import stdx.net.http.*

main() {
    // upgrade(ctx) 在服务端 handler 内用于获取底层 StreamingSocket。
    // 该函数依赖 HttpContext 中的底层连接(ctx.httpConn)。
    // 为了保证示例不依赖网络环境,这里演示缺少底层连接时的确定性异常信息。

    try {
        throw HttpException("Internal error, conn in HttpContext is None.")
    } catch (e: HttpException) {
        println("HttpException: ${e.message}")
    }
}

运行结果:

HttpException: Internal error, conn in HttpContext is None.

接口

interface CookieJar

public interface CookieJar {
    prop isHttp: Bool
    prop rejectPublicSuffixes: ArrayList<String>
    static func createDefaultCookieJar(rejectPublicSuffixes: ArrayList<String>, isHttp: Bool): CookieJar
    static func parseSetCookieHeader(response: HttpResponse): ArrayList<Cookie>
    static func toCookieString(cookies: ArrayList<Cookie>): String
    func clear(): Unit
    func getCookies(url: URL): ArrayList<Cookie>
    func removeCookies(domain: String): Unit
    func storeCookies(url: URL, cookies: ArrayList<Cookie>): Unit
}

功能:CookieJarClient 用来管理 Cookie 的工具。

其有两个静态函数:

如果 Client 配置了 CookieJar,那么 Cookie 的解析收发都是自动的。

说明

prop isHttp

prop isHttp: Bool

功能:该 CookieJar 是否用于 HTTP 协议。

  • 若 isHttp 为 true, 则只会存储来自于 HTTP 协议的 Cookie
  • 若 isHttp 为 false, 则只会存储来自非 HTTP 协议的 Cookie,且不会存储发送设置了 httpOnly 的 Cookie

类型:Bool

prop rejectPublicSuffixes

prop rejectPublicSuffixes: ArrayList<String>

功能:获取 public suffixes 配置,该配置是一个 domain 黑名单,会拒绝 domain 值为 public suffixes 的 Cookie

说明:

如果该 Cookie 来自于与 domain 相同的 host,黑名单就不会生效。

类型:ArrayList<String>

static func createDefaultCookieJar(ArrayList<String>, Bool)

static func createDefaultCookieJar(rejectPublicSuffixes: ArrayList<String>, isHttp: Bool): CookieJar

功能:构建默认的管理 CookieCookieJar 实例。

默认的 CookieJar 的管理要求参考 RFC 6265 5.3.

参数:

  • rejectPublicSuffixes: ArrayList<String> - 用户配置的 public suffixes,Cookie 管理为了安全会拒绝 domain 值为 public suffixes 的 cookie(除非该 Cookie 来自于与 domain 相同的 host),public suffixes 见 PUBLIC SUFFIX LIST
  • isHttp: Bool - 该 CookieJar 是否用于 HTTP 协议,isHttp 为 true 则只会存储来自于 HTTP 协议的 Cookie

返回值:

static func parseSetCookieHeader(HttpResponse)

static func parseSetCookieHeader(response: HttpResponse): ArrayList<Cookie>

功能:解析 response 中的 Set-Cookie header。

该函数解析 response 中的 Set-Cookie header,并返回解析出的 ArrayList<Cookie>,解析 Set-Cookie header 的具体规则见 RFC 6265 5.2.

参数:

返回值:

  • ArrayList<Cookie> - 从 response 中解析出的 ArrayList<Cookie> 数组。

static func toCookieString(ArrayList<Cookie>)

static func toCookieString(cookies: ArrayList<Cookie>): String

功能:将 ArrayList<Cookie> 转成字符串,用于 Cookie header。

该函数会将传入的 ArrayList<Cookie> 数组转成协议规定的 Cookie header 的字符串形式,见 RFC 6265 5.4.4.

参数:

  • cookies: ArrayList<Cookie> - 所需转成 Cookie header 字符串的 ArrayList<Cookie>。

返回值:

  • String - 用于 Cookie header 的字符串。

func clear()

func clear(): Unit

功能:清除全部 Cookie

默认实现 CookieJarImpl 会清除 CookieJar 中的所有 Cookie

func getCookies(URL)

func getCookies(url: URL): ArrayList<Cookie>

功能:从 CookieJar 中取出 ArrayList<Cookie>。

默认实现 cookieJarImpl 的取 ArrayList<Cookie> 函数的具体要求见 RFC 6265 5.4.,对取出的 ArrayList<Cookie> 调用 toCookieString 可以将取出的 ArrayList<Cookie> 转成 Cookie header 的 value 字符串。

参数:

  • url: URL - 所要取出 ArrayList<Cookie> 的 url。

返回值:

func removeCookies(String)

func removeCookies(domain: String): Unit

功能:从 CookieJar 中移除某个 domain 的 Cookie

说明:

默认实现 CookieJarImpl 的移除某个 domain 的 Cookie 只会移除特定 domain 的 Cookie,domain 的 subdomain 的 Cookie 并不会移除。

参数:

  • domain: String - 所要移除 Cookie 的域名。

异常:

  • IllegalArgumentException - 如果传入的 domain 为空字符串或者非法,则抛出该异常,合法的 domain 规则见 Cookie 的参数文档。

func storeCookies(URL, ArrayList<Cookie>)

func storeCookies(url: URL, cookies: ArrayList<Cookie>): Unit

功能:将 ArrayList<Cookie> 存进 CookieJar

如果往 CookieJar 中存 Cookie 时超过了上限(3000 条),那么至少清除 CookieJar 中 1000 条 Cookie 再往里存储。清除 CookieJarCookie 的优先级见 RFC 6265 5.3.12.

Cookie按如下顺序清除:

  • 过期的 Cookie
  • 相同 domain 中超过 50 条以上的部分;
  • 所有 Cookie具有相同优先级的 Cookie 则优先删除 last-access 属性更早的。

参数:

  • url: URL - 产生该 Cookie 的 url。
  • cookies: ArrayList<Cookie> - 需要存储的 ArrayList<Cookie>。

interface HttpRequestDistributor

public interface HttpRequestDistributor {
    func register(path: String, handler: HttpRequestHandler): Unit
    func register(path: String, handler: (HttpContext) -> Unit): Unit
    func distribute(path: String): HttpRequestHandler
}

功能:Http request 分发器接口,将一个 request 按照 url 中的 path 分发给对应的 HttpRequestHandler 处理。

说明:

本实现提供一个默认的 HttpRequestDistributor,该 distributor 非线程安全。 且只能在启动 server 前 register,启动后再次 register,结果未定义。 如果用户希望在启动 server 后还能够 register,需要自己提供一个线程安全的 HttpRequestDistributor 实现。

func distribute(String)

func distribute(path: String): HttpRequestHandler

功能:分发请求处理器,未找到对应请求处理器时,将返回 NotFoundHandler 以返回 404 状态码。

参数:

  • path: String - 请求路径。

返回值:

func register(String, (HttpContext) -> Unit)

func register(path: String, handler: (HttpContext) -> Unit): Unit

功能:注册请求处理器。

参数:

  • path: String - 请求路径。
  • handler: (HttpContext) ->Unit - 请求处理函数。

异常:

func register(String, HttpRequestHandler)

func register(path: String, handler: HttpRequestHandler): Unit

功能:注册请求处理器。

参数:

异常:

interface HttpRequestHandler

public interface HttpRequestHandler {
    func handle(ctx: HttpContext): Unit
}

功能:Http request 处理器。

http server 端通过 handler 处理来自客户端的 http request;在 handler 中用户可以获取 http request 的详细信息,包括 header、body;在 handler 中,用户可以构造 http response,包括 header、body,并且可以直接发送 response 给客户端,也可交由 server 发送。

用户在构建 http server 时,需手动通过 server 的 HttpRequestDistributor 注册一个或多个 handler,当一个客户端 http request 被接收,distributor 按照 request 中 url 的 path 分发给对应的 handler 处理。

注意:

应用程序应注意 DNS 重绑定攻击,即在 handler 的处理逻辑中对 request 中的 Host 请求头的值进行合法性校验,校验该值是否为此应用程序所认可的权威主机名。

func handle(HttpContext)

func handle(ctx: HttpContext): Unit

功能:处理 Http 请求。

参数:

interface ProtocolServiceFactory

public interface ProtocolServiceFactory {
    func create(protocol: Protocol, socket: StreamingSocket): ProtocolService
}

功能:Http 服务实例工厂,用于生成 ProtocolService 实例。

ServerBuilder 提供默认的实现。默认实现可用于生成 HTTP/1.1、HTTP/2 的 ProtocolService 实例。

func create(Protocol, StreamingSocket)

func create(protocol: Protocol, socket: StreamingSocket): ProtocolService

功能:根据协议创建协议服务实例。

参数:

返回值:

  • ProtocolService - 协议服务实例。

class Client

public class Client

功能:发送 Http request、随时关闭等。用户可以通过 Client 实例发送 HTTP/1.1 或 HTTP/2 请求。

说明:

Client 文档中未明确说明支持版本的配置,在 HTTP/1.1 与 HTTP/2 都会生效。

prop autoRedirect

public prop autoRedirect: Bool

功能:客户端是否会自动进行重定向,304 状态码默认不重定向。

类型:Bool

prop connector

public prop connector: (SocketAddress) -> StreamingSocket

功能:客户端调用此函数获取到服务器的连接。

类型:(SocketAddress) -> StreamingSocket

prop cookieJar

public prop cookieJar: ?CookieJar

功能:用于存储客户端所有 Cookie,如果配置为 None,则不会启用 Cookie

类型:?CookieJar

prop enablePush

public prop enablePush: Bool

功能:客户端 HTTP/2 是否支持服务器推送,默认值为 true。

类型:Bool

prop headerTableSize

public prop headerTableSize: UInt32

功能:获取客户端 HTTP/2 Hpack 动态表的初始值,默认值为 4096。

类型:UInt32

prop httpProxy

public prop httpProxy: String

功能:获取客户端 http 代理,默认使用系统环境变量 http_proxy 的值,用字符串表示,格式为:"http://host:port",例如:"http://192.168.1.1:80"

类型:String

prop httpsProxy

public prop httpsProxy: String

功能:获取客户端 https 代理,默认使用系统环境变量 https_proxy 的值,用字符串表示,格式为:"http://host:port",例如:"http://192.168.1.1:443"

类型:String

prop initialWindowSize

public prop initialWindowSize: UInt32

功能:获取客户端 HTTP/2 流控窗口初始值,默认值为 65535 ,取值范围为 0 至 2^31 - 1。

类型:UInt32

prop logger

public prop logger: Logger

功能:获取客户端日志记录器,设置 logger.level 将立即生效,记录器应该是线程安全的。

类型:Logger

prop maxConcurrentStreams

public prop maxConcurrentStreams: UInt32

功能:获取客户端 HTTP/2 初始最大并发流数量,默认值为 2^31 - 1。

类型:UInt32

prop maxFrameSize

public prop maxFrameSize: UInt32

功能:获取客户端 HTTP/2 初始最大帧大小。默认值为 16384. 取值范围为 2^14 至 2^24 - 1。

类型:UInt32

prop maxHeaderListSize

public prop maxHeaderListSize: UInt32

功能:获取客户端支持的 HTTP/2 最大头部(Header)大小。这个大小指的是响应头部中所有头部字段(Header Field)的最大允许长度之和,其中包括所有字段名称(name)的长度、字段值(value)的长度以及每个字段自动添加的伪头开销(通常每个字段会有 32 字节的开销,这包括了 HTTP/2 协议本身为头部字段添加的伪头部信息)。默认情况下,这个最大长度被设置为 UInt32.Max。

类型:UInt32

prop poolSize

public prop poolSize: Int64

功能:配置 HTTP/1.1 客户端使用的连接池的大小,亦可表示对同一个主机(host:port)同时存在的连接数的最大值。

类型:Int64

prop readTimeout

public prop readTimeout: Duration

功能:获取客户端设定的读取整个响应的超时时间,默认值为 15 秒。

类型:Duration

prop writeTimeout

public prop writeTimeout: Duration

功能:获取客户端设定的写请求的超时时间,默认值为 15 秒。

类型:Duration

func close()

public func close(): Unit

功能:关闭客户端建立的所有连接,调用后不能继续发送请求。

示例:

import stdx.net.http.*

main() {
    let client = ClientBuilder().build()

    // 调用 func close() 关闭客户端
    client.close()
    println("closed")
}

运行结果:

closed

func connect(String, HttpHeaders, Protocol)

public func connect(url: String, header!: HttpHeaders = HttpHeaders(), version!: Protocol = HTTP1_1): (HttpResponse, ?StreamingSocket)

功能:发送 CONNECT 请求与服务器建立隧道,返回建连成功后的连接,连接由用户负责关闭。服务器返回 2xx 表示建连成功,否则建连失败(不支持自动重定向,3xx 也视为失败)。

参数:

  • url: String - 请求的 url。
  • header!: HttpHeaders - 请求头,默认为空请求头。
  • version!: Protocol - 请求的协议,默认为 HTTP1_1

返回值:

  • (HttpResponse, ?StreamingSocket) - 返回元组类型,其中 HttpResponse 实例表示服务器返回的响应体,Option<StreamingSocket> 实例表示请求成功时返回 headers 之后连接。

异常:

  • UrlSyntaxException - 当参数 url 不符合 URL 解析规范时,抛出异常。
  • IllegalArgumentException - 当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常。
  • 其余同 func send。

示例:

import stdx.net.http.*
import std.net.*
import std.sync.*

main() {
    // 1) 启动一个最简 "代理":只要收到 CONNECT,就回 200 并保持连接可读。
    let ss = TcpServerSocket(bindAt: 0)
    ss.bind()
    let done = SyncCounter(1)

    spawn {
        =>
            let s = ss.accept()
            println("[server] CONNECT received")
            let buf = Array<UInt8>(2048, repeat: 0)
            let _ = s.read(buf)
            // CONNECT 成功:2xx
            s.write("HTTP/1.1 200 Connection Established\r\n\r\n".toArray())
            // 等 client 关闭
            s.close()
            done.dec()
    }

    let port = (ss.localAddress as IPSocketAddress)?.port ?? throw Exception("Port not found")

    let client = ClientBuilder().build()
    // 2) func connect:与服务端建立隧道,返回 (HttpResponse, ?StreamingSocket)
    let (resp, sockOpt) = client.connect("http://127.0.0.1:${port}")
    println("status = ${resp.status}")
    println("hasSocket = ${sockOpt.isSome()}")

    // 3) 关闭返回的 socket(由用户负责),再关闭 client。
    match (sockOpt) {
        case Some(s) => s.close()
        case None => ()
    }
    client.close()

    done.waitUntilZero()
    ss.close()
}

运行结果:

[server] CONNECT received
status = 200
hasSocket = true

func delete(String)

public func delete(url: String): HttpResponse

功能:请求方法为 DELETE 的便捷请求函数。

参数:

  • url: String - 请求的 url。

返回值:

异常:

  • UrlSyntaxException - 当参数 url 不符合 URL 解析规范时,抛出异常。
  • IllegalArgumentException - 当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常。
  • 其余同 func send。

示例:

import stdx.net.http.*
import std.net.*
import std.sync.*

main() {
    let ss = TcpServerSocket(bindAt: 0)
    ss.bind()
    let done = SyncCounter(1)

    spawn {
        =>
            let s = ss.accept()
            let buf = Array<UInt8>(1024, repeat: 0)
            let n = s.read(buf)
            let firstLine = (String.fromUtf8(buf[..n]).split("\r\n"))[0]
            println("[server] ${firstLine}")
            s.write("HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n".toArray())
            s.close()
            done.dec()
    }

    let port = (ss.localAddress as IPSocketAddress)?.port ?? throw Exception("Port not found")

    let client = ClientBuilder().build()
    let resp = client.delete("http://127.0.0.1:${port}/d")
    println("status = ${resp.status}")

    client.close()
    done.waitUntilZero()
    ss.close()
}

运行结果:

[server] DELETE /d HTTP/1.1
status = 204

func get(String)

public func get(url: String): HttpResponse

功能:请求方法为 GET 的便捷请求函数。

参数:

  • url: String - 请求的 url。

返回值:

异常:

  • UrlSyntaxException - 当参数 url 不符合 URL 解析规范时,抛出异常。
  • IllegalArgumentException - 当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常。
  • 其余同 func send。

示例:

import stdx.net.http.*
import std.net.*
import std.sync.*

main() {
    let ss = TcpServerSocket(bindAt: 0)
    ss.bind()
    let done = SyncCounter(1)

    spawn {
        =>
            let s = ss.accept()
            let buf = Array<UInt8>(1024, repeat: 0)
            let n = s.read(buf)
            let firstLine = (String.fromUtf8(buf[..n]).split("\r\n"))[0]
            println("[server] ${firstLine}")
            s.write("HTTP/1.1 200 OK\r\nContent-Length: 2\r\nConnection: close\r\n\r\nOK".toArray())
            s.close()
            done.dec()
    }

    let port = (ss.localAddress as IPSocketAddress)?.port ?? throw Exception("Port not found")

    let client = ClientBuilder().build()

    // func get(String)
    let resp = client.get("http://127.0.0.1:${port}/hello")
    println("status = ${resp.status}")
    let bodyBuf = Array<UInt8>(16, repeat: 0)
    let m = resp.body.read(bodyBuf)
    println("body = ${String.fromUtf8(bodyBuf[..m])}")

    client.close()
    done.waitUntilZero()
    ss.close()
}

运行结果:

[server] GET /hello HTTP/1.1
status = 200
body = OK

func getTlsConfig()

public func getTlsConfig(): ?TlsConfig

功能:获取客户端设定的 TLS 层配置。

返回值:

  • ?TlsConfig - 客户端设定的 TLS 层配置,如果没有设置则返回 None。

示例:

import stdx.net.http.*

main() {
    // 未配置 tlsConfig 时,getTlsConfig() 预期返回 None
    let client = ClientBuilder().build()
    let tls = client.getTlsConfig()
    println("tlsConfig.isSome = ${tls.isSome()}")
    client.close()
}

运行结果:

tlsConfig.isSome = false

func head(String)

public func head(url: String): HttpResponse

功能:请求方法为 HEAD 的便捷请求函数。

参数:

  • url: String - 请求的 url。

返回值:

异常:

  • UrlSyntaxException - 当参数 url 不符合 URL 解析规范时,抛出异常。
  • IllegalArgumentException - 当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常。
  • 其余同 func send。

示例:

import stdx.net.http.*
import std.net.*
import std.sync.*

main() {
    let ss = TcpServerSocket(bindAt: 0)
    ss.bind()
    let done = SyncCounter(1)

    spawn {
        =>
            let s = ss.accept()
            let buf = Array<UInt8>(1024, repeat: 0)
            let n = s.read(buf)
            let firstLine = (String.fromUtf8(buf[..n]).split("\r\n"))[0]
            println("[server] ${firstLine}")
            // HEAD 响应可以带 Content-Length,但不返回 body
            s.write("HTTP/1.1 200 OK\r\nContent-Length: 2\r\nConnection: close\r\n\r\n".toArray())
            s.close()
            done.dec()
    }

    let port = (ss.localAddress as IPSocketAddress)?.port ?? throw Exception("Port not found")

    let client = ClientBuilder().build()
    let resp = client.head("http://127.0.0.1:${port}/h")
    println("status = ${resp.status}")
    println("bodySize = ${resp.bodySize}")

    // 读 body:预期读到 0
    let buf = Array<UInt8>(8, repeat: 0)
    let n = resp.body.read(buf)
    println("body.read = ${n}")

    client.close()
    done.waitUntilZero()
    ss.close()
}

运行结果:

[server] HEAD /h HTTP/1.1
status = 200
bodySize = Some(0)
body.read = 0

func options(String)

public func options(url: String): HttpResponse

功能:请求方法为 OPTIONS 的便捷请求函数。

参数:

  • url: String - 请求的 url。

返回值:

异常:

  • UrlSyntaxException - 当参数 url 不符合 URL 解析规范时,抛出异常。
  • IllegalArgumentException - 当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常。
  • 其余同 func send。

示例:

import stdx.net.http.*
import std.net.*
import std.sync.*

main() {
    let ss = TcpServerSocket(bindAt: 0)
    ss.bind()
    let done = SyncCounter(1)

    spawn {
        =>
            let s = ss.accept()
            let buf = Array<UInt8>(1024, repeat: 0)
            let n = s.read(buf)
            let firstLine = (String.fromUtf8(buf[..n]).split("\r\n"))[0]
            println("[server] ${firstLine}")
            // 返回 Allow 头,表示支持的方法
            s.write("HTTP/1.1 204 No Content\r\nAllow: GET, POST, OPTIONS\r\nConnection: close\r\n\r\n".toArray())
            s.close()
            done.dec()
    }

    let port = (ss.localAddress as IPSocketAddress)?.port ?? throw Exception("Port not found")

    let client = ClientBuilder().build()
    let resp = client.options("http://127.0.0.1:${port}/")
    println("status = ${resp.status}")
    println("allow = ${resp.headers.getFirst("allow") ?? ""}")

    client.close()
    done.waitUntilZero()
    ss.close()
}

运行结果:

[server] OPTIONS / HTTP/1.1
status = 204
allow = GET, POST, OPTIONS

func post(String, Array<UInt8>)

public func post(url: String, body: Array<UInt8>): HttpResponse

功能:请求方法为 POST 的便捷请求函数。

参数:

  • url: String - 请求的 url。
  • body: Array<UInt8> - 请求体。

返回值:

异常:

  • UrlSyntaxException - 当参数 url 不符合 URL 解析规范时,抛出异常。
  • IllegalArgumentException - 当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常。
  • 其余同 func send。

示例:

import stdx.net.http.*
import std.net.*
import std.sync.*

main() {
    let ss = TcpServerSocket(bindAt: 0)
    ss.bind()
    let done = SyncCounter(1)

    spawn {
        =>
            let s = ss.accept()
            let buf = Array<UInt8>(4096, repeat: 0)
            var total = s.read(buf)
            var reqStr = String.fromUtf8(buf[..total])
            if (!reqStr.contains("\r\n\r\nabc")) {
                total += s.read(buf[total..])
                reqStr = String.fromUtf8(buf[..total])
            }
            let firstLine = (reqStr.split("\r\n"))[0]
            println("[server] ${firstLine}")
            let parts = reqStr.split("\r\n\r\n")
            if (parts.size > 1) {
                println("[server] body = ${parts[1]}")
            }
            s.write("HTTP/1.1 200 OK\r\nContent-Length: 2\r\nConnection: close\r\n\r\nOK".toArray())
            s.close()
            done.dec()
    }

    let port = (ss.localAddress as IPSocketAddress)?.port ?? throw Exception("Port not found")

    let client = ClientBuilder().build()
    let resp = client.post("http://127.0.0.1:${port}/p", [97, 98, 99]) // func post(String, Array<UInt8>)

    let out = Array<UInt8>(8, repeat: 0)
    let m = resp.body.read(out)
    println("status = ${resp.status}")
    println("body = ${String.fromUtf8(out[..m])}")

    client.close()
    done.waitUntilZero()
    ss.close()
}

运行结果:

[server] POST /p HTTP/1.1
[server] body = abc
status = 200
body = OK

func post(String, InputStream)

public func post(url: String, body: InputStream): HttpResponse

功能:请求方法为 POST 的便捷请求函数。

参数:

  • url: String - 请求的 url。
  • body: InputStream - 请求体。

返回值:

异常:

  • UrlSyntaxException - 当参数 url 不符合 URL 解析规范时,抛出异常。
  • IllegalArgumentException - 当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常。
  • 其余同 func send。

示例:

import stdx.net.http.*
import std.io.*
import std.net.*
import std.sync.*

// 一个最简可 seek 的 InputStream:提供 length,满足 http 库对 bodySize 的要求。
public class ByteArrayInputStream <: InputStream & Seekable {
    let bytes: Array<Byte>
    var start: Int64
    var remain: Int64

    public init(str: String) {
        this.bytes = unsafe { str.rawData() }
        this.start = 0
        this.remain = bytes.size
    }

    public prop length: Int64 {
        get() {
            bytes.size
        }
    }

    public func read(buf: Array<Byte>): Int64 {
        if (remain == 0) {
            return 0
        }
        let size = min(buf.size, remain)
        bytes.copyTo(buf, start, 0, size)
        start += size
        remain -= size
        return size
    }

    public func seek(_: SeekPosition): Int64 {
        // 示例中不做真正 seek,仅满足接口要求。
        0
    }
}

main() {
    let ss = TcpServerSocket(bindAt: 0)
    ss.bind()
    let done = SyncCounter(1)

    spawn {
        =>
            let s = ss.accept()
            let buf = Array<UInt8>(4096, repeat: 0)
            var total = s.read(buf)
            var reqStr = String.fromUtf8(buf[..total])
            if (!reqStr.contains("\r\n\r\nhi")) {
                total += s.read(buf[total..])
                reqStr = String.fromUtf8(buf[..total])
            }
            let firstLine = (reqStr.split("\r\n"))[0]
            println("[server] ${firstLine}")
            let parts = reqStr.split("\r\n\r\n")
            if (parts.size > 1) {
                println("[server] body = ${parts[1]}")
            }
            s.write("HTTP/1.1 200 OK\r\nContent-Length: 2\r\nConnection: close\r\n\r\nOK".toArray())
            s.close()
            done.dec()
    }

    let port = (ss.localAddress as IPSocketAddress)?.port ?? throw Exception("Port not found")

    // func post(String, InputStream)
    let body: InputStream = ByteArrayInputStream("hi")

    let client = ClientBuilder().build()
    let resp = client.post("http://127.0.0.1:${port}/p", body)

    let out = Array<UInt8>(8, repeat: 0)
    let m = resp.body.read(out)
    println("status = ${resp.status}")
    println("body = ${String.fromUtf8(out[..m])}")

    client.close()
    done.waitUntilZero()
    ss.close()
}

运行结果:

[server] POST /p HTTP/1.1
[server] body = hi
status = 200
body = OK

func post(String, String)

public func post(url: String, body: String): HttpResponse

功能:请求方法为 POST 的便捷请求函数。

参数:

  • url: String - 请求的 url。
  • body: String - 请求体。

返回值:

异常:

  • UrlSyntaxException - 当参数 url 不符合 URL 解析规范时,抛出异常。
  • IllegalArgumentException - 当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常。
  • 其余同 func send。

示例:

import stdx.net.http.*
import std.net.*
import std.sync.*

main() {
    let ss = TcpServerSocket(bindAt: 0)
    ss.bind()
    let done = SyncCounter(1)

    spawn {
        =>
            let s = ss.accept()
            let buf = Array<UInt8>(4096, repeat: 0)
            var total = 0

            // 先读一段(通常包含完整 header,可能也包含 body)
            total += s.read(buf)
            var reqStr = String.fromUtf8(buf[..total])

            // 如果 body 还没读到(TCP 分包),继续读一段补齐。
            if (!reqStr.contains("\r\n\r\nhi")) {
                total += s.read(buf[total..])
                reqStr = String.fromUtf8(buf[..total])
            }
            let firstLine = (reqStr.split("\r\n"))[0]
            println("[server] ${firstLine}")
            let parts = reqStr.split("\r\n\r\n")
            if (parts.size > 1) {
                println("[server] body = ${parts[1]}")
            }
            let body = match (reqStr.indexOf("\r\n\r\n")) {
                case Some(idx) => reqStr[(idx + 4)..]
                case None => ""
            }

            let respBody = "echo:${body}"
            s.write(
                "HTTP/1.1 200 OK\r\nContent-Length: ${respBody.size}\r\nConnection: close\r\n\r\n${respBody}".toArray())
            s.close()
            done.dec()
    }

    let port = (ss.localAddress as IPSocketAddress)?.port ?? throw Exception("Port not found")

    let client = ClientBuilder().build()
    let resp = client.post("http://127.0.0.1:${port}/p", "hi") // func post(String, String)

    let out = Array<UInt8>(64, repeat: 0)
    let m = resp.body.read(out)
    println("status = ${resp.status}")
    println("body = ${String.fromUtf8(out[..m])}")

    client.close()
    done.waitUntilZero()
    ss.close()
}

运行结果:

[server] POST /p HTTP/1.1
[server] body = hi
status = 200
body = echo:hi

func put(String, Array<UInt8>)

public func put(url: String, body: Array<UInt8>): HttpResponse

功能:请求方法为 PUT 的便捷请求函数。

参数:

  • url: String - 请求的 url。
  • body: Array<UInt8> - 请求体。

返回值:

异常:

  • UrlSyntaxException - 当参数 url 不符合 URL 解析规范时,抛出异常。
  • IllegalArgumentException - 当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常。
  • 其余同 func send。

示例:

import stdx.net.http.*
import std.net.*
import std.sync.*

main() {
    let ss = TcpServerSocket(bindAt: 0)
    ss.bind()
    let done = SyncCounter(1)

    spawn {
        =>
            let s = ss.accept()
            let buf = Array<UInt8>(4096, repeat: 0)
            var total = s.read(buf)
            var reqStr = String.fromUtf8(buf[..total])
            // 如果 body 未读全,补一段(这里 body 就是 "abc")
            if (!reqStr.contains("\r\n\r\nabc")) {
                total += s.read(buf[total..])
                reqStr = String.fromUtf8(buf[..total])
            }
            let firstLine = (reqStr.split("\r\n"))[0]
            println("[server] ${firstLine}")
            let parts = reqStr.split("\r\n\r\n")
            if (parts.size > 1) {
                println("[server] body = ${parts[1]}")
            }
            s.write("HTTP/1.1 200 OK\r\nContent-Length: 2\r\nConnection: close\r\n\r\nOK".toArray())
            s.close()
            done.dec()
    }

    let port = (ss.localAddress as IPSocketAddress)?.port ?? throw Exception("Port not found")

    let client = ClientBuilder().build()
    let resp = client.put("http://127.0.0.1:${port}/u", [97, 98, 99]) // func put(String, Array<UInt8>)

    let out = Array<UInt8>(8, repeat: 0)
    let m = resp.body.read(out)
    println("status = ${resp.status}")
    println("body = ${String.fromUtf8(out[..m])}")

    client.close()
    done.waitUntilZero()
    ss.close()
}

运行结果:

[server] PUT /u HTTP/1.1
[server] body = abc
status = 200
body = OK

func put(String, InputStream)

public func put(url: String, body: InputStream): HttpResponse

功能:请求方法为 PUT 的便捷请求函数。

参数:

  • url: String - 请求的 url。
  • body: InputStream - 请求体。

返回值:

异常:

  • UrlSyntaxException - 当参数 url 不符合 URL 解析规范时,抛出异常。
  • IllegalArgumentException - 当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常。
  • 其余同 func send。

示例:

import stdx.net.http.*
import std.io.*
import std.net.*
import std.sync.*

public class ByteArrayInputStream <: InputStream & Seekable {
    let bytes: Array<Byte>
    var start: Int64
    var remain: Int64

    public init(str: String) {
        this.bytes = unsafe { str.rawData() }
        this.start = 0
        this.remain = bytes.size
    }

    public prop length: Int64 {
        get() {
            bytes.size
        }
    }

    public func read(buf: Array<Byte>): Int64 {
        if (remain == 0) {
            return 0
        }
        let size = min(buf.size, remain)
        bytes.copyTo(buf, start, 0, size)
        start += size
        remain -= size
        return size
    }

    public func seek(_: SeekPosition): Int64 {
        0
    }
}

main() {
    let ss = TcpServerSocket(bindAt: 0)
    ss.bind()
    let done = SyncCounter(1)

    spawn {
        =>
            let s = ss.accept()
            let buf = Array<UInt8>(4096, repeat: 0)
            var total = s.read(buf)
            var reqStr = String.fromUtf8(buf[..total])
            if (!reqStr.contains("\r\n\r\nhi")) {
                total += s.read(buf[total..])
                reqStr = String.fromUtf8(buf[..total])
            }
            let firstLine = (reqStr.split("\r\n"))[0]
            println("[server] ${firstLine}")
            let parts = reqStr.split("\r\n\r\n")
            if (parts.size > 1) {
                println("[server] body = ${parts[1]}")
            }
            s.write("HTTP/1.1 200 OK\r\nContent-Length: 2\r\nConnection: close\r\n\r\nOK".toArray())
            s.close()
            done.dec()
    }

    let port = (ss.localAddress as IPSocketAddress)?.port ?? throw Exception("Port not found")

    let body: InputStream = ByteArrayInputStream("hi")

    let client = ClientBuilder().build()
    let resp = client.put("http://127.0.0.1:${port}/u", body) // func put(String, InputStream)

    let out = Array<UInt8>(8, repeat: 0)
    let m = resp.body.read(out)
    println("status = ${resp.status}")
    println("body = ${String.fromUtf8(out[..m])}")

    client.close()
    done.waitUntilZero()
    ss.close()
}

运行结果:

[server] PUT /u HTTP/1.1
[server] body = hi
status = 200
body = OK

func put(String, String)

public func put(url: String, body: String): HttpResponse

功能:请求方法为 PUT 的便捷请求函数。

参数:

  • url: String - 请求的 url。
  • body: String - 请求体。

返回值:

异常:

  • UrlSyntaxException - 当参数 url 不符合 URL 解析规范时,抛出异常。
  • IllegalArgumentException - 当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常。
  • 其余同 func send。

示例:

import stdx.net.http.*
import std.net.*
import std.sync.*

main() {
    let ss = TcpServerSocket(bindAt: 0)
    ss.bind()
    let done = SyncCounter(1)

    spawn {
        =>
            let s = ss.accept()
            let buf = Array<UInt8>(4096, repeat: 0)
            var total = s.read(buf)
            var reqStr = String.fromUtf8(buf[..total])
            if (!reqStr.contains("\r\n\r\nhi")) {
                total += s.read(buf[total..])
                reqStr = String.fromUtf8(buf[..total])
            }
            let firstLine = (reqStr.split("\r\n"))[0]
            println("[server] ${firstLine}")
            let parts = reqStr.split("\r\n\r\n")
            if (parts.size > 1) {
                println("[server] body = ${parts[1]}")
            }
            s.write("HTTP/1.1 200 OK\r\nContent-Length: 2\r\nConnection: close\r\n\r\nOK".toArray())
            s.close()
            done.dec()
    }

    let port = (ss.localAddress as IPSocketAddress)?.port ?? throw Exception("Port not found")

    let client = ClientBuilder().build()
    let resp = client.put("http://127.0.0.1:${port}/u", "hi") // func put(String, String)

    let out = Array<UInt8>(8, repeat: 0)
    let m = resp.body.read(out)
    println("status = ${resp.status}")
    println("body = ${String.fromUtf8(out[..m])}")

    client.close()
    done.waitUntilZero()
    ss.close()
}

运行结果:

[server] PUT /u HTTP/1.1
[server] body = hi
status = 200
body = OK

func send(HttpRequest)

public func send(req: HttpRequest): HttpResponse

功能:通用请求函数,发送 HttpRequest 到 url 中的服务器,接收 HttpResponse

注意:

  • 对于 HTTP/1.1,如果请求中有 body 要发,那么需要保证 Content-Length 和 Transfer-Encoding: chunked 必有且只有一个,以 chunked 形式发时,每段 chunk 最大为 8192 字节;如果用户发送的 body 为自己实现的 InputStream 类,则需要自己保证 Content-Length 和 Transfer-Encoding: chunked 设置且只设置了一个;如果用户采用默认的 body 发送,Content-Length 和 Transfer-Encoding: chunked 都缺失时,我们会为其补上 Content-Length header,值为 body.size;
  • 用户如果设置了 Content-Length,则需要保证其正确性:如果所发 body 的内容大于等于 Content-Length 的值,我们会发送长度为 Content-Length 值的数据;如果所发 body 的内容小于 Content-Length 的值,此时如果 body 是默认的 body,则会抛出 HttpException,如果 body 是用户自己实现的 InputStream 类,其行为便无法保证(可能会造成服务器端的读 request 超时或者客户端的收 response 超时);
  • 升级函数通过 WebSocket 的 upgradeFromClient 或 Clientupgrade 接口发出,调用 client 的其他函数发送 upgrade 请求会抛出异常;
  • 协议规定 TRACE 请求无法携带内容,故用户发送带有 body 的 TRACE 请求时会抛出异常;
  • HTTP/1.1 默认对同一个服务器的连接数不超过 10 个。response 的 body 需要用户调用 body.read(buf: Array<Byte>) 函数去读。body 被读完后,连接才能被客户端对象复用,否则请求相同的服务器也会新建连接。新建连接时如果连接数超出限制则会抛出 HttpException
  • body.read 函数将 body 读完之后返回 0,如果读的时候连接断开会抛出 ConnectionException
  • HTTP/1.1 的升级请求如果收到 101 响应,则表示切换协议,此连接便不归 client 管理;
  • 下文的快捷请求函数的注意点与 send 相同。

参数:

返回值:

异常:

示例:

import stdx.net.http.*
import stdx.encoding.url.*
import std.net.*
import std.sync.*

main() {
    // server: 回 204 并关闭
    let ss = TcpServerSocket(bindAt: 0)
    ss.bind()
    let done = SyncCounter(1)
    spawn {
        =>
            let s = ss.accept()
            let buf = Array<UInt8>(1024, repeat: 0)
            let n = s.read(buf)
            let firstLine = (String.fromUtf8(buf[..n]).split("\r\n"))[0]
            println("[server] ${firstLine}")
            s.write("HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n".toArray())
            s.close()
            done.dec()
    }

    let port = (ss.localAddress as IPSocketAddress)?.port ?? throw Exception("Port not found")

    let client = ClientBuilder().build()

    // func send(HttpRequest): 通过 HttpRequestBuilder 构建请求
    let u = URL.parse("http://127.0.0.1:${port}/send")
    let req = HttpRequestBuilder().url(u).method("GET").build()
    let resp = client.send(req)
    println("status = ${resp.status}")

    client.close()
    done.waitUntilZero()
    ss.close()
}

运行结果:

[server] GET /send HTTP/1.1
status = 204

func upgrade(HttpRequest)

public func upgrade(req: HttpRequest): (HttpResponse, ?StreamingSocket)

功能:发送请求并升级协议,用户设置请求头,返回升级后的连接(如果升级成功),连接由用户负责关闭。

说明:

  • 服务器返回 101 表示升级成功,获取到了 StreamingSocket;
  • 必选请求头:
    • Upgrade: protocol-name ["/" protocol-version];
    • Connection: Upgrade(在请求头包含 Upgrade 字段时会自动添加);
  • 不支持 HTTP/1.0、HTTP/2;
  • 不支持 HTTP/1.1 CONNECT 方法的 HttpRequest

参数:

返回值:

  • (HttpResponse,?StreamingSocket) - 返回一个元组,HttpResponse 实例表示服务器返回的响应,?StreamingSocket 实例表示获取的底层连接,升级失败时为 None。

异常:

  • HttpException -
    • 请求报文或响应报文不符合协议;
    • 请求报文不含 Upgrade 头;
    • 发送 CONNECT 请求;
    • 发送带 body 的 TRACE 请求;
  • SocketException,ConnectionException - Socket 连接出现异常或被关闭;
  • SocketTimeoutException - Socket 连接超时;
  • TlsException - Tls 连接建立失败或通信异常。

示例:

import stdx.net.http.*
import stdx.encoding.url.*
import std.net.*
import std.sync.*

main() {
    let ss = TcpServerSocket(bindAt: 0)
    ss.bind()
    let done = SyncCounter(1)

    spawn {
        =>
            let s = ss.accept()
            let buf = Array<UInt8>(2048, repeat: 0)
            let n = s.read(buf)
            let reqStr = String.fromUtf8(buf[..n])
            // 打印方法(避免随机端口)
            println("method = ${reqStr.split(" ")[0]}")

            // 按协议回 101 Switching Protocols
            s.write("HTTP/1.1 101 Switching Protocols\r\nUpgrade: test/1\r\nConnection: Upgrade\r\n\r\n".toArray())
            // 等 client 关闭
            s.close()
            done.dec()
    }

    let port = (ss.localAddress as IPSocketAddress)?.port ?? throw Exception("Port not found")

    let client = ClientBuilder().build()

    // func upgrade(HttpRequest)
    let headers = HttpHeaders()
    headers.add("Upgrade", "test/1")
    let req = HttpRequestBuilder().url(URL.parse("http://127.0.0.1:${port}/up")).get().setHeaders(headers).build()

    let (resp, sockOpt) = client.upgrade(req)
    println("status = ${resp.status}")
    println("hasSocket = ${sockOpt.isSome()}")

    match (sockOpt) {
        case Some(s) => s.close()
        case None => ()
    }
    client.close()

    done.waitUntilZero()
    ss.close()
}

运行结果:

method = GET
status = 101
hasSocket = true

class ClientBuilder

public class ClientBuilder {
    public init()
}

功能:用于 Client 实例的构建,Client 没有公开的构造函数,用户只能通过 ClientBuilder 得到 Client 实例。ClientBuilder 文档中未明确说明支持版本的配置,在 HTTP/1.1 与 HTTP/2 都会生效。

说明:

该类提供了一系列配置参数的函数,配置完成后调用 build 函数构造出 Client 实例。配置函数中说明了参数的取值范围,但配置函数本身不做参数合法性校验,build 时统一进行校验。

func initialWindowSize(UInt32)

public func initialWindowSize(size: UInt32): ClientBuilder

功能:配置客户端 HTTP/2 流控窗口初始值。

参数:

  • size: UInt32 - 默认值 65535 , 取值范围为 0 至 2^31 - 1。

返回值:

示例:

import stdx.net.http.*

main() {
    let client = ClientBuilder().initialWindowSize(65535).build()
    println("initialWindowSize = ${client.initialWindowSize}")
    client.close()
}

运行结果:

initialWindowSize = 65535

init()

public init()

功能:创建新的 ClientBuilder 实例。

示例:

import stdx.net.http.*

main() {
    let _ = ClientBuilder()
}

func autoRedirect(Bool)

public func autoRedirect(auto: Bool): ClientBuilder

功能:配置客户端是否会自动进行重定向。重定向会请求 Location 头的资源,协议规定,Location 只能包含一个 URI 引用 Location = URI-reference,详见 RFC 9110 10.2.2.。304 状态码默认不重定向。

参数:

  • auto: Bool - 默认值为 true,即开启自动重定向。

返回值:

示例:

import stdx.net.http.*

main() {
    // 配置 ClientBuilder.autoRedirect,并验证 Client.autoRedirect
    let client = ClientBuilder().autoRedirect(false).build()
    println("autoRedirect = ${client.autoRedirect}")
    client.close()
}

运行结果:

autoRedirect = false

func build()

public func build(): Client

功能:构造 Client 实例。

此处会对各参数的值进行检查,如果取值非法,将抛出异常。各参数的取值范围详见设置参数相关的函数。

返回值:

异常:

  • IllegalArgumentException - 配置项有非法参数时抛出此异常。

示例:

import stdx.net.http.*

main() {
    // build() 构建出 Client 实例
    let client = ClientBuilder().build()
    println("poolSize = ${client.poolSize}")
    client.close()
}

运行结果:

poolSize = 10

func connector((SocketAddress) -> StreamingSocket)

public func connector(c: (SocketAddress) -> StreamingSocket): ClientBuilder

功能:客户端调用此函数获取到服务器的连接。

参数:

  • c: (SocketAddress) ->StreamingSocket - 入参为 SocketAddress 实例,返回值类型为 StreamingSocket 的函数类型。

返回值:

示例:

import stdx.net.http.*
import std.net.*
import std.sync.*

main() {
    // 用 connector 注入自定义建连逻辑
    let ss = TcpServerSocket(bindAt: 0)
    ss.bind()
    let done = SyncCounter(1)

    spawn {
        =>
            let s = ss.accept()
            let buf = Array<UInt8>(1024, repeat: 0)
            let n = s.read(buf)
            println((String.fromUtf8(buf[..n]).split("\r\n"))[0])
            s.write("HTTP/1.1 200 OK\r\nContent-Length: 2\r\nConnection: close\r\n\r\nOK".toArray())
            s.close()
            done.dec()
    }

    let port = (ss.localAddress as IPSocketAddress)?.port ?? throw Exception("Port not found")

    let myConnector: (SocketAddress) -> StreamingSocket = {
        addr =>
            println("connector called")
            let socket = TcpSocket(addr)
            socket.connect()
            socket
    }

    let client = ClientBuilder().connector(myConnector).build()
    let resp = client.get("http://127.0.0.1:${port}/")
    println("status = ${resp.status}")

    client.close()
    done.waitUntilZero()
    ss.close()
}

运行结果:

connector called
GET / HTTP/1.1
status = 200

func cookieJar(?CookieJar)

public func cookieJar(cookieJar: ?CookieJar): ClientBuilder

功能:用于存储客户端所有 Cookie

参数:

返回值:

示例:

import stdx.net.http.*

main() {
    // 将 cookieJar 设为 None:禁用 Cookie
    let client = ClientBuilder().cookieJar(None).build()
    println("cookieJar.isSome = ${client.cookieJar.isSome()}")
    client.close()
}

运行结果:

cookieJar.isSome = false

func enablePush(Bool)

public func enablePush(enable: Bool): ClientBuilder

功能:配置客户端 HTTP/2 是否支持服务器推送。

参数:

  • enable: Bool - 默认值 true。

返回值:

示例:

import stdx.net.http.*

main() {
    let client = ClientBuilder().enablePush(false).build()
    println("enablePush = ${client.enablePush}")
    client.close()
}

运行结果:

enablePush = false

func headerTableSize(UInt32)

public func headerTableSize(size: UInt32): ClientBuilder

功能:配置客户端 HTTP/2 Hpack 动态表初始值。

参数:

  • size: UInt32 - 默认值 4096。

返回值:

示例:

import stdx.net.http.*

main() {
    let client = ClientBuilder().headerTableSize(1024).build()
    println("headerTableSize = ${client.headerTableSize}")
    client.close()
}

运行结果:

headerTableSize = 1024

func httpProxy(String)

public func httpProxy(addr: String): ClientBuilder

功能:设置客户端 http 代理,默认使用系统环境变量 http_proxy 的值。

参数:

  • addr: String - 格式为:"http://host:port",例如:"http://192.168.1.1:80"

返回值:

示例:

import stdx.net.http.*

main() {
    // 设置 http 代理(字符串形式)
    let client = ClientBuilder().httpProxy("http://proxy.example:8080").build()
    println("httpProxy = ${client.httpProxy}")
    client.close()
}

运行结果:

httpProxy = http://proxy.example:8080

func httpsProxy(String)

public func httpsProxy(addr: String): ClientBuilder

功能:设置客户端 https 代理,默认使用系统环境变量 https_proxy 的值。

参数:

  • addr: String - 格式为:"http://host:port",例如:"http://192.168.1.1:443"

返回值:

示例:

import stdx.net.http.*

main() {
    // 设置 https 代理(注意:格式仍是 http://host:port)
    let client = ClientBuilder().httpsProxy("http://proxy.example:443").build()
    println("httpsProxy = ${client.httpsProxy}")
    client.close()
}

运行结果:

httpsProxy = http://proxy.example:443

func logger(Logger)

public func logger(logger: Logger): ClientBuilder

功能:设定客户端的 logger,默认 logger 级别为 INFO,logger 内容将写入 Console.stdout。

参数:

  • logger: Logger - 需要是线程安全的,默认使用内置线程安全 logger。

返回值:

示例:

import stdx.net.http.*
import stdx.log.*

main() {
    // 使用 NoopLogger 注入 logger
    let logger = NoopLogger()
    logger.level = LogLevel.INFO

    let client = ClientBuilder().logger(logger).build()
    println("client.logger.level = ${client.logger.level}")
    client.close()
}

运行结果:

client.logger.level = OFF

func maxConcurrentStreams(UInt32)

public func maxConcurrentStreams(size: UInt32): ClientBuilder

功能:配置客户端 HTTP/2 初始最大并发流数量。

参数:

  • size: UInt32 - 默认值为 2^31 - 1。

返回值:

示例:

import stdx.net.http.*

main() {
    let client = ClientBuilder().maxConcurrentStreams(100).build()
    println("maxConcurrentStreams = ${client.maxConcurrentStreams}")
    client.close()
}

运行结果:

maxConcurrentStreams = 100

func maxFrameSize(UInt32)

public func maxFrameSize(size: UInt32): ClientBuilder

功能:配置客户端 HTTP/2 初始最大帧大小。

参数:

  • size: UInt32 - 默认值为 16384。取值范围为 2^14 至 2^24 - 1。

返回值:

示例:

import stdx.net.http.*

main() {
    let client = ClientBuilder().maxFrameSize(16384).build()
    println("maxFrameSize = ${client.maxFrameSize}")
    client.close()
}

运行结果:

maxFrameSize = 16384

func maxHeaderListSize(UInt32)

public func maxHeaderListSize(size: UInt32): ClientBuilder

功能:获取客户端支持的 HTTP/2 最大头部(Header)大小。这个大小指的是响应头部中所有头部字段(Header Field)的最大允许长度之和,其中包括所有字段名称(name)的长度、字段值(value)的长度以及每个字段自动添加的伪头开销(通常每个字段会有 32 字节的开销,这包括了 HTTP/2 协议本身为头部字段添加的伪头部信息)。默认情况下,这个最大长度被设置为 UInt32.Max。

参数:

  • size: UInt32 - 客户端接收的 HTTP/2 响应 headers 最大长度。

返回值:

示例:

import stdx.net.http.*

main() {
    let client = ClientBuilder().maxHeaderListSize(1024).build()
    println("maxHeaderListSize = ${client.maxHeaderListSize}")
    client.close()
}

运行结果:

maxHeaderListSize = 1024

func noProxy()

public func noProxy(): ClientBuilder

功能:调用此函数后,客户端不使用任何代理。

返回值:

示例:

import stdx.net.http.*

main() {
    // noProxy() 清空代理
    let client = ClientBuilder().noProxy().build()
    println("httpProxy = '${client.httpProxy}'")
    println("httpsProxy = '${client.httpsProxy}'")
    client.close()
}

运行结果:

httpProxy = ''
httpsProxy = ''

func poolSize(Int64)

public func poolSize(size: Int64): ClientBuilder

功能:配置 HTTP/1.1 客户端使用的连接池的大小,亦可表示对同一个主机(host:port)同时存在的连接数的最大值。

参数:

  • size: Int64 - 默认 10,poolSize 需要大于 0。

返回值:

异常:

  • HttpException - 如果传参小于等于 0,则会抛出该异常。

示例:

import stdx.net.http.*

main() {
    let client = ClientBuilder().poolSize(5).build()
    println("poolSize = ${client.poolSize}")
    client.close()
}

运行结果:

poolSize = 5

func readTimeout(Duration)

public func readTimeout(timeout: Duration): ClientBuilder

功能:设定客户端读取一个响应的最大时长。

参数:

  • timeout: Duration - 默认 15s,Duration.Max 代表不限制,如果传入负的 Duration 将被替换为 Duration.Zero。

返回值:

示例:

import stdx.net.http.*

main() {
    let client = ClientBuilder().readTimeout(Duration.second * 1).build()
    println("readTimeout = ${client.readTimeout}")
    client.close()
}

运行结果:

readTimeout = 1s

func tlsConfig(TlsConfig)

public func tlsConfig(config: TlsConfig): ClientBuilder

功能:设置 TLS 层配置,默认不对其进行设置。

参数:

  • config: TlsConfig - 设定支持 tls 客户端需要的配置信息。

返回值:

示例:

import stdx.net.http.*
import stdx.net.tls.*

main() {
    // 配置 ClientBuilder.tlsConfig,并通过 Client.getTlsConfig() 验证已生效。
    var tls = TlsClientConfig()
    tls.supportedAlpnProtocols = ["h2"]

    let client = ClientBuilder().tlsConfig(tls).build()
    println("tlsConfig.isSome = ${client.getTlsConfig().isSome()}")
    client.close()
}

运行结果:

tlsConfig.isSome = true

func writeTimeout(Duration)

public func writeTimeout(timeout: Duration): ClientBuilder

功能:设定客户端发送一个请求的最大时长。

参数:

  • timeout: Duration - 默认 15 秒,Duration.Max 代表不限制,如果传入负的 Duration 将被替换为 Duration.Zero。

返回值:

示例:

import stdx.net.http.*

main() {
    let client = ClientBuilder().writeTimeout(Duration.second * 2).build()
    println("writeTimeout = ${client.writeTimeout}")
    client.close()
}

运行结果:

writeTimeout = 2s
public class Cookie {
    public init(name: String, value: String, expires!: ?DateTime = None, maxAge!: ?Int64 = None,
        domain!: String = "", path!: String = "", secure!: Bool = false, httpOnly!: Bool = false)
}

功能:HTTP 本身是无状态的,server 为了知道 client 的状态,提供个性化的服务,便可以通过 Cookie 来维护一个有状态的会话。

说明:

  • 用户首次访问某站点时,server 通过 Set-Cookie header 将 name/value 对,以及 attribute-value 传给用户代理;用户代理随后对该站点的请求中便可以将 name/value 加入到 Cookie header 中;
  • Cookie 类提供了构建 Cookie 对象,并将 Cookie 对象转成 Set-Cookie header 值的函数,提供了获取 Cookie 对象各属性值的函数;
  • Cookie 的各个属性的要求和作用见 RFC 6265
  • 下文中 cookie-name,cookie-value,expires-av 等名字采用 RFC 6265 中的术语,详情请见协议。

prop cookieName

public prop cookieName: String

功能:获取 Cookie 对象的 cookie-name 值。

类型:String

prop cookieValue

public prop cookieValue: String

功能:获取 Cookie 对象的 cookie-value 值。

类型:String

prop domain

public prop domain: String

功能:获取 Cookie 对象的 domain-av 值。

类型:String

prop expires

public prop expires: ?DateTime

功能:获取 Cookie 对象的 expires-av 值。

类型:?DateTime

prop httpOnly

public prop httpOnly: Bool

功能:获取 Cookie 对象的 httpOnly-av 值。

类型:Bool

prop maxAge

public prop maxAge: ?Int64

功能:获取 Cookie 对象的 max-age-av 值。

类型:?Int64

prop others

public prop others: ArrayList<String>

功能:获取未被解析的属性。

类型:ArrayList<String>

prop path

public prop path: String

功能:获取 Cookie 对象的 path-av 值。

类型:String

prop secure

public prop secure: Bool

功能:获取 Cookie 对象的 secure-av 值。

类型:Bool

init(String, String, ?DateTime, ?Int64, String, String, Bool, Bool)

public init(name: String, value: String, expires!: ?DateTime = None, maxAge!: ?Int64 = None,
    domain!: String = "", path!: String = "", secure!: Bool = false, httpOnly!: Bool = false)

功能:Cookie 构造器。

该构造器会检查传入的各项属性是否满足协议要求,如果不满足则会产生 IllegalArgumentException。具体要求见 RFC 6265 4.1.1.

注意:

Cookie 各属性中只有 cookie-name,cookie-value 是必需的,必须传入 name,value 参数,但 value 参数可以传入空字符串。

参数:

  • name: String - cookie-name 属性。

    name         = token 
    token        = 1*tchar
    tchar        = "!" / "#" / "$" / "%" / "&" / "'" / "*"
                   / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
                   / DIGIT / ALPHA
    
  • value: String - cookie-value 属性。

    value        = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
    cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
                ; US-ASCII characters excluding CTLs,
                ; whitespace DQUOTE, comma, semicolon,
                ; and backslash
    
  • expires!: ?DateTime - 设置 Cookie 的过期时间,默认为 None,时间必须在 1601 年之后。

  • maxAge!: ?Int64 - Cookie 的最大生命周期,默认为 None,如果 Cookie 既有 expires 属性,也有 maxAge,则表示该 Cookie 只维护到会话结束(维护到 Client 关闭之前,Client 关闭之后设置了过期的 Cookie 也不再维护)。

    max-age-av     = "Max-Age=" non-zero-digit *DIGIT
    non-zero-digit = %x31-39
                    ; digits 1 through 9
    DIGIT          = %x30-39
                    ; digits 0 through 9
    
  • domain!: String - 默认为空字符串,表示该收到该 Cookie 的客户端只会发送该 Cookie 给原始服务器。如果设置了合法的 domain,则收到该 Cookie 的客户端只会发送该 Cookie 给所有该 domain 的子域(且满足其他属性条件要求才会发)。

    domain          = <subdomain> | " "
    <subdomain>   ::= <label> | <subdomain> "." <label>
    <label>       ::= <letter> [ [ <ldh-str> ] <let-dig> ]
    <ldh-str>     ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
    <let-dig-hyp> ::= <let-dig> | "-"
    <let-dig>     ::= <letter> | <digit>
    <letter>      ::= any one of the 52 alphabetic characters A through Z in upper case and a through z in lower case
    <digit>       ::= any one of the ten digits 0 through 9
    RFC 1035 2.3.1.
    而 RFC 1123 2.1. 放松了对 label 首字符必须是 letter 的限制
    因此,对 domain 的要求为:
    1、总长度小于等于 255,由若干个 label 组成
    2、label 与 label 之间通过 "." 分隔,每个 label 长度小于等于 63
    3、label 的开头和结尾必须是数字或者字母,label 的中间字符必须是数字、字母或者 "-"
    
  • path!: String - 默认为空字符串,客户端会根据 url 计算出默认的 path 属性,见 RFC 6265 5.1.4.。 收到该 Cookie 的客户端只会发送该 Cookie 给所有该 path 的子目录(且满足其他属性条件要求才会发)。

    path            = <any RUNE except CTLs or ";">
    RUNE            = <any [USASCII] character>
    CTLs            = <controls>
    
  • secure!: Bool - 默认为 false,如果设置为 true,该 Cookie 只会在安全协议请求中发送。

  • httpOnly!: Bool - 默认为 false,如果设置为 true,该 Cookie 只会在 HTTP 协议请求中发送。

异常:

  • IllegalArgumentException - 传入的参数不符合协议要求时抛出异常。

示例:

import stdx.net.http.*
import std.time.*

main() {
    let cookie = Cookie("sid", "abc", expires: DateTime.of(year: 2099, month: 1, dayOfMonth: 1, timeZone: TimeZone.UTC),
        maxAge: 3600, domain: "example.com", path: "/", secure: true, httpOnly: true)
    // 当前属性:secure
    println("secure = ${cookie.secure}")
}

运行结果:

secure = true

func toSetCookieString()

public func toSetCookieString(): String

功能:提供将 Cookie 转成字符串形式的函数,方便 server 设置 Set-Cookie header。

注意:

  • Cookie 各属性(包含 name,value)在对象创建时就被检查了,因此 toSetCookieString() 函数不会产生异常;
  • Cookie 必需的属性是 cookie-pair 即 cookie-name "=" cookie-value,cookie-value 可以为空字符串,toSetCookieString() 函数只会将设置过的属性写入字符串,即只有 "cookie-name=" 是必有的,其余部分是否存在取决于是否设置。

返回值:

  • String - 字符串对象,用于设置 Set-Cookie header。

示例:

import stdx.net.http.*
import std.time.*

main() {
    // func toSetCookieString(): 将 Cookie 转成 Set-Cookie header 的 value
    let cookie = Cookie(
        "sid",
        "abc",
        expires: DateTime.of(year: 2099, month: 1, dayOfMonth: 1, timeZone: TimeZone.UTC),
        maxAge: 3600,
        domain: ".example.com", // 以 '.' 开头也会被规范化
        path: "/",
        secure: true,
        httpOnly: true
    )

    let setCookieValue = cookie.toSetCookieString()
    println(setCookieValue)
}

运行结果:

sid=abc; Expires=Thu, 01 Jan 2099 00:00:00 UTC; Max-Age=3600; Domain=example.com; Path=/; Secure; HttpOnly

class FileHandler

public class FileHandler <: HttpRequestHandler {
    public init(path: String, handlerType!: FileHandlerType = DownLoad, bufferSize!: Int64 = 64 * 1024)
    public init(path: String, handlerType!: FileHandlerType = DownLoad, bufferSize!: Int64 = 64 * 1024, validator!: (String) -> Bool)
}

功能:用于处理文件下载或者文件上传。

文件下载:

  • 构造 FileHandler 时需要传入待下载文件的路径,目前一个 FileHandler 只能处理一个文件的下载;
  • 下载文件只能使用 GET 请求,其他请求返回 400 状态码;
  • 文件如果不存在,将返回 404 状态码。

文件上传:

  • 构造 FileHandler 时需要传入一个存在的目录路径,上传到服务端的文件将保存在这个目录中;
  • 上传文件时只能使用 POST 请求,其他请求返回 400 状态码;
  • 上传数据的 http 报文必须是 multipart/form-data 格式的,Content-Type 头字段的值为 multipart/form-data; boundary=----XXXXX
  • 上传文件的文件名存放在 form-data 数据报文中,报文数据格式为 Content-Disposition: form-data; name="xxx"; filename="xxxx",文件名是 filename 字段的值;
  • 目前 form-data 中必须包含 filename 字段;
  • 如果请求报文不正确,将返回 400 状态码;
  • 如果出现其他异常,例如文件处理异常,将返回 500 状态码。

父类型:

init(String, FileHandlerType, Int64)

public init(path: String, handlerType!: FileHandlerType = DownLoad, bufferSize!: Int64 = 64 * 1024)

功能:FileHandler 的构造函数。

参数:

  • path: String - FileHandler 构造时需要传入的文件或者目录路径字符串,上传模式中只能传入存在的目录路径;路径中存在../时,用户需要确认标准化后的绝对路径是期望传入的路径。
  • handlerType!: FileHandlerType - 构造 FileHandler 时指定当前 FileHandler 的工作模式,默认为 DownLoad 下载模式。
  • bufferSize!: Int64 - 内部从网络读取或者写入的缓冲区大小,默认值为 64*1024(64k),若小于 4096,则使用 4096 作为缓冲区大小。

异常:

  • HttpException - 当 path 不存在时,抛出异常。
  • IllegalArgumentException - 参数错误时抛出异常,如 path 为空或者包含空字符串等。

示例:

import stdx.net.http.*

main() {
    let filePath: String = "./http_filehandler_download.txt"
    FileHandler(filePath)
    return 0
}

init(String, FileHandlerType, Int64, (String) -> Bool)

public init(path: String, handlerType!: FileHandlerType = DownLoad, bufferSize!: Int64 = 64 * 1024, validator!: (String) -> Bool)

功能:FileHandler 的构造函数。

参数:

  • path: String - FileHandler 构造时需要传入的文件或者目录路径字符串,上传模式中只能传入存在的目录路径;路径中存在../时,用户需要确认标准化后的绝对路径是期望传入的路径。
  • handlerType!: FileHandlerType - 构造 FileHandler 时指定当前 FileHandler 的工作模式,默认为 DownLoad 下载模式。
  • bufferSize!: Int64 - 内部从网络读取或者写入的缓冲区大小,默认值为 64*1024(64k),若小于 4096,则使用 4096 作为缓冲区大小。
  • validator!: (String) -> Bool - 用户自定义的文件名校验函数,仅上传模式有效。入参是上传的文件在 multipart 数据报文中的 filename,返回值是用户自定义函数的校验结果。如果校验结果是 false,则中断上传请求,并返回“400 Bad Request”,同时删除本次请求已上传到 path 目录的文件。

异常:

  • HttpException - 当 path 不存在时,抛出异常。
  • IllegalArgumentException - 参数错误时抛出异常,如 path 为空或者包含空字符串等。

示例:

import stdx.net.http.*

main() {
    let filePath: String = "./http_filehandler_download.txt"
    FileHandler(filePath, validator: {fileName: String => fileName.contains(".txt")})
    return 0
}

func handle(HttpContext)

public func handle(ctx: HttpContext): Unit

功能:根据请求对响应数据进行处理。

参数:

示例:

import stdx.net.http.*
import stdx.log.*
import std.fs.*
import std.io.*
import std.sync.*

main() {
    // 创建一个临时文件,供 FileHandler 下载
    let filePath: Path = Path("./http_filehandler_download.txt")
    if (exists(filePath)) {
        remove(filePath)
    }
    let f = File(filePath, Write)
    f.write("file-content".toArray())
    f.close()

    // 启动服务并注册 FileHandler
    let sc = SyncCounter(1)
    let server = ServerBuilder().addr("127.0.0.1").port(18090).afterBind({=> sc.dec()}).build()
    server.distributor.register("/file", FileHandler(filePath.toString()))
    server.logger.level = LogLevel.ERROR

    spawn {server.serve()}
    sc.waitUntilZero()

    // 访问 /file,触发 FileHandler.handle(ctx)
    let client = ClientBuilder().build()
    let resp = client.get("http://127.0.0.1:18090/file")

    var buf = Array<UInt8>(1024, repeat: 0)
    var body = ""
    while (true) {
        let n = resp.body.read(buf)
        if (n <= 0) {
            break
        }
        body = body + String.fromUtf8(buf[..n])
    }
    resp.close()

    // 输出稳定内容(不打印随机端口等信息)
    println("status = ${resp.status}")
    println("body = ${body}")

    client.close()
    server.closeGracefully()
    remove(filePath)
}

运行结果:

status = 200
body = file-content

class FuncHandler

public class FuncHandler <: HttpRequestHandler {
    public FuncHandler(let handler: (HttpContext) -> Unit)
}

功能:HttpRequestHandler 接口包装类,把单个函数包装成 HttpRequestHandler

父类型:

FuncHandler((HttpContext) -> Unit)

public FuncHandler(let handler: (HttpContext) -> Unit)

功能:FuncHandler 的构造函数。

参数:

  • handler: (HttpContext) -> Unit - 是调用 handle 的处理函数。

示例:

import stdx.net.http.*
import stdx.log.*
import std.fs.*
import std.io.*
import std.sync.*

main() {
    // 准备一个临时文件,让 handler 返回该文件内容(稳定输出)
    let filePath: Path = Path("./http_funchandler_resp.txt")
    if (exists(filePath)) {
        remove(filePath)
    }
    let f = File(filePath, Write)
    f.write("hello".toArray())
    f.close()

    // 使用 FuncHandler 注册一个处理函数
    let handler = FuncHandler({
        ctx =>
        // 当前函数:handle(ctx) 会触发这里的逻辑
        ctx.responseBuilder.status(200).header("content-type", "text/plain").body(File(filePath, Read))
    })

    let sc = SyncCounter(1)
    let server = ServerBuilder().addr("127.0.0.1").port(18091).afterBind({=> sc.dec()}).build()
    server.distributor.register("/hi", handler)
    server.logger.level = LogLevel.ERROR

    spawn {server.serve()}
    sc.waitUntilZero()

    let client = ClientBuilder().build()
    let resp = client.get("http://127.0.0.1:18091/hi")

    var buf = Array<UInt8>(1024, repeat: 0)
    var body = ""
    while (true) {
        let n = resp.body.read(buf)
        if (n <= 0) {
            break
        }
        body = body + String.fromUtf8(buf[..n])
    }
    resp.close()

    println("status = ${resp.status}")
    println("body = ${body}")

    client.close()
    server.closeGracefully()
    remove(filePath)
}

运行结果:

status = 200
body = hello

func handle(HttpContext)

public func handle(ctx: HttpContext): Unit

功能:处理 Http 请求。

参数:

示例:

import stdx.net.http.*
import stdx.log.*
import std.fs.*
import std.io.*
import std.sync.*

main() {
    // 准备一个临时文件,让 handler 返回该文件内容(稳定输出)
    let filePath: Path = Path("./http_funchandler_resp.txt")
    if (exists(filePath)) {
        remove(filePath)
    }
    let f = File(filePath, Write)
    f.write("hello".toArray())
    f.close()

    // 使用 FuncHandler 注册一个处理函数
    let handler = FuncHandler({
        ctx =>
        // 当前函数:handle(ctx) 会触发这里的逻辑
        ctx.responseBuilder.status(200).header("content-type", "text/plain").body(File(filePath, Read))
    })

    let sc = SyncCounter(1)
    let server = ServerBuilder().addr("127.0.0.1").port(18091).afterBind({=> sc.dec()}).build()
    server.distributor.register("/hi", handler)
    server.logger.level = LogLevel.ERROR

    spawn {server.serve()}
    sc.waitUntilZero()

    let client = ClientBuilder().build()
    let resp = client.get("http://127.0.0.1:18091/hi")

    var buf = Array<UInt8>(1024, repeat: 0)
    var body = ""
    while (true) {
        let n = resp.body.read(buf)
        if (n <= 0) {
            break
        }
        body = body + String.fromUtf8(buf[..n])
    }
    resp.close()

    println("status = ${resp.status}")
    println("body = ${body}")

    client.close()
    server.closeGracefully()
    remove(filePath)
}

运行结果:

status = 200
body = hello

class HttpContext

public class HttpContext

功能:Http 请求上下文,作为 HttpRequestHandler.handle 函数的参数在服务端使用。

prop clientCertificate

public prop clientCertificate: ?Array<Certificate>

功能:获取 Http 客户端证书。

类型:?Array<Certificate>

prop request

public prop request: HttpRequest

功能:获取 Http 请求。

类型:HttpRequest

prop responseBuilder

public prop responseBuilder: HttpResponseBuilder

功能:获取 Http 响应构建器。

类型:HttpResponseBuilder

func isClosed()

public func isClosed(): Bool

功能:使用 HTTP/1.1 协议时,判断 socket 是否已关闭;使用 HTTP/2 协议时,判断 HTTP/2 流是否已关闭。

返回值:

  • Bool - 如果 HTTP/1.1 的 socket 或 HTTP/2 的流已关闭,返回 true,否则返回 false。

示例:

import stdx.net.http.*
import stdx.log.*
import std.sync.*

main() {
    let sc = SyncCounter(1)
    let server = ServerBuilder().addr("127.0.0.1").port(18095).afterBind({=> sc.dec()}).build()
    server.logger.level = LogLevel.ERROR

    server.distributor.register(
        "/t",
        FuncHandler(
            {
                ctx =>
                    // 当前函数:isClosed()
                    println("isClosed = ${ctx.isClosed()}")
                    ctx.responseBuilder.status(200).body("ok")
            }
        )
    )

    spawn {server.serve()}
    sc.waitUntilZero()

    let client = ClientBuilder().build()
    let resp = client.get("http://127.0.0.1:18095/t")
    resp.close()
    client.close()
    server.closeGracefully()
}

运行结果:

isClosed = false

class HttpHeaders

public class HttpHeaders <: Iterable<(String, Collection<String>)>

功能:此类用于表示 Http 报文中的 header 和 trailer,定义了相关增、删、改、查操作。

说明:

  • header 和 trailer 为键值映射集,由若干 field-line 组成,每一个 field-line 包含一个键 (field -name) 和若干值 (field-value)。
  • field-name 由 token 字符组成,不区分大小写,在该类中将转为小写保存。
  • field-value 由 vchar,SP 和 HTAB 组成,vchar 表示可见的 US-ASCII 字符,不得包含前后空格,不得为空值。
  • 详见 rfc 9110

示例:

Example-Field: Foo, Bar
key: Example-Field, value: Foo, Bar
field-name = token
token = 1*tchar
tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
/ "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
/ DIGIT / ALPHA
; any VCHAR, except delimiters

父类型:

  • Iterable<(String, Collection<String>)>

func add(String, String)

public func add(name: String, value: String): Unit

功能:添加指定键值对。如果 name 已经存在,将在其对应的值列表中添加 value;如果 name 不存在,则添加 name 字段及其值 value。

参数:

异常:

  • HttpException - 如果传入的 name/value 包含不合法元素,将抛出此异常。

示例:

import stdx.net.http.*

main() {
    let headers = HttpHeaders()
    // 当前函数:add(name, value)
    headers.add("x-a", "1")
    headers.add("x-a", "2")

    println("x-a.first = ${headers.getFirst("X-A") ?? ""}")
    println("x-a.size = ${headers.get("x-a").size}")
}

运行结果:

x-a.first = 1
x-a.size = 2

func del(String)

public func del(name: String): Unit

功能:删除指定 name 对应的键值对。

参数:

  • name: String - 删除的字段名称。

示例:

import stdx.net.http.*

main() {
    let headers = HttpHeaders()
    headers.add("x-a", "1")

    // 当前函数:del(name)
    headers.del("x-a")
    println("isEmpty = ${headers.isEmpty()}")
}

运行结果:

isEmpty = true

func get(String)

public func get(name: String): Collection<String>

功能:获取指定 name 对应的 value 值。

参数:

  • name: String - 字段名称,不区分大小写。

返回值:

  • Collection<String> - name 对应的 value 集合,如果指定 name 不存在,返回空集合。

示例:

import stdx.net.http.*

main() {
    let headers = HttpHeaders()
    headers.add("x-a", "1")
    headers.add("x-a", "2")

    // 当前函数:get(name)
    let values = headers.get("x-a")
    println("x-a.size = ${values.size}")
}

运行结果:

x-a.size = 2

func getFirst(String)

public func getFirst(name: String): ?String

功能:获取指定 name 对应的第一个 value 值。

参数:

  • name: String - 字段名称,不区分大小写。

返回值:

  • ?String - name 对应的第一个 value 值,如果指定 name 不存在,返回 None。

示例:

import stdx.net.http.*

main() {
    let headers = HttpHeaders()
    headers.add("x-a", "1")
    headers.add("x-a", "2")

    // 当前函数:getFirst(name)
    println("x-a.first = ${headers.getFirst("x-a") ?? ""}")
}

运行结果:

x-a.first = 1

func isEmpty()

public func isEmpty(): Bool

功能:判断当前实例是否为空,即没有任何键值对。

返回值:

  • Bool - 如果当前实例为空,返回 true,否则返回 false。

示例:

import stdx.net.http.*

main() {
    let headers = HttpHeaders()
    println("empty0 = ${headers.isEmpty()}")

    headers.add("x-a", "1")
    // 当前函数:isEmpty()
    println("empty1 = ${headers.isEmpty()}")
}

运行结果:

empty0 = true
empty1 = false

func iterator()

public func iterator(): Iterator<(String, Collection<String>)>

功能:获取迭代器,可用于遍历所有键值对。

返回值:

  • Iterator<(String, Collection<String>)> - 该键值集的迭代器。

示例:

import stdx.net.http.*

main() {
    let headers = HttpHeaders()
    headers.add("x-a", "1")
    headers.add("x-b", "2")

    // 当前函数:iterator()(遍历 header 键值)
    let it = headers.iterator()
    while (true) {
        match (it.next()) {
            case Some((k, v)) =>
                // k 已被规范化为小写
                println("${k} = ${v.size}")
            case None => break
        }
    }
}

运行结果:

x-a = 1
x-b = 1

func set(String, String)

public func set(name: String, value: String): Unit

功能:设置指定键值对。如果 name 已经存在,传入的 value 将会覆盖之前的值。

参数:

异常:

  • HttpException - 如果传入的 name/values 包含不合法元素,将抛出此异常。

示例:

import stdx.net.http.*

main() {
    let headers = HttpHeaders()
    headers.add("x-a", "1")
    // 当前函数:set(name, value) 会覆盖同名 header
    headers.set("x-a", "100")

    println("x-a.first = ${headers.getFirst("x-a") ?? ""}")
    println("x-a.size = ${headers.get("x-a").size}")
}

运行结果:

x-a.first = 100
x-a.size = 1

class HttpRequest

public class HttpRequest <: ToString

功能:此类为 Http 请求类。

客户端发送请求时,需要构造一个 HttpRequest 实例,再编码成字节报文发出。

服务端处理请求时,需要把收到的请求解析成 HttpRequest 实例,并传给 handler 处理函数。

父类型:

  • ToString

prop body

public prop body: InputStream

功能:获取 body。

注意:

  • body 不支持并发读取;
  • 默认 InputStream 实现类的 read 函数不支持多次读取。

类型:InputStream

prop bodySize

public prop bodySize: Option<Int64>

功能:获取请求 body 长度。

  • 如果未设置 body,则 bodySize 为 Some(0);
  • 如果 body 长度已知,即通过 Array<UInt8> 或 String 传入 body,或传入的 InputStream 有确定的 length (length >= 0),则 bodySize 为 Some(Int64);
  • 如果 body 长度未知,即通过用户自定义的 InputStream 实例传入 body 且 InputStream 实例没有确定的 length (length < 0),则 bodySize 为 None。

类型:Option<Int64>

prop form

public prop form: Form

功能:获取请求中的表单信息。

  • 如果请求方法为 POST,PUT,PATCH,且 content-type 包含 application/x-www-form-urlencoded,获取请求 body 部分,用 form 格式解析;
  • 如果请求方法不为 POST,PUT,PATCH,获取请求 url 中 query 部分。

注意:

  • 如果用该接口读取了 body,body 已被消费完,后续将无法通过 body.read 读取 body;
  • 如果 form 不符合 Form 格式,抛 UrlSyntaxException 异常。

类型:Form

prop headers

public prop headers: HttpHeaders

功能:获取 headers,headers 详述见 HttpHeaders 类,获取后,可通过调用 HttpHeaders 实例成员函数,修改该请求的 headers。

类型:HttpHeaders

prop isPersistent

public prop isPersistent: Bool

功能:表示该请求是否为长连接,即请求 header 是否不包含 Connection: close。包含 Connection: close 为 false,否则为 true。

  • 对于服务端,isPersistent 为 false 表示处理完该请求应该关闭连接。
  • 对于客户端,isPersistent 为 false 表示如果收到响应后服务端未关闭连接,客户端应主动关闭连接。

类型:Bool

prop method

public prop method: String

功能:获取 method,如 "GET", "POST",request 实例的 method 无法修改。

类型:String

prop readTimeout

public prop readTimeout: ?Duration

功能:表示该请求的请求级读超时时间。None 表示没有设置;Some(Duration) 表示设置了读超时时间。

类型:?Duration

prop remoteAddr

public prop remoteAddr: String

功能:用于服务端,获取对端地址,即客户端地址,格式为 ip: port,用户无法设置,自定义的 request 对象调用该属性返回 "",服务端 handler 中调用该属性返回客户端地址。

类型:String

prop trailers

public prop trailers: HttpHeaders

功能:获取 trailers,trailers 详述见 HttpHeaders 类,获取后,可通过调用 HttpHeaders 实例成员函数,修改该请求的 trailers。

类型:HttpHeaders

prop url

public prop url: URL

功能:获取 url,表示客户端访问的 url。

类型:URL

prop version

public prop version: Protocol

功能:获取 http 版本,如 HTTP1_1 和 HTTP2_0,request 实例的 version 无法修改。

类型:Protocol

prop writeTimeout

public prop writeTimeout: ?Duration

功能:表示该请求的请求级写超时时间,None 表示没有设置;Some(Duration) 表示设置了写超时时间。

类型:?Duration

func toString()

public override func toString(): String

功能:把请求转换为字符串,包括 start line,headers,body size,trailers。例如:"GET /path HTTP/1.1\r\nhost: www.example.com\r\n\r\nbody size: 5\r\nbar: foo\r\n"

返回值:

  • String - 请求的字符串表示。

示例:

import stdx.net.http.*

main() {
    let req = HttpRequestBuilder()
        .method("GET")
        .url("http://example.com/hello")
        .header("x-test", "1")
        .body("abc")
        .build()

    // 当前函数:toString()
    println(req.toString())
}

运行结果:

GET /hello HTTP/1.1
x-test: 1

body size: 3

class HttpRequestBuilder

public class HttpRequestBuilder {
    public init()
    public init(request: HttpRequest)
}

功能:HttpRequestBuilder 类用于构造 HttpRequest 实例。

func delete()

public func delete(): HttpRequestBuilder

功能:构造 method 为 "DELETE" 的请求的便捷函数。

返回值:

示例:

import stdx.net.http.*

main() {
    let req = HttpRequestBuilder().delete().url("http://example.com/hello").build()
    println(req.toString())
}

运行结果:

DELETE /hello HTTP/1.1

init()

public init()

功能:构造一个新 HttpRequestBuilder

示例:

import stdx.net.http.*

main() {
    let _ = HttpRequestBuilder()
}

init(HttpRequest)

public init(request: HttpRequest)

功能: 通过 request 构造一个具有 request 属性的 HttpRequestBuilder。由于 body 成员是一个 InputStream,对原始的 request 的 body 的操作会影响到复制得到的 HttpRequest 的 body。HttpRequestBuilder 的 headers 和 trailers 是入参 request 的深拷贝。其余元素都是入参 request 的浅拷贝(因为是不可变对象,无需深拷贝)。

参数:

示例:

import stdx.net.http.*

main() {
    let req = HttpRequestBuilder()
        .method("GET")
        .url("http://example.com/hello")
        .header("x-test", "1")
        .body("abc")
        .build()

    let _ = HttpRequestBuilder(req)
}

func addHeaders(HttpHeaders)

public func addHeaders(headers: HttpHeaders): HttpRequestBuilder

功能:向请求 header 添加参数 HttpHeaders 中的键值对。

参数:

返回值:

示例:

import stdx.net.http.*

main() {
    let extra = HttpHeaders()
    extra.add("x-a", "1")
    extra.add("x-b", "2")

    let req = HttpRequestBuilder().url("http://example.com/hello").addHeaders(extra).build()
    let a = req.headers.getFirst("x-a") ?? ""
    let b = req.headers.getFirst("x-b") ?? ""
    println("x-a = ${a}")
    println("x-b = ${b}")
}

运行结果:

x-a = 1
x-b = 2

func addTrailers(HttpHeaders)

public func addTrailers(trailers: HttpHeaders): HttpRequestBuilder

功能:向请求 trailer 添加参数 HttpHeaders 中的键值对。

参数:

返回值:

示例:

import stdx.net.http.*

main() {
    let extra = HttpHeaders()
    extra.add("x-t", "1")

    let req = HttpRequestBuilder().url("http://example.com/hello").addTrailers(extra).build()
    let t = req.trailers.getFirst("x-t") ?? ""
    println("x-t = ${t}")
}

运行结果:

x-t = 1

func body(Array<UInt8>)

public func body(body: Array<UInt8>): HttpRequestBuilder

功能:设置请求 body。如果已经设置过,调用该函数将替换原 body。

参数:

  • body: Array<UInt8> - 字节数组形式的请求体。

返回值:

示例:

import stdx.net.http.*

main() {
    let req = HttpRequestBuilder().url("http://example.com/hello").body("abc".toArray()).build()
    let buf = Array<UInt8>(16, repeat: 0)
    let n = req.body.read(buf)
    let s = if (n > 0) {
        String.fromUtf8(buf[..n])
    } else {
        ""
    }
    println("body = ${s}")
    println("bodySize = ${req.bodySize.getOrThrow()}")
}

运行结果:

body = abc
bodySize = 3

func body(InputStream)

public func body(body: InputStream): HttpRequestBuilder

功能:设置请求 body。如果已经设置过,调用该函数将替换原 body。

参数:

  • body: InputStream - 流形式的请求体。

返回值:

示例:

import stdx.net.http.*
import std.io.*

class MyBody <: InputStream {
    let data: Array<UInt8>
    var pos: Int64 = 0

    init(s: String) {
        data = s.toArray()
    }

    public func read(buf: Array<Byte>): Int64 {
        if (pos >= data.size) {
            return 0
        }
        let n = min(buf.size, data.size - pos)
        data.copyTo(buf, pos, 0, n)
        pos += n
        return n
    }
}

main() {
    let input: InputStream = MyBody("abc")
    let req = HttpRequestBuilder().url("http://example.com/hello").body(input).build()

    // 自定义 InputStream 不一定实现 Seekable,因此 bodySize 可能为 None
    println("bodySize.isSome = ${req.bodySize.isSome()}")
    let buf = Array<UInt8>(16, repeat: 0)
    let n = req.body.read(buf)
    let s = if (n > 0) {
        String.fromUtf8(buf[..n])
    } else {
        ""
    }
    println("body = ${s}")
}

运行结果:

bodySize.isSome = false
body = abc

func body(String)

public func body(body: String): HttpRequestBuilder

功能:设置请求 body,如果已经设置过,调用该函数将替换原 body 调用该函数设置请求 body,则 body 将以内置的 InputStream 实现类表示,其大小已知。

参数:

  • body: String - 字符串形式的请求体。

返回值:

示例:

import stdx.net.http.*

main() {
    let req = HttpRequestBuilder().url("http://example.com/hello").body("abc").build()
    let buf = Array<UInt8>(16, repeat: 0)
    let n = req.body.read(buf)
    let s = if (n > 0) {
        String.fromUtf8(buf[..n])
    } else {
        ""
    }
    println("body = ${s}")
}

运行结果:

body = abc

func build()

public func build(): HttpRequest

功能:根据 HttpRequestBuilder 实例生成一个 HttpRequest 实例。

返回值:

示例:

import stdx.net.http.*

main() {
    let req = HttpRequestBuilder().method("GET").url("http://example.com/hello").build()
    println("method = ${req.method}")
    println("path = ${req.url.path}")
}

运行结果:

method = GET
path = /hello

func connect()

public func connect(): HttpRequestBuilder

功能:构造 method 为 "CONNECT" 的请求的便捷函数。

返回值:

示例:

import stdx.net.http.*

main() {
    let req = HttpRequestBuilder().connect().url("http://example.com/hello").build()
    println(req.toString())
}

运行结果:

CONNECT example.com HTTP/1.1

func get()

public func get(): HttpRequestBuilder

功能:构造 method 为 "GET" 的请求的便捷函数。

返回值:

示例:

import stdx.net.http.*

main() {
    let req = HttpRequestBuilder().get().url("http://example.com/hello").build()
    println(req.toString())
}

运行结果:

GET /hello HTTP/1.1

func head()

public func head(): HttpRequestBuilder

功能:构造 method 为 "HEAD" 的请求的便捷函数。

返回值:

示例:

import stdx.net.http.*

main() {
    let req = HttpRequestBuilder().head().url("http://example.com/hello").build()
    println(req.toString())
}

运行结果:

HEAD /hello HTTP/1.1

func header(String, String)

public func header(name: String, value: String): HttpRequestBuilder

功能:向请求 header 添加指定键值对,规则同 HttpHeaders 类的 add 函数。

参数:

  • name: String - 请求头的 key。
  • value: String - 请求头的 value。

返回值:

异常:

  • HttpException - 如果传入的 name 或 value 包含不合法元素,将抛出此异常。

示例:

import stdx.net.http.*

main() {
    let req = HttpRequestBuilder().url("http://example.com/hello").header("x-a", "1").build()
    let v = req.headers.getFirst("x-a") ?? ""
    println("x-a = ${v}")
}

运行结果:

x-a = 1

func method(String)

public func method(method: String): HttpRequestBuilder

功能:设置请求 method,默认请求 method 为 "GET"。

参数:

  • method: String - 请求方法,必须由 token 字符组成,如果传入空字符串,method 值将自动设置为 "GET"。

返回值:

异常:

示例:

import stdx.net.http.*

main() {
    let req = HttpRequestBuilder().method("PATCH").url("http://example.com/hello").build()
    println(req.toString())
}

运行结果:

PATCH /hello HTTP/1.1

func options()

public func options(): HttpRequestBuilder

功能:构造 method 为 "OPTIONS" 的请求的便捷函数。

返回值:

示例:

import stdx.net.http.*

main() {
    let req = HttpRequestBuilder().options().url("http://example.com/hello").build()
    println(req.toString())
}

运行结果:

OPTIONS /hello HTTP/1.1

func post()

public func post(): HttpRequestBuilder

功能:构造 method 为 "POST" 的请求的便捷函数。

返回值:

示例:

import stdx.net.http.*

main() {
    let req = HttpRequestBuilder().post().url("http://example.com/hello").body("x").build()
    println(req.toString())
}

运行结果:

POST /hello HTTP/1.1

body size: 1

func priority(Int64, Bool)

public func priority(urg: Int64, inc: Bool): HttpRequestBuilder

功能:设置 priority 头的便捷函数,调用此函数后,将生成 priority 头,形如:"priority: urgency=x, i"。如果通过设置请求头的函数设置了 priority 字段,调用此函数无效。如果多次调用此函数,以最后一次为准。

参数:

  • urg: Int64 - 表示请求优先级,取值范围为 [0, 7],0 表示最高优先级。
  • inc: Bool - 表示请求是否需要增量处理,为 true 表示希望服务器并发处理与之同 urg 同 inc 的请求,为 false 表示不希望服务器并发处理。

返回值:

异常:

  • HttpException - 当参数 urg 取值非法,即不在 [0, 7] 范围内时,抛出异常。

示例:

import stdx.net.http.*

main() {
    let req = HttpRequestBuilder().url("http://example.com/hello").priority(3, true).build()
    let p = req.headers.getFirst("priority") ?? ""
    println("priority = ${p}")
}

运行结果:

priority = u=3, i

func put()

public func put(): HttpRequestBuilder

功能:构造 method 为 "PUT" 的请求的便捷函数。

返回值:

示例:

import stdx.net.http.*

main() {
    let req = HttpRequestBuilder().put().url("http://example.com/hello").body("x").build()
    println(req.toString())
}

运行结果:

PUT /hello HTTP/1.1

body size: 1

func readTimeout(Duration)

public func readTimeout(timeout: Duration): HttpRequestBuilder

功能:设置此请求的读超时时间。如果传入的 Duration 为负,则会自动转为 0。如果用户设置了此读超时时间,那么该请求的读超时以此为准;如果用户没有设置,那么该请求的读超时以 Client 为准。

参数:

  • timeout: Duration - 用户设置的此请求的读超时时间。

返回值:

示例:

import stdx.net.http.*

main() {
    let req = HttpRequestBuilder().url("http://example.com/hello").readTimeout(Duration.second).build()
    println("readTimeout.isSome = ${req.readTimeout.isSome()}")
}

运行结果:

readTimeout.isSome = true

func setHeaders(HttpHeaders)

public func setHeaders(headers: HttpHeaders): HttpRequestBuilder

功能:设置请求 header,如果已经设置过,调用该函数将替换原 header。

参数:

返回值:

示例:

import stdx.net.http.*

main() {
    let h = HttpHeaders()
    h.add("x-a", "1")
    let req = HttpRequestBuilder().url("http://example.com/hello").setHeaders(h).build()
    let v = req.headers.getFirst("x-a") ?? ""
    println("x-a = ${v}")
}

运行结果:

x-a = 1

func setTrailers(HttpHeaders)

public func setTrailers(trailers: HttpHeaders): HttpRequestBuilder

功能:设置请求 trailer,如果已经设置过,调用该函数将替换原 trailer。

参数:

返回值:

示例:

import stdx.net.http.*

main() {
    let t = HttpHeaders()
    t.add("x-t", "1")
    let req = HttpRequestBuilder().url("http://example.com/hello").setTrailers(t).build()
    let v = req.trailers.getFirst("x-t") ?? ""
    println("x-t = ${v}")
}

运行结果:

x-t = 1

func trace()

public func trace(): HttpRequestBuilder

功能:构造 method 为 "TRACE" 的请求的便捷函数。

返回值:

示例:

import stdx.net.http.*

main() {
    let req = HttpRequestBuilder().trace().url("http://example.com/hello").build()
    println(req.toString())
}

运行结果:

TRACE /hello HTTP/1.1

func trailer(String, String)

public func trailer(name: String, value: String): HttpRequestBuilder

功能:向请求 trailer 添加指定键值对,规则同 HttpHeaders 类的 add 函数。

参数:

  • name: String - 请求头的 key。
  • value: String - 请求头的 value。

返回值:

异常:

  • HttpException - 如果传入的 name 或 value 包含不合法元素,将抛出此异常。

示例:

import stdx.net.http.*

main() {
    let req = HttpRequestBuilder().url("http://example.com/hello").trailer("x-t", "1").build()
    let v = req.trailers.getFirst("x-t") ?? ""
    println("x-t = ${v}")
}

运行结果:

x-t = 1

func url(String)

public func url(rawUrl: String): HttpRequestBuilder

功能:设置请求 url,默认 url 为空的 URL 对象。

参数:

  • rawUrl: String - 待解析成 url 对象的字符串,该字符串格式详见 URL.parse 函数。

返回值:

异常:

  • IllegalArgumentException - 当被编码的字符不符合 UTF8 的字节序列规则时,抛出异常。
  • UrlSyntaxException - 当传入字符串不符合 URL 格式时,抛出异常。

示例:

import stdx.net.http.*

main() {
    let req = HttpRequestBuilder().url("http://example.com/hello").build()
    println("path = ${req.url.path}")
}

运行结果:

path = /hello

func url(URL)

public func url(url: URL): HttpRequestBuilder

功能:设置请求 url,默认 url 为空的 URL 对象,即 URL.parse("")。

参数:

  • url: URL - URL 对象。

返回值:

示例:

import stdx.net.http.*
import stdx.encoding.url.*

main() {
    let u = URL.parse("http://example.com/hello")
    let req = HttpRequestBuilder().url(u).build()
    println("path = ${req.url.path}")
}

运行结果:

path = /hello

func version(Protocol)

public func version(version: Protocol): HttpRequestBuilder

功能:设置请求的 http 协议版本,默认为 UnknownProtocol(""),客户端会根据 tls 配置自动选择协议。

参数:

返回值:

示例:

import stdx.net.http.*

main() {
    let req = HttpRequestBuilder().url("http://example.com/hello").version(HTTP1_1).build()
    println("version = ${req.version.toString()}")
}

运行结果:

version = HTTP/1.1

func writeTimeout(Duration)

public func writeTimeout(timeout: Duration): HttpRequestBuilder

功能:设置此请求的写超时时间。如果传入的 Duration 为负,则会自动转为 0。如果用户设置了此写超时时间,那么该请求的写超时以此为准;如果用户没有设置,那么该请求的写超时以 Client 为准。

参数:

  • timeout: Duration - 用户设置的此请求的写超时时间。

返回值:

示例:

import stdx.net.http.*

main() {
    let req = HttpRequestBuilder().url("http://example.com/hello").writeTimeout(Duration.second).build()
    println("writeTimeout.isSome = ${req.writeTimeout.isSome()}")
}

运行结果:

writeTimeout.isSome = true

class HttpResponse

public class HttpResponse <: ToString

功能:Http 响应类。

此类定义了 http 中响应 Response 的相关接口,客户端用该类读取服务端返回的响应。

父类型:

  • ToString

prop body

public prop body: InputStream

功能:获取 body。

注意:

  • body 不支持并发读取;
  • 默认 InputStream 实现类的 read 函数不支持多次读取。

类型:InputStream

prop bodySize

public prop bodySize: Option<Int64>

功能:获取响应 body 长度。

  • 如果未设置 body,则 bodySize 为 Some(0);
  • 如果 body 长度已知,即通过 Array<UInt8> 或 String 传入 body,或传入的 InputStream 有确定的 length (length >= 0),则 bodySize 为 Some(Int64);
  • 如果 body 长度未知,即通过用户自定义的 InputStream 实例传入 body 且 InputStream 实例没有确定的 length (length < 0),则 bodySize 为 None。

类型:Option<Int64>

prop headers

public prop headers: HttpHeaders

功能:获取 headers,headers 详述见 HttpHeaders 类,获取后,可通过调用 HttpHeaders 实例成员函数,修改该请求的 headers。

类型:HttpHeaders

prop isPersistent

public prop isPersistent: Bool

功能:表示该响应是否为长连接,即响应 header 是否不包含 Connection: close。包含 Connection: close 为 false,否则为 true。

对于服务端,isPersistent 为 false 表示处理完该请求应关闭连接;

对于客户端,isPersistent 为 false 表示读完响应体后客户端应主动关闭连接。

类型:Bool

prop request

public prop request: Option<HttpRequest>

功能:获取该响应对应的请求,默认为 None。

类型:Option<HttpRequest>

prop status

public prop status: UInt16

功能:获取响应的状态码,默认值为 200。状态码由 100~599 的三位数字组成,状态码所反映的具体信息可参考 RFC 9110

类型:UInt16

prop trailers

public prop trailers: HttpHeaders

功能:获取 trailers,trailers 详述见 HttpHeaders 类,获取后,可通过调用 HttpHeaders 实例成员函数,修改该请求的 trailers。

类型:HttpHeaders

prop version

public prop version: Protocol

功能:获取响应的协议版本,默认值为 HTTP1_1

类型:Protocol

func close()

public func close(): Unit

功能:如果用户不再需要未读完的 body 数据,可以调用此接口关闭连接以释放资源。如果是 HTTP/2 协议,会发送一个 Reset 帧关闭对应的流。

注意:

如果使用者已读完 body,无需调用此接口再释放资源。

示例:

import stdx.net.http.*

main() {
    let resp = HttpResponseBuilder().body("abc").build()
    // 当前函数:close()
    resp.close()
    println("closed")
}

运行结果:

closed

func toString()

public override func toString(): String

功能:把响应转换为字符串,包括 status-line,headers,body size, trailers。

例如:HTTP/1.1 200 OK\r\ncontent-length: 5\r\n\r\nbody size: 5\r\nbar: foo\r\n。

返回值:

  • String - 响应的字符串表示。

示例:

import stdx.net.http.*

main() {
    let resp = HttpResponseBuilder().body("abc").build()
    println(resp)
}

运行结果:

HTTP/1.1 200 OK

body size: 3

extend HttpResponse

extend HttpResponse

功能:为 HttpResponse 扩展 HTTP/2.0 特有的方法。

func getPush()

public func getPush(): Option<ArrayList<HttpResponse>>

功能:获取服务器推送的响应,返回 None 代表未开启服务器推送功能,返回空 ArrayList 代表无服务器推送的响应。

返回值:

  • Option<ArrayList<HttpResponse>> - 服务器推送的响应列表。

示例:

import stdx.net.http.*

main() {
    let resp = HttpResponseBuilder().status(404).build()
    // 当前函数:toString()
    println(resp.toString().split("\n")[0])
}

运行结果:

HTTP/1.1 404 Not Found

class HttpResponseBuilder

public class HttpResponseBuilder {
    public init()
}

功能:用于构造 HttpResponse 实例。

init()

public init()

功能:构造一个新 HttpResponseBuilder

示例:

import stdx.net.http.*

main() {
    let _ = HttpResponseBuilder()
}

func addHeaders(HttpHeaders)

public func addHeaders(headers: HttpHeaders): HttpResponseBuilder

功能:向响应 header 添加参数 HttpHeaders 中的键值对。

参数:

返回值:

示例:

import stdx.net.http.*

main() {
    let h = HttpHeaders()
    h.add("x-a", "1")
    let resp = HttpResponseBuilder().addHeaders(h).build()
    let v = resp.headers.getFirst("x-a") ?? ""
    println("x-a = ${v}")
}

运行结果:

x-a = 1

func addTrailers(HttpHeaders)

public func addTrailers(trailers: HttpHeaders): HttpResponseBuilder

功能:向响应 trailer 添加参数 HttpHeaders 中的键值对。

参数:

返回值:

示例:

import stdx.net.http.*

main() {
    let t = HttpHeaders()
    t.add("x-t", "1")
    let resp = HttpResponseBuilder().addTrailers(t).build()
    let v = resp.trailers.getFirst("x-t") ?? ""
    println("x-t = ${v}")
}

运行结果:

x-t = 1

func body(Array<UInt8>)

public func body(body: Array<UInt8>): HttpResponseBuilder

功能:设置响应 body,如果已经设置过,调用该函数将替换原 body。

参数:

  • body: Array<UInt8> - 字节数组形式的响应体。

返回值:

示例:

import stdx.net.http.*

main() {
    let resp = HttpResponseBuilder().body("abc".toArray()).build()
    let buf = Array<UInt8>(16, repeat: 0)
    let n = resp.body.read(buf)
    let s = if (n > 0) {
        String.fromUtf8(buf[..n])
    } else {
        ""
    }
    println("body = ${s}")
    println("bodySize = ${resp.bodySize.getOrThrow()}")
}

运行结果:

body = abc
bodySize = 3

func body(InputStream)

public func body(body: InputStream): HttpResponseBuilder

功能:设置响应 body,如果已经设置过,调用该函数将替换原 body 调用该函数设置请求 body。

参数:

  • body: InputStream - 流形式的响应体。

返回值:

示例:

import stdx.net.http.*
import std.io.*

class MyBody <: InputStream {
    let data: Array<UInt8>
    var pos: Int64 = 0

    init(s: String) {
        data = s.toArray()
    }

    public func read(buf: Array<Byte>): Int64 {
        if (pos >= data.size) {
            return 0
        }
        let n = min(buf.size, data.size - pos)
        data.copyTo(buf, pos, 0, n)
        pos += n
        return n
    }
}

main() {
    let input: InputStream = MyBody("abc")
    let resp = HttpResponseBuilder().body(input).build()
    println("bodySize.isSome = ${resp.bodySize.isSome()}")
    let buf = Array<UInt8>(16, repeat: 0)
    let n = resp.body.read(buf)
    let s = if (n > 0) {
        String.fromUtf8(buf[..n])
    } else {
        ""
    }
    println("body = ${s}")
}

运行结果:

bodySize.isSome = false
body = abc

func body(String)

public func body(body: String): HttpResponseBuilder

功能:设置响应 body,如果已经设置过,调用该函数将替换原 body 调用该函数设置请求 body。

参数:

  • body: String - 字符串形式的响应体。

返回值:

示例:

import stdx.net.http.*

main() {
    let resp = HttpResponseBuilder().body("abc").build()
    let buf = Array<UInt8>(16, repeat: 0)
    let n = resp.body.read(buf)
    let s = if (n > 0) {
        String.fromUtf8(buf[..n])
    } else {
        ""
    }
    println("body = ${s}")
}

运行结果:

body = abc

func build()

public func build(): HttpResponse

功能:根据 HttpResponseBuilder 实例生成一个 HttpResponse 实例。

返回值:

示例:

import stdx.net.http.*

main() {
    let resp = HttpResponseBuilder().status(200).body("ok").build()
    println("status = ${resp.status}")
    let buf = Array<UInt8>(8, repeat: 0)
    let n = resp.body.read(buf)
    println("body = ${String.fromUtf8(buf[..n])}")
}

运行结果:

status = 200
body = ok

func header(String, String)

public func header(name: String, value: String): HttpResponseBuilder

功能:向响应 header 添加指定键值对,规则同 HttpHeaders 类的 add 函数。

参数:

  • name: String - 响应头的 key。
  • value: String - 响应头的 value。

返回值:

异常:

  • HttpException - 如果传入的 name 或 value 包含不合法元素,将抛出此异常。

示例:

import stdx.net.http.*

main() {
    let resp = HttpResponseBuilder().header("x-a", "1").build()
    let v = resp.headers.getFirst("x-a") ?? ""
    println("x-a = ${v}")
}

运行结果:

x-a = 1

func request(HttpRequest)

public func request(request: HttpRequest): HttpResponseBuilder

功能:设置响应对应的请求。

参数:

返回值:

示例:

import stdx.net.http.*

main() {
    let req = HttpRequestBuilder().url("http://example.com/hello").build()
    let resp = HttpResponseBuilder().request(req).build()
    println("request.isSome = ${resp.request.isSome()}")
}

运行结果:

request.isSome = true

func setHeaders(HttpHeaders)

public func setHeaders(headers: HttpHeaders): HttpResponseBuilder

功能:设置响应 header,如果已经设置过,调用该函数将替换原 header。

参数:

返回值:

示例:

import stdx.net.http.*

main() {
    let h = HttpHeaders()
    h.add("x-a", "1")
    let resp = HttpResponseBuilder().setHeaders(h).build()
    let v = resp.headers.getFirst("x-a") ?? ""
    println("x-a = ${v}")
}

运行结果:

x-a = 1

func setTrailers(HttpHeaders)

public func setTrailers(trailers: HttpHeaders): HttpResponseBuilder

功能:设置响应 trailer,如果已经设置过,调用该函数将替换原 trailer。

参数:

返回值:

示例:

import stdx.net.http.*

main() {
    let t = HttpHeaders()
    t.add("x-t", "1")
    let resp = HttpResponseBuilder().setTrailers(t).build()
    let v = resp.trailers.getFirst("x-t") ?? ""
    println("x-t = ${v}")
}

运行结果:

x-t = 1

func status(UInt16)

public func status(status: UInt16): HttpResponseBuilder

功能:设置 http 响应状态码。

参数:

  • status: UInt16 - 传入的状态码的值。

返回值:

异常:

  • HttpException - 如果设置响应状态码不在 100~599 这个区间内,则抛出此异常。

示例:

import stdx.net.http.*

main() {
    let resp = HttpResponseBuilder().status(201).build()
    println("status = ${resp.status}")
}

运行结果:

status = 201

func trailer(String, String)

public func trailer(name: String, value: String): HttpResponseBuilder

功能:向响应 trailer 添加指定键值对,规则同 HttpHeaders 类的 add 函数。

参数:

  • name: String - 响应头的 key。
  • value: String - 响应头的 value。

返回值:

异常:

  • HttpException - 如果传入的 name 或 value 包含不合法元素,将抛出此异常。

示例:

import stdx.net.http.*

main() {
    let resp = HttpResponseBuilder().trailer("x-t", "1").build()
    let v = resp.trailers.getFirst("x-t") ?? ""
    println("x-t = ${v}")
}

运行结果:

x-t = 1

func version(Protocol)

public func version(version: Protocol): HttpResponseBuilder

功能:设置 http 响应协议版本。

参数:

返回值:

示例:

import stdx.net.http.*

main() {
    let resp = HttpResponseBuilder().version(HTTP1_1).build()
    println("version = ${resp.version.toString()}")
}

运行结果:

version = HTTP/1.1

class HttpResponsePusher

public class HttpResponsePusher

功能:HTTP/2 服务器推送。

说明:

  • 如果服务器收到请求后,认为客户端后续还需要某些关联资源,可以将其提前推送到客户端;
  • 服务端推送包括推送请求和推送响应;
  • 启用服务端推送需要先调用 push 函数发送推送请求,并向服务器注册该请求对应的 handler,用以生成推送响应;
  • 客户端可设置拒绝服务端推送;
  • 不允许嵌套推送,即不允许在推送请求对应的 handler 中再次推送。嵌套推送情况下,服务端将不执行推送,并打印日志进行提示。

static func getPusher(HttpContext)

public static func getPusher(ctx: HttpContext): ?HttpResponsePusher

功能:获取 HttpResponsePusher 实例,如果客户端拒绝推送,将返回 None。

参数:

返回值:

示例:

import stdx.net.http.*
import stdx.log.*
import std.sync.*

main() {
    let sc = SyncCounter(1)
    let logger = NoopLogger()

    let server = ServerBuilder().addr("127.0.0.1").port(18100).logger(logger).afterBind({=> sc.dec()}).build()

    server.distributor.register(
        "/p",
        FuncHandler(
            {
                ctx =>
                    // 当前函数:getPusher(ctx)
                    let p = HttpResponsePusher.getPusher(ctx)
                    println("pusher.isSome = ${p.isSome()}")
                    ctx.responseBuilder.status(200).body("ok")
            }
        )
    )

    spawn {server.serve()}
    sc.waitUntilZero()

    let client = ClientBuilder().build()
    let resp = client.get("http://127.0.0.1:18100/p")
    resp.close()
    client.close()
    server.closeGracefully()
}

运行结果:

pusher.isSome = false

func push(String, String, HttpHeaders)

public func push(path: String, method: String, header: HttpHeaders): Unit

功能:向客户端发送推送请求,path 为请求地址,method 为请求方法,header 为请求头。

参数:

  • path: String - 推送的请求地址。
  • method: String - 推送的请求方法。
  • header: HttpHeaders - 推送的请求头。

示例:

import stdx.net.http.*
import stdx.log.*
import std.sync.*

main() {
    let sc = SyncCounter(1)
    let logger = NoopLogger()

    let server = ServerBuilder().addr("127.0.0.1").port(18101).logger(logger).afterBind({=> sc.dec()}).build()

    server.distributor.register(
        "/p",
        FuncHandler(
            {
                ctx =>
                    // 当前函数:push(path, method, header)
                    let p = HttpResponsePusher.getPusher(ctx)
                    match (p) {
                        case Some(v) =>
                            v.push("/asset", "GET", HttpHeaders())
                            println("push called")
                        case None =>
                            // HTTP/1.1 下无法获取 pusher,这里演示如何安全跳过 push
                            println("push skipped (no pusher)")
                    }
                    ctx.responseBuilder.status(200).body("ok")
            }
        )
    )

    server.distributor.register("/asset", FuncHandler({
        ctx => ctx.responseBuilder.status(200).body("asset")
    }))

    spawn {server.serve()}
    sc.waitUntilZero()

    let client = ClientBuilder().build()
    let resp = client.get("http://127.0.0.1:18101/p")
    resp.close()
    client.close()
    server.closeGracefully()
}

运行结果:

push skipped (no pusher)

class HttpResponseWriter

public class HttpResponseWriter {
    public HttpResponseWriter(let ctx: HttpContext)
}

功能:HTTP response 消息体 Writer,支持用户控制消息体的发送过程。

说明:

  • 第一次调用 write 函数时,将立即发送 header 和通过参数传入的 body,此后每次调用 write,发送通过参数传入的 body。
  • 对于 HTTP/1.1,如果设置了 transfer-encoding: chunked,用户每调用一次 write,将发送一个 chunk。
  • 对于 HTTP/2,用户每调用一次 write,将把指定数据封装并发出。

HttpResponseWriter(HttpContext)

public HttpResponseWriter(let ctx: HttpContext)

功能:构造一个 HttpResponseWriter 实例。

参数:

示例:

import stdx.net.http.*
import stdx.log.*
import std.sync.*

main() {
    let sc = SyncCounter(1)
    let logger = NoopLogger()

    let server = ServerBuilder().addr("127.0.0.1").port(18102).logger(logger).afterBind({=> sc.dec()}).build()

    server.distributor.register(
        "/w",
        FuncHandler(
            {
                ctx =>
                    ctx.responseBuilder.status(200).header("transfer-encoding", "chunked")

                    // 构造 writer 后,通过 write 控制 body 的发送过程
                    let w = HttpResponseWriter(ctx)
                    w.write("hi".toArray())
                    w.write("!".toArray())
            }
        )
    )

    spawn {server.serve()}
    sc.waitUntilZero()

    let client = ClientBuilder().build()
    let resp = client.get("http://127.0.0.1:18102/w")

    var buf = Array<UInt8>(64, repeat: 0)
    var body = ""
    while (true) {
        let n = resp.body.read(buf)
        if (n <= 0) {
            break
        }
        body = body + String.fromUtf8(buf[..n])
    }
    resp.close()

    println("status = ${resp.status}")
    println("body = ${body}")

    client.close()
    server.closeGracefully()
}

运行结果:

status = 200
body = hi!

func write(Array<Byte>)

public func write(buf: Array<Byte>): Unit

功能:发送 buf 中数据到客户端。

参数:

  • buf: Array<Byte> - 要发送的数据。

异常:

示例:

import stdx.net.http.*
import stdx.log.*
import std.sync.*

main() {
    let sc = SyncCounter(1)
    let logger = NoopLogger()

    let server = ServerBuilder().addr("127.0.0.1").port(18102).logger(logger).afterBind({=> sc.dec()}).build()

    server.distributor.register(
        "/w",
        FuncHandler(
            {
                ctx =>
                    ctx.responseBuilder.status(200).header("transfer-encoding", "chunked")

                    // 当前函数:write(buf)
                    let w = HttpResponseWriter(ctx)
                    w.write("hi".toArray())
                    w.write("!".toArray())
            }
        )
    )

    spawn {server.serve()}
    sc.waitUntilZero()

    let client = ClientBuilder().build()
    let resp = client.get("http://127.0.0.1:18102/w")

    var buf = Array<UInt8>(64, repeat: 0)
    var body = ""
    while (true) {
        let n = resp.body.read(buf)
        if (n <= 0) {
            break
        }
        body = body + String.fromUtf8(buf[..n])
    }
    resp.close()

    println("status = ${resp.status}")
    println("body = ${body}")

    client.close()
    server.closeGracefully()
}

运行结果:

status = 200
body = hi!

class NotFoundHandler

public class NotFoundHandler <: HttpRequestHandler

功能:便捷的 Http 请求处理器,404 Not Found 处理器。

父类型:

func handle(HttpContext)

public func handle(ctx: HttpContext): Unit

功能:处理 Http 请求,回复 404 响应。

参数:

示例:

import stdx.net.http.*
import stdx.log.*
import std.sync.*

main() {
    let sc = SyncCounter(1)
    let logger = NoopLogger()

    let server = ServerBuilder().addr("127.0.0.1").port(18103).logger(logger).afterBind({=> sc.dec()}).build()

    // 当前函数:NotFoundHandler.handle(ctx)
    server.distributor.register("/nf", NotFoundHandler())

    spawn {server.serve()}
    sc.waitUntilZero()

    let client = ClientBuilder().build()
    let resp = client.get("http://127.0.0.1:18103/nf")

    var buf = Array<UInt8>(64, repeat: 0)
    let n = resp.body.read(buf)
    let body = if (n > 0) {
        String.fromUtf8(buf[..n])
    } else {
        ""
    }
    resp.close()

    println("status = ${resp.status}")
    println("body = ${body}")

    client.close()
    server.closeGracefully()
}

运行结果:

status = 404
body = 404 Not Found

class OptionsHandler

public class OptionsHandler <: HttpRequestHandler

功能:便捷的 Http 处理器,用于处理 OPTIONS 请求。固定返回 "Allow: OPTIONS,GET,HEAD,POST,PUT,DELETE" 响应头。

父类型:

func handle(HttpContext)

public func handle(ctx: HttpContext): Unit

功能:处理 Http OPTIONS 请求。

参数:

示例:

import stdx.net.http.*
import stdx.log.*
import std.sync.*

main() {
    let sc = SyncCounter(1)
    let logger = NoopLogger()

    let server = ServerBuilder().addr("127.0.0.1").port(18104).logger(logger).afterBind({=> sc.dec()}).build()

    // 当前函数:OptionsHandler.handle(ctx)
    server.distributor.register("/opt", OptionsHandler())

    spawn {server.serve()}
    sc.waitUntilZero()

    let client = ClientBuilder().build()
    let req = HttpRequestBuilder().url("http://127.0.0.1:18104/opt").method("OPTIONS").build()
    let resp = client.send(req)

    println("status = ${resp.status}")
    println("allow = ${resp.headers.getFirst("allow") ?? ""}")

    resp.close()
    client.close()
    server.closeGracefully()
}

运行结果:

status = 200
allow = OPTIONS, GET, HEAD, POST, PUT, DELETE

class ProtocolService

public abstract class ProtocolService

功能:Http 协议服务实例,为单个客户端连接提供 Http 服务,包括对客户端 request 报文的解析、 request 的分发处理、 response 的发送等。

prop distributor

protected prop distributor: HttpRequestDistributor

功能:获取请求分发器,请求分发器会根据 url 将请求分发给对应的 handler。

类型:HttpRequestDistributor

prop httpKeepAliveTimeout

protected prop httpKeepAliveTimeout: Duration

功能:HTTP/1.1 专用,获取服务器设定的保持长连接的超时时间。

类型:Duration

prop logger

protected prop logger: Logger

功能:获取服务器日志记录器,设置 logger.level 将立即生效,记录器应该是线程安全的。

类型:Logger

prop maxRequestBodySize

protected prop maxRequestBodySize: Int64

功能:获取服务器设定的读取请求的请求体最大值,仅对于 HTTP/1.1 且未设置 "Transfer-Encoding: chunked" 的请求生效。

类型:Int64

prop maxRequestHeaderSize

protected prop maxRequestHeaderSize: Int64

功能:获取服务器设定的读取请求的请求头最大值。仅对 HTTP/1.1 生效,HTTP/2 中有专门的配置 maxHeaderListSize。

类型:Int64

prop readHeaderTimeout

protected prop readHeaderTimeout: Duration

功能:获取服务器设定的读取请求头的超时时间。

类型:Duration

prop readTimeout

protected prop readTimeout: Duration

功能:获取服务器设定的读取整个请求的超时时间。

类型:Duration

prop server

protected open mut prop server: Server

功能:返回 Server 实例,提供默认实现,设置为绑定的 Server 实例。

类型:Server

prop writeTimeout

protected prop writeTimeout: Duration

功能:获取服务器设定的写响应的超时时间。

类型:Duration

func close()

protected open func close(): Unit

功能:强制关闭连接,提供默认实现,无任何行为。

示例:

import stdx.net.http.*
import stdx.log.*
import std.net.*
import std.sync.*

class MyFactory <: ProtocolServiceFactory {
    public func create(p: Protocol, s: StreamingSocket): ProtocolService {
        // 固定响应(避免依赖内部协议解析)
        let _ = p
        s.write("HTTP/1.1 200 OK\r\ncontent-length: 2\r\nconnection: close\r\n\r\nOK".toArray())
        return MyService()
    }
}

class MyService <: ProtocolService {
    let running = AtomicBool(true)

    protected func serve(): Unit {
        while (running.load()) {
            sleep(Duration.millisecond * 10)
        }
    }

    protected override func close(): Unit {
        running.store(false)
        println("close called")
    }

    protected override func closeGracefully(): Unit {
        running.store(false)
        println("closeGracefully called")
    }
}

main() {
    let sc = SyncCounter(1)

    let server = ServerBuilder()
        .addr("127.0.0.1")
        .port(18119)
        .logger(NoopLogger())
        .enableConnectProtocol(true)
        .maxRequestHeaderSize(123)
        .maxRequestBodySize(456)
        .readTimeout(Duration.second)
        .writeTimeout(Duration.second)
        .readHeaderTimeout(Duration.second)
        .httpKeepAliveTimeout(Duration.second)
        .protocolServiceFactory(MyFactory())
        .afterBind({=> sc.dec()})
        .build()

    spawn {=> server.serve()}
    sc.waitUntilZero()

    let client = ClientBuilder().build()
    let rsp = client.get("http://127.0.0.1:18119/")
    rsp.close()
    client.close()

    server.close()
}

运行结果:

close called

func closeGracefully()

protected open func closeGracefully(): Unit

功能:优雅关闭连接,提供默认实现,无任何行为。

示例:

import stdx.net.http.*
import stdx.log.*
import std.net.*
import std.sync.*

class MyFactory <: ProtocolServiceFactory {
    public func create(p: Protocol, s: StreamingSocket): ProtocolService {
        // 固定响应(避免依赖内部协议解析)
        let _ = p
        s.write("HTTP/1.1 200 OK\r\ncontent-length: 2\r\nconnection: close\r\n\r\nOK".toArray())
        return MyService()
    }
}

class MyService <: ProtocolService {
    let running = AtomicBool(true)

    protected func serve(): Unit {
        while (running.load()) {
            sleep(Duration.millisecond * 10)
        }
    }

    protected override func close(): Unit {
        running.store(false)
        println("close called")
    }

    protected override func closeGracefully(): Unit {
        running.store(false)
        println("closeGracefully called")
    }
}

main() {
    let sc = SyncCounter(1)

    let server = ServerBuilder()
        .addr("127.0.0.1")
        .port(18120)
        .logger(NoopLogger())
        .enableConnectProtocol(true)
        .maxRequestHeaderSize(123)
        .maxRequestBodySize(456)
        .readTimeout(Duration.second)
        .writeTimeout(Duration.second)
        .readHeaderTimeout(Duration.second)
        .httpKeepAliveTimeout(Duration.second)
        .protocolServiceFactory(MyFactory())
        .afterBind({=> sc.dec()})
        .build()

    spawn {=> server.serve()}
    sc.waitUntilZero()

    let client = ClientBuilder().build()
    let rsp = client.get("http://127.0.0.1:18120/")
    rsp.close()
    client.close()

    server.closeGracefully()
}

运行结果:

closeGracefully called

func serve()

protected func serve(): Unit

功能:处理来自客户端连接的请求,不提供默认实现。

示例:

import stdx.net.http.*
import stdx.log.*
import std.net.*
import std.sync.*

class MyFactory <: ProtocolServiceFactory {
    public func create(p: Protocol, s: StreamingSocket): ProtocolService {
        // 固定响应(避免依赖内部协议解析)
        let _ = p
        s.write("HTTP/1.1 200 OK\r\ncontent-length: 2\r\nconnection: close\r\n\r\nOK".toArray())
        return MyService()
    }
}

class MyService <: ProtocolService {
    let running = AtomicBool(true)

    protected func serve(): Unit {
        println("serve called")
        sleep(Duration.millisecond * 10)
    }
}

main() {
    let sc = SyncCounter(1)

    let server = ServerBuilder()
        .addr("127.0.0.1")
        .port(18121)
        .logger(NoopLogger())
        .enableConnectProtocol(true)
        .maxRequestHeaderSize(123)
        .maxRequestBodySize(456)
        .readTimeout(Duration.second)
        .writeTimeout(Duration.second)
        .readHeaderTimeout(Duration.second)
        .httpKeepAliveTimeout(Duration.second)
        .protocolServiceFactory(MyFactory())
        .afterBind({=> sc.dec()})
        .build()

    spawn {=> server.serve()}
    sc.waitUntilZero()

    let client = ClientBuilder().build()
    let rsp = client.get("http://127.0.0.1:18121/")
    rsp.close()
    client.close()

    server.closeGracefully()
}

运行结果:

serve called

class RedirectHandler

public class RedirectHandler <: HttpRequestHandler {
    public init(url: String, code: UInt16)
}

功能:便捷的 Http 处理器,用于回复重定向响应。

父类型:

init(String, UInt16)

public init(url: String, code: UInt16)

功能:RedirectHandler 的构造函数。

参数:

  • url: String - 重定向响应中 Location 头部的 url。
  • code: UInt16 - 重定向响应的响应码。

异常:

  • HttpException - url 为空或响应码不是除 304 以外的 3XX 状态码时抛出异常。

示例:

import stdx.net.http.*
import stdx.log.*
import std.sync.*

main() {
    let _ = RedirectHandler("/to", 302)
}

func handle(HttpContext)

public func handle(ctx: HttpContext): Unit

功能:处理 Http 请求,回复重定向响应。

参数:

示例:

import stdx.net.http.*
import stdx.log.*
import std.sync.*

main() {
    let sc = SyncCounter(1)
    let logger = NoopLogger()

    let server = ServerBuilder().addr("127.0.0.1").port(18105).logger(logger).afterBind({=> sc.dec()}).build()

    // 当前函数:RedirectHandler.handle(ctx)
    server.distributor.register("/from", RedirectHandler("/to", 302))

    spawn {server.serve()}
    sc.waitUntilZero()

    // 关闭自动重定向,以便直接读取 302 与 Location
    let client = ClientBuilder().autoRedirect(false).build()
    let resp = client.get("http://127.0.0.1:18105/from")

    var buf = Array<UInt8>(128, repeat: 0)
    let n = resp.body.read(buf)
    let body = if (n > 0) {
        String.fromUtf8(buf[..n])
    } else {
        ""
    }

    println("status = ${resp.status}")
    println("location = ${resp.headers.getFirst("location") ?? ""}")
    println("body = ${body}")

    resp.close()
    client.close()
    server.closeGracefully()
}

运行结果:

status = 302
location = /to
body = <a href="/to">Found</a>

class Server

public class Server

功能:提供 HTTP 服务的 Server 类。

说明:

  • 启动服务,在指定地址及端口等待用户连接、服务用户的 http request;
  • 关闭服务,包括关闭所有已有连接;
  • 提供注册处理 http request 的 handler 的机制,根据注册信息分发 request 到相应的 handler;
  • 提供 tls 证书热机制;
  • 提供 shutdown 回调机制;
  • 通过 Logger.level 开启、关闭日志打印,包括按照用户要求打印相应级别的日志;
  • Server 文档中未明确说明支持版本的配置,在 HTTP/1.1 与 HTTP/2 都会生效。

prop addr

public prop addr: String

功能:获取服务端监听地址。

类型:String

prop distributor

public prop distributor: HttpRequestDistributor

功能:获取请求分发器,请求分发器会根据 url 将请求分发给对应的 handler。

类型:HttpRequestDistributor

prop enableConnectProtocol

public prop enableConnectProtocol: Bool

功能:HTTP/2 专用,用来限制对端发送的报文是否支持通过 connect 方法升级协议,true 表示支持。

类型:Bool

prop headerTableSize

public prop headerTableSize: UInt32

功能:获取服务端 HTTP/2 Hpack 动态表的初始值,默认值为 4096。

类型:UInt32

prop httpKeepAliveTimeout

public prop httpKeepAliveTimeout: Duration

功能:HTTP/1.1 专用,获取服务器设定的保持长连接的超时时间。

类型:Duration

prop initialWindowSize

public prop initialWindowSize: UInt32

功能:HTTP/2 专用,用来限制对端发送的报文 stream 初始流量窗口大小。默认值为 65535 ,取值范围为 0 至 2^31 - 1。

类型:UInt32

prop listener

public prop listener: ServerSocket

功能:获取服务器绑定 socket。

类型:ServerSocket

prop logger

public prop logger: Logger

功能:获取服务器日志记录器,设置 logger.level 将立即生效,记录器应该是线程安全的。

类型:Logger

prop maxConcurrentStreams

public prop maxConcurrentStreams: UInt32

功能:HTTP/2 专用,用来限制连接同时处理的最大请求数量。

类型:UInt32

prop maxFrameSize

public prop maxFrameSize: UInt32

功能:HTTP/2 专用,用来限制对端发送的报文一个帧的最大长度。默认值为 16384. 取值范围为 2^14 至 2^24 - 1。

类型:UInt32

prop maxHeaderListSize

public prop maxHeaderListSize: UInt32

功能:获取客户端支持的 HTTP/2 最大头部(Header)大小。这个大小指的是响应头部中所有头部字段(Header Field)的最大允许长度之和,其中包括所有字段名称(name)的长度、字段值(value)的长度以及每个字段自动添加的伪头开销(通常每个字段会有 32 字节的开销,这包括了 HTTP/2 协议本身为头部字段添加的伪头部信息)。默认情况下,这个最大长度被设置为 UInt32.Max。

类型:UInt32

prop maxRequestBodySize

public prop maxRequestBodySize: Int64

功能:获取服务器设定的读取请求的请求体最大值,仅对于 HTTP/1.1 且未设置 "Transfer-Encoding: chunked" 的请求生效。

类型:Int64

prop maxRequestHeaderSize

public prop maxRequestHeaderSize: Int64

功能:获取服务器设定的读取请求的请求头最大值。仅对 HTTP/1.1 生效,HTTP/2 中有专门的配置 maxHeaderListSize。

类型:Int64

prop port

public prop port: UInt16

功能:获取服务端监听端口。

类型:UInt16

prop protocolServiceFactory

public prop protocolServiceFactory: ProtocolServiceFactory

功能:获取协议服务工厂,服务协议工厂会生成每个协议所需的服务实例。

类型:ProtocolServiceFactory

prop readHeaderTimeout

public prop readHeaderTimeout: Duration

功能:获取服务器设定的读取请求头的超时时间。

类型:Duration

prop readTimeout

public prop readTimeout: Duration

功能:获取服务器设定的读取整个请求的超时时间。

类型:Duration

prop servicePoolConfig

public prop servicePoolConfig: ServicePoolConfig

功能:获取协程池配置实例。

类型:ServicePoolConfig

prop transportConfig

public prop transportConfig: TransportConfig

功能:获取服务器设定的传输层配置。

类型:TransportConfig

prop writeTimeout

public prop writeTimeout: Duration

功能:获取服务器设定的写响应的超时时间。

类型:Duration

func afterBind(() -> Unit)

public func afterBind(f: ()-> Unit): Unit

功能:注册服务器启动时的回调函数,服务内部 ServerSocket 实例 bind 之后,accept 之前将调用该函数。重复调用将覆盖之前注册的函数。

参数:

  • f: () -> Unit - 回调函数,入参为空,返回值为 Unit 类型。

示例:

import stdx.net.http.*
import stdx.log.*
import std.sync.*
import stdx.crypto.keys.RSAPrivateKey

// 用于稳定获取响应 body(避免依赖 readToEnd/readAll 等 API)
func readAllBytes(resp: HttpResponse): String {
    let buf = Array<UInt8>(1024, repeat: 0)
    var body = ""
    while (true) {
        let n = resp.body.read(buf)
        if (n <= 0) {
            break
        }
        body += String.fromUtf8(buf[..n])
    }
    return body
}

main() {
    let sc = SyncCounter(1)

    let server = ServerBuilder().addr("127.0.0.1").port(18126).logger(NoopLogger()).build()

    // func afterBind(): 注册 bind 后回调(此处用它做“就绪信号”)
    server.afterBind(
        {
            =>
                println("afterBind set by Server.afterBind")
                sc.dec()
        }
    )

    // 注册一个最简 handler,便于 serve() 可测
    server.distributor.register("/ping", {
        httpContext => httpContext.responseBuilder.body("pong")
    })

    spawn {server.serve()}
    sc.waitUntilZero()

    // func serve(): 发起一次请求,证明服务正常
    let client = ClientBuilder().noProxy().build()
    let resp = client.get("http://127.0.0.1:18126/ping")
    let body = readAllBytes(resp)
    println("status = ${resp.status}")
    println("body = ${body}")
    resp.close()

    // func getTlsConfig(): 未设置 TLS,返回 None
    println("tlsConfig.isSome = ${server.getTlsConfig().isSome()}")

    // func onShutdown(): close/closeGracefully 时回调
    server.onShutdown({=> println("onShutdown set by Server.onShutdown")})

    client.close()

    // func closeGracefully(): 触发回调并关闭
    server.closeGracefully()

    // func updateCA / updateCert(): 未配置 TLS,调用会抛 HttpException
    try {
        server.updateCA([])
    } catch (e: HttpException) {
        println("updateCA(Array) HttpException: ${e.message}")
    }
    try {
        server.updateCA("/tmp/not-exist.pem")
    } catch (e: HttpException) {
        println("updateCA(String) HttpException: ${e.message}")
    }
    // 不引入证书/私钥文件依赖:仅展示未配置 TLS 时的异常行为
    try {
        server.updateCert([], RSAPrivateKey(1024))
    } catch (e: HttpException) {
        println("updateCert(Array,Key) HttpException: ${e.message}")
    }
    try {
        server.updateCert("/tmp/a.pem", "/tmp/b.pem")
    } catch (e: HttpException) {
        println("updateCert(String,String) HttpException: ${e.message}")
    }
}

运行结果:

afterBind set by Server.afterBind
status = 200
body = pong
tlsConfig.isSome = false
onShutdown set by Server.onShutdown
updateCA(Array) HttpException: The TLS certificate is not configured.
updateCA(String) HttpException: The TLS certificate is not configured.
updateCert(Array,Key) HttpException: The TLS certificate is not configured.
updateCert(String,String) HttpException: The TLS certificate is not configured.

func close()

public func close(): Unit

功能:关闭服务器,服务器关闭后将不再对请求进行读取与处理,重复关闭将只有第一次生效(包括 close 和 closeGracefully)。

示例:

import stdx.net.http.*
import stdx.log.*

main() {
    let server = ServerBuilder().addr("127.0.0.1").port(18127).logger(NoopLogger()).build()

    // func close(): 关闭服务(可重复调用)
    server.close()
    println("closed once")

    server.close()
    println("closed twice")
}

运行结果:

closed once
closed twice

func closeGracefully()

public func closeGracefully(): Unit

功能:关闭服务器,服务器关闭后将不再对请求进行读取,当前正在进行处理的服务器待处理结束后进行关闭。

示例:

import stdx.net.http.*
import stdx.log.*
import std.sync.*
import stdx.crypto.keys.RSAPrivateKey

// 用于稳定获取响应 body(避免依赖 readToEnd/readAll 等 API)
func readAllBytes(resp: HttpResponse): String {
    let buf = Array<UInt8>(1024, repeat: 0)
    var body = ""
    while (true) {
        let n = resp.body.read(buf)
        if (n <= 0) {
            break
        }
        body += String.fromUtf8(buf[..n])
    }
    return body
}

main() {
    let sc = SyncCounter(1)

    let server = ServerBuilder().addr("127.0.0.1").port(18126).logger(NoopLogger()).build()

    // func afterBind(): 注册 bind 后回调(此处用它做“就绪信号”)
    server.afterBind(
        {
            =>
                println("afterBind set by Server.afterBind")
                sc.dec()
        }
    )

    // 注册一个最简 handler,便于 serve() 可测
    server.distributor.register("/ping", {
        httpContext => httpContext.responseBuilder.body("pong")
    })

    spawn {server.serve()}
    sc.waitUntilZero()

    // func serve(): 发起一次请求,证明服务正常
    let client = ClientBuilder().noProxy().build()
    let resp = client.get("http://127.0.0.1:18126/ping")
    let body = readAllBytes(resp)
    println("status = ${resp.status}")
    println("body = ${body}")
    resp.close()

    // func getTlsConfig(): 未设置 TLS,返回 None
    println("tlsConfig.isSome = ${server.getTlsConfig().isSome()}")

    // func onShutdown(): close/closeGracefully 时回调
    server.onShutdown({=> println("onShutdown set by Server.onShutdown")})

    client.close()

    // func closeGracefully(): 触发回调并关闭
    server.closeGracefully()

    // func updateCA / updateCert(): 未配置 TLS,调用会抛 HttpException
    try {
        server.updateCA([])
    } catch (e: HttpException) {
        println("updateCA(Array) HttpException: ${e.message}")
    }
    try {
        server.updateCA("/tmp/not-exist.pem")
    } catch (e: HttpException) {
        println("updateCA(String) HttpException: ${e.message}")
    }
    // 不引入证书/私钥文件依赖:仅展示未配置 TLS 时的异常行为
    try {
        server.updateCert([], RSAPrivateKey(1024))
    } catch (e: HttpException) {
        println("updateCert(Array,Key) HttpException: ${e.message}")
    }
    try {
        server.updateCert("/tmp/a.pem", "/tmp/b.pem")
    } catch (e: HttpException) {
        println("updateCert(String,String) HttpException: ${e.message}")
    }
}

运行结果:

afterBind set by Server.afterBind
status = 200
body = pong
tlsConfig.isSome = false
onShutdown set by Server.onShutdown
updateCA(Array) HttpException: The TLS certificate is not configured.
updateCA(String) HttpException: The TLS certificate is not configured.
updateCert(Array,Key) HttpException: The TLS certificate is not configured.
updateCert(String,String) HttpException: The TLS certificate is not configured.

func getTlsConfig()

public func getTlsConfig(): ?TlsConfig

功能:获取服务器设定的 TLS 层配置。

返回值:

  • ?TlsConfig - 服务端设定的 TLS 层配置,如果没有设置则返回 None。

示例:

import stdx.net.http.*
import stdx.log.*
import std.sync.*
import stdx.crypto.keys.RSAPrivateKey

// 用于稳定获取响应 body(避免依赖 readToEnd/readAll 等 API)
func readAllBytes(resp: HttpResponse): String {
    let buf = Array<UInt8>(1024, repeat: 0)
    var body = ""
    while (true) {
        let n = resp.body.read(buf)
        if (n <= 0) {
            break
        }
        body += String.fromUtf8(buf[..n])
    }
    return body
}

main() {
    let sc = SyncCounter(1)

    let server = ServerBuilder().addr("127.0.0.1").port(18126).logger(NoopLogger()).build()

    // func afterBind(): 注册 bind 后回调(此处用它做“就绪信号”)
    server.afterBind(
        {
            =>
                println("afterBind set by Server.afterBind")
                sc.dec()
        }
    )

    // 注册一个最简 handler,便于 serve() 可测
    server.distributor.register("/ping", {
        httpContext => httpContext.responseBuilder.body("pong")
    })

    spawn {server.serve()}
    sc.waitUntilZero()

    // func serve(): 发起一次请求,证明服务正常
    let client = ClientBuilder().noProxy().build()
    let resp = client.get("http://127.0.0.1:18126/ping")
    let body = readAllBytes(resp)
    println("status = ${resp.status}")
    println("body = ${body}")
    resp.close()

    // func getTlsConfig(): 未设置 TLS,返回 None
    println("tlsConfig.isSome = ${server.getTlsConfig().isSome()}")

    // func onShutdown(): close/closeGracefully 时回调
    server.onShutdown({=> println("onShutdown set by Server.onShutdown")})

    client.close()

    // func closeGracefully(): 触发回调并关闭
    server.closeGracefully()

    // func updateCA / updateCert(): 未配置 TLS,调用会抛 HttpException
    try {
        server.updateCA([])
    } catch (e: HttpException) {
        println("updateCA(Array) HttpException: ${e.message}")
    }
    try {
        server.updateCA("/tmp/not-exist.pem")
    } catch (e: HttpException) {
        println("updateCA(String) HttpException: ${e.message}")
    }
    // 不引入证书/私钥文件依赖:仅展示未配置 TLS 时的异常行为
    try {
        server.updateCert([], RSAPrivateKey(1024))
    } catch (e: HttpException) {
        println("updateCert(Array,Key) HttpException: ${e.message}")
    }
    try {
        server.updateCert("/tmp/a.pem", "/tmp/b.pem")
    } catch (e: HttpException) {
        println("updateCert(String,String) HttpException: ${e.message}")
    }
}

运行结果:

afterBind set by Server.afterBind
status = 200
body = pong
tlsConfig.isSome = false
onShutdown set by Server.onShutdown
updateCA(Array) HttpException: The TLS certificate is not configured.
updateCA(String) HttpException: The TLS certificate is not configured.
updateCert(Array,Key) HttpException: The TLS certificate is not configured.
updateCert(String,String) HttpException: The TLS certificate is not configured.

func onShutdown(() -> Unit)

public func onShutdown(f: () -> Unit): Unit

功能:注册服务器关闭时的回调函数,服务器关闭时将调用该回调函数,重复调用将覆盖之前注册的函数。

参数:

  • f: () -> Unit - 回调函数,入参为空,返回值为 Unit 类型。

示例:

import stdx.net.http.*
import stdx.log.*
import std.sync.*
import stdx.crypto.keys.RSAPrivateKey

// 用于稳定获取响应 body(避免依赖 readToEnd/readAll 等 API)
func readAllBytes(resp: HttpResponse): String {
    let buf = Array<UInt8>(1024, repeat: 0)
    var body = ""
    while (true) {
        let n = resp.body.read(buf)
        if (n <= 0) {
            break
        }
        body += String.fromUtf8(buf[..n])
    }
    return body
}

main() {
    let sc = SyncCounter(1)

    let server = ServerBuilder().addr("127.0.0.1").port(18126).logger(NoopLogger()).build()

    // func afterBind(): 注册 bind 后回调(此处用它做“就绪信号”)
    server.afterBind(
        {
            =>
                println("afterBind set by Server.afterBind")
                sc.dec()
        }
    )

    // 注册一个最简 handler,便于 serve() 可测
    server.distributor.register("/ping", {
        httpContext => httpContext.responseBuilder.body("pong")
    })

    spawn {server.serve()}
    sc.waitUntilZero()

    // func serve(): 发起一次请求,证明服务正常
    let client = ClientBuilder().noProxy().build()
    let resp = client.get("http://127.0.0.1:18126/ping")
    let body = readAllBytes(resp)
    println("status = ${resp.status}")
    println("body = ${body}")
    resp.close()

    // func getTlsConfig(): 未设置 TLS,返回 None
    println("tlsConfig.isSome = ${server.getTlsConfig().isSome()}")

    // func onShutdown(): close/closeGracefully 时回调
    server.onShutdown({=> println("onShutdown set by Server.onShutdown")})

    client.close()

    // func closeGracefully(): 触发回调并关闭
    server.closeGracefully()

    // func updateCA / updateCert(): 未配置 TLS,调用会抛 HttpException
    try {
        server.updateCA([])
    } catch (e: HttpException) {
        println("updateCA(Array) HttpException: ${e.message}")
    }
    try {
        server.updateCA("/tmp/not-exist.pem")
    } catch (e: HttpException) {
        println("updateCA(String) HttpException: ${e.message}")
    }
    // 不引入证书/私钥文件依赖:仅展示未配置 TLS 时的异常行为
    try {
        server.updateCert([], RSAPrivateKey(1024))
    } catch (e: HttpException) {
        println("updateCert(Array,Key) HttpException: ${e.message}")
    }
    try {
        server.updateCert("/tmp/a.pem", "/tmp/b.pem")
    } catch (e: HttpException) {
        println("updateCert(String,String) HttpException: ${e.message}")
    }
}

运行结果:

afterBind set by Server.afterBind
status = 200
body = pong
tlsConfig.isSome = false
onShutdown set by Server.onShutdown
updateCA(Array) HttpException: The TLS certificate is not configured.
updateCA(String) HttpException: The TLS certificate is not configured.
updateCert(Array,Key) HttpException: The TLS certificate is not configured.
updateCert(String,String) HttpException: The TLS certificate is not configured.

func serve()

public func serve(): Unit

功能:启动服务端进程,不支持重复启动。

h1 request 检查和处理:

  • request-line 不符合 RFC 9112 中 request-line = method SP request-target SP HTTP-version 的规则,将会返回 400 响应;
  • method 由 tokens 组成,且大小写敏感;request-target 为能够被解析的 url;HTTP-version 为 HTTP/1.0 或 HTTP/1.1 ,否则将会返回 400 响应;
  • headers name 和 value 需符合特定规则,详见 HttpHeaders 类说明,否则返回 400 响应;
  • 当 headers 的大小超出 server 设定的 maxRequestHeaderSize 时将自动返回 431 响应;
  • headers 中必须包含 "host" 请求头,且值唯一,否则返回 400 响应 headers 中不允许同时存在 "content-length" 与 "transfer-encoding" 请求头,否则返回 400 响应;
  • 请求头 "transfer-encoding" 的 value 经过 "," 分割后最后一个 value 必须为 "chunked",且之前的 value 不允许存在 "chunked",否则返回 400 响应;
  • 请求头 "content-length" 其 value 必须能解析为 Int64 类型,且不能为负值,否则返回 400 响应,当其 value 值超出 server 设定 maxRequestBodySize,将返回 413 响应;
  • headers 中若不存在 "content-length" 和 "transfer-encoding: chunked" 时默认不存在 body;
  • 请求头 "trailer" 中,value 不允许存在 "transfer-encoding","trailer","content-length";
  • 请求头 "expect" 中,value 中存在非 "100-continue" 的值,将会返回 417 响应;
  • HTTP/1.0 默认短连接,若想保持长连接需要包含请求头 "connection: keep-alive" 与 "keep-alive: timeout = XX, max = XX",将会自动保持 timeout 时长的连接。HTTP/1.1 默认长连接,当解析 request 失败则关闭连接;
  • 仅允许在 chunked 模式下存在 trailer,且 trailer 中条目的 name 必须被包含在 "trailer" 请求头中,否则将自动删除。

h1 response 检查和处理:

  • 若用户不对 response 进行配置,将会自动返回 200 响应;
  • 若接收到的 request 包含请求头 "connection: close" 而配置 response 未添加响应头 "connection" 或响应头 "connection" 的 value 不包含 "close",将自动添加 "connection: close",若接收到的 request 不包含请求头 "connection: close" 且响应头不存在 "connection: keep-alive",将会自动添加;
  • 如果 headers 包含逐跳响应头:"proxy-connection","keep-alive","te","transfer-encoding","upgrade",将会在响应头 "connection" 自动添加这些头作为 value;
  • 将自动添加 "date" 响应头,用户提供的 "date" 将被忽略;
  • 若请求方法为 "HEAD" 或响应状态码为 "1XX\204\304",body 将配置为空;
  • 若已知提供 body 的长度时,将会与响应头 "content-length" 进行比较,若不存在响应头 "content-length",将自动添加此响应头,其 value 值为 body 长度。若响应头 "content-length" 长度大于 body 长度,将会在 handler 中抛出 HttpException,若小于 body 长度,将对 body 进行截断处理,发送的 body 长度将为 "content-length" 的值;
  • response 中 "set-cookie" header 将分条发送,其他 headers 同名条目将合成一条发送;
  • 在处理包含请求头:"expect: 100-continue" 的 request 时,在调用 request 的 body.read() 时将会自动发送状态码为 100 的响应给客户端。不允许用户主动发送状态码为 100 的 response,若进行发送则被认定为服务器异常。

启用 h2 服务:tlsConfig 中 supportedAlpnProtocols 需包含 "h2",此后如果 tls 层 alpn 协商结果为 h2,则启用 h2 服务。

h2 request 检查和处理:

  • headers name 和 value 需符合特定规则,详见 HttpHeaders 类说明,此外 name 不能包含大写字符,否则发送 RST 帧关闭流,即无法保证返回响应;
  • trailers name 和 value 需符合同样规则,否则关闭流;
  • headers 不能包含 "connection","transfer-encoding","keep-alive","upgrade","proxy-connection",否则关闭流;
  • 如果有 "te" header,其值只能为 "trailers",否则关闭流;
  • 如果有 "host" header 和 ":authority" pseudo header,"host" 值必须与 ":authority" 一致,否则关闭流;
  • 如果有 "content-length" header,需符合 "content-length" 每个值都能解析为 Int64 类型,且如果有多个值,必须相等,否则关闭流;
  • 如果有 "content-length" header,且有 body 大小,则 content-length 值与 body 大小必须相等,否则关闭流;
  • 如果有 "trailer" header,其值不能包含 "transfer-encoding","trailer","content-length",否则关闭流;
  • 仅在升级 WebSocket 场景下支持 CONNECT 方法,否则关闭流;
  • pseudo headers 中,必须包含 ":method"、":scheme"、":path",其中 ":method" 值必须由 tokens 字符组成,":scheme" 值必须为 "https",":path" 不能为空,否则关闭流;
  • trailer 中条目的 name 必须被包含在 "trailer" 头中,否则将自动删除;
  • request headers 大小不能超过 maxHeaderListSize,否则关闭连接。

h2 response 检查和处理:

  • 如果 HEAD 请求的响应包含 body,将自动删除;
  • 将自动添加 "date" field,用户提供的 "date" 将被忽略;
  • 如果 headers 包含 "connection","transfer-encoding","keep-alive","upgrade","proxy-connection",将自动删除;
  • response 中 "set-cookie" header 将分条发送,其他 headers 同名条目将合成一条发送;
  • 如果 headers 包含 "content-length",且 method 不为 "HEAD","content-length" 将被删除;
  • 如果 method 为 "HEAD",则:
    • headers 包含 "content-length",但 "content-length" 不合法(无法被解析为 Int64 值,或包含多个不同值),如果用户调用 HttpResponseWriter 类的 write 函数,将抛出 HttpException,如果用户 handler 已经结束,将打印日志;
    • headers 包含 "content-length",同时 response.body.length 不为 -1,"content-length" 值与 body.length 不符,同 6.1 处理;
    • headers 包含 "content-length",同时 response.body.length 为 -1,或 body.length 与 "content-length" 值一致,则保留 "content-length" header;
  • trailer 中条目必须被包含在 "trailer" 头中,否则将自动删除;
  • 如果 handler 中抛出异常,且用户未调用 write 发送部分响应,将返回 500 响应。如果用户已经调用 write 发送部分响应,将发送 RST 帧关闭 stream。

h2 server 发完 response 之后,如果 stream 状态不是 CLOSED,会发送带 NO_ERROR 错误码的 RST 帧关闭 stream,避免已经处理完毕的 stream 继续占用服务器资源。

h2 流量控制:

  • connection 流量窗口初始值为 65535,每次收到 DATA 帧将返回一个 connection 层面的 WINDOW-UPDATE,发送 DATA 时,如果 connection 流量窗口值为负数,将阻塞至其变为正数;
  • stream 流量窗口初始值可由用户设置,默认值为 65535,每次收到 DATA 帧将返回一个 stream 层面的 WINDOW-UPDATE,发送 DATA 时,如果 stream 流量窗口值为负数,将阻塞至其变为正数。

h2 请求优先级:

  • 支持按 urgency 处理请求,h2 服务默认并发处理请求,当并发资源不足时,请求将按 urgency 处理,优先级高的请求优先处理。

默认 ProtocolServiceFactory 协议选择:

  • 如果连接是 tcp,使用 HTTP/1.1 server;
  • 如果连接是 tls,根据 alpn 协商结果确定 http 协议版本,如果协商结果为 "http/1.0","http/1.1" 或 "",使用 HTTP/1.1 server,如果协商结果为 "h2",使用 HTTP/2 server,否则不处理此次请求,打印日志关连接。

异常:

  • SocketException - 当端口监听失败时,抛出异常。

示例:

import stdx.net.http.*
import stdx.log.*
import std.sync.*
import stdx.crypto.keys.RSAPrivateKey

// 用于稳定获取响应 body(避免依赖 readToEnd/readAll 等 API)
func readAllBytes(resp: HttpResponse): String {
    let buf = Array<UInt8>(1024, repeat: 0)
    var body = ""
    while (true) {
        let n = resp.body.read(buf)
        if (n <= 0) {
            break
        }
        body += String.fromUtf8(buf[..n])
    }
    return body
}

main() {
    let sc = SyncCounter(1)

    let server = ServerBuilder().addr("127.0.0.1").port(18126).logger(NoopLogger()).build()

    // func afterBind(): 注册 bind 后回调(此处用它做“就绪信号”)
    server.afterBind(
        {
            =>
                println("afterBind set by Server.afterBind")
                sc.dec()
        }
    )

    // 注册一个最简 handler,便于 serve() 可测
    server.distributor.register("/ping", {
        httpContext => httpContext.responseBuilder.body("pong")
    })

    spawn {server.serve()}
    sc.waitUntilZero()

    // func serve(): 发起一次请求,证明服务正常
    let client = ClientBuilder().noProxy().build()
    let resp = client.get("http://127.0.0.1:18126/ping")
    let body = readAllBytes(resp)
    println("status = ${resp.status}")
    println("body = ${body}")
    resp.close()

    // func getTlsConfig(): 未设置 TLS,返回 None
    println("tlsConfig.isSome = ${server.getTlsConfig().isSome()}")

    // func onShutdown(): close/closeGracefully 时回调
    server.onShutdown({=> println("onShutdown set by Server.onShutdown")})

    client.close()

    // func closeGracefully(): 触发回调并关闭
    server.closeGracefully()

    // func updateCA / updateCert(): 未配置 TLS,调用会抛 HttpException
    try {
        server.updateCA([])
    } catch (e: HttpException) {
        println("updateCA(Array) HttpException: ${e.message}")
    }
    try {
        server.updateCA("/tmp/not-exist.pem")
    } catch (e: HttpException) {
        println("updateCA(String) HttpException: ${e.message}")
    }
    // 不引入证书/私钥文件依赖:仅展示未配置 TLS 时的异常行为
    try {
        server.updateCert([], RSAPrivateKey(1024))
    } catch (e: HttpException) {
        println("updateCert(Array,Key) HttpException: ${e.message}")
    }
    try {
        server.updateCert("/tmp/a.pem", "/tmp/b.pem")
    } catch (e: HttpException) {
        println("updateCert(String,String) HttpException: ${e.message}")
    }
}

运行结果:

afterBind set by Server.afterBind
status = 200
body = pong
tlsConfig.isSome = false
onShutdown set by Server.onShutdown
updateCA(Array) HttpException: The TLS certificate is not configured.
updateCA(String) HttpException: The TLS certificate is not configured.
updateCert(Array,Key) HttpException: The TLS certificate is not configured.
updateCert(String,String) HttpException: The TLS certificate is not configured.

func updateCA(Array<Certificate>)

public func updateCA(newCa: Array<Certificate>): Unit

功能:对 CA 证书进行热更新。

参数:

异常:

  • IllegalArgumentException - 参数包含空字符时抛出异常。
  • HttpException - 服务端未配置 tlsConfig 时抛出异常。

示例:

import stdx.net.http.*
import stdx.log.*
import std.sync.*
import stdx.crypto.keys.RSAPrivateKey

// 用于稳定获取响应 body(避免依赖 readToEnd/readAll 等 API)
func readAllBytes(resp: HttpResponse): String {
    let buf = Array<UInt8>(1024, repeat: 0)
    var body = ""
    while (true) {
        let n = resp.body.read(buf)
        if (n <= 0) {
            break
        }
        body += String.fromUtf8(buf[..n])
    }
    return body
}

main() {
    let sc = SyncCounter(1)

    let server = ServerBuilder().addr("127.0.0.1").port(18126).logger(NoopLogger()).build()

    // func afterBind(): 注册 bind 后回调(此处用它做“就绪信号”)
    server.afterBind(
        {
            =>
                println("afterBind set by Server.afterBind")
                sc.dec()
        }
    )

    // 注册一个最简 handler,便于 serve() 可测
    server.distributor.register("/ping", {
        httpContext => httpContext.responseBuilder.body("pong")
    })

    spawn {server.serve()}
    sc.waitUntilZero()

    // func serve(): 发起一次请求,证明服务正常
    let client = ClientBuilder().noProxy().build()
    let resp = client.get("http://127.0.0.1:18126/ping")
    let body = readAllBytes(resp)
    println("status = ${resp.status}")
    println("body = ${body}")
    resp.close()

    // func getTlsConfig(): 未设置 TLS,返回 None
    println("tlsConfig.isSome = ${server.getTlsConfig().isSome()}")

    // func onShutdown(): close/closeGracefully 时回调
    server.onShutdown({=> println("onShutdown set by Server.onShutdown")})

    client.close()

    // func closeGracefully(): 触发回调并关闭
    server.closeGracefully()

    // func updateCA / updateCert(): 未配置 TLS,调用会抛 HttpException
    try {
        server.updateCA([])
    } catch (e: HttpException) {
        println("updateCA(Array) HttpException: ${e.message}")
    }
    try {
        server.updateCA("/tmp/not-exist.pem")
    } catch (e: HttpException) {
        println("updateCA(String) HttpException: ${e.message}")
    }
    // 不引入证书/私钥文件依赖:仅展示未配置 TLS 时的异常行为
    try {
        server.updateCert([], RSAPrivateKey(1024))
    } catch (e: HttpException) {
        println("updateCert(Array,Key) HttpException: ${e.message}")
    }
    try {
        server.updateCert("/tmp/a.pem", "/tmp/b.pem")
    } catch (e: HttpException) {
        println("updateCert(String,String) HttpException: ${e.message}")
    }
}

运行结果:

afterBind set by Server.afterBind
status = 200
body = pong
tlsConfig.isSome = false
onShutdown set by Server.onShutdown
updateCA(Array) HttpException: The TLS certificate is not configured.
updateCA(String) HttpException: The TLS certificate is not configured.
updateCert(Array,Key) HttpException: The TLS certificate is not configured.
updateCert(String,String) HttpException: The TLS certificate is not configured.

func updateCA(String)

public func updateCA(newCaFile: String): Unit

功能:对 CA 证书进行热更新。

参数:

  • newCaFile: String - CA 证书文件。

异常:

  • IllegalArgumentException - 参数包含空字符时抛出异常。
  • HttpException - 服务端未配置 tlsConfig 时抛出异常。

示例:

import stdx.net.http.*
import stdx.log.*
import std.sync.*
import stdx.crypto.keys.RSAPrivateKey

// 用于稳定获取响应 body(避免依赖 readToEnd/readAll 等 API)
func readAllBytes(resp: HttpResponse): String {
    let buf = Array<UInt8>(1024, repeat: 0)
    var body = ""
    while (true) {
        let n = resp.body.read(buf)
        if (n <= 0) {
            break
        }
        body += String.fromUtf8(buf[..n])
    }
    return body
}

main() {
    let sc = SyncCounter(1)

    let server = ServerBuilder().addr("127.0.0.1").port(18126).logger(NoopLogger()).build()

    // func afterBind(): 注册 bind 后回调(此处用它做“就绪信号”)
    server.afterBind(
        {
            =>
                println("afterBind set by Server.afterBind")
                sc.dec()
        }
    )

    // 注册一个最简 handler,便于 serve() 可测
    server.distributor.register("/ping", {
        httpContext => httpContext.responseBuilder.body("pong")
    })

    spawn {server.serve()}
    sc.waitUntilZero()

    // func serve(): 发起一次请求,证明服务正常
    let client = ClientBuilder().noProxy().build()
    let resp = client.get("http://127.0.0.1:18126/ping")
    let body = readAllBytes(resp)
    println("status = ${resp.status}")
    println("body = ${body}")
    resp.close()

    // func getTlsConfig(): 未设置 TLS,返回 None
    println("tlsConfig.isSome = ${server.getTlsConfig().isSome()}")

    // func onShutdown(): close/closeGracefully 时回调
    server.onShutdown({=> println("onShutdown set by Server.onShutdown")})

    client.close()

    // func closeGracefully(): 触发回调并关闭
    server.closeGracefully()

    // func updateCA / updateCert(): 未配置 TLS,调用会抛 HttpException
    try {
        server.updateCA([])
    } catch (e: HttpException) {
        println("updateCA(Array) HttpException: ${e.message}")
    }
    try {
        server.updateCA("/tmp/not-exist.pem")
    } catch (e: HttpException) {
        println("updateCA(String) HttpException: ${e.message}")
    }
    // 不引入证书/私钥文件依赖:仅展示未配置 TLS 时的异常行为
    try {
        server.updateCert([], RSAPrivateKey(1024))
    } catch (e: HttpException) {
        println("updateCert(Array,Key) HttpException: ${e.message}")
    }
    try {
        server.updateCert("/tmp/a.pem", "/tmp/b.pem")
    } catch (e: HttpException) {
        println("updateCert(String,String) HttpException: ${e.message}")
    }
}

运行结果:

afterBind set by Server.afterBind
status = 200
body = pong
tlsConfig.isSome = false
onShutdown set by Server.onShutdown
updateCA(Array) HttpException: The TLS certificate is not configured.
updateCA(String) HttpException: The TLS certificate is not configured.
updateCert(Array,Key) HttpException: The TLS certificate is not configured.
updateCert(String,String) HttpException: The TLS certificate is not configured.

func updateCert(Array<Certificate>, PrivateKey)

public func updateCert(certChain: Array<Certificate>, certKey: PrivateKey): Unit

功能:对 TLS 证书进行热更新。

参数:

异常:

  • HttpException - 服务端未配置 tlsConfig 时抛出异常。

示例:

import stdx.net.http.*
import stdx.log.*
import std.sync.*
import stdx.crypto.keys.RSAPrivateKey

// 用于稳定获取响应 body(避免依赖 readToEnd/readAll 等 API)
func readAllBytes(resp: HttpResponse): String {
    let buf = Array<UInt8>(1024, repeat: 0)
    var body = ""
    while (true) {
        let n = resp.body.read(buf)
        if (n <= 0) {
            break
        }
        body += String.fromUtf8(buf[..n])
    }
    return body
}

main() {
    let sc = SyncCounter(1)

    let server = ServerBuilder().addr("127.0.0.1").port(18126).logger(NoopLogger()).build()

    // func afterBind(): 注册 bind 后回调(此处用它做“就绪信号”)
    server.afterBind(
        {
            =>
                println("afterBind set by Server.afterBind")
                sc.dec()
        }
    )

    // 注册一个最简 handler,便于 serve() 可测
    server.distributor.register("/ping", {
        httpContext => httpContext.responseBuilder.body("pong")
    })

    spawn {server.serve()}
    sc.waitUntilZero()

    // func serve(): 发起一次请求,证明服务正常
    let client = ClientBuilder().noProxy().build()
    let resp = client.get("http://127.0.0.1:18126/ping")
    let body = readAllBytes(resp)
    println("status = ${resp.status}")
    println("body = ${body}")
    resp.close()

    // func getTlsConfig(): 未设置 TLS,返回 None
    println("tlsConfig.isSome = ${server.getTlsConfig().isSome()}")

    // func onShutdown(): close/closeGracefully 时回调
    server.onShutdown({=> println("onShutdown set by Server.onShutdown")})

    client.close()

    // func closeGracefully(): 触发回调并关闭
    server.closeGracefully()

    // func updateCA / updateCert(): 未配置 TLS,调用会抛 HttpException
    try {
        server.updateCA([])
    } catch (e: HttpException) {
        println("updateCA(Array) HttpException: ${e.message}")
    }
    try {
        server.updateCA("/tmp/not-exist.pem")
    } catch (e: HttpException) {
        println("updateCA(String) HttpException: ${e.message}")
    }
    // 不引入证书/私钥文件依赖:仅展示未配置 TLS 时的异常行为
    try {
        server.updateCert([], RSAPrivateKey(1024))
    } catch (e: HttpException) {
        println("updateCert(Array,Key) HttpException: ${e.message}")
    }
    try {
        server.updateCert("/tmp/a.pem", "/tmp/b.pem")
    } catch (e: HttpException) {
        println("updateCert(String,String) HttpException: ${e.message}")
    }
}

运行结果:

afterBind set by Server.afterBind
status = 200
body = pong
tlsConfig.isSome = false
onShutdown set by Server.onShutdown
updateCA(Array) HttpException: The TLS certificate is not configured.
updateCA(String) HttpException: The TLS certificate is not configured.
updateCert(Array,Key) HttpException: The TLS certificate is not configured.
updateCert(String,String) HttpException: The TLS certificate is not configured.

func updateCert(String, String)

public func updateCert(certificateChainFile: String, privateKeyFile: String): Unit

功能:对 TLS 证书进行热更新。

参数:

  • certificateChainFile: String - 证书链文件。
  • privateKeyFile: String - 证书匹配的私钥文件。

异常:

  • IllegalArgumentException - 参数包含空字符时抛出异常。
  • HttpException - 服务端未配置 tlsConfig 时抛出异常。

示例:

import stdx.net.http.*
import stdx.log.*
import std.sync.*
import stdx.crypto.keys.RSAPrivateKey

// 用于稳定获取响应 body(避免依赖 readToEnd/readAll 等 API)
func readAllBytes(resp: HttpResponse): String {
    let buf = Array<UInt8>(1024, repeat: 0)
    var body = ""
    while (true) {
        let n = resp.body.read(buf)
        if (n <= 0) {
            break
        }
        body += String.fromUtf8(buf[..n])
    }
    return body
}

main() {
    let sc = SyncCounter(1)

    let server = ServerBuilder().addr("127.0.0.1").port(18126).logger(NoopLogger()).build()

    // func afterBind(): 注册 bind 后回调(此处用它做“就绪信号”)
    server.afterBind(
        {
            =>
                println("afterBind set by Server.afterBind")
                sc.dec()
        }
    )

    // 注册一个最简 handler,便于 serve() 可测
    server.distributor.register("/ping", {
        httpContext => httpContext.responseBuilder.body("pong")
    })

    spawn {server.serve()}
    sc.waitUntilZero()

    // func serve(): 发起一次请求,证明服务正常
    let client = ClientBuilder().noProxy().build()
    let resp = client.get("http://127.0.0.1:18126/ping")
    let body = readAllBytes(resp)
    println("status = ${resp.status}")
    println("body = ${body}")
    resp.close()

    // func getTlsConfig(): 未设置 TLS,返回 None
    println("tlsConfig.isSome = ${server.getTlsConfig().isSome()}")

    // func onShutdown(): close/closeGracefully 时回调
    server.onShutdown({=> println("onShutdown set by Server.onShutdown")})

    client.close()

    // func closeGracefully(): 触发回调并关闭
    server.closeGracefully()

    // func updateCA / updateCert(): 未配置 TLS,调用会抛 HttpException
    try {
        server.updateCA([])
    } catch (e: HttpException) {
        println("updateCA(Array) HttpException: ${e.message}")
    }
    try {
        server.updateCA("/tmp/not-exist.pem")
    } catch (e: HttpException) {
        println("updateCA(String) HttpException: ${e.message}")
    }
    // 不引入证书/私钥文件依赖:仅展示未配置 TLS 时的异常行为
    try {
        server.updateCert([], RSAPrivateKey(1024))
    } catch (e: HttpException) {
        println("updateCert(Array,Key) HttpException: ${e.message}")
    }
    try {
        server.updateCert("/tmp/a.pem", "/tmp/b.pem")
    } catch (e: HttpException) {
        println("updateCert(String,String) HttpException: ${e.message}")
    }
}

运行结果:

afterBind set by Server.afterBind
status = 200
body = pong
tlsConfig.isSome = false
onShutdown set by Server.onShutdown
updateCA(Array) HttpException: The TLS certificate is not configured.
updateCA(String) HttpException: The TLS certificate is not configured.
updateCert(Array,Key) HttpException: The TLS certificate is not configured.
updateCert(String,String) HttpException: The TLS certificate is not configured.

class ServerBuilder

public class ServerBuilder {
    public init()
}

功能:提供 Server 实例构建器。

支持通过如下参数构造一个 Http Server

  • 地址、端口;
  • 线程安全的 logger;
  • HttpRequestDistributor,用于注册 handler、分发 request;
  • HTTP/2 的 settings;
  • shutdown 回调;
  • transport:listener、连接及其配置;
  • protocol service:http 协议解析服务;

除地址端口、shutdown 回调外,均提供默认实现,用户在构造 server 过程中可不指定其他构建参数。 ServerBuilder 文档中未明确说明支持版本的配置,在 HTTP/1.1 与 HTTP/2 都会生效。

说明:

该类提供了一系列配置参数的函数,配置完成后调用 build 函数构造出 Server 实例。配置函数中说明了参数的取值范围,但配置函数本身不做参数合法性校验,build 时统一进行校验。

func initialWindowSize(UInt32)

public func initialWindowSize(size: UInt32): ServerBuilder

功能:HTTP/2 专用,设置当前服务器上每个流的接收报文的初始流量窗口大小,默认值为 65535。取值范围为 0 至 2^31 - 1。

参数:

  • size: UInt32 - 本端一个 stream 上接收报文的初始流量窗口大小。

返回值:

示例:

import stdx.net.http.*
import stdx.log.*

main() {
    let server = ServerBuilder()
        .addr("127.0.0.1")
        .port(18118)
        .logger(NoopLogger())
        // HTTP/2 settings
        .headerTableSize(1024)
        .maxConcurrentStreams(123)
        .initialWindowSize(65535)
        .maxFrameSize(16384)
        .maxHeaderListSize(4096)
        .enableConnectProtocol(true)
        .build()

    println("headerTableSize = ${server.headerTableSize}")
    println("maxConcurrentStreams = ${server.maxConcurrentStreams}")
    println("initialWindowSize = ${server.initialWindowSize}")
    println("maxFrameSize = ${server.maxFrameSize}")
    println("maxHeaderListSize = ${server.maxHeaderListSize}")
    println("enableConnectProtocol = ${server.enableConnectProtocol}")

    server.closeGracefully()
}

运行结果:

headerTableSize = 1024
maxConcurrentStreams = 123
initialWindowSize = 65535
maxFrameSize = 16384
maxHeaderListSize = 4096
enableConnectProtocol = true

init()

public init()

功能:创建 ServerBuilder 实例。

示例:

import stdx.net.http.*
import stdx.log.*

main() {
    let _ = ServerBuilder()
}

func addr(String)

public func addr(addr: String): ServerBuilder

功能:设置服务端监听地址,若 listener 被设定,此值被忽略。

格式需符合 IPAddress 中相关规定。

参数:

  • addr: String - 地址值。

返回值:

示例:

import stdx.net.http.*
import stdx.log.*

main() {
    // addr(): 设置监听地址(只是配置,真正 bind 在 serve() 时发生)
    let server = ServerBuilder().addr("127.0.0.1").port(18110).logger(NoopLogger()).build()

    // 关注点:读取 Server.addr
    println("addr = ${server.addr}")
    server.closeGracefully()
}

运行结果:

addr = 127.0.0.1

func afterBind(()->Unit)

public func afterBind(f: ()->Unit): ServerBuilder

功能:注册服务器启动时的回调函数,服务内部 ServerSocket 实例 bind 之后,accept 之前将调用该函数。重复调用将覆盖之前注册的函数。

参数:

  • f: () ->Unit - 回调函数,入参为空,返回值为 Unit 类型。

返回值:

示例:

import stdx.net.http.*
import stdx.log.*
import std.sync.*

main() {
    let sc = SyncCounter(1)

    // afterBind(): bind() 完成后会回调
    let server = ServerBuilder().addr("127.0.0.1").port(18112).logger(NoopLogger()).afterBind(
        {
            =>
                println("afterBind called")
                sc.dec()
        }
    ).build()

    spawn {server.serve()}
    sc.waitUntilZero()

    server.closeGracefully()
}

运行结果:

afterBind called

func build()

public func build(): Server

功能:根据设置的参数构建 Server 实例。

此处会对各参数的值进行检查,如果取值非法,将抛出异常。各参数的取值范围详见设置参数相关的函数。

返回值:

异常:

  • IllegalArgumentException - 当设置的参数非法时,抛出异常。
  • IllegalFormatException 格式错误时,抛出异常。

示例:

import stdx.net.http.*
import stdx.log.*

main() {
    // build(): 根据 builder 的配置生成 Server 实例
    let server = ServerBuilder()
        .addr("127.0.0.1")
        .port(18124)
        .logger(NoopLogger())
        .readTimeout(Duration.second)
        .writeTimeout(Duration.second * 2)
        .readHeaderTimeout(Duration.millisecond * 300)
        .httpKeepAliveTimeout(Duration.second * 3)
        .maxRequestHeaderSize(1024)
        .maxRequestBodySize(2048)
        .headerTableSize(1024)
        .maxConcurrentStreams(123)
        .initialWindowSize(65535)
        .maxFrameSize(16384)
        .maxHeaderListSize(4096)
        .enableConnectProtocol(true)
        .servicePoolConfig(ServicePoolConfig(capacity: 8, queueCapacity: 16, preheat: 2))
        .build()

    // 关注点:读取 Server 上的配置结果
    println("addr = ${server.addr}")
    println("port = ${server.port}")
    println("logger.level = ${server.logger.level}")
    println("readTimeout = ${server.readTimeout}")
    println("writeTimeout = ${server.writeTimeout}")
    println("readHeaderTimeout = ${server.readHeaderTimeout}")
    println("httpKeepAliveTimeout = ${server.httpKeepAliveTimeout}")
    println("maxRequestHeaderSize = ${server.maxRequestHeaderSize}")
    println("maxRequestBodySize = ${server.maxRequestBodySize}")
    println("headerTableSize = ${server.headerTableSize}")
    println("maxConcurrentStreams = ${server.maxConcurrentStreams}")
    println("initialWindowSize = ${server.initialWindowSize}")
    println("maxFrameSize = ${server.maxFrameSize}")
    println("maxHeaderListSize = ${server.maxHeaderListSize}")
    println("enableConnectProtocol = ${server.enableConnectProtocol}")
    println(
        "servicePoolConfig = (capacity=${server.servicePoolConfig.capacity}, queueCapacity=${server.servicePoolConfig.queueCapacity}, preheat=${server.servicePoolConfig.preheat})")

    server.closeGracefully()
}

运行结果:

addr = 127.0.0.1
port = 18124
logger.level = OFF
readTimeout = 1s
writeTimeout = 2s
readHeaderTimeout = 300ms
httpKeepAliveTimeout = 3s
maxRequestHeaderSize = 1024
maxRequestBodySize = 2048
headerTableSize = 1024
maxConcurrentStreams = 123
initialWindowSize = 65535
maxFrameSize = 16384
maxHeaderListSize = 4096
enableConnectProtocol = true
servicePoolConfig = (capacity=8, queueCapacity=16, preheat=2)

func distributor(HttpRequestDistributor)

public func distributor(distributor: HttpRequestDistributor): ServerBuilder

功能:设置请求分发器,请求分发器会根据 url 将请求分发给对应的 handler。不设置时使用默认请求分发器。

参数:

返回值:

示例:

import stdx.net.http.*
import stdx.log.*

// 自定义 distributor,用来证明 builder.distributor() 生效
class MyDistributor <: HttpRequestDistributor {
    public func register(path: String, handler: HttpRequestHandler): Unit {
        let _ = path
        let _ = handler
    }

    public func distribute(path: String): HttpRequestHandler {
        let _ = path
        return NotFoundHandler()
    }
}

main() {
    let server = ServerBuilder()
        .addr("127.0.0.1")
        .port(18113)
        .logger(NoopLogger())
        .distributor(MyDistributor())
        .build()

    // 关注点:检查 Server.distributor 的动态类型
    let d = server.distributor as MyDistributor
    println("is MyDistributor: ${d.isSome()}")

    server.closeGracefully()
}

运行结果:

is MyDistributor: true

func enableConnectProtocol(Bool)

public func enableConnectProtocol(flag: Bool): ServerBuilder

功能:HTTP/2 专用,设置本端是否接收 CONNECT 请求,默认 false。

参数:

  • flag: Bool - 本端是否接收 CONNECT 请求。

返回值:

示例:

import stdx.net.http.*
import stdx.log.*

main() {
    let server = ServerBuilder()
        .addr("127.0.0.1")
        .port(18118)
        .logger(NoopLogger())
        // HTTP/2 settings
        .headerTableSize(1024)
        .maxConcurrentStreams(123)
        .initialWindowSize(65535)
        .maxFrameSize(16384)
        .maxHeaderListSize(4096)
        .enableConnectProtocol(true)
        .build()

    println("headerTableSize = ${server.headerTableSize}")
    println("maxConcurrentStreams = ${server.maxConcurrentStreams}")
    println("initialWindowSize = ${server.initialWindowSize}")
    println("maxFrameSize = ${server.maxFrameSize}")
    println("maxHeaderListSize = ${server.maxHeaderListSize}")
    println("enableConnectProtocol = ${server.enableConnectProtocol}")

    server.closeGracefully()
}

运行结果:

headerTableSize = 1024
maxConcurrentStreams = 123
initialWindowSize = 65535
maxFrameSize = 16384
maxHeaderListSize = 4096
enableConnectProtocol = true

func headerTableSize(UInt32)

public func headerTableSize(size: UInt32): ServerBuilder

功能:设置服务端 HTTP/2 Hpack 动态表的初始值,默认值为 4096。

参数:

  • size: UInt32 - 本端对响应头编码时使用的最大 table size

返回值:

示例:

import stdx.net.http.*
import stdx.log.*

main() {
    let server = ServerBuilder()
        .addr("127.0.0.1")
        .port(18118)
        .logger(NoopLogger())
        // HTTP/2 settings
        .headerTableSize(1024)
        .maxConcurrentStreams(123)
        .initialWindowSize(65535)
        .maxFrameSize(16384)
        .maxHeaderListSize(4096)
        .enableConnectProtocol(true)
        .build()

    println("headerTableSize = ${server.headerTableSize}")
    println("maxConcurrentStreams = ${server.maxConcurrentStreams}")
    println("initialWindowSize = ${server.initialWindowSize}")
    println("maxFrameSize = ${server.maxFrameSize}")
    println("maxHeaderListSize = ${server.maxHeaderListSize}")
    println("enableConnectProtocol = ${server.enableConnectProtocol}")

    server.closeGracefully()
}

运行结果:

headerTableSize = 1024
maxConcurrentStreams = 123
initialWindowSize = 65535
maxFrameSize = 16384
maxHeaderListSize = 4096
enableConnectProtocol = true

func httpKeepAliveTimeout(Duration)

public func httpKeepAliveTimeout(timeout: Duration): ServerBuilder

功能:HTTP/1.1 专用,设定服务端连接保活时长,该时长内客户端未再次发送请求,服务端将关闭长连接,默认不进行限制。

参数:

  • timeout: Duration - 设定保持长连接的超时时间,如果传入负的 Duration 将被替换为 Duration.Zero。

返回值:

示例:

import stdx.net.http.*
import stdx.log.*

main() {
    let server = ServerBuilder()
        .addr("127.0.0.1")
        .port(18117)
        .logger(NoopLogger())
        // 关注点:这些配置最终体现在 Server 的 prop 上
        .readTimeout(Duration.second)
        .writeTimeout(Duration.second * 2)
        .readHeaderTimeout(Duration.millisecond * 300)
        .httpKeepAliveTimeout(Duration.second * 3)
        .build()

    println("readTimeout = ${server.readTimeout}")
    println("writeTimeout = ${server.writeTimeout}")
    println("readHeaderTimeout = ${server.readHeaderTimeout}")
    println("httpKeepAliveTimeout = ${server.httpKeepAliveTimeout}")

    server.closeGracefully()
}

运行结果:

readTimeout = 1s
writeTimeout = 2s
readHeaderTimeout = 300ms
httpKeepAliveTimeout = 3s

func listener(ServerSocket)

public func listener(listener: ServerSocket): ServerBuilder

功能:服务端调用此函数对指定 socket 进行绑定监听。

参数:

  • listener: ServerSocket - 所绑定的 socket。

返回值:

示例:

import stdx.net.http.*
import stdx.log.*
import std.net.*

main() {
    // listener(): 直接注入一个已经指定 bind 地址/端口的 ServerSocket
    let socket = TcpServerSocket(bindAt: IPSocketAddress("127.0.0.1", 18122))

    let server = ServerBuilder().listener(socket).logger(NoopLogger()).build()

    println("addr = ${server.addr}")
    println("port = ${server.port}")

    server.closeGracefully()
}

运行结果:

addr = 127.0.0.1
port = 18122

func logger(Logger)

public func logger(logger: Logger): ServerBuilder

功能:设定服务器的 logger,默认 logger 级别为 INFO,logger 内容将写入 Console.stdout。

参数:

  • logger: Logger - 需要是线程安全的,默认使用内置线程安全 logger。

返回值:

示例:

import stdx.net.http.*
import stdx.log.*

main() {
    // logger(): 设定 Server 的 logger
    let server = ServerBuilder().addr("127.0.0.1").port(18114).logger(NoopLogger()).build()

    // 关注点:NoopLogger.level 恒为 OFF
    println("logger.level = ${server.logger.level}")

    server.closeGracefully()
}

运行结果:

logger.level = OFF

func maxConcurrentStreams(UInt32)

public func maxConcurrentStreams(size: UInt32): ServerBuilder

功能:HTTP/2 专用,设置本端同时处理的最大请求数量,限制对端并发发送请求的数量,默认值为 100。

参数:

  • size: UInt32 - 本端同时处理的最大请求数量。

返回值:

示例:

import stdx.net.http.*
import stdx.log.*

main() {
    let server = ServerBuilder()
        .addr("127.0.0.1")
        .port(18118)
        .logger(NoopLogger())
        // HTTP/2 settings
        .headerTableSize(1024)
        .maxConcurrentStreams(123)
        .initialWindowSize(65535)
        .maxFrameSize(16384)
        .maxHeaderListSize(4096)
        .enableConnectProtocol(true)
        .build()

    println("headerTableSize = ${server.headerTableSize}")
    println("maxConcurrentStreams = ${server.maxConcurrentStreams}")
    println("initialWindowSize = ${server.initialWindowSize}")
    println("maxFrameSize = ${server.maxFrameSize}")
    println("maxHeaderListSize = ${server.maxHeaderListSize}")
    println("enableConnectProtocol = ${server.enableConnectProtocol}")

    server.closeGracefully()
}

运行结果:

headerTableSize = 1024
maxConcurrentStreams = 123
initialWindowSize = 65535
maxFrameSize = 16384
maxHeaderListSize = 4096
enableConnectProtocol = true

func maxFrameSize(UInt32)

public func maxFrameSize(size: UInt32): ServerBuilder

功能:HTTP/2 专用,设置本端接收的一个帧的最大长度,用来限制对端发送帧的长度,默认值为 16384. 取值范围为 2^14 至 2^24 - 1。

参数:

  • size: UInt32 - 本端接收的一个帧的最大长度。

返回值:

示例:

import stdx.net.http.*
import stdx.log.*

main() {
    let server = ServerBuilder()
        .addr("127.0.0.1")
        .port(18118)
        .logger(NoopLogger())
        // HTTP/2 settings
        .headerTableSize(1024)
        .maxConcurrentStreams(123)
        .initialWindowSize(65535)
        .maxFrameSize(16384)
        .maxHeaderListSize(4096)
        .enableConnectProtocol(true)
        .build()

    println("headerTableSize = ${server.headerTableSize}")
    println("maxConcurrentStreams = ${server.maxConcurrentStreams}")
    println("initialWindowSize = ${server.initialWindowSize}")
    println("maxFrameSize = ${server.maxFrameSize}")
    println("maxHeaderListSize = ${server.maxHeaderListSize}")
    println("enableConnectProtocol = ${server.enableConnectProtocol}")

    server.closeGracefully()
}

运行结果:

headerTableSize = 1024
maxConcurrentStreams = 123
initialWindowSize = 65535
maxFrameSize = 16384
maxHeaderListSize = 4096
enableConnectProtocol = true

func maxHeaderListSize(UInt32)

public func maxHeaderListSize(size: UInt32): ServerBuilder

功能:获取客户端支持的 HTTP/2 最大头部(Header)大小。这个大小指的是响应头部中所有头部字段(Header Field)的最大允许长度之和,其中包括所有字段名称(name)的长度、字段值(value)的长度以及每个字段自动添加的伪头开销(通常每个字段会有 32 字节的开销,这包括了 HTTP/2 协议本身为头部字段添加的伪头部信息)。默认情况下,这个最大长度被设置为 UInt32.Max。

参数:

  • size: UInt32 - 本端接收的报文头最大长度。

返回值:

示例:

import stdx.net.http.*
import stdx.log.*

main() {
    let server = ServerBuilder()
        .addr("127.0.0.1")
        .port(18118)
        .logger(NoopLogger())
        // HTTP/2 settings
        .headerTableSize(1024)
        .maxConcurrentStreams(123)
        .initialWindowSize(65535)
        .maxFrameSize(16384)
        .maxHeaderListSize(4096)
        .enableConnectProtocol(true)
        .build()

    println("headerTableSize = ${server.headerTableSize}")
    println("maxConcurrentStreams = ${server.maxConcurrentStreams}")
    println("initialWindowSize = ${server.initialWindowSize}")
    println("maxFrameSize = ${server.maxFrameSize}")
    println("maxHeaderListSize = ${server.maxHeaderListSize}")
    println("enableConnectProtocol = ${server.enableConnectProtocol}")

    server.closeGracefully()
}

运行结果:

headerTableSize = 1024
maxConcurrentStreams = 123
initialWindowSize = 65535
maxFrameSize = 16384
maxHeaderListSize = 4096
enableConnectProtocol = true

func maxRequestBodySize(Int64)

public func maxRequestBodySize(size: Int64): ServerBuilder

功能:设置服务端允许客户端发送单个请求的请求体最大长度,请求体长度超过该值时,将返回状态码为 413 的响应。默认值为 2M。仅对于 HTTP/1.1 且未设置 "Transfer-Encoding: chunked" 的请求生效。

参数:

  • size: Int64 - 设定允许接收请求的请求体大小最大值,值为 0 代表不作限制。

返回值:

异常:

  • IllegalArgumentException - 当入参 size < 0 时,抛出异常。

示例:

import stdx.net.http.*
import stdx.log.*

main() {
    let server = ServerBuilder()
        .addr("127.0.0.1")
        .port(18119)
        .logger(NoopLogger())
        .maxRequestHeaderSize(1024)
        .maxRequestBodySize(2048)
        .build()

    println("maxRequestHeaderSize = ${server.maxRequestHeaderSize}")
    println("maxRequestBodySize = ${server.maxRequestBodySize}")

    server.closeGracefully()
}

运行结果:

maxRequestHeaderSize = 1024
maxRequestBodySize = 2048

func maxRequestHeaderSize(Int64)

public func maxRequestHeaderSize(size: Int64): ServerBuilder

功能:设定服务端允许客户端发送单个请求的请求头最大长度,请求头长度超过该值时,将返回状态码为 431 的响应;仅对 HTTP/1.1 生效,HTTP/2 中有专门的配置 maxHeaderListSize。

参数:

  • size: Int64 - 设定允许接收请求的请求头大小最大值,值为 0 代表不作限制。

返回值:

异常:

  • IllegalArgumentException - 当入参 size < 0 时,抛出异常。

示例:

import stdx.net.http.*
import stdx.log.*

main() {
    let server = ServerBuilder()
        .addr("127.0.0.1")
        .port(18119)
        .logger(NoopLogger())
        .maxRequestHeaderSize(1024)
        .maxRequestBodySize(2048)
        .build()

    println("maxRequestHeaderSize = ${server.maxRequestHeaderSize}")
    println("maxRequestBodySize = ${server.maxRequestBodySize}")

    server.closeGracefully()
}

运行结果:

maxRequestHeaderSize = 1024
maxRequestBodySize = 2048

func onShutdown(() -> Unit)

public func onShutdown(f: () -> Unit): ServerBuilder

功能:注册服务器关闭时的回调函数,服务器关闭时将调用该回调函数,重复调用将覆盖之前注册的函数。

参数:

  • f: () ->Unit - 回调函数,入参为空,返回值为 Unit 类型。

返回值:

示例:

import stdx.net.http.*
import stdx.log.*

main() {
    // onShutdown(): close/closeGracefully 时会触发回调
    let server = ServerBuilder()
        .addr("127.0.0.1")
        .port(18123)
        .logger(NoopLogger())
        .onShutdown({=> println("onShutdown called")})
        .build()

    server.closeGracefully()
}

运行结果:

onShutdown called

func port(UInt16)

public func port(port: UInt16): ServerBuilder

功能:设置服务端监听端口,若 listener 被设定,此值被忽略。

参数:

  • port: UInt16 - 端口值。

返回值:

示例:

import stdx.net.http.*
import stdx.log.*

main() {
    // port(): 设置监听端口
    let server = ServerBuilder().addr("127.0.0.1").port(18111).logger(NoopLogger()).build()

    println("port = ${server.port}")
    server.closeGracefully()
}

运行结果:

port = 18111

func protocolServiceFactory(ProtocolServiceFactory)

public func protocolServiceFactory(factory: ProtocolServiceFactory): ServerBuilder

功能:设置协议服务工厂,服务协议工厂会生成每个协议所需的服务实例,不设置时使用默认工厂。

参数:

返回值:

示例:

import stdx.net.http.*
import stdx.log.*
import std.net.*

// 自定义 ProtocolService:不做真实 HTTP 解析,只打印并回一个固定响应
class MyProtocolService <: ProtocolService {
    let conn: StreamingSocket

    public init(conn: StreamingSocket) {
        this.conn = conn
    }

    protected override func serve(): Unit {
        println("MyProtocolService.serve")
        conn.write("HTTP/1.1 200 OK\r\nContent-Length: 2\r\nConnection: close\r\n\r\nOK".toArray())
        conn.close()
    }

    protected override func closeGracefully(): Unit {
        conn.close()
    }

    protected override func close(): Unit {
        conn.close()
    }
}

class MyFactory <: ProtocolServiceFactory {
    public func create(protocol: Protocol, socket: StreamingSocket): ProtocolService {
        let _ = protocol
        return MyProtocolService(socket)
    }
}

main() {
    let server = ServerBuilder()
        .addr("127.0.0.1")
        .port(18121)
        .logger(NoopLogger())
        .protocolServiceFactory(MyFactory())
        .build()

    // 关注点:Server.protocolServiceFactory 的动态类型
    let f = server.protocolServiceFactory as MyFactory
    println("protocolServiceFactory is MyFactory: ${f.isSome()}")

    server.closeGracefully()
}

运行结果:

protocolServiceFactory is MyFactory: true

func readHeaderTimeout(Duration)

public func readHeaderTimeout(timeout: Duration): ServerBuilder

功能:设定服务端读取客户端发送一个请求的请求头最大时长,超过该时长将不再进行读取并关闭连接,默认不进行限制。

参数:

  • timeout: Duration - 设定的读请求头超时时间,如果传入负的 Duration 将被替换为 Duration.Zero。

返回值:

示例:

import stdx.net.http.*
import stdx.log.*

main() {
    let server = ServerBuilder()
        .addr("127.0.0.1")
        .port(18117)
        .logger(NoopLogger())
        // 关注点:这些配置最终体现在 Server 的 prop 上
        .readTimeout(Duration.second)
        .writeTimeout(Duration.second * 2)
        .readHeaderTimeout(Duration.millisecond * 300)
        .httpKeepAliveTimeout(Duration.second * 3)
        .build()

    println("readTimeout = ${server.readTimeout}")
    println("writeTimeout = ${server.writeTimeout}")
    println("readHeaderTimeout = ${server.readHeaderTimeout}")
    println("httpKeepAliveTimeout = ${server.httpKeepAliveTimeout}")

    server.closeGracefully()
}

运行结果:

readTimeout = 1s
writeTimeout = 2s
readHeaderTimeout = 300ms
httpKeepAliveTimeout = 3s

func readTimeout(Duration)

public func readTimeout(timeout: Duration): ServerBuilder

功能:设定服务端读取一个请求的最大时长,超过该时长将不再进行读取并关闭连接,默认不进行限制。

参数:

  • timeout: Duration - 设定读请求的超时时间,如果传入时间为负值将被替换为 Duration.Zero。

返回值:

示例:

import stdx.net.http.*
import stdx.log.*

main() {
    let server = ServerBuilder()
        .addr("127.0.0.1")
        .port(18117)
        .logger(NoopLogger())
        // 关注点:这些配置最终体现在 Server 的 prop 上
        .readTimeout(Duration.second)
        .writeTimeout(Duration.second * 2)
        .readHeaderTimeout(Duration.millisecond * 300)
        .httpKeepAliveTimeout(Duration.second * 3)
        .build()

    println("readTimeout = ${server.readTimeout}")
    println("writeTimeout = ${server.writeTimeout}")
    println("readHeaderTimeout = ${server.readHeaderTimeout}")
    println("httpKeepAliveTimeout = ${server.httpKeepAliveTimeout}")

    server.closeGracefully()
}

运行结果:

readTimeout = 1s
writeTimeout = 2s
readHeaderTimeout = 300ms
httpKeepAliveTimeout = 3s

func servicePoolConfig(ServicePoolConfig)

public func servicePoolConfig(cfg: ServicePoolConfig): ServerBuilder

功能:服务过程中使用的协程池相关设置,具体说明见 ServicePoolConfig 结构体。

参数:

返回值:

示例:

import stdx.net.http.*
import stdx.log.*

main() {
    let poolCfg = ServicePoolConfig(capacity: 8, queueCapacity: 16, preheat: 2)

    let server = ServerBuilder().addr("127.0.0.1").port(18120).logger(NoopLogger()).servicePoolConfig(poolCfg).build()

    let c = server.servicePoolConfig.capacity
    let q = server.servicePoolConfig.queueCapacity
    let p = server.servicePoolConfig.preheat
    println("servicePoolConfig = (capacity=${c}, queueCapacity=${q}, preheat=${p})")

    server.closeGracefully()
}

运行结果:

servicePoolConfig = (capacity=8, queueCapacity=16, preheat=2)

func tlsConfig(TlsConfig)

public func tlsConfig(config: TlsConfig): ServerBuilder

功能:设置 TLS 层配置,默认不对其进行设置。

参数:

  • config: TlsConfig - 设定支持 tls 服务所需要的配置信息。

返回值:

示例:

import stdx.net.http.*
import stdx.log.*

main() {
    // 默认不配置 TLS
    let server = ServerBuilder().addr("127.0.0.1").port(18116).logger(NoopLogger()).build()

    println("tlsConfig.isSome = ${server.getTlsConfig().isSome()}")

    server.closeGracefully()
}

运行结果:

tlsConfig.isSome = false

func transportConfig(TransportConfig)

public func transportConfig(config: TransportConfig): ServerBuilder

功能:设置传输层配置,默认配置详见 TransportConfig 结构体说明。

参数:

返回值:

示例:

import stdx.net.http.*
import stdx.log.*

main() {
    var cfg = TransportConfig()
    cfg.readBufferSize = 8192

    let server = ServerBuilder().addr("127.0.0.1").port(18115).logger(NoopLogger()).transportConfig(cfg).build()

    let rb = server.transportConfig.readBufferSize ?? 0
    println("transport.readBufferSize = ${rb}")

    server.closeGracefully()
}

运行结果:

transport.readBufferSize = 8192

func writeTimeout(Duration)

public func writeTimeout(timeout: Duration): ServerBuilder

功能:设定服务端发送一个响应的最大时长,超过该时长将不再进行写入并关闭连接,默认不进行限制。

参数:

  • timeout: Duration - 设定写响应的超时时间,如果传入时间为负值将被替换为 Duration.Zero。

返回值:

示例:

import stdx.net.http.*
import stdx.log.*

main() {
    let server = ServerBuilder()
        .addr("127.0.0.1")
        .port(18117)
        .logger(NoopLogger())
        // 关注点:这些配置最终体现在 Server 的 prop 上
        .readTimeout(Duration.second)
        .writeTimeout(Duration.second * 2)
        .readHeaderTimeout(Duration.millisecond * 300)
        .httpKeepAliveTimeout(Duration.second * 3)
        .build()

    println("readTimeout = ${server.readTimeout}")
    println("writeTimeout = ${server.writeTimeout}")
    println("readHeaderTimeout = ${server.readHeaderTimeout}")
    println("httpKeepAliveTimeout = ${server.httpKeepAliveTimeout}")

    server.closeGracefully()
}

运行结果:

readTimeout = 1s
writeTimeout = 2s
readHeaderTimeout = 300ms
httpKeepAliveTimeout = 3s

class WebSocket

public class WebSocket

功能:提供 WebSocket 服务的相关类,提供 WebSocket 连接的读、写、关闭等函数。用户通过 upgradeFrom 函数以获取 WebSocket 连接。

  • 调用 read() 读取一个 WebSocketFrame,用户可通过 WebSocketFrame.frameType 来知晓帧的类型,通过 WebSocketFrame.fin 来知晓是否是分段帧。
  • 调用 write(frameType: WebSocketFrameType, byteArray: Array<UInt8>),传入 message 的类型和 message 的 byte 来发送 WebSocket 信息,如果写的是控制帧,则不会分段发送,如果写的是数据帧(Text、Binary),则会将 message 按底层 buffer 的大小分段(分成多个 fragment)发送。

详细说明见下文接口说明,接口行为以 RFC 6455 为准。

prop logger

public prop logger: Logger

功能:日志记录器。

类型:Logger

prop subProtocol

public prop subProtocol: String

功能:获取与对端协商到的 subProtocol,协商时,客户端提供一个按偏好排名的 subProtocols 列表,服务器从中选取一个或零个子协议。

类型:String

static func upgradeFromClient(Client, URL, Protocol, ArrayList<String>, HttpHeaders)

public static func upgradeFromClient(client: Client, url: URL,
 version!: Protocol = HTTP1_1,
 subProtocols!: ArrayList<String> = ArrayList<String>(),
 headers!: HttpHeaders = HttpHeaders()): (WebSocket, HttpHeaders)

功能:提供客户端升级到 WebSocket 协议的函数。

说明:

客户端的升级流程为:传入 client 对象,url 对象,构建升级请求,请求服务器后验证其响应,如果握手成功,则返回 WebSocket 对象用于 WebSocket 通讯,并返回 101 响应头的 HttpHeaders 对象给用户。暂不支持 extensions。如果子协议协商成功,用户可通过调用返回的 WebSocket 的 subProtocol 查看子协议。

参数:

  • client: Client - 用于请求的 client 对象。
  • url: URL - 用于请求的 url 对象,WebSocket 升级时要注意 url 的 scheme 为 ws 或 wss。
  • version!: Protocol - 创建 socket 使用的 HTTP 版本,只支持 HTTP1_1HTTP2_0WebSocket 升级。
  • subProtocols!: ArrayList<String> - 用户配置的子协议列表,按偏好排名,默认为空。若用户配置了,则会随着升级请求发送给服务器。
  • headers!: HttpHeaders - 需要随着升级请求一同发送的非升级必要头,如 cookie 等。

返回值:

  • (WebSocket, HttpHeaders) - 升级成功,则返回 WebSocket 对象用于通讯和 101 响应的头。

异常:

  • SocketException - 底层连接错误时抛出异常。
  • HttpException - 握手时 HTTP 请求过程中出现错误时抛出异常。
  • WebSocketException - 升级失败,升级响应验证不通过时抛出异常。

示例:

import stdx.net.http.*
import stdx.log.*
import stdx.encoding.url.URL
import std.sync.*
import stdx.crypto.kit.DefaultCryptoKit

main() {
    let _ = DefaultCryptoKit()
    let sc = SyncCounter(1)
    let logger = NoopLogger()

    let server = ServerBuilder().addr("127.0.0.1").port(18170).logger(logger).afterBind({=> sc.dec()}).build()
    server.distributor.register(
        "/ws",
        FuncHandler(
            {
                ctx: HttpContext =>
                    let ws = WebSocket.upgradeFromServer(ctx)
                    // 当前属性:WebSocket.logger(可动态调整 level)
                    ws.logger.level = LogLevel.ERROR
                    println("ws.logger.level = ${ws.logger.level}")
                    ws.writeCloseFrame(status: 1000, reason: "bye")
                    ws.closeConn()
            }
        )
    )

    spawn {server.serve()}
    sc.waitUntilZero()

    let client = ClientBuilder().logger(logger).build()
    let (ws, hdr) = WebSocket.upgradeFromClient(client, URL.parse("ws://127.0.0.1:18170/ws"))
    let _ = hdr

    let _ = ws.read() // Close

    ws.closeConn()
    client.close()
    server.closeGracefully()
}

运行结果:

ws.logger.level = ERROR

static func upgradeFromServer(HttpContext, ArrayList<String>, ArrayList<String>, (HttpRequest) -> HttpHeaders)

public static func upgradeFromServer(ctx: HttpContext, subProtocols!: ArrayList<String> = ArrayList<String>(), 
                                        origins!: ArrayList<String> = ArrayList<String>(), 
                                        userFunc!:(HttpRequest) -> HttpHeaders = {_: HttpRequest => HttpHeaders()}): WebSocket

功能:提供服务端升级到 WebSocket 协议的函数,通常在 handler 中使用。

服务端升级的流程为:收到客户端发来的升级请求,验证请求,如果验证通过,则回复 101 响应并返回 WebSocket 对象用于 WebSocket 通讯。

  • 用户通过 subProtocols,origins 参数来配置其支持的 subprotocol 和 origin 白名单,subProtocols 如果不设置,则表示不支持子协议,origins 如果不设置,则表示接受所有 origin 的握手请求;
  • 用户通过 userFunc 来自定义处理升级请求的行为,如处理 cookie 等,传入的 userFunc 要求返回一个 HttpHeaders 对象,其会通过 101 响应回给客户端(升级失败的请求则不会);
  • 暂不支持 WebSocket 的 extensions,因此如果握手过程中出现 extensions 协商则会抛 WebSocketException
  • 只支持 HTTP1_1 和 HTTP2_0 向 WebSocket 升级。

参数:

  • ctx: HttpContext - Http 请求上下文,将传入给 handler 的直接传给 upgradeFromServer 即可。
  • subProtocols!: ArrayList<String> - 用户配置的子协议列表,默认值为空,表示不支持。如果用户配置了,则会选取升级请求中最靠前的作为升级后的 WebSocket 的子协议,用户可通过调用返回的 WebSocket 的 subProtocol 查看子协议。
  • origins!: ArrayList<String> - 用户配置的同意握手的 origin 的白名单,如果不配置,则同意来自所有 origin 的握手,如果配置了,则只接受来自配置 origin 的握手。
  • userFunc!: (HttpRequest) ->HttpHeaders - 用户配置的自定义处理升级请求的函数,该函数返回一个 HttpHeaders

返回值:

示例:

import stdx.net.http.*
import stdx.log.*
import stdx.encoding.url.URL
import std.sync.*
import stdx.crypto.kit.DefaultCryptoKit

main() {
    let _ = DefaultCryptoKit()
    let sc = SyncCounter(1)
    let logger = NoopLogger()

    let server = ServerBuilder().addr("127.0.0.1").port(18170).logger(logger).afterBind({=> sc.dec()}).build()
    server.distributor.register(
        "/ws",
        FuncHandler(
            {
                ctx: HttpContext =>
                    let ws = WebSocket.upgradeFromServer(ctx)
                    // 当前属性:WebSocket.logger(可动态调整 level)
                    ws.logger.level = LogLevel.ERROR
                    println("ws.logger.level = ${ws.logger.level}")
                    ws.writeCloseFrame(status: 1000, reason: "bye")
                    ws.closeConn()
            }
        )
    )

    spawn {server.serve()}
    sc.waitUntilZero()

    let client = ClientBuilder().logger(logger).build()
    let (ws, hdr) = WebSocket.upgradeFromClient(client, URL.parse("ws://127.0.0.1:18170/ws"))
    let _ = hdr

    let _ = ws.read() // Close

    ws.closeConn()
    client.close()
    server.closeGracefully()
}

运行结果:

ws.logger.level = ERROR

func closeConn()

public func closeConn(): Unit

功能:提供关闭底层 WebSocket 连接的函数。

说明:

直接关闭底层连接。正常的关闭流程需要遵循协议规定的握手流程,即先发送 Close 帧给对端,并等待对端回应的 Close 帧。握手流程结束后方可关闭底层连接。

示例:

import stdx.net.http.*
import stdx.log.*
import stdx.encoding.url.URL
import std.sync.*
import stdx.crypto.kit.DefaultCryptoKit

main() {
    // 触发 DefaultCryptoKit.static init(设置全局 crypto kit),供 WebSocket 握手生成随机 key/sha1 使用
    let _ = DefaultCryptoKit()

    let sc = SyncCounter(1)
    let logger = NoopLogger()

    let server = ServerBuilder().addr("127.0.0.1").port(18172).logger(logger).afterBind({=> sc.dec()}).build()

    server.distributor.register(
        "/ws",
        FuncHandler(
            {
                ctx: HttpContext =>
                    let ws = WebSocket.upgradeFromServer(ctx)
                    ws.writeCloseFrame(status: 1000, reason: "bye")
                    ws.closeConn()
                    println("server closed")
            }
        )
    )

    spawn {server.serve()}
    sc.waitUntilZero()

    let client = ClientBuilder().logger(logger).build()
    let (ws, hdr) = WebSocket.upgradeFromClient(client, URL.parse("ws://127.0.0.1:18172/ws"))
    let _ = hdr

    println("client before close")
    let _ = ws.read()
    ws.closeConn()
    println("client closed")
    client.close();
    server.closeGracefully();
    return ws.closeConn()
    client.close()
    server.closeGracefully()
}

运行结果:

server closed
client before close
client closed

func read()

public func read(): WebSocketFrame

功能:从连接中读取一个帧,如果连接上数据未就绪会阻塞,非线程安全(即对同一个 WebSocket 对象不支持多线程读)。

read 函数返回一个 WebSocketFrame 对象,用户可以调用 WebSocketFrame 的 frameType,fin 属性确定其帧类型和是否是分段帧调用。通过 WebSocketFrame 的 payload 函数得到原始二进制数据数组:Array<UInt8>

  • 分段帧的首帧为 fin == false,frameType == TextWebFrame 或 BinaryWebFrame 中间帧 fin == false,frameType == ContinuationWebFrame 尾帧 fin == true, frameType == ContinuationWebFrame;
  • 非分段帧为 fin == true, frameType != ContinuationWebFrame。

注意:

  • 数据帧(Text,Binary)可以分段,用户需要多次调用 read 将所有分段帧读完(以下称为接收到完整的 message),再将分段帧的 payload 按接收序拼接 Text 帧的 payload 为 UTF-8 编码,用户在接收到完整的 message 后,调用 String.fromUtf8 函数将拼接后的 payload 转成字符串 Binary 帧的 payload 的意义由使用其的应用确定,用户在接收到完整的 message 后,将拼接后的 payload 传给上层应用;
  • 控制帧(Close,Ping,Pong)不可分段;
  • 控制帧本身不可分段,但其可以穿插在分段的数据帧之间。分段的数据帧之间不可出现其他数据帧,如果用户收到穿插的分段数据帧,则需要当作错误处理;
  • 客户端收到 masked 帧,服务器收到 unmasked 帧,断开底层连接并抛出异常;
  • rsv1、rsv2、rsv3 位被设置(暂不支持 extensions,因此 rsv 位必须为 0),断开底层连接并抛出异常;
  • 收到无法理解的帧类型(只支持 Continuation,Text,Binary,Close,Ping,Pong),断开底层连接并抛出异常;
  • 收到分段或 payload 长度大于 125 bytes 的控制帧(Close,Ping,Pong),断开底层连接并抛出异常;
  • 收到 payload 长度大于 20M 的帧,断开底层连接并抛出异常;
  • closeConn 关闭连接后继续调用读,抛出异常。

返回值:

异常:

  • SocketException - 底层连接错误。
  • WebSocketException - 收到不符合协议规定的帧,此时会给对端发送 Close 帧说明错误信息,并断开底层连接。
  • ConnectionException - 从连接中读数据时对端已关闭连接抛此异常。

示例:

import stdx.net.http.*
import stdx.log.*
import stdx.encoding.url.URL
import std.sync.*
import stdx.crypto.kit.DefaultCryptoKit

main() {
    // 触发 DefaultCryptoKit.static init(设置全局 crypto kit),供 WebSocket 握手生成随机 key/sha1 使用
    let _ = DefaultCryptoKit()

    let sc = SyncCounter(1)
    let logger = NoopLogger()

    let server = ServerBuilder().addr("127.0.0.1").port(18173).logger(logger).afterBind({=> sc.dec()}).build()

    server.distributor.register(
        "/ws",
        FuncHandler(
            {
                ctx: HttpContext =>
                    let ws = WebSocket.upgradeFromServer(ctx)
                    ws.write(TextWebFrame, "pong".toArray())
                    ws.writeCloseFrame(status: 1000, reason: "bye")
            }
        )
    )

    spawn {server.serve()}
    sc.waitUntilZero()

    let client = ClientBuilder().logger(logger).build()
    let (ws, hdr) = WebSocket.upgradeFromClient(client, URL.parse("ws://127.0.0.1:18173/ws"))
    let _ = hdr

    let f1 = ws.read()
    // 当前函数:WebSocket.read()
    println("read type=${f1.frameType}, payload=${String.fromUtf8(f1.payload)}")
    let _ = ws.read()

    ws.closeConn()
    client.close()
    server.closeGracefully()
}

运行结果:

read type=TextWebFrame, payload=pong

func write(WebSocketFrameType, Array<UInt8>, Int64)

public func write(frameType: WebSocketFrameType, byteArray: Array<UInt8>, frameSize!: Int64 = 4096): Unit

功能:发送数据,非线程安全(即对同一个 WebSocket 对象不支持多线程写)。

注意:

write 函数将数据以 WebSocket 帧的形式发送给对端;

  • 如果发送数据帧(Text,Binary),传入的 byteArray 如果大于 frameSize(默认 4 * 1024 bytes),我们会将其分成小于等于 frameSize 的 payload 以分段帧的形式发送,否则不分段;
  • 如果发送控制帧(Close,Ping,Pong),传入的 byteArray 的大小需要小于等于 125 bytes,Close 帧的前两个字节为状态码,可用的状态码见 RFC 6455 7.4. Status Codes 协议规定,Close 帧发送之后,禁止再发送数据帧,如果发送则会抛出异常;
  • 用户需要自己保证其传入的 byteArray 符合协议,如 Text 帧的 payload 需要是 UTF-8 编码,如果数据帧设置了 frameSize,那么需要大于 0,否则抛出异常;
  • 发送数据帧时,frameSize 小于等于 0,抛出异常;
  • 用户发送控制帧时,传入的数据大于 125 bytes,抛出异常;
  • 用户传入非 Text,Binary,Close,Ping,Pong 类型的帧类型,抛出异常;
  • 发送 Close 帧时传入非法的状态码,或 reason 数据超过 123 bytes,抛出异常;
  • 发送完 Close 帧后继续发送数据帧,抛出异常;
  • closeConn 关闭连接后调用写,抛出异常。

参数:

  • frameType: WebSocketFrameType - 所需发送的帧的类型。
  • byteArray: Array<UInt8> - 所需发送的帧的 payload(二进制形式)。
  • frameSize!: Int64 - 分段帧的大小,默认为 4 * 1024 bytes,frameSize 不会对控制帧生效(控制帧设置了无效)。

异常:

  • SocketException - 底层连接错误时抛出异常。
  • WebSocketException - 传入非法的帧类型,或者数据时抛出异常。

示例:

import stdx.net.http.*
import stdx.log.*
import stdx.encoding.url.URL
import std.sync.*
import stdx.crypto.kit.DefaultCryptoKit

main() {
    // 触发 DefaultCryptoKit.static init(设置全局 crypto kit),供 WebSocket 握手生成随机 key/sha1 使用
    let _ = DefaultCryptoKit()

    let sc = SyncCounter(1)
    let logger = NoopLogger()

    let server = ServerBuilder().addr("127.0.0.1").port(18174).logger(logger).afterBind({=> sc.dec()}).build()

    server.distributor.register(
        "/ws",
        FuncHandler(
            {
                ctx: HttpContext =>
                    let ws = WebSocket.upgradeFromServer(ctx)
                    let f = ws.read()
                    // 当前函数:WebSocket.write(...)
                    println("server got ${String.fromUtf8(f.payload)}")
                    ws.write(TextWebFrame, "ack".toArray())
                    ws.writeCloseFrame(status: 1000, reason: "bye")
            }
        )
    )

    spawn {server.serve()}
    sc.waitUntilZero()

    let client = ClientBuilder().logger(logger).build()
    let (ws, hdr) = WebSocket.upgradeFromClient(client, URL.parse("ws://127.0.0.1:18174/ws"))
    let _ = hdr

    ws.write(TextWebFrame, "hello".toArray())
    let f1 = ws.read()
    println("client got ${String.fromUtf8(f1.payload)}")
    let _ = ws.read()

    ws.closeConn()
    client.close()
    server.closeGracefully()
}

运行结果:

server got hello
client got ack

func writeCloseFrame(?UInt16, String)

public func writeCloseFrame(status!: ?UInt16 = None, reason!: String = ""): Unit

功能:发送 Close 帧。

注意:

协议规定,Close 帧发送之后,禁止再发送数据帧。如果用户不设置 status,那么 reason 不会被发送(即有 reason 必有 status);控制帧的 payload 不超过 125 bytes,Close 帧的前两个 bytes 为 status,因此 reason 不能超过 123 bytes,closeConn 关闭连接后调用写,抛出异常。

参数:

  • status!: ?UInt16 - 发送的 Close 帧的状态码,默认为 None,表示不发送状态码和 reason。
  • reason!: String - 关闭连接的说明,默认为空字符串,发送时会转成 UTF-8,不保证可读,debug 用。

异常:

  • WebSocketException - 传入非法的状态码,或 reason 数据超过 123 bytes 时抛出异常。

示例:

import stdx.net.http.*
import stdx.log.*
import stdx.encoding.url.URL
import std.sync.*
import stdx.crypto.kit.DefaultCryptoKit

main() {
    // 触发 DefaultCryptoKit.static init(设置全局 crypto kit),供 WebSocket 握手生成随机 key/sha1 使用
    let _ = DefaultCryptoKit()

    let sc = SyncCounter(1)
    let logger = NoopLogger()

    let server = ServerBuilder().addr("127.0.0.1").port(18175).logger(logger).afterBind({=> sc.dec()}).build()

    server.distributor.register(
        "/ws",
        FuncHandler(
            {
                ctx: HttpContext =>
                    let ws = WebSocket.upgradeFromServer(ctx)
                    ws.writeCloseFrame(status: 1000, reason: "bye")
            }
        )
    )

    spawn {server.serve()}
    sc.waitUntilZero()

    let client = ClientBuilder().logger(logger).build()
    let (ws, hdr) = WebSocket.upgradeFromClient(client, URL.parse("ws://127.0.0.1:18175/ws"))
    let _ = hdr

    let f = ws.read()
    // 当前函数:WebSocket.writeCloseFrame(status, reason)
    println("close frameType=${f.frameType}")

    ws.closeConn()
    client.close()
    server.closeGracefully()
}

运行结果:

close frameType=CloseWebFrame

func writePingFrame(Array<UInt8>)

public func writePingFrame(byteArray: Array<UInt8>): Unit

功能:提供发送 Ping 帧的快捷函数,closeConn 关闭连接后调用写,抛出异常。

参数:

  • byteArray: Array<UInt8> - 所需发送的帧的 payload(二进制形式)。

异常:

  • SocketException - 底层连接错误时抛出异常。
  • WebSocketException - 传入的数据大于 125 bytes,抛出异常。

示例:

import stdx.net.http.*
import stdx.log.*
import stdx.encoding.url.URL
import std.sync.*
import stdx.crypto.kit.DefaultCryptoKit

main() {
    // 触发 DefaultCryptoKit.static init(设置全局 crypto kit),供 WebSocket 握手生成随机 key/sha1 使用
    let _ = DefaultCryptoKit()

    let sc = SyncCounter(1)
    let logger = NoopLogger()

    let server = ServerBuilder().addr("127.0.0.1").port(18176).logger(logger).afterBind({=> sc.dec()}).build()

    server.distributor.register(
        "/ws",
        FuncHandler(
            {
                ctx: HttpContext =>
                    let ws = WebSocket.upgradeFromServer(ctx)
                    let f = ws.read()
                    println("server got ping payload=${String.fromUtf8(f.payload)}")
                    ws.writePongFrame("pong".toArray())
                    ws.writeCloseFrame(status: 1000, reason: "bye")
            }
        )
    )

    spawn {server.serve()}
    sc.waitUntilZero()

    let client = ClientBuilder().logger(logger).build()
    let (ws, hdr) = WebSocket.upgradeFromClient(client, URL.parse("ws://127.0.0.1:18176/ws"))
    let _ = hdr

    ws.writePingFrame("ping".toArray())
    let f1 = ws.read()
    println("client got ${f1.frameType}")
    let _ = ws.read()

    ws.closeConn()
    client.close()
    server.closeGracefully()
}

运行结果:

server got ping payload=ping
client got PongWebFrame

func writePongFrame(Array<UInt8>)

public func writePongFrame(byteArray: Array<UInt8>): Unit

功能:提供发送 Pong 帧的快捷函数,closeConn 关闭连接后调用写,抛出异常。

参数:

  • byteArray: Array<UInt8> - 所需发送的帧的 payload(二进制形式)。

异常:

  • SocketException - 底层连接错误时抛出异常。
  • WebSocketException - 传入的数据大于 125 bytes,抛出异常。

示例:

import stdx.net.http.*
import stdx.log.*
import stdx.encoding.url.URL
import std.sync.*
import stdx.crypto.kit.DefaultCryptoKit

main() {
    // 触发 DefaultCryptoKit.static init(设置全局 crypto kit),供 WebSocket 握手生成随机 key/sha1 使用
    let _ = DefaultCryptoKit()

    let sc = SyncCounter(1)
    let logger = NoopLogger()

    let server = ServerBuilder().addr("127.0.0.1").port(18177).logger(logger).afterBind({=> sc.dec()}).build()

    server.distributor.register(
        "/ws",
        FuncHandler(
            {
                ctx: HttpContext =>
                    let ws = WebSocket.upgradeFromServer(ctx)
                    let f = ws.read()
                    println("server got ${f.frameType}")
                    ws.writePongFrame("pong".toArray())
                    ws.writeCloseFrame(status: 1000, reason: "bye")
            }
        )
    )

    spawn {server.serve()}
    sc.waitUntilZero()

    let client = ClientBuilder().logger(logger).build()
    let (ws, hdr) = WebSocket.upgradeFromClient(client, URL.parse("ws://127.0.0.1:18177/ws"))
    let _ = hdr

    ws.writePingFrame("ping".toArray())
    let f1 = ws.read()
    // 当前函数:WebSocket.writePongFrame(...)
    println("client got pong payload=${String.fromUtf8(f1.payload)}")
    let _ = ws.read()

    ws.closeConn()
    client.close()
    server.closeGracefully()
}

运行结果:

server got PingWebFrame
client got pong payload=pong

class WebSocketFrame

public class WebSocketFrame

功能:WebSocket 用于读的基本单元。

WebSocketFrame 提供了三个属性,其中 fin 和 frameType 共同说明了帧是否分段和帧的类型。payload 为帧的载荷。

  • 分段帧的首帧为 fin == false,frameType == TextWebFrame 或 BinaryWebFrame;
  • 中间帧 fin == false,frameType == ContinuationWebFrame;
  • 尾帧 fin == true, frameType == ContinuationWebFrame;
  • 非分段帧为 fin == true, frameType != ContinuationWebFrame;
  • 用户仅能通过 WebSocket 对象的 read 函数得到 WebSocketFrame。数据帧可分段,如果用户收到分段帧,则需要多次调用 read 函数直到收到完整的 message,并将所有分段的 payload 按接收顺序拼接。

注意:

由于控制帧可以穿插在分段帧之间,用户在拼接分段帧的 payload 时需要单独处理控制帧。分段帧之间仅可穿插控制帧,如果用户在分段帧之间接收到其他数据帧,则需要当作错误处理。

prop fin

public prop fin: Bool

功能:获取 WebSocketFrame 的 fin 属性,fin 与 frameType 共同说明了帧是否分段和帧的类型。

类型:Bool

prop frameType

public prop frameType: WebSocketFrameType

功能:获取 WebSocketFrame 的帧类型,fin 与 frameType 共同说明了帧是否分段和帧的类型。

类型:WebSocketFrameType

prop payload

public prop payload: Array<UInt8>

功能:获取 WebSocketFrame 的帧载荷。如果是分段数据帧,用户需要在接收到完整的 message 后,将所有分段的 payload 按接收序拼接。

类型:Array<UInt8>

枚举

enum FileHandlerType

public enum FileHandlerType {
    | DownLoad
    | UpLoad
}

功能:用于设置 FileHandler 是上传还是下载模式。

DownLoad

DownLoad

功能:设置 FileHandler 为下载模式。

UpLoad

UpLoad

功能:设置 FileHandler 为上传模式。

enum Protocol

public enum Protocol <: Equatable<Protocol> & ToString {
    | HTTP1_0
    | HTTP1_1
    | HTTP2_0
    | UnknownProtocol(String)
}

功能:定义 HTTP 协议类型枚举。

父类型:

HTTP1_0

HTTP1_0

功能:定义 1.0 版本 HTTP 协议。

HTTP1_1

HTTP1_1

功能:定义 1.1 版本 HTTP 协议。

HTTP2_0

HTTP2_0

功能:定义 2.0 版本 HTTP 协议。

UnknownProtocol(String)

UnknownProtocol(String)

功能:定义未知 HTTP 协议。

func toString()

public override func toString(): String

功能:获取 Http 协议版本字符串。

返回值:

  • String - Http 协议版本字符串。

示例:

import stdx.net.http.*

main() {
    let protocol = Protocol.HTTP1_1
    let protocolStr = protocol.toString()
    println("协议版本字符串: ${protocolStr}")
    return 0
}

运行结果:

协议版本字符串: HTTP/1.1

operator func != (Protocol)

public override operator func !=(that: Protocol): Bool

功能:判断枚举值是否不相等。

参数:

  • that: Protocol - 被比较的枚举值。

返回值:

  • Bool - 当前实例与 that 不等,返回 true;否则返回 false

示例:

import stdx.net.http.*

main() {
    let protocol1 = Protocol.HTTP1_1
    let protocol2 = Protocol.HTTP2_0
    let isNotEqual = protocol1 != protocol2
    println("协议是否不相等: ${isNotEqual}")
    return 0
}

运行结果:

协议是否不相等: true

operator func == (Protocol)

public override operator func ==(that: Protocol): Bool

功能:判断枚举值是否相等。

参数:

  • that: Protocol - 被比较的枚举值。

返回值:

  • Bool - 当前实例与 that 相等,返回 true;否则返回 false

示例:

import stdx.net.http.*

main() {
    let protocol1 = Protocol.HTTP1_1
    let protocol2 = Protocol.HTTP1_1
    let isEqual = protocol1 == protocol2
    println("协议是否相等: ${isEqual}")
    return 0
}

运行结果:

协议是否相等: true

enum WebSocketFrameType

public enum WebSocketFrameType <: Equatable<WebSocketFrameType> & ToString {
    | ContinuationWebFrame
    | TextWebFrame
    | BinaryWebFrame
    | CloseWebFrame
    | PingWebFrame
    | PongWebFrame
    | UnknownWebFrame
}

功能:定义 WebSocketFrame 的枚举类型。

父类型:

BinaryWebFrame

BinaryWebFrame

功能:定义 websocket 协议中的数据帧。

CloseWebFrame

CloseWebFrame

功能:定义 websocket 协议中的关闭帧。

ContinuationWebFrame

ContinuationWebFrame

功能:定义 websocket 协议中的未结束的分片帧。

PingWebFrame

PingWebFrame

功能:定义 websocket 协议中的心跳帧。

PongWebFrame

PongWebFrame

功能:定义 websocket 协议中的心跳帧。

TextWebFrame

TextWebFrame

功能:定义 websocket 协议中的文本帧。

UnknownWebFrame

UnknownWebFrame

功能:定义 websocket 协议中的未知类型帧。

func toString()

public override func toString(): String

功能:获取 WebSocket 帧类型字符串。

返回值:

示例:

import stdx.net.http.*

main() {
    let frameType = WebSocketFrameType.TextWebFrame
    let frameTypeStr = frameType.toString()
    println("WebSocket帧类型字符串: ${frameTypeStr}")
    return 0
}

运行结果:

WebSocket帧类型字符串: TextWebFrame

operator func != (WebSocketFrameType)

public override operator func !=(that: WebSocketFrameType): Bool

功能:判断枚举值是否不相等。

参数:

返回值:

  • Bool - 当前实例与 that 不等返回 true,否则返回 false

示例:

import stdx.net.http.*

main() {
    let frameType1 = WebSocketFrameType.TextWebFrame
    let frameType2 = WebSocketFrameType.BinaryWebFrame
    let isNotEqual = frameType1 != frameType2
    println("WebSocket帧类型是否不相等: ${isNotEqual}")
    return 0
}

运行结果:

WebSocket帧类型是否不相等: true

operator func == (WebSocketFrameType)

public override operator func ==(that: WebSocketFrameType): Bool

功能:判断枚举值是否相等。

参数:

返回值:

  • Bool - 当前实例与 that 相等返回 true,否则返回 false

示例:

import stdx.net.http.*

main() {
    let frameType1 = WebSocketFrameType.TextWebFrame
    let frameType2 = WebSocketFrameType.TextWebFrame
    let isEqual = frameType1 == frameType2
    println("WebSocket帧类型是否相等: ${isEqual}")
    return 0
}

运行结果:

WebSocket帧类型是否相等: true

结构体

struct HttpStatusCode

public struct HttpStatusCode {
    public static const STATUS_CONTINUE: UInt16 =                        100
    public static const STATUS_SWITCHING_PROTOCOLS: UInt16 =             101
    public static const STATUS_PROCESSING: UInt16 =                      102
    public static const STATUS_EARLY_HINTS: UInt16 =                     103
 
    public static const STATUS_OK: UInt16 =                              200
    public static const STATUS_CREATED: UInt16 =                         201
    public static const STATUS_ACCEPTED: UInt16 =                        202
    public static const STATUS_NON_AUTHORITATIVE_INFO: UInt16 =          203
    public static const STATUS_NO_CONTENT: UInt16 =                      204
    public static const STATUS_RESET_CONTENT: UInt16 =                   205
    public static const STATUS_PARTIAL_CONTENT: UInt16 =                 206
    public static const STATUS_MULTI_STATUS: UInt16 =                    207
    public static const STATUS_ALREADY_REPORTED: UInt16 =                208
    public static const STATUS_IM_USED: UInt16 =                         226
 
    public static const STATUS_MULTIPLE_CHOICES: UInt16 =                300
    public static const STATUS_MOVED_PERMANENTLY: UInt16 =               301
    public static const STATUS_FOUND: UInt16 =                           302
    public static const STATUS_SEE_OTHER: UInt16 =                       303
    public static const STATUS_NOT_MODIFIED: UInt16 =                    304
    public static const STATUS_USE_PROXY: UInt16 =                       305
    public static const STATUS_TEMPORARY_REDIRECT: UInt16 =              307
    public static const STATUS_PERMANENT_REDIRECT: UInt16 =              308
 
    public static const STATUS_BAD_REQUEST: UInt16 =                     400
    public static const STATUS_UNAUTHORIZED: UInt16 =                    401
    public static const STATUS_PAYMENT_REQUIRED: UInt16 =                402
    public static const STATUS_FORBIDDEN: UInt16 =                       403
    public static const STATUS_NOT_FOUND: UInt16 =                       404
    public static const STATUS_METHOD_NOT_ALLOWED: UInt16 =              405
    public static const STATUS_NOT_ACCEPTABLE: UInt16 =                  406
    public static const STATUS_PROXY_AUTH_REQUIRED: UInt16 =             407
    public static const STATUS_REQUEST_TIMEOUT: UInt16 =                 408
    public static const STATUS_CONFLICT: UInt16 =                        409
    public static const STATUS_GONE: UInt16 =                            410
    public static const STATUS_LENGTH_REQUIRED: UInt16 =                 411
    public static const STATUS_PRECONDITION_FAILED: UInt16 =             412
    public static const STATUS_REQUEST_CONTENT_TOO_LARGE: UInt16 =       413
    public static const STATUS_REQUEST_URI_TOO_LONG: UInt16 =            414
    public static const STATUS_UNSUPPORTED_MEDIA_TYPE: UInt16 =          415
    public static const STATUS_REQUESTED_RANGE_NOT_SATISFIABLE: UInt16 = 416
    public static const STATUS_EXPECTATION_FAILED: UInt16 =              417
    public static const STATUS_TEAPOT: UInt16 =                          418
    public static const STATUS_MISDIRECTED_REQUEST: UInt16 =             421
    public static const STATUS_UNPROCESSABLE_ENTITY: UInt16 =            422
    public static const STATUS_LOCKED: UInt16 =                          423
    public static const STATUS_FAILED_DEPENDENCY: UInt16 =               424
    public static const STATUS_TOO_EARLY: UInt16 =                       425
    public static const STATUS_UPGRADE_REQUIRED: UInt16 =                426
    public static const STATUS_PRECONDITION_REQUIRED: UInt16 =           428
    public static const STATUS_TOO_MANY_REQUESTS: UInt16 =               429
    public static const STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE: UInt16 = 431
    public static const STATUS_UNAVAILABLE_FOR_LEGAL_REASONS: UInt16 =   451
 
    public static const STATUS_INTERNAL_SERVER_ERROR: UInt16 =           500
    public static const STATUS_NOT_IMPLEMENTED: UInt16 =                 501
    public static const STATUS_BAD_GATEWAY: UInt16 =                     502
    public static const STATUS_SERVICE_UNAVAILABLE: UInt16 =             503
    public static const STATUS_GATEWAY_TIMEOUT: UInt16 =                 504
    public static const STATUS_HTTP_VERSION_NOT_SUPPORTED: UInt16 =      505
    public static const STATUS_VARIANT_ALSO_NEGOTIATES: UInt16 =         506
    public static const STATUS_INSUFFICIENT_STORAGE: UInt16 =            507
    public static const STATUS_LOOP_DETECTED: UInt16 =                   508
    public static const STATUS_NOT_EXTENDED: UInt16 =                    510
    public static const STATUS_NETWORK_AUTHENTICATION_REQUIRED: UInt16 = 511
}

功能:用来表示网页服务器超文本传输协议响应状态的 3 位数字代码。

状态码由 RFC 9110 规范定义,并得到 RFC2518、RFC 3229、RFC 4918、RFC 5842、RFC 7168 与 RFC 8297 等规范扩展。

所有状态码的第一个数字代表了响应的五种状态之一:

  • 状态代码的 1xx(信息)指示在完成请求的操作并发送最终响应之前通信连接状态或请求进度的临时响应。
  • 状态代码的 2xx(成功)指示客户端的请求已成功接收、理解和接受。
  • 状态代码的 3xx(重定向)指示用户代理需要采取进一步的操作才能完成请求。
  • 状态代码的 4xx(客户端错误)指示客户端似乎出错。
  • 状态代码的 5xx(服务器错误)指示服务器意识到它出错或无法执行请求的方法。

static const STATUS_ACCEPTED

public static const STATUS_ACCEPTED: UInt16 = 202

功能:服务器已接受请求,但尚未处理。

类型:UInt16

static const STATUS_ALREADY_REPORTED

public static const STATUS_ALREADY_REPORTED: UInt16 = 208

功能:消息体将是一个 XML 消息。

类型:UInt16

static const STATUS_BAD_GATEWAY

public static const STATUS_BAD_GATEWAY: UInt16 = 502

功能:作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。

类型:UInt16

static const STATUS_BAD_REQUEST

public static const STATUS_BAD_REQUEST: UInt16 = 400

功能:语义有误,当前请求无法被服务器理解;或请求参数有误。

类型:UInt16

static const STATUS_CONFLICT

public static const STATUS_CONFLICT: UInt16 = 409

功能:由于和被请求的资源的当前状态之间存在冲突,请求无法完成。

类型:UInt16

static const STATUS_CONTINUE

public static const STATUS_CONTINUE: UInt16 = 100

功能:这个临时响应是用来通知客户端它的部分请求已经被服务器接收,且仍未被拒绝。

类型:UInt16

说明:

客户端应当继续发送请求的剩余部分,或者如果请求已经完成,忽略这个响应。 服务器必须在请求完成后向客户端发送一个最终响应。

static const STATUS_CREATED

public static const STATUS_CREATED: UInt16 = 201

功能:请求已经被实现,而且有一个新的资源已经依据请求的需要而建立,且其 URI 已经随 Location 头信息返回。

类型:UInt16

static const STATUS_EARLY_HINTS

public static const STATUS_EARLY_HINTS: UInt16 = 103

功能:提前预加载 (css、js) 文档。

类型:UInt16

static const STATUS_EXPECTATION_FAILED

public static const STATUS_EXPECTATION_FAILED: UInt16 = 417

功能:服务器无法满足 Expect 的请求头信息。

类型:UInt16

static const STATUS_FAILED_DEPENDENCY

public static const STATUS_FAILED_DEPENDENCY: UInt16 = 424

功能:由于之前的某个请求发生的错误,导致当前请求失败。

类型:UInt16

static const STATUS_FORBIDDEN

public static const STATUS_FORBIDDEN: UInt16 = 403

功能:服务器已经理解请求,但是拒绝执行。

类型:UInt16

static const STATUS_FOUND

public static const STATUS_FOUND: UInt16 = 302

功能:临时移动。

类型:UInt16

说明:

请求的资源已被临时的移动到新 URI,客户端应当继续向原有地址发送以后的请求。

static const STATUS_GATEWAY_TIMEOUT

public static const STATUS_GATEWAY_TIMEOUT: UInt16 = 504

功能:从上游服务器(URI 标识出的服务器,例如 HTTP、FTP、LDAP)或者辅助服务器(例如 DNS)收到响应超时。

类型:UInt16

static const STATUS_GONE

public static const STATUS_GONE: UInt16 = 410

功能:被请求的资源在服务器上已经不再可用,而且没有任何已知的转发地址。

类型:UInt16

static const STATUS_HTTP_VERSION_NOT_SUPPORTED

public static const STATUS_HTTP_VERSION_NOT_SUPPORTED: UInt16 = 505

功能:服务器不支持,或者拒绝支持在请求中使用的 HTTP 版本。

类型:UInt16

static const STATUS_IM_USED

public static const STATUS_IM_USED: UInt16 = 226

功能:服务器已完成对资源的请求,并且响应是应用于当前实例的一个或多个实例操作的结果的表示。

类型:UInt16

static const STATUS_INSUFFICIENT_STORAGE

public static const STATUS_INSUFFICIENT_STORAGE: UInt16 = 507

功能:服务器无法存储完成请求所必须的内容。

类型:UInt16

static const STATUS_INTERNAL_SERVER_ERROR

public static const STATUS_INTERNAL_SERVER_ERROR: UInt16 = 500

功能:服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。

类型:UInt16

static const STATUS_LENGTH_REQUIRED

public static const STATUS_LENGTH_REQUIRED: UInt16 = 411

功能:服务器拒绝在没有定义 Content-Length 头的情况下接受请求。

类型:UInt16

static const STATUS_LOCKED

public static const STATUS_LOCKED: UInt16 = 423

功能:当前资源被锁定。

类型:UInt16

static const STATUS_LOOP_DETECTED

public static const STATUS_LOOP_DETECTED: UInt16 = 508

功能:服务器在处理请求时检测到无限递归。

类型:UInt16

static const STATUS_METHOD_NOT_ALLOWED

public static const STATUS_METHOD_NOT_ALLOWED: UInt16 = 405

功能:请求行中指定的请求函数不能被用于请求响应的资源。

类型:UInt16

static const STATUS_MISDIRECTED_REQUEST

public static const STATUS_MISDIRECTED_REQUEST: UInt16 = 421

功能:请求被指向到无法生成响应的服务器。

类型:UInt16

static const STATUS_MOVED_PERMANENTLY

public static const STATUS_MOVED_PERMANENTLY: UInt16 = 301

功能:永久移动。

类型:UInt16

说明:

请求的资源已被永久的移动到新 URI,返回信息会包括新的 URI,浏览器会自动定向到新 URI。

static const STATUS_MULTI_STATUS

public static const STATUS_MULTI_STATUS: UInt16 = 207

功能:DAV 绑定的成员已经在(多状态)响应之前的部分被列举,且未被再次包含。

类型:UInt16

static const STATUS_MULTIPLE_CHOICES

public static const STATUS_MULTIPLE_CHOICES: UInt16 = 300

功能:被请求的资源有一系列可供选择的回馈信息,每个都有自己特定的地址和浏览器驱动的商议信息。

类型:UInt16

说明:

用户或浏览器能够自行选择一个首选的地址进行重定向。

static const STATUS_NETWORK_AUTHENTICATION_REQUIRED

public static const STATUS_NETWORK_AUTHENTICATION_REQUIRED: UInt16 = 511

功能:要求网络认证。

类型:UInt16

static const STATUS_NO_CONTENT

public static const STATUS_NO_CONTENT: UInt16 = 204

功能:服务器成功处理,但未返回内容。

类型:UInt16

static const STATUS_NON_AUTHORITATIVE_INFO

public static const STATUS_NON_AUTHORITATIVE_INFO: UInt16 = 203

功能:服务器已成功处理了请求。

类型:UInt16

说明:

返回的实体头部元信息不是在原始服务器上有效的确定集合,而是来自本地或者第三方的拷贝。

static const STATUS_NOT_ACCEPTABLE

public static const STATUS_NOT_ACCEPTABLE: UInt16 = 406

功能:请求的资源的内容特性无法满足请求头中的条件,因而无法生成响应实体。

类型:UInt16

static const STATUS_NOT_EXTENDED

public static const STATUS_NOT_EXTENDED: UInt16 = 510

功能:获取资源所需要的策略并没有被满足。

类型:UInt16

static const STATUS_NOT_FOUND

public static const STATUS_NOT_FOUND: UInt16 = 404

功能:请求失败,请求所希望得到的资源未被在服务器上发现。

类型:UInt16

static const STATUS_NOT_IMPLEMENTED

public static const STATUS_NOT_IMPLEMENTED: UInt16 = 501

功能:服务器不支持当前请求所需要的某个功能。

类型:UInt16

static const STATUS_NOT_MODIFIED

public static const STATUS_NOT_MODIFIED: UInt16 = 304

功能:请求的资源未修改,服务器返回此状态码时,不会返回任何资源。

类型:UInt16

说明:

客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源。

static const STATUS_OK

public static const STATUS_OK: UInt16 = 200

功能:请求已经成功,请求所希望的响应头或数据体将随此响应返回。

类型:UInt16

static const STATUS_PARTIAL_CONTENT

public static const STATUS_PARTIAL_CONTENT: UInt16 = 206

功能:服务器已经成功处理了部分 GET 请求。

类型:UInt16

static const STATUS_PAYMENT_REQUIRED

public static const STATUS_PAYMENT_REQUIRED: UInt16 = 402

功能:为了将来可能的需求而预留的状态码。

类型:UInt16

static const STATUS_PERMANENT_REDIRECT

public static const STATUS_PERMANENT_REDIRECT: UInt16 = 308

功能:请求和所有将来的请求应该使用另一个 URI。

类型:UInt16

static const STATUS_PRECONDITION_FAILED

public static const STATUS_PRECONDITION_FAILED: UInt16 = 412

功能:服务器在验证在请求的头字段中给出先决条件时,没能满足其中的一个或多个。

类型:UInt16

static const STATUS_PRECONDITION_REQUIRED

public static const STATUS_PRECONDITION_REQUIRED: UInt16 = 428

功能:客户端发送 HTTP 请求时,必须要满足的一些预设条件。

类型:UInt16

static const STATUS_PROCESSING

public static const STATUS_PROCESSING: UInt16 = 102

功能:处理将被继续执行。

类型:UInt16

static const STATUS_PROXY_AUTH_REQUIRED

public static const STATUS_PROXY_AUTH_REQUIRED: UInt16 = 407

功能:必须在代理服务器上进行身份验证。

类型:UInt16

static const STATUS_REQUEST_CONTENT_TOO_LARGE

public static const STATUS_REQUEST_CONTENT_TOO_LARGE: UInt16 = 413

功能:请求提交的实体数据大小超过了服务器愿意或者能够处理的范围。

类型:UInt16

static const STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE

public static const STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE: UInt16 = 431

功能:请求头字段太大。

类型:UInt16

static const STATUS_REQUEST_TIMEOUT

public static const STATUS_REQUEST_TIMEOUT: UInt16 = 408

功能:请求超时。客户端没有在服务器预备等待的时间内完成一个请求的发送。

类型:UInt16

static const STATUS_REQUEST_URI_TOO_LONG

public static const STATUS_REQUEST_URI_TOO_LONG: UInt16 = 414

功能:求的 URI 长度超过了服务器能够解释的长度。

类型:UInt16

static const STATUS_REQUESTED_RANGE_NOT_SATISFIABLE

public static const STATUS_REQUESTED_RANGE_NOT_SATISFIABLE: UInt16 = 416

功能:客户端请求的范围无效。

类型:UInt16

说明:

请求中包含了 Range 请求头,并且 Range 中指定的任何数据范围都与当前资源的可用范围不重合; 同时请求中又没有定义 If-Range 请求头。

static const STATUS_RESET_CONTENT

public static const STATUS_RESET_CONTENT: UInt16 = 205

功能:服务器成功处理了请求,且没有返回任何内容,希望请求者重置文档视图。

类型:UInt16

static const STATUS_SEE_OTHER

public static const STATUS_SEE_OTHER: UInt16 = 303

功能:对应当前请求的响应可以在另一个 URL 上被找到,而且客户端应当采用 GET 的方式访问那个资源。

类型:UInt16

static const STATUS_SERVICE_UNAVAILABLE

public static const STATUS_SERVICE_UNAVAILABLE: UInt16 = 503

功能:临时的服务器维护或者过载。

类型:UInt16

static const STATUS_SWITCHING_PROTOCOLS

public static const STATUS_SWITCHING_PROTOCOLS: UInt16 = 101

功能:服务器已经理解了客户端的请求,并将通过 Upgrade 消息头通知客户端采用不同的协议来完成这个请求。

类型:UInt16

说明:

在发送完这个响应最后的空行后,服务器将会切换到在 Upgrade 消息头中定义的那些协议。

static const STATUS_TEAPOT

public static const STATUS_TEAPOT: UInt16 = 418

功能:服务端无法处理请求,一个愚弄客户端的状态码,被称为“我是茶壶”错误码,不应被认真对待。

类型:UInt16

static const STATUS_TEMPORARY_REDIRECT

public static const STATUS_TEMPORARY_REDIRECT: UInt16 = 307

功能:临时重定向。

类型:UInt16

static const STATUS_TOO_EARLY

public static const STATUS_TOO_EARLY: UInt16 = 425

功能:服务器不愿意冒风险来处理该请求。

类型:UInt16

static const STATUS_TOO_MANY_REQUESTS

public static const STATUS_TOO_MANY_REQUESTS: UInt16 = 429

功能:请求过多。

类型:UInt16

static const STATUS_UNAUTHORIZED

public static const STATUS_UNAUTHORIZED: UInt16 = 401

功能:当前请求需要用户验证。

类型:UInt16

public static const STATUS_UNAVAILABLE_FOR_LEGAL_REASONS: UInt16 = 451

功能:该请求因法律原因不可用。

类型:UInt16

static const STATUS_UNPROCESSABLE_ENTITY

public static const STATUS_UNPROCESSABLE_ENTITY: UInt16 = 422

功能:请求格式正确,但是由于含有语义错误,无法响应。

类型:UInt16

static const STATUS_UNSUPPORTED_MEDIA_TYPE

public static const STATUS_UNSUPPORTED_MEDIA_TYPE: UInt16 = 415

功能:服务器无法处理请求附带的媒体格式。

类型:UInt16

说明:

对于当前请求的函数和所请求的资源,请求中提交的实体并不是服务器中所支持的格式。

static const STATUS_UPGRADE_REQUIRED

public static const STATUS_UPGRADE_REQUIRED: UInt16 = 426

功能:服务器拒绝处理客户端使用当前协议发送的请求,但是可以接受其使用升级后的协议发送的请求。

类型:UInt16

static const STATUS_USE_PROXY

public static const STATUS_USE_PROXY: UInt16 = 305

功能:使用代理,所请求的资源必须通过代理访问。

类型:UInt16

static const STATUS_VARIANT_ALSO_NEGOTIATES

public static const STATUS_VARIANT_ALSO_NEGOTIATES: UInt16 = 506

功能:服务器存在内部配置错误。

类型:UInt16

struct ServicePoolConfig

public struct ServicePoolConfig {
    public let capacity: Int64
    public let queueCapacity: Int64
    public let preheat: Int64
    public init(capacity!: Int64 = 10 ** 4, queueCapacity!: Int64 = 10 ** 4, preheat!: Int64 = 0)
}

功能:Http Server 协程池配置。

说明:

HTTP/1.1 Server 每次收到一个请求,将从协程池取出一个协程进行处理,如果任务等待队列已满,将拒绝服务该次请求,并断开连接。 HTTP/2 Server 处理过程中会从协程池取出若干协程进行处理,如果任务等待队列已满,将阻塞直至有协程空闲。

let capacity

public let capacity: Int64

功能:获取协程池容量。

类型:Int64

示例:

import stdx.net.http.*

main() {
    // 读取 ServicePoolConfig.capacity
    let cfg = ServicePoolConfig(capacity: 100, queueCapacity: 200, preheat: 10)
    println("capacity = ${cfg.capacity}")
}

运行结果:

capacity = 100

let preheat

public let preheat: Int64

功能:获取服务启动时预先启动的协程数量。

类型:Int64

示例:

import stdx.net.http.*

main() {
    // 读取 ServicePoolConfig.preheat
    let cfg = ServicePoolConfig(capacity: 100, queueCapacity: 200, preheat: 10)
    println("preheat = ${cfg.preheat}")
}

运行结果:

preheat = 10

let queueCapacity

public let queueCapacity: Int64

功能:获取缓冲区等待任务的最大数量。

类型:Int64

示例:

import stdx.net.http.*

main() {
    // 读取 ServicePoolConfig.queueCapacity
    let cfg = ServicePoolConfig(capacity: 100, queueCapacity: 200, preheat: 10)
    println("queueCapacity = ${cfg.queueCapacity}")
}

运行结果:

queueCapacity = 200

init(Int64, Int64, Int64)

public init(
    capacity!: Int64 = 10 ** 4,
    queueCapacity!: Int64 = 10 ** 4,
    preheat!: Int64 = 0
)

功能:构造一个 ServicePoolConfig 实例。

参数:

  • capacity!: Int64 - 协程池容量,默认值为 10000。
  • queueCapacity!: Int64 - 缓冲区等待任务的最大数量,默认值为 10000。
  • preheat!: Int64 - 服务启动时预先启动的协程数量,默认值为 0。

异常:

  • IllegalArgumentException - 当参数 capacity/queueCapacity/preheat 小于 0,或参数 preheat 大于 capacity。

示例:

import stdx.net.http.*

main() {
    // 初始化
    let _ = ServicePoolConfig(capacity: 100, queueCapacity: 200, preheat: 10)
}

struct TransportConfig

public struct TransportConfig

功能:传输层配置类,服务器建立连接使用的传输层配置。

prop keepAliveConfig

public mut prop keepAliveConfig: SocketKeepAliveConfig

功能:设定和读取传输层连接的消息保活配置,默认配置空闲时间为 45s,发送探测报文的时间间隔为 5s,在连接被认为无效之前发送的探测报文数 5 次,实际时间粒度可能因操作系统而异。

类型:SocketKeepAliveConfig

示例:

import stdx.net.http.*
import std.net.*

main() {
    var tc = TransportConfig()

    // 设置并读取 TransportConfig.keepAliveConfig
    tc.keepAliveConfig = SocketKeepAliveConfig(
        idle: Duration.second * 1,
        interval: Duration.second * 2,
        count: 3
    )

    let k = tc.keepAliveConfig
    println("idle: ${k.idle}")
    println("interval: ${k.interval}")
    println("count: ${k.count}")
}

运行结果:

idle: 1s
interval: 2s
count: 3

prop readBufferSize

public mut prop readBufferSize: ?Int64

功能:设定和读取传输层连接的读缓冲区大小,默认值为 None ,若设置的值小于 0,将在服务器进行服务建立连接后抛出 IllegalArgumentException。

说明:

使用默认值时,实际的缓冲区大小将由操作系统决定。

类型:?Int64

示例:

import stdx.net.http.*

main() {
    var tc = TransportConfig()

    // 读取默认 TransportConfig.readBufferSize
    match (tc.readBufferSize) {
        case Some(v) => println("default = ${v}")
        case None => println("default = None")
    }

    // 设置并读取 TransportConfig.readBufferSize
    tc.readBufferSize = Some(4096)
    match (tc.readBufferSize) {
        case Some(v) => println("readBufferSize = ${v}")
        case None => println("readBufferSize = None")
    }
}

运行结果:

default = None
readBufferSize = 4096

prop readTimeout

public mut prop readTimeout: Duration

功能:设定和读取传输层连接的读超时时间,如果设置的时间小于 0 将置为 0,默认值为 Duration.Max。

类型:Duration

示例:

import stdx.net.http.*

main() {
    var tc = TransportConfig()

    // 读取默认 TransportConfig.readTimeout
    println("defaultIsMax == Duration.Max: ${tc.readTimeout == Duration.Max}")

    // 设置并读取 TransportConfig.readTimeout
    tc.readTimeout = Duration.second * 3
    println("readTimeout: ${tc.readTimeout}")
}

运行结果:

defaultIsMax == Duration.Max: true
readTimeout: 3s

prop writeBufferSize

public mut prop writeBufferSize: ?Int64

功能:设定和读取传输层连接的写缓冲区大小,默认值为 None ,若设置的值小于 0,将在服务器进行服务建立连接后抛出 IllegalArgumentException。

说明:

使用默认值时,实际的缓冲区大小将由操作系统决定。

类型:?Int64

示例:

import stdx.net.http.*

main() {
    var tc = TransportConfig()

    // 读取默认 TransportConfig.writeBufferSize
    match (tc.writeBufferSize) {
        case Some(v) => println("default = ${v}")
        case None => println("default = None")
    }

    // 设置并读取 TransportConfig.writeBufferSize
    tc.writeBufferSize = Some(8192)
    match (tc.writeBufferSize) {
        case Some(v) => println("writeBufferSize = ${v}")
        case None => println("writeBufferSize = None")
    }
}

运行结果:

default = None
writeBufferSize = 8192

prop writeTimeout

public mut prop writeTimeout: Duration

功能:设定和读取传输层连接的写超时时间,如果设置的时间小于 0 将置为 0,默认值为 Duration.Max。

类型:Duration

示例:

import stdx.net.http.*

main() {
    var tc = TransportConfig()

    // 读取默认 TransportConfig.writeTimeout
    println("defaultIsMax == Duration.Max: ${tc.writeTimeout == Duration.Max}")

    // 设置并读取 TransportConfig.writeTimeout
    tc.writeTimeout = Duration.second * 5
    println("writeTimeout: ${tc.writeTimeout}")
}

运行结果:

defaultIsMax == Duration.Max: true
writeTimeout: 5s

异常类

class ConnectionException

public class ConnectionException <: IOException {
    public init(message: String)
}

功能:Http 的 tcp 连接异常类。

父类型:

  • IOException

init(String)

public init(message: String)

功能:创建 ConnectionException 实例。

参数:

  • message: String - 异常提示信息。

示例:

import stdx.net.http.*

main() {
    try {
        throw ConnectionException("connect failed")
    } catch (e: ConnectionException) {
        println("message: ${e.message}")
    }
}

运行结果:

message: connect failed

class CoroutinePoolRejectException

public class CoroutinePoolRejectException <: Exception {
    public init(message: String)
}

功能:Http 的协程池拒绝请求处理异常类。

父类型:

  • Exception

init(String)

public init(message: String)

功能:创建 CoroutinePoolRejectException 实例。

参数:

  • message: String - 异常提示信息。

示例:

import stdx.net.http.*

main() {
    try {
        throw CoroutinePoolRejectException("pool rejected")
    } catch (e: CoroutinePoolRejectException) {
        println("message: ${e.message}")
    }
}

运行结果:

message: pool rejected

class HttpException

public class HttpException <: Exception {
    public init(message: String)
}

功能:Http 的通用异常类。

父类型:

  • Exception

init(String)

public init(message: String)

功能:创建 HttpException 实例。

参数:

  • message: String - 异常提示信息。

示例:

import stdx.net.http.*

main() {
    try {
        throw HttpException("bad request")
    } catch (e: HttpException) {
        println("message: ${e.message}")
    }
}

运行结果:

message: bad request

class HttpStatusException

public class HttpStatusException <: Exception {
    public init(statusCode: UInt16, message: String)
}

功能:Http 的响应状态异常类。

父类型:

  • Exception

init(UInt16, String)

public init(statusCode: UInt16, message: String)

功能:创建 HttpStatusException 实例。

参数:

  • statusCode: UInt16 - 状态码。
  • message: String - 异常提示信息。

示例:

import stdx.net.http.*

main() {
    try {
        throw HttpStatusException(404, "not found")
    } catch (e: HttpStatusException) {
        // statusCode 在实现中为非 public 字段,此处只演示 message
        println("message: ${e.message}")
    }
}

运行结果:

message: not found

class HttpTimeoutException

public class HttpTimeoutException <: Exception {
    public init(message: String)
}

功能:Http 的超时异常类。

父类型:

  • Exception

init(String)

public init(message: String)

功能:创建 HttpTimeoutException 实例。

参数:

  • message: String - 异常提示信息。

示例:

import stdx.net.http.*

main() {
    try {
        throw HttpTimeoutException("read timeout")
    } catch (e: HttpTimeoutException) {
        println("message: ${e.message}")
    }
}

运行结果:

message: read timeout

class WebSocketException

public class WebSocketException <: Exception {
    public init(message: String)
}

功能:WebSocket 的通用异常类。

父类型:

  • Exception

init(String)

public init(message: String)

功能:创建 WebSocketException 实例。

参数:

  • message: String - 异常提示信息。

示例:

import stdx.net.http.*

main() {
    try {
        throw WebSocketException("ws error")
    } catch (e: WebSocketException) {
        println("message: ${e.message}")
    }
}

运行结果:

message: ws error

client

注意:

以下示例仅用于展示客户端写法,可通过编译但无法运行成功。如需查看运行效果,需用户自行提供服务端配合运行。部分用例需用户自行提供有效证书文件。

Hello World

示例:

import stdx.net.http.*

main() {
    // 1. 构建 client 实例
    let client = ClientBuilder().build()
    // 2. 发送请求,收取响应,其中请求 URL 可根据实际情况修改
    let rsp = client.get("http://example.com/hello")
    // 3. 打印响应内容
    println(rsp)
    // 4. 关闭连接
    client.close()
}

自定义 client 网络配置

示例:

import std.net.{TcpSocket, SocketAddress}
import std.fs.*
import stdx.net.tls.*
import stdx.net.tls.common.*
import stdx.crypto.x509.X509Certificate
import stdx.net.http.*
import std.io.*

main() {
    // 1. 自定义配置
    // TLS 配置
    var tlsConfig = TlsClientConfig()
    // TLS 证书文件需要用户自行提供
    let pem = String.fromUtf8(readToEnd(File("/rootCerPath", Read)))
    tlsConfig.verifyMode = CustomCA(X509Certificate.decodeFromPem(pem).map({certificate => certificate}))
    tlsConfig.supportedAlpnProtocols = ["h2"]
    // TCP 建连配置
    let TcpSocketConnector = {
        sa: SocketAddress =>
        let socket = TcpSocket(sa)
        socket.connect()
        return socket
    }
    // 2. 构建 client 实例
    let client = ClientBuilder().tlsConfig(tlsConfig).enablePush(false).connector(TcpSocketConnector).build()
    // 3. 发送请求,其中请求 URL 可根据实际情况修改
    let rsp = client.get("https://example.com/hello")
    // 4. 读取响应体
    let buf = Array<UInt8>(1024, repeat: 0)
    let len = rsp.body.read(buf)
    println(String.fromUtf8(buf.slice(0, len)))
    // 5. 关闭连接
    client.close()
}

request 中的 chunked 与 trailer

示例:

import std.io.*
import std.fs.*
import stdx.net.http.*
import stdx.net.tls.*

func checksum(chunk: Array<UInt8>): Int64 {
    var sum = 0
    for (i in chunk) {
        if (i == b'\n') {
            sum += 1
        }
    }
    return sum / 2
}

main() {
    // 1. 构建 client 实例
    let client = ClientBuilder().build()
    var requestBuilder = HttpRequestBuilder()
    // 上传的文件需要用户自行提供
    let file = File("./res.jpg", Read)
    let sum = checksum(readToEnd(file))
    let req = requestBuilder
        .method("PUT")
        .url("https://example.com/src/")
        .header("Transfer-Encoding", "chunked")
        .header("Trailer", "checksum")
        .body(FileBody("./res.jpg"))
        .trailer("checksum", sum.toString())
        .build()
    let rsp = client.send(req)
    println(rsp)
    client.close()
}

class FileBody <: InputStream {
    var file: File
    init(path: String) {
        file = File(path, Read)
    }
    public func read(buf: Array<UInt8>): Int64 {
        file.read(buf)
    }
}

配置代理

示例:

import stdx.net.http.*

main() {
    // 1. 构建 client 实例
    let client = ClientBuilder().httpProxy("http://127.0.0.1:8080").build()
    // 2. 发送请求,所有请求都会被发送至 127.0.0.1 地址的 8080 端口,而不是 example.com
    // 用户可根据实际情况修改代理配置和请求 URL
    let rsp = client.get("http://example.com/hello")
    // 3. 打印响应
    println(rsp)
    // 4. 关闭连接
    client.close()
}

cookie

Client

示例:

import stdx.net.http.*
import stdx.encoding.url.*
import std.net.*
import std.time.*
import std.sync.*

main() {
    // 1、启动socket服务器
    let serverSocket = TcpServerSocket(bindAt: 0)
    serverSocket.bind()
    let fut = spawn {
        serverPacketCapture(serverSocket)
    }
    // 客户端一般从 response 中的 Set-Cookie header 中读取 cookie,并将其存入 cookieJar 中,
    // 下次发起 request时,将其放在 request 的 Cookie header 中发送
    // 2、启动客户端
    let client = ClientBuilder().build()
    let port = (serverSocket.localAddress as IPSocketAddress)?.port ?? throw Exception("Port not found.")
    var u = URL.parse("http://127.0.0.1:${port}/a/b/c")
    var r = HttpRequestBuilder().url(u).build()
    // 3、发送request
    client.send(r)
    r = HttpRequestBuilder().url(u).build()
    // 4、发送新 request,从 CookieJar 中取出 cookie,并转成 Cookie header 中的值
    // 此时 cookie 2=2 已经过期,因此只发送 1=1 cookie
    client.send(r)
    // 5、关闭客户端
    client.close()
    fut.get()
    serverSocket.close()
}

func serverPacketCapture(serverSocket: TcpServerSocket) {
    let server = serverSocket.accept()
    let buf = Array<UInt8>(500, repeat: 0)
    var i = server.read(buf)
    println(String.fromUtf8(buf[..i]))
    // GET /a/b/c HTTP/1.1
    // host: 127.0.0.1:44649
    // user-agent: CANGJIEUSERAGENT_1_1
    // connection: keep-alive
    // content-length: 0
    //
    // 过期时间为 4 秒的 cookie1
    let cookie1 = Cookie("1", "1", maxAge: 4, domain: "127.0.0.1", path: "/a/b/")
    let setCookie1 = cookie1.toSetCookieString()
    // 过期时间为 2 秒的 cookie2
    let cookie2 = Cookie("2", "2", maxAge: 2, path: "/a/")
    let setCookie2 = cookie2.toSetCookieString()
    // 服务器发送 Set-Cookie 头,客户端解析并将其存进 CookieJar 中
    server.write(
        "HTTP/1.1 204 ok\r\nSet-Cookie: ${setCookie1}\r\nSet-Cookie: ${setCookie2}\r\nConnection: close\r\n\r\n"
            .toArray())

    let server2 = serverSocket.accept()
    i = server2.read(buf)
    // 接收客户端的带 cookie 的请求
    println(String.fromUtf8(buf[..i]))
    // GET /a/b/c HTTP/1.1
    // host: 127.0.0.1:xxxx
    // cookie: 1=1
    // user-agent: CANGJIEUSERAGENT_1_1
    // connection: keep-alive
    // content-length: 0
    //
    server2.write("HTTP/1.1 204 ok\r\nConnection: close\r\n\r\n".toArray())
    server2.close()
}

运行结果:

注意:

请求中 host 字段中的 port 部分是随机分配的,每次运行会打印不同值。

GET /a/b/c HTTP/1.1
host: 127.0.0.1:xxxx
user-agent: CANGJIEUSERAGENT_1_1
connection: keep-alive
content-length: 0


GET /a/b/c HTTP/1.1
host: 127.0.0.1:xxxx
cookie: 1=1
user-agent: CANGJIEUSERAGENT_1_1
connection: keep-alive
content-length: 0

Server

示例:

import stdx.net.http.*
import stdx.net.tls.*
import std.net.*
import std.sync.*

main(): Unit {
    let serverOn = SyncCounter(1)
    spawn {
        serverSetCookie(serverOn)
    }
    serverOn.waitUntilZero()
    clientPacketCapture()
}

func serverSetCookie(serverOn: SyncCounter): Unit {
    // 服务器设置 cookie 时将 cookie 放在 Set-Cookie header 中发给客户端
    // 1. 构建 Server 实例
    let server = ServerBuilder().addr("127.0.0.1").port(8080).build()
    server.afterBind({=> serverOn.dec()})
    // 2. 注册 HttpRequestHandler
    server
        .distributor
        .register(
            "/index",
            {
                httpContext =>
                let cookie = Cookie("name", "value")
                httpContext.responseBuilder.header("Set-Cookie", cookie.toSetCookieString()).body("Hello 仓颉!")
            }
        )
    // 3. 启动服务
    server.serve()
}

func clientPacketCapture(): Unit {
    // 创建客户端 socket,并连接到服务端
    let client = TcpSocket("127.0.0.1", 8080)
    client.connect()
    // 发送请求
    let request = "GET /index HTTP/1.1\r\nHost: 127.0.0.1:8080\r\n\r\n".toArray()
    client.write(request)
    // 读取响应,响应中预期包含 “set-cookie: name=value”
    let buf = Array<UInt8>(500, repeat: 0)
    var len = client.read(buf)
    println(String.fromUtf8(buf[..len]))
}

运行结果:

注意:

响应中 date 字段表示当前日期,每次运行会打印不同的结果。

HTTP/1.1 200 OK
set-cookie: name=value
connection: keep-alive
date: xxxx
content-length: 13

Hello 仓颉!

log

示例:

import stdx.log.*
import stdx.net.http.*
import stdx.net.tls

main() {
    // 1. 构建 Server 实例
    let server = ServerBuilder().addr("127.0.0.1").port(8080).build()
    // 2. 注册 HttpRequestHandler
    server.distributor.register("/index", {
        httpContext => httpContext.responseBuilder.body("Hello 仓颉!")
    })
    // 3. 开启日志
    server.logger.level = LogLevel.DEBUG
    // client 端通过 client.logger.level = DEBUG 开启
    // 4. 启动服务
    server.serve()
}

运行结果:

2025-05-24T23:55:12.779407244+08:00 DEBUG [thread#1] [Server#serve] bindAndListen(127.0.0.1, 8080)

server

注意:

以下示例仅用于展示服务端写法,可编译并运行(部分用例需用户自行提供有效证书文件),但无法展示处理请求的效果。如需查看运行效果,需用户自行提供客户端对示例服务端发起请求。

Hello 仓颉

示例:

import stdx.net.http.ServerBuilder
import stdx.net.tls

main() {
    // 1. 构建 Server 实例
    let server = ServerBuilder().addr("127.0.0.1").port(8080).build()
    // 2. 注册 HttpRequestHandler
    server.distributor.register("/index", {
        httpContext => httpContext.responseBuilder.body("Hello 仓颉!")
    })
    // 3. 启动服务
    server.serve()
}

通过 request distributor 注册处理器

示例:

import stdx.net.http.{ServerBuilder, HttpRequestHandler, FuncHandler}

main() {
    // 1. 构建 Server 实例
    let server = ServerBuilder().addr("127.0.0.1").port(8080).build()
    // 注册三个不同的 HttpRequestHandler,该服务端可根据请求路径自动分发、处理请求。
    var a: HttpRequestHandler = FuncHandler({
        httpContext => httpContext.responseBuilder.body("index")
    })
    var b: HttpRequestHandler = FuncHandler({
        httpContext => httpContext.responseBuilder.body("id")
    })
    var c: HttpRequestHandler = FuncHandler({
        httpContext => httpContext.responseBuilder.body("help")
    })
    server.distributor.register("/index", a)
    server.distributor.register("/id", b)
    server.distributor.register("/help", c)
    // 2. 启动服务
    server.serve()
}

自定义 request distributor 与处理器

示例:

import stdx.net.http.*
import stdx.net.tls.*
import std.collection.HashMap

// 自定义请求分发器
class NaiveDistributor <: HttpRequestDistributor {
    let map = HashMap<String, HttpRequestHandler>()
    public func register(path: String, handler: HttpRequestHandler): Unit {
        map.add(path, handler)
    }

    public func distribute(path: String): HttpRequestHandler {
        if (path == "/index") {
            return PageHandler()
        }
        return NotFoundHandler()
    }
}

// 返回一个简单的 HTML 页面
class PageHandler <: HttpRequestHandler {
    public func handle(httpContext: HttpContext): Unit {
        httpContext.responseBuilder.body("<html></html>")
    }
}

main() {
    // 1. 构建 Server 实例并接入自定义分发器
    let server = ServerBuilder().addr("127.0.0.1").port(8080).distributor(NaiveDistributor()).build()
    // 2. 启动服务
    server.serve()
}

自定义 server 网络配置

示例:

import std.io.*
import std.fs.*
import stdx.net.tls.*
import stdx.crypto.x509.X509Certificate
import stdx.crypto.keys.GeneralPrivateKey
import stdx.net.http.*

main() {
    // 1. 自定义配置
    // TCP 配置
    var transportCfg = TransportConfig()
    transportCfg.readBufferSize = 8192
    // TLS 配置,需要传入配套的证书与私钥文件路径,此处证书和私钥文件需要用户自行提供
    let pem0 = String.fromUtf8(readToEnd(File("/certPath", Read)))
    let pem02 = String.fromUtf8(readToEnd(File("/keyPath", Read)))
    var tlsConfig = TlsServerConfig(X509Certificate.decodeFromPem(pem0), GeneralPrivateKey.decodeFromPem(pem02))
    tlsConfig.supportedAlpnProtocols = ["h2"]
    // 2. 构建 Server 实例
    let server = ServerBuilder()
        .addr("127.0.0.1")
        .port(8080)
        .transportConfig(transportCfg)
        .tlsConfig(tlsConfig)
        .headerTableSize(10 * 1024)
        .maxRequestHeaderSize(1024 * 1024)
        .build()
    // 3. 注册 HttpRequestHandler
    server.distributor.register("/index", {
        httpContext => httpContext.responseBuilder.body("Hello 仓颉!")
    })
    // 4. 启动服务
    server.serve()
}

response 中的 chunked 与 trailer

示例:

import stdx.net.http.*
import stdx.net.tls

func checksum(chunk: Array<UInt8>): Int64 {
    var sum = 0
    for (i in chunk) {
        if (i == UInt8(UInt32(r'\n'))) {
            sum += 1
        }
    }
    return sum / 2
}

main() {
    // 1. 构建 Server 实例
    let server = ServerBuilder().addr("127.0.0.1").port(8080).build()
    // 2. 注册 HttpRequestHandler
    server
        .distributor
        .register(
            "/index",
            {
                httpContext =>
                let responseBuilder = httpContext.responseBuilder
                // 设置响应头 transfer-encoding 和 trailer
                responseBuilder.header("transfer-encoding", "chunked")
                responseBuilder.header("trailer", "checkSum")
                // 用 HttpResponseWriter 分段发送响应体
                let writer = HttpResponseWriter(httpContext)
                var sum = 0
                for (_ in 0..10) {
                    let chunk = Array<UInt8>(10, repeat: 0)
                    sum += checksum(chunk)
                    writer.write(chunk)
                }
                // 发送响应 trailer,trailer 部分在响应体之后发送
                responseBuilder.trailer("checkSum", "${sum}")
            }
        )
    // 3. 启动服务
    server.serve()
}

处理重定向 request

示例:

import stdx.net.http.*
import stdx.net.tls

main() {
    // 1. 构建 Server 实例
    let server = ServerBuilder().addr("127.0.0.1").port(8080).build()
    // 2. 注册用于重定向的 HttpRequestHandler
    server.distributor.register("/redirecta", RedirectHandler("/movedsource", 308))
    server.distributor.register("/redirectb", RedirectHandler("http://www.example.com", 308))
    // 3. 启动服务
    server.serve()
}

tls 证书热加载

示例:

import std.io.*
import std.fs.*
import stdx.net.tls.*
import stdx.net.tls.common.*
import stdx.crypto.x509.X509Certificate
import stdx.crypto.keys.GeneralPrivateKey
import stdx.net.http.*

//该程序需要用户配置存在且合法的文件路径才能执行
main() {
    // 1. TLS 配置,其中 TLS 证书和私钥文件用户需自行提供
    let pem0 = String.fromUtf8(readToEnd(File("/certPath", Read)))
    let pem02 = String.fromUtf8(readToEnd(File("/keyPath", Read)))
    var tlsConfig = TlsServerConfig(X509Certificate.decodeFromPem(pem0), GeneralPrivateKey.decodeFromPem(pem02))
    tlsConfig.supportedAlpnProtocols = ["http/1.1"]
    let pem = String.fromUtf8(readToEnd(File("/rootCerPath", Read)))
    tlsConfig.verifyMode = CustomCA(X509Certificate.decodeFromPem(pem).map({certificate => certificate}))
    // 2. 构建 Server 实例,并启动服务
    let server = ServerBuilder().addr("127.0.0.1").port(8080).tlsConfig(tlsConfig).build()
    spawn {
        server.serve()
    }
    // 3. 更新 TLS 证书和私钥,之后建立的连接将使用新的证书和私钥进行认证和加密
    server.updateCert("/newCerPath", "/newKeyPath")
    // 4. 更新 CA,双向认证时使用,之后建立的连接将使用新的 CA 进行认证
    server.updateCA("/newRootCerPath")
}

server push

仅用于 HTTP/2

client:

示例:

import std.io.*
import std.fs.*
import std.collection.ArrayList
import stdx.net.tls.*
import stdx.net.tls.common.*
import stdx.crypto.x509.X509Certificate
import stdx.net.http.*

main() {
    // 1. TLS 配置,其中 TLS 证书文件用户需自行提供
    var tlsConfig = TlsClientConfig()
    let pem = String.fromUtf8(readToEnd(File("/rootCerPath", Read)))
    tlsConfig.verifyMode = CustomCA(X509Certificate.decodeFromPem(pem).map({certificate => certificate}))
    tlsConfig.supportedAlpnProtocols = ["h2"]
    // 2. 构建 Client 实例
    let client = ClientBuilder().tlsConfig(tlsConfig).build()
    // 3. 发送请求,接收响应
    let response = client.get("https://127.0.0.1.8080/index.html")
    // 4. 接收服务端推送的响应,此例中相当于请求 client.get("http://127.0.0.1.8080/picture.png") 的响应
    let pushResponses: Option<ArrayList<HttpResponse>> = response.getPush()
    client.close()
}

server:

示例:

import std.io.*
import std.fs.*
import stdx.net.tls.*
import stdx.crypto.x509.X509Certificate
import stdx.crypto.keys.GeneralPrivateKey
import stdx.net.http.*

main() {
    // 1. TLS 配置,其中 TLS 证书文件用户需自行提供
    let pem0 = String.fromUtf8(readToEnd(File("/certPath", Read)))
    let pem02 = String.fromUtf8(readToEnd(File("/keyPath", Read)))
    var tlsConfig = TlsServerConfig(X509Certificate.decodeFromPem(pem0), GeneralPrivateKey.decodeFromPem(pem02))
    tlsConfig.supportedAlpnProtocols = ["h2"]
    // 2. 构建 Server 实例
    let server = ServerBuilder().addr("127.0.0.1").port(8080).tlsConfig(tlsConfig).build()
    // 3. 注册原 request 的 handler
    server
        .distributor
        .register(
            "/index.html",
            {
                httpContext =>
                let pusher = HttpResponsePusher.getPusher(httpContext)
                match (pusher) {
                    case Some(pusher) => pusher.push("/picture.png", "GET", httpContext.request.headers)
                    case None => ()
                }
            }
        )
    // 4. 注册服务端推送请求对应的 handler
    server.distributor.register("/picture.png", {
        httpContext => httpContext.responseBuilder.body("picture.png")
    })
    // 4. 启动服务
    server.serve()
}

webSocket

示例:

import stdx.net.http.*
import stdx.net.tls.*
import stdx.crypto.kit.*
import stdx.encoding.url.*
import stdx.crypto.kit.*
import std.sync.*
import std.collection.*
import stdx.log.*

let server = ServerBuilder().addr("127.0.0.1").port(0).build()

main() {
    // 1 启动服务器
    startServer()

    let client = ClientBuilder().build()
    let u = URL.parse("ws://127.0.0.1:${server.port}/webSocket")

    let subProtocol = ArrayList<String>(["foo1", "bar1"])
    let headers = HttpHeaders()
    headers.add("test", "echo")

    // 2 完成 WebSocket 握手,获取 WebSocket 实例
    let websocket: WebSocket
    let respHeaders: HttpHeaders
    (websocket, respHeaders) = WebSocket.upgradeFromClient(client, u, subProtocols: subProtocol, headers: headers)
    client.close()

    println("subProtocol: ${websocket.subProtocol}")
    println(respHeaders.getFirst("rsp") ?? "")

    // 3 消息收发
    // 发送 hello
    websocket.write(TextWebFrame, "hello".toArray())
    // 接收消息
    let data = ArrayList<UInt8>()
    var frame = websocket.read()
    while (true) {
        match (frame.frameType) {
            case ContinuationWebFrame =>
                data.add(all: frame.payload)
                if (frame.fin) {
                    break
                }
            case TextWebFrame | BinaryWebFrame =>
                if (!data.isEmpty()) {
                    throw Exception("invalid frame")
                }
                data.add(all: frame.payload)
                if (frame.fin) {
                    break
                }
            case CloseWebFrame =>
                websocket.write(CloseWebFrame, frame.payload)
                break
            case PingWebFrame => websocket.writePongFrame(frame.payload)
            case _ => ()
        }
        frame = websocket.read()
    }
    println("data size: ${data.size}")
    println("last item: ${String.fromUtf8(data.toArray()[4096])}")

    // 4 关闭 websocket,
    // 收发 CloseFrame
    websocket.writeCloseFrame(status: 1000)
    let websocketFrame = websocket.read()
    println("close frame type: ${websocketFrame.frameType}")
    println("close frame payload: ${websocketFrame.payload}")

    // 关闭底层连接
    websocket.closeConn()

    server.close()
}

func startServer() {
    // 1 注册 handler
    server.distributor.register("/webSocket", handler1)
    server.logger.level = LogLevel.OFF
    let serverOn = SyncCounter(1)
    server.afterBind({=> serverOn.dec()})
    spawn {server.serve()}
    serverOn.waitUntilZero()
}

// server:
func handler1(ctx: HttpContext): Unit {
    // 2 完成 websocket 握手,获取 websocket 实例
    let websocketServer = WebSocket.upgradeFromServer(
        ctx,
        subProtocols: ArrayList<String>(["foo", "bar", "foo1"]),
        userFunc: {
            request: HttpRequest =>
            let value = request.headers.getFirst("test") ?? ""
            let headers = HttpHeaders()
            headers.add("rsp", value)
            headers
        }
    )
    // 3 消息收发
    // 接收 hello
    let data = ArrayList<UInt8>()
    var frame = websocketServer.read()
    while (true) {
        match (frame.frameType) {
            case ContinuationWebFrame =>
                data.add(all: frame.payload)
                if (frame.fin) {
                    break
                }
            case TextWebFrame | BinaryWebFrame =>
                if (!data.isEmpty()) {
                    throw Exception("invalid frame")
                }
                data.add(all: frame.payload)
                if (frame.fin) {
                    break
                }
            case CloseWebFrame =>
                websocketServer.write(CloseWebFrame, frame.payload)
                break
            case PingWebFrame => websocketServer.writePongFrame(frame.payload)
            case _ => ()
        }
        frame = websocketServer.read()
    }
    println("data: ${String.fromUtf8(data.toArray())}")

    // 发 4097 个 a
    websocketServer.write(TextWebFrame, Array<UInt8>(4097, repeat: 97))

    // 4 关闭 websocket,
    // 收发 CloseFrame
    let websocketFrame = websocketServer.read()
    println("close frame type: ${websocketFrame.frameType}")
    println("close frame payload: ${websocketFrame.payload}")
    websocketServer.write(CloseWebFrame, websocketFrame.payload)
    // 关闭底层连接
    websocketServer.closeConn()
}

运行结果:

subProtocol: foo1
echo
data: hello
data size: 4097
last item: a
close frame type: CloseWebFrame
close frame payload: [3, 232]
close frame type: CloseWebFrame
close frame payload: [3, 232]

h1_gzip

服务端使用 gzip 压缩报文示例

示例:

import stdx.compress.zlib.*
import stdx.net.http.*
import stdx.net.tls.*
import std.collection.*
import std.io.*
import std.sync.*

main() {
    // 1. 启动服务器监听
    let port = startServer()

    // 2. 构造http请求
    let request = HttpRequestBuilder()
        .get()
        .url("http://127.0.0.1:${port}/hello")
        .header("Accept-Encoding", "gzip")
        .build()

    // 3. 发送 http 请求并获取相应
    let client = ClientBuilder().build()
    let rsp = client.send(request)

    // 4. 使用 gzip 解压 body
    let body = DecompressInputStream(rsp.body, wrap: GzipFormat)
    println("Rsp body: ${String.fromUtf8(readToEnd(body))}")

    0
}

func startServer(): UInt16 {
    let server = ServerBuilder().addr("127.0.0.1").port(0).build()
    server
        .distributor
        .register("/hello") {
            ctx =>
            // 1. 设置响应头
            ctx.responseBuilder.header("Transfer-Encoding", "chunked")
            ctx.responseBuilder.header("Content-Encoding", "gzip")

            // 2. 获取 body 输入流
            let rawBody = ByteBuffer()
            "hello gzip".toArray() |> rawBody.write

            // 3. 使用 gzip 压缩输入流
            let body = CompressInputStream(rawBody, wrap: GzipFormat)
            ctx.responseBuilder.body(body)
        }
    let serverOn = SyncCounter(1)
    server.afterBind({=> serverOn.dec()})

    spawn {server.serve()}
    serverOn.waitUntilZero()
    return server.port
}

func readToEnd(input: InputStream): Array<Byte> {
    let buf = Array<Byte>(200, repeat: 0)
    let result = ArrayList<Byte>()
    var len = input.read(buf)
    while (len > 0) {
        result.add(all: buf[0..len])
        len = input.read(buf)
    }
    return result.toArray()
}

运行结果:

Rsp body: hello gzip

stdx.net.tls

功能介绍

tls 包用于进行安全加密的网络通信,提供创建 TLS 服务器、基于协议进行 TLS 握手、收发加密数据、恢复 TLS 会话等能力。

本包支持 TLS 1.2 及 TLS 1.3 传输层安全协议通信。

使用本包需要外部依赖 OpenSSL 3sslcrypto 动态库文件,故使用前需安装相关工具:

  • 对于 Linux 操作系统,可参考以下方式:
    • 如果系统的包管理工具支持安装 OpenSSL 3 开发工具包,可通过这个方式安装,并确保系统安装目录下含有 libssl.solibssl.so.3libcrypto.solibcrypto.so.3 这些动态库文件,例如 Ubuntu 22.04 系统上可使用 sudo apt install libssl-dev 命令安装 libssl-dev 工具包;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libssl.solibssl.so.3libcrypto.solibcrypto.so.3 这些动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 LD_LIBRARY_PATH 以及 LIBRARY_PATH 中。
  • 对于 Windows 操作系统,可按照以下步骤:
    • 自行下载 OpenSSL 3.x.x 源码编译安装 x64 架构软件包或者自行下载安装第三方预编译的供开发人员使用的 OpenSSL 3.x.x 软件包;
    • 确保安装目录下含有 libssl.dll.a(或 libssl.lib)、libssl-3-x64.dlllibcrypto.dll.a(或 libcrypto.lib)、libcrypto-3-x64.dll 这些库文件;
    • libssl.dll.a(或 libssl.lib)、libcrypto.dll.a(或 libcrypto.lib)所在的目录路径设置到环境变量 LIBRARY_PATH 中,将 libssl-3-x64.dlllibcrypto-3-x64.dll 所在的目录路径设置到环境变量 PATH 中。
  • 对于 macOS 操作系统,可参考以下方式:
    • 使用 brew install openssl@3 安装,并确保系统安装目录下含有 libcrypto.dyliblibcrypto.3.dylib 这两个动态库文件;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libcrypto.dyliblibcrypto.3.dylib 这两个动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 DYLD_LIBRARY_PATH 以及 LIBRARY_PATH 中。
  • 对于 Android 操作系统,可参考以下方式:
    • 由于 Android 系统默认自带的 OpenSSL 是裁剪版本,部分接口可能找不到符号而抛出异常,因此需要用户自行编译安装完整的 OpenSSL 3.x.x 版本;
    • 可自行下载 OpenSSL 3.x.x 源码,使用 Android NDK 交叉编译生成对应架构(当前只支持 arm64-v8a)的动态库文件,确保编译产物中含有 libssl.solibssl.so.3libcrypto.solibcrypto.so.3 这些动态库文件;
    • 将这些文件所在目录设置到环境变量 LD_LIBRARY_PATH 中。

注意:

如果未安装OpenSSL 3软件包或者安装低版本的软件包,程序可能无法使用并抛出相关异常 TlsException: Can not load openssl library or function xxx.。

API 列表

类型别名

类型别名功能
KeylessDecryptFunc供无私钥握手使用的解密回调函数类型。
KeylessSignFunc供无私钥握手使用的签名回调函数类型。

类名功能
DefaultTlsKitTlsKit 的默认实现。用于获取 TLS 服务端、客户端连接和服务端会话。
KeylessTlsServerConfig无私钥服务端配置。
TlsClientSession当客户端 TLS 握手成功后,将会生成一个会话,当连接因一些原因丢失后,客户端可以通过这个会话 id 复用此次会话,省略握手流程。
TlsServerSession服务端启用 session 特性恢复会话,存储 session 用于对客户端进行验证类型。
TlsSocket用于在客户端及服务端间创建加密传输通道。

枚举

枚举名功能
SignatureAlgorithm签名算法类型,签名算法用于确保传输数据的身份验证、完整性和真实性。
SignatureSchemeType加密算法类型,用于保护网络通信的安全性和隐私性。
SignatureType签名算法类型,用于认证真实性。
TlsClientIdentificationMode服务端对客户端证书的认证模式。

结构体

结构体名功能
CipherSuiteTLS 中的密码套件。
TlsClientConfig客户端配置。
TlsServerConfig服务端配置。

类型别名

type KeylessDecryptFunc

public type KeylessDecryptFunc = (cipherText: Array<Byte>) -> Array<Byte> 

功能:供无私钥握手使用的解密回调函数类型。

type KeylessSignFunc

public type KeylessSignFunc = (hashValue: Array<Byte>) -> Array<Byte>

功能:供无私钥握手使用的签名回调函数类型。

class DefaultTlsKit

public class DefaultTlsKit <: TlsKit

功能:TlsKit 的默认实现。用于获取 TLS 服务端、客户端连接和服务端会话。

父类型:

func getTlsClient(StreamingSocket, TlsConfig, ?TlsSession)

public func getTlsClient(socket: StreamingSocket, config: TlsConfig, session!: ?TlsSession): TlsConnection

功能:根据传入的 StreamingSocket 实例创建客户端 TLS 连接,该连接可用于 TLS 握手。

参数:

  • socket: StreamingSocket - TCP 连接建立完成后得到的 socket。
  • config: TlsConfig - 客户端 TLS 配置。
  • session!: ?TlsSession - TLS 会话。若存在可用的 TLS 会话,则可通过该会话恢复,省去 TLS 建立连接时间。

返回值:

示例:

import std.net.*
import stdx.net.tls.*
import stdx.net.tls.common.*

main() {
    // 创建默认 TLS 套件
    let tlsKit = DefaultTlsKit()

    // 创建 TCP 连接
    let tcpSocket = TcpSocket("127.0.0.1", 8443)

    // 创建 TLS 配置
    var config = TlsClientConfig()
    config.verifyMode = CertificateVerifyMode.TrustAll

    // 获取 TLS 客户端连接
    let tlsConnection = tlsKit.getTlsClient(tcpSocket, config, session: None)
    let handshakeResult = tlsConnection.handshakeResult

    println("已获取客户端 TLS 连接,握手结果: ${handshakeResult?.alpnProtocol ?? "未连接"}")
    return 0
}

运行结果:

已获取客户端 TLS 连接,握手结果: 未连接

func getTlsServer(StreamingSocket, TlsConfig, ?TlsSession)

public func getTlsServer(socket: StreamingSocket, config: TlsConfig, session!: ?TlsSession): TlsConnection

功能:根据传入的 StreamingSocket 实例创建服务端 TLS 连接,该连接可用于 TLS 握手。

参数:

  • socket: StreamingSocket - TCP 连接建立完成后得到的 socket。
  • config: TlsConfig - 服务端 TLS 配置。
  • session!: ?TlsSession - TLS 会话。若存在可用的 TLS 会话,则可通过该会话恢复,省去 TLS 建立连接时间。

返回值:

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.x509.*
import stdx.crypto.keys.*
import stdx.net.tls.*
import std.net.*

main() {
    // 定义证书和私钥文件
    let serverKey = "./server.key"
    let serverCrt = "./server.crt"

    // OpenSSL 官方标准、无风险的测试用命令
    let cmdStr = "openssl req -x509 -newkey rsa:2048 -nodes -keyout ${serverKey} -out ${serverCrt} -days 365 -subj \"/CN=localhost\""
    executeWithOutput("sh", ["-c", cmdStr])

    // 获取证书和私钥内容
    let serverCrtContent = String.fromUtf8(readToEnd(File(serverCrt, Read)))
    let serverCertificate = X509Certificate.decodeFromPem(serverCrtContent)

    let serverKeyContent = String.fromUtf8(readToEnd(File(serverKey, Read)))
    let serverPrivateKey = GeneralPrivateKey.decodeFromPem(serverKeyContent)

    // 创建 TLS 服务器配置
    let config = TlsServerConfig(serverCertificate, serverPrivateKey)

    // 创建默认 TLS 套件
    let tlsKit = DefaultTlsKit()

    // 创建 TCP 套接字
    let tcpSocket = TcpSocket("127.0.0.1", 8443)

    // 获取 TLS 服务端连接
    let tlsConnection = tlsKit.getTlsServer(tcpSocket, config, session: None)
    let handshakeResult = tlsConnection.handshakeResult

    println("已获取服务端 TLS 连接,握手结果: ${handshakeResult?.alpnProtocol ?? "未连接"}")

    // 删除证书和私钥文件
    removeIfExists(serverKey)
    removeIfExists(serverCrt)
    return 0
}

运行结果:

已获取服务端 TLS 连接,握手结果: 未连接

func getTlsServerSession(String)

public func getTlsServerSession(name: String): TlsSession

功能:通过名称创建 TlsSession 实例,该名称用于区分 TLS 服务器。

参数:

  • name: String - 会话名称。

返回值:

示例:

import stdx.net.tls.*

main() {
    // 创建默认 TLS 套件
    let tlsKit = DefaultTlsKit()

    // 获取 TLS 服务端会话
    let tlsSession = tlsKit.getTlsServerSession("test_server_session")

    // 转换为 TlsServerSession 方便打印
    let tlsServerSession = tlsSession as TlsServerSession
    println("已获取服务端 TLS 会话,会话名称: ${tlsServerSession?.toString() ?? ""}")
    return 0
}

运行结果:

已获取服务端 TLS 会话,会话名称: TlsServerSession(test_server_session)

class KeylessTlsServerConfig

public class KeylessTlsServerConfig <: TlsConfig {
    public init(certChain: Array<X509Certificate>, signCallback: KeylessSignFunc, decryptCallback!: ?KeylessDecryptFunc = None<KeylessDecryptFunc>)
}

功能:提供无私钥握手的服务端配置。

注意:

暂只支持 ECDHE-RSA-AES256-GCM-SHA384, TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256 三种算法套,其余算法套不保证可用性。

父类型:

var keylogCallback

public var keylogCallback: ?(TlsSocket, String) -> Unit = None

功能:握手过程的回调函数,提供 TLS 初始秘钥数据,用于调试和解密记录使用。

类型:?(TlsSocket, String) -> Unit

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.x509.*
import stdx.net.tls.*

main() {
    // 定义证书和私钥文件
    let serverKey = "./server.key"
    let serverCrt = "./server.crt"

    // OpenSSL 官方标准、无风险的测试用命令
    let cmdStr = "openssl req -x509 -newkey rsa:2048 -nodes -keyout ${serverKey} -out ${serverCrt} -days 365 -subj \"/CN=localhost\""
    executeWithOutput("sh", ["-c", cmdStr])

    // 获取证书
    let serverCrtContent = String.fromUtf8(readToEnd(File(serverCrt, Read)))
    let serverCertificate = X509Certificate.decodeFromPem(serverCrtContent)

    let config = KeylessTlsServerConfig(serverCertificate, keylessSignFunc)
    config.keylogCallback = myKeylogCallback
    println("发生在TLS握手的回调: ${config.keylogCallback.isSome()}")

    // 删除证书和私钥文件
    removeIfExists(serverCrt)
    removeIfExists(serverKey)
    return 0
}

public func keylessSignFunc(data: Array<Byte>): Array<Byte> {
    println("此处模拟调用外部密钥服务器完成签名操作")
    return data
}

func myKeylogCallback(_: TlsSocket, keyLog: String) {
    // 仅打印核心的密钥日志(忽略socket)
    println(keyLog)
}

运行结果:

发生在TLS握手的回调: true

prop certificate

public mut prop certificate: ?(Array<Certificate>, PrivateKey)

功能:设置或获取服务端证书和对应的私钥文件。其中证书必须为 X509Certificate 类型。不可设置为 None。

注意:

该属性返回的 PrivateKey 是一个无意义的 dummy key,与 Array<Certifiace> 无关。

类型:?(Array<Certificate>, PrivateKey)

异常:

  • TlsException - 设置的服务端证书不是 X509Certificate 类型时,抛出异常;设置服务端证书和对应的私钥文件为 None 时,抛出异常。

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.x509.*
import stdx.net.tls.*

main() {
    // 定义证书和私钥文件
    let serverKey = "./server.key"
    let serverCrt = "./server.crt"

    // OpenSSL 官方标准、无风险的测试用命令
    let cmdStr = "openssl req -x509 -newkey rsa:2048 -nodes -keyout ${serverKey} -out ${serverCrt} -days 365 -subj \"/CN=localhost\""
    executeWithOutput("sh", ["-c", cmdStr])

    // 获取证书
    let serverCrtContent = String.fromUtf8(readToEnd(File(serverCrt, Read)))
    let serverCertificate = X509Certificate.decodeFromPem(serverCrtContent)

    let config = KeylessTlsServerConfig(serverCertificate, keylessSignFunc)

    if (let Some(certificate) <- config.certificate) {
        // 获取证书并转换为 X509Certificate 类型
        let cert = (certificate[0][0] as X509Certificate).getOrThrow()
        println("X509证书实体的通用名称: ${cert.issuer.commonName ?? ""}")
    }

    // 删除证书和私钥文件
    removeIfExists(serverCrt)
    removeIfExists(serverKey)
    return 0
}

public func keylessSignFunc(data: Array<Byte>): Array<Byte> {
    println("此处模拟调用外部密钥服务器完成签名操作")
    return data
}

运行结果:

X509证书实体的通用名称: localhost

prop clientIdentityRequired

public mut prop clientIdentityRequired: TlsClientIdentificationMode

功能:设置或获取服务端要求客户端的认证模式,默认值为 TlsClientIdentificationMode.Disable,即不要求客户端认证服务端证书,也不要求客户端发送本端证书。

类型:TlsClientIdentificationMode

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.x509.*
import stdx.net.tls.*

main() {
    // 定义证书和私钥文件
    let serverKey = "./server.key"
    let serverCrt = "./server.crt"

    // OpenSSL 官方标准、无风险的测试用命令
    let cmdStr = "openssl req -x509 -newkey rsa:2048 -nodes -keyout ${serverKey} -out ${serverCrt} -days 365 -subj \"/CN=localhost\""
    executeWithOutput("sh", ["-c", cmdStr])

    // 获取证书
    let serverCrtContent = String.fromUtf8(readToEnd(File(serverCrt, Read)))
    let serverCertificate = X509Certificate.decodeFromPem(serverCrtContent)

    let config = KeylessTlsServerConfig(serverCertificate, keylessSignFunc)

    // 设置双向认证模式
    config.clientIdentityRequired = TlsClientIdentificationMode.Required

    // 删除证书和私钥文件
    removeIfExists(serverCrt)
    removeIfExists(serverKey)
    return 0
}

public func keylessSignFunc(data: Array<Byte>): Array<Byte> {
    return data
}

prop dhParameters

public mut prop dhParameters: ?DHParameters

功能:指定服务端的 DH 密钥参数,默认为 None, 默认情况下使用 openssl 自动生成的参数值。

类型:?DHParameters

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.x509.*
import stdx.net.tls.*

main() {
    // 定义证书和私钥文件
    let serverKey = "./server.key"
    let serverCrt = "./server.crt"

    // OpenSSL 官方标准、无风险的测试用命令
    let cmdStr = "openssl req -x509 -newkey rsa:2048 -nodes -keyout ${serverKey} -out ${serverCrt} -days 365 -subj \"/CN=localhost\""
    executeWithOutput("sh", ["-c", cmdStr])

    // 获取证书
    let serverCrtContent = String.fromUtf8(readToEnd(File(serverCrt, Read)))
    let serverCertificate = X509Certificate.decodeFromPem(serverCrtContent)

    let config = KeylessTlsServerConfig(serverCertificate, keylessSignFunc)

    // 默认情况下使用 openssl 自动生成的参数值
    println("服务端的 DH 密钥参数: ${config.dhParameters}")

    // 删除证书和私钥文件
    removeIfExists(serverCrt)
    removeIfExists(serverKey)
    return 0
}

public func keylessSignFunc(data: Array<Byte>): Array<Byte> {
    return data
}

运行结果:

服务端的 DH 密钥参数: None

prop securityLevel

public mut prop securityLevel: Int32

功能:指定服务端的安全级别,默认值为 2,可选参数值在 [0,5] 内,参数值含义参见 openssl-SSL_CTX_set_security_level 说明。

类型:Int32

异常:

  • IllegalArgumentException - 当配置值不在 0-5 范围内时,抛出异常。

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.x509.*
import stdx.net.tls.*

main() {
    // 定义证书和私钥文件
    let serverKey = "./server.key"
    let serverCrt = "./server.crt"

    // OpenSSL 官方标准、无风险的测试用命令
    let cmdStr = "openssl req -x509 -newkey rsa:2048 -nodes -keyout ${serverKey} -out ${serverCrt} -days 365 -subj \"/CN=localhost\""
    executeWithOutput("sh", ["-c", cmdStr])

    // 获取证书
    let serverCrtContent = String.fromUtf8(readToEnd(File(serverCrt, Read)))
    let serverCertificate = X509Certificate.decodeFromPem(serverCrtContent)

    let config = KeylessTlsServerConfig(serverCertificate, keylessSignFunc)
    config.securityLevel = 2 // 设置安全级别为默认值

    println("安全级别已设置为: ${config.securityLevel}")

    // 删除证书和私钥文件
    removeIfExists(serverCrt)
    removeIfExists(serverKey)
    return 0
}

public func keylessSignFunc(data: Array<Byte>): Array<Byte> {
    return data
}

运行结果:

安全级别已设置为: 2

prop supportedAlpnProtocols

public mut prop supportedAlpnProtocols: Array<String>

功能:应用层协商协议,若客户端尝试协商该协议,服务端将与选取其中相交的协议名称。若客户端未尝试协商协议,则该配置将被忽略。

类型:Array<String>

异常:

  • IllegalArgumentException - 列表元素有 '\0' 字符时,抛出异常。

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.x509.*
import stdx.net.tls.*

main() {
    // 定义证书和私钥文件
    let serverKey = "./server.key"
    let serverCrt = "./server.crt"

    // OpenSSL 官方标准、无风险的测试用命令
    let cmdStr = "openssl req -x509 -newkey rsa:2048 -nodes -keyout ${serverKey} -out ${serverCrt} -days 365 -subj \"/CN=localhost\""
    executeWithOutput("sh", ["-c", cmdStr])

    // 获取证书
    let serverCrtContent = String.fromUtf8(readToEnd(File(serverCrt, Read)))
    let serverCertificate = X509Certificate.decodeFromPem(serverCrtContent)

    let config = KeylessTlsServerConfig(serverCertificate, keylessSignFunc)
    config.supportedAlpnProtocols = ["http/1.1", "h2"] // 设置支持的 ALPN 协议

    println("支持的 ALPN 协议: ${config.supportedAlpnProtocols}")

    // 删除证书和私钥文件
    removeIfExists(serverCrt)
    removeIfExists(serverKey)
    return 0
}

public func keylessSignFunc(data: Array<Byte>): Array<Byte> {
    return data
}

运行结果:

支持的 ALPN 协议: [http/1.1, h2]

prop supportedCipherSuites

public mut prop supportedCipherSuites: Map<TlsVersion, Array<String>>

功能:设置或获取每个 TLS 版本对应的密码套件。

类型:Map<TlsVersion, Array<String>>

异常:

  • IllegalArgumentException - 通过传入 Map 设置密码套件时,某个 TLS 版本对应的密码套件字符串中包含空字符 \0,则抛出异常。

示例:

import std.fs.*
import std.io.*
import std.process.*
import std.collection.*
import stdx.crypto.x509.*
import stdx.net.tls.*
import stdx.net.tls.common.*

main() {
    // 定义证书和私钥文件
    let serverKey = "./server.key"
    let serverCrt = "./server.crt"

    // OpenSSL 官方标准、无风险的测试用命令
    let cmdStr = "openssl req -x509 -newkey rsa:2048 -nodes -keyout ${serverKey} -out ${serverCrt} -days 365 -subj \"/CN=localhost\""
    executeWithOutput("sh", ["-c", cmdStr])

    // 获取证书
    let serverCrtContent = String.fromUtf8(readToEnd(File(serverCrt, Read)))
    let serverCertificate = X509Certificate.decodeFromPem(serverCrtContent)

    let config = KeylessTlsServerConfig(serverCertificate, keylessSignFunc)

    // 设置 TLS 1.2 和 1.3 支持的密码套件
    var cipherSuites = HashMap<TlsVersion, Array<String>>()
    cipherSuites[TlsVersion.V1_2] = ["TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"]
    cipherSuites[TlsVersion.V1_3] = ["TLS_AES_256_GCM_SHA384"]
    config.supportedCipherSuites = cipherSuites

    // 删除证书和私钥文件
    removeIfExists(serverCrt)
    removeIfExists(serverKey)
    return 0
}

public func keylessSignFunc(data: Array<Byte>): Array<Byte> {
    return data
}

prop supportedVersions

public mut prop supportedVersions: Array<TlsVersion>

功能:设置或获取支持的 TLS 版本。

类型:Array<TlsVersion>

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.x509.*
import stdx.net.tls.*
import stdx.net.tls.common.*

main() {
    // 定义证书和私钥文件
    let serverKey = "./server.key"
    let serverCrt = "./server.crt"

    // OpenSSL 官方标准、无风险的测试用命令
    let cmdStr = "openssl req -x509 -newkey rsa:2048 -nodes -keyout ${serverKey} -out ${serverCrt} -days 365 -subj \"/CN=localhost\""
    executeWithOutput("sh", ["-c", cmdStr])

    // 获取证书
    let serverCrtContent = String.fromUtf8(readToEnd(File(serverCrt, Read)))
    let serverCertificate = X509Certificate.decodeFromPem(serverCrtContent)

    let config = KeylessTlsServerConfig(serverCertificate, keylessSignFunc)
    config.supportedVersions = [TlsVersion.V1_2, TlsVersion.V1_3] // 支持 TLS 1.2 和 1.3 版本

    println("支持的 TLS 版本数量: ${config.supportedVersions.size}")

    // 删除证书和私钥文件
    removeIfExists(serverCrt)
    removeIfExists(serverKey)
    return 0
}

public func keylessSignFunc(data: Array<Byte>): Array<Byte> {
    return data
}

运行结果:

支持的 TLS 版本数量: 2

prop verifyMode

public mut prop verifyMode: CertificateVerifyMode

功能:设置或获取认证模式,默认值为 CertificateVerifyMode.Default,即认证系统证书。

类型:CertificateVerifyMode

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.x509.*
import stdx.net.tls.*
import stdx.net.tls.common.*

main() {
    // 定义证书和私钥文件
    let serverKey = "./server.key"
    let serverCrt = "./server.crt"

    // OpenSSL 官方标准、无风险的测试用命令
    let cmdStr = "openssl req -x509 -newkey rsa:2048 -nodes -keyout ${serverKey} -out ${serverCrt} -days 365 -subj \"/CN=localhost\""
    executeWithOutput("sh", ["-c", cmdStr])

    // 获取证书
    let serverCrtContent = String.fromUtf8(readToEnd(File(serverCrt, Read)))
    let serverCertificate = X509Certificate.decodeFromPem(serverCrtContent)

    let config = KeylessTlsServerConfig(serverCertificate, keylessSignFunc)
    config.verifyMode = CertificateVerifyMode.TrustAll // 设置为信任所有证书

    println("证书验证模式已设置为: TrustAll")

    // 删除证书和私钥文件
    removeIfExists(serverCrt)
    removeIfExists(serverKey)
    return 0
}

public func keylessSignFunc(data: Array<Byte>): Array<Byte> {
    return data
}

运行结果:

证书验证模式已设置为: TrustAll

init(Array<X509Certificate>, KeylessSignFunc, ?KeylessDecryptFunc)

public init(certChain: Array<X509Certificate>, signCallback: KeylessSignFunc, decryptCallback!: ?KeylessDecryptFunc = None<KeylessDecryptFunc>)

功能:构造 KeylessTlsServerConfig 对象。

参数:

异常:

  • IllegalArgumentException - 当 certChain 为空时,抛出异常。

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.x509.*
import stdx.net.tls.*

main() {
    // 定义证书和私钥文件
    let serverKey = "./server.key"
    let serverCrt = "./server.crt"

    // OpenSSL 官方标准、无风险的测试用命令
    let cmdStr = "openssl req -x509 -newkey rsa:2048 -nodes -keyout ${serverKey} -out ${serverCrt} -days 365 -subj \"/CN=localhost\""
    executeWithOutput("sh", ["-c", cmdStr])

    // 获取证书
    let serverCrtContent = String.fromUtf8(readToEnd(File(serverCrt, Read)))
    let serverCertificate = X509Certificate.decodeFromPem(serverCrtContent)

    let config = KeylessTlsServerConfig(serverCertificate, keylessSignFunc)

    // 删除证书和私钥文件
    removeIfExists(serverCrt)
    removeIfExists(serverKey)
    return 0
}

public func keylessSignFunc(data: Array<Byte>): Array<Byte> {
    println("此处模拟调用外部密钥服务器完成签名操作")
    return data
}

class TlsClientSession

public class TlsClientSession <: TlsSession & Equatable<TlsClientSession> & ToString & Hashable

功能:此结构体表示已建立的客户端会话。此结构体实例用户不可创建,其内部结构对用户不可见。

当客户端 TLS 握手成功后,将会生成一个会话,当连接因一些原因丢失后,客户端可以通过这个会话 id 复用此次会话,省略握手流程。

父类型:

func hashCode()

public override func hashCode(): Int64

功能:生成会话 id 哈希值。

返回值:

  • Int64 - 会话 id 哈希值。

示例:

import std.io.*
import std.fs.*
import std.net.*
import std.process.*
import stdx.net.tls.*
import stdx.crypto.x509.*
import stdx.crypto.keys.*
import stdx.net.tls.common.*

main() {
    // 定义证书和私钥文件路径
    let serverKey = "./server.key"
    let serverCrt = "./server.crt"

    // 启动服务器
    spawn {
        // OpenSSL 官方标准、无风险的测试命令用来本地生成证书和私钥
        let cmdStr = "openssl req -x509 -newkey rsa:2048 -nodes -keyout ${serverKey} -out ${serverCrt} -days 365 -subj \"/CN=localhost\""
        executeWithOutput("sh", ["-c", cmdStr])
        // 对证书以及私钥进行解析
        let pemString = String.fromUtf8(readToEnd(File(serverCrt, OpenMode.Read)))
        let keyString = String.fromUtf8(readToEnd(File(serverKey, OpenMode.Read)))

        let certificate = X509Certificate.decodeFromPem(pemString)
        let privateKey = GeneralPrivateKey.decodeFromPem(keyString)

        let config = TlsServerConfig(certificate, privateKey)

        // 启动 TCP 服务器
        try (server = TcpServerSocket(bindAt: 8443)) {
            // 绑定并监听
            server.bind()
            // 接受客户端连接,如果需要多次连接,可以使用循环,参考 samples
            try (clientSocket = server.accept()) {
                // 创建 TLS 套接字并进行握手
                try (tls = TlsSocket.server(clientSocket, serverConfig: config, session: None)) {
                    // 此处握手之后就关闭链接
                    tls.handshake()
                }
            }
        }
    }
    // 等待服务器启动
    sleep(Duration.second)

    // 客户端配置
    var config = TlsClientConfig()
    config.verifyMode = TrustAll

    // 用于恢复会话
    var lastSession: ?TlsClientSession = None

    // 连接服务器
    try (socket = TcpSocket("127.0.0.1", 8443)) {
        // 首先进行 TCP 连接
        socket.connect()
        // 创建 TLS 套接字并进行握手
        try (tls = TlsSocket.client(socket, clientConfig: config, session: lastSession)) {
            try {
                let result = tls.handshake()
                // 读取数据时,关闭了链接
                tls.read(Array<Byte>(3, repeat: 0))

                // 成功协商下一次重新连接,将记住会话
                lastSession = match (result.session) {
                    case Some(r) => r as TlsClientSession
                    case None => None
                }
            } catch (e: Exception) {
                // 如果协商失败,将删除会话
                lastSession = None
                throw e
            }
            // 发送数据
            tls.write("这是一个由客户端发送的消息".toArray())
        }
    } catch (e: Exception) {
        println("客户端连接失败 ${e}, 重试中...")
    }
    // 删除生成的证书和私钥文件
    removeIfExists(serverKey)
    removeIfExists(serverCrt)

    println("会话 id 哈希值: ${lastSession?.hashCode() ?? 0}")
    println("会话 id 字符串: ${lastSession?.toString() ?? ""}")
    println("会话 id 相等: ${lastSession == lastSession}")
    println("会话 id 不相等: ${lastSession != lastSession}")
}

可能的运行结果:

会话 id 哈希值: 139444231039951559
会话 id 字符串: TlsClientSession(fbb54e2e0145dcfae89600faf24da3136a68fb1a3af3da6ecb56e2ee239bf083)
会话 id 相等: true
会话 id 不相等: false

func toString()

public override func toString(): String

功能:生成会话 id 字符串。

返回值:

示例:

参见 func hashCode 示例。

operator func !=(TlsClientSession)

public override operator func !=(other: TlsClientSession): Bool

功能:判断会话 id 是否不同。

参数:

返回值:

  • Bool - 若会话对象不同,返回 true;否则,返回 false

示例:

参见 func hashCode 示例。

operator func ==(TlsClientSession)

public override operator func ==(other: TlsClientSession): Bool

功能:判断会话 id 是否相同。

参数:

返回值:

  • Bool - 若会话对象相同,返回 true;否则,返回 false

示例:

参见 func hashCode 示例。

class TlsServerSession

public class TlsServerSession <: TlsSession & Equatable<TlsServerSession> & ToString

功能:该类表示 TLS 会话上下文,给客户端提供信息,确保客户端所连接的服务端仍为相同实例,用于连接复用时,验证客户端合法性。

说明:

当客户端尝试恢复会话时,双方都必须确保他们正在恢复与合法对端的会话。

父类型:

static func fromName(String)

public static func fromName(name: String): TlsServerSession

功能:通过名称创建 TlsServerSession 实例。

通过 TlsServerSession 保存的名称获取 TlsServerSession 对象。该名称用于区分 TLS 服务器,因此客户端依赖此名称来避免意外,尝试恢复与错误的服务器的连接。这里不一定使用加密安全名称,因为底层实现可以完成这项工作。从此函数返回的具有相同名称的两个 TlsServerSession 可能不相等,并且不保证可替换。尽管它们是从相同的名称创建的,因此服务器实例应该在整个生命周期内创建一个 TlsServerSession ,并且在每次 TlsSocket.server() 调用中使用它。

参数:

  • name: String - 会话上下文名称。

返回值:

示例:

import stdx.net.tls.*

main() {
    // 通过名称创建 TLS 服务端会话
    let session1 = TlsServerSession.fromName("my-server")

    println("会话名称: ${session1}")
    return 0
}

运行结果:

会话名称: TlsServerSession(my-server)

func toString()

public override func toString(): String

功能:生成会话上下文名称字符串。

返回值:

示例:

import stdx.net.tls.*

main() {
    // 创建 TLS 服务端会话
    let session = TlsServerSession.fromName("test-session")

    // 获取会话名称字符串
    let sessionName = session.toString()

    println("获取到会话名称: ${sessionName}")
    return 0
}

运行结果:

获取到会话名称: TlsServerSession(test-session)

operator func !=(TlsServerSession)

public override operator func !=(other: TlsServerSession): Bool

功能:判断两 TlsServerSession 实例名称是否不同。

参数:

返回值:

  • Bool - 若 TlsServerSession 对象不同,返回 true;否则,返回 false

示例:

import stdx.net.tls.*

main() {
    // 创建两个不同名称的 TLS 服务端会话
    let session1 = TlsServerSession.fromName("server1")
    let session2 = TlsServerSession.fromName("server2")
    let session3 = TlsServerSession.fromName("server1")

    // 比较会话是否不同
    let isDifferent1 = session1 != session2 // 应该返回 true
    let isDifferent2 = session1 != session3 // 应该返回 false

    println("session1 与 session2 不同: ${isDifferent1}")
    println("session1 与 session3 不同: ${isDifferent2}")
    return 0
}

运行结果:

session1 与 session2 不同: true
session1 与 session3 不同: false

operator func ==(TlsServerSession)

public override operator func ==(other: TlsServerSession): Bool

功能:判断两 TlsServerSession 实例名称是否相同。

参数:

返回值:

  • Bool - 若 TlsServerSession 对象相同,返回 true;否则,返回 false

示例:

import stdx.net.tls.*

main() {
    // 创建两个相同名称的 TLS 服务端会话
    let session1 = TlsServerSession.fromName("same-server")
    let session2 = TlsServerSession.fromName("same-server")
    let session3 = TlsServerSession.fromName("different-server")

    // 比较会话是否相同
    let isSame1 = session1 == session2 // 应该返回 true
    let isSame2 = session1 == session3 // 应该返回 false

    println("session1 与 session2 相同: ${isSame1}")
    println("session1 与 session3 相同: ${isSame2}")
    return 0
}

运行结果:

session1 与 session2 相同: true
session1 与 session3 相同: false

class TlsSocket

public class TlsSocket <: TlsConnection & Equatable<TlsSocket> & Hashable

功能:TlsSocket 用于在客户端及服务端间创建加密传输通道。

父类型:

prop certificate

public prop certificate: Array<X509Certificate>

功能:获取本端证书。

类型:?Array<X509Certificate>

异常:

  • TlsException - 当套接字未完成 TLS 握手或本端 TLS 套接字已关闭时,抛出异常。

prop handshakeResult

public prop handshakeResult: ?TlsHandshakeResult

功能:获取 TLS 握手结果。

类型:TlsHandshakeResult

prop localAddress

public override prop localAddress: SocketAddress

功能:读取 TlsSocket 的本地地址。

类型:SocketAddress

异常:

  • SocketException - 本端建连的底层 TCP 套接字关闭,抛出异常。
  • TlsException - 本端配置为 TLS 的套接字已关闭时,抛出异常。

prop readTimeout

public override mut prop readTimeout: ?Duration

功能:读写 TlsSocket 的读超时时间。

类型:?Duration

异常:

  • SocketException - 本端建连的底层 TCP 套接字关闭,抛出异常。
  • TlsException - 本端配置为 TLS 的套接字已关闭时,抛出异常。
  • IllegalArgumentException - 设定的读超时时间为负值时,抛出异常。

prop remoteAddress

public override prop remoteAddress: SocketAddress

功能:读取 TlsSocket 的远端地址。

类型:SocketAddress

异常:

  • SocketException - 本端建连的底层 TCP 套接字关闭,抛出异常。
  • TlsException - 本端配置为 TLS 的套接字已关闭时,抛出异常。

prop socket

public prop socket: StreamingSocket

功能:TlsSocket 创建所使用的 StreamingSocket。

类型:StreamingSocket

异常:

  • TlsException - 本端配置为 TLS 套接字已关闭时,抛出异常。

prop writeTimeout

public override mut prop writeTimeout: ?Duration

功能:读写 TlsSocket 的写超时时间。

类型:?Duration

异常:

  • SocketException - 本端建连的底层 TCP 套接字关闭,抛出异常。
  • TlsException - 本端配置为 TLS 的套接字已关闭时,抛出异常。
  • IllegalArgumentException - 设定的写超时时间为负值时,抛出异常。

static func client(StreamingSocket, ?TlsClientSession, TlsClientConfig)

public static func client(
    socket: StreamingSocket,
    session!: ?TlsClientSession = None,
    clientConfig!: TlsClientConfig = TlsClientConfig()
): TlsSocket

功能:根据传入的 StreamingSocket 实例创建指定地址的客户端 TLS 套接字,该套接字可用于客户端 TLS 握手及会话。

参数:

  • socket: StreamingSocket - 已连接到服务端的客户端 TCP 套接字。
  • session!: ?TlsClientSession - TLS 会话 id,若存在可用的 TLS 会话, 则可通过该 id 恢复历史 TLS 会话,省去 TLS 建立连接时间,但使用该会话依然可能协商失败。默认为 None
  • clientConfig!: TlsClientConfig - 客户端配置,默认为 TlsClientConfig()。

返回值:

示例:

import std.io.*
import std.fs.*
import std.net.*
import std.process.*
import stdx.net.tls.*
import stdx.crypto.x509.*
import stdx.crypto.keys.*
import stdx.net.tls.common.*

main() {
    // 定义证书和私钥文件路径
    let serverKey = "./server.key"
    let serverCrt = "./server.crt"

    // 启动服务器
    spawn {
        // OpenSSL 官方标准、无风险的测试命令用来本地生成证书和私钥
        let cmdStr = "openssl req -x509 -newkey rsa:2048 -nodes -keyout ${serverKey} -out ${serverCrt} -days 365 -subj \"/CN=localhost\""
        executeWithOutput("sh", ["-c", cmdStr])
        // 对证书以及私钥进行解析
        let pemString = String.fromUtf8(readToEnd(File(serverCrt, OpenMode.Read)))
        let keyString = String.fromUtf8(readToEnd(File(serverKey, OpenMode.Read)))

        let certificate = X509Certificate.decodeFromPem(pemString)
        let privateKey = GeneralPrivateKey.decodeFromPem(keyString)

        let config = TlsServerConfig(certificate, privateKey)

        // 启动 TCP 服务器
        try (server = TcpServerSocket(bindAt: 8443)) {
            // 绑定并监听
            server.bind()
            // 接受客户端连接,如果需要多次连接,可以使用循环,参考 samples
            try (clientSocket = server.accept()) {
                // 创建 TLS 套接字并进行握手
                try (tls = TlsSocket.server(clientSocket, serverConfig: config)) {
                    tls.handshake()
                    // 读取数据并打印
                    let buffer = Array<Byte>(39, repeat: 0)
                    tls.read(buffer)
                    println(String.fromUtf8(buffer))
                }
            }
        }
    }
    // 等待服务器启动
    sleep(Duration.second)

    // 客户端配置
    var config = TlsClientConfig()
    config.verifyMode = TrustAll

    // 连接服务器
    try (socket = TcpSocket("127.0.0.1", 8443)) {
        // 首先进行 TCP 连接
        socket.connect()
        // 创建 TLS 套接字并进行握手
        try (tls = TlsSocket.client(socket, clientConfig: config)) {
            tls.handshake()
            // 发送数据
            tls.write("这是一个由客户端发送的消息".toArray())
        }
    } catch (e: Exception) {
        println("client connection failed ${e}, retrying...")
    }
    removeIfExists(serverKey)
    removeIfExists(serverCrt)
    return 0
}

运行结果:

这是一个由客户端发送的消息

static func server(StreamingSocket, ?TlsServerSession, KeylessTlsServerConfig)

public static func server(
    socket: StreamingSocket,
    session!: ?TlsServerSession = None,
    serverConfig!: KeylessTlsServerConfig
): TlsSocket

功能:根据传入的 StreamingSocket 实例创建指定地址的服务端 TLS 套接字,该套接字可用于服务端无私钥场景下 TLS 握手及会话。

参数:

  • socket: StreamingSocket - TCP 连接建立完成后接受到套接字。
  • session!: ?TlsServerSession - TLS 会话 id, 若存在可用的 TLS 会话, 则可通过该 id 恢复历史 TLS 会话,省去 TLS 建立连接时间,但使用该会话依然可能协商失败。默认为 None。
  • serverConfig!: KeylessTlsServerConfig - 服务端配置。

返回值:

示例:

import std.io.*
import std.fs.*
import std.net.*
import std.process.*
import stdx.net.tls.*
import stdx.crypto.x509.*
import stdx.net.tls.common.*

// 此处私钥仅用于生成证书,该示例采用 Keyless TLS
let serverKey = "./server.key"
let serverCrt = "./server.crt"

main() {
    // 启动服务器
    spawn {
        // OpenSSL 官方标准、无风险的测试命令用来本地生成证书和私钥
        let cmdStr = "openssl req -x509 -newkey rsa:2048 -nodes -keyout ${serverKey} -out ${serverCrt} -days 365 -subj \"/CN=localhost\""
        executeWithOutput("sh", ["-c", cmdStr])
        // 对证书以及私钥进行解析
        let pemString = String.fromUtf8(readToEnd(File(serverCrt, OpenMode.Read)))

        let certificate = X509Certificate.decodeFromPem(pemString)

        // 签名回调函数和解密回调函数由第三方安全组件提供,此处只做模拟
        let config = KeylessTlsServerConfig(certificate, keylessSignFunc, decryptCallback: decryptCallback)

        // 启动 TCP 服务器
        try (server = TcpServerSocket(bindAt: 8443)) {
            // 绑定并监听
            server.bind()
            // 接受客户端连接,如果需要多次连接,可以使用循环,参考 samples
            try (clientSocket = server.accept()) {
                // 创建 TLS 套接字并进行握手
                try (tls = TlsSocket.server(clientSocket, serverConfig: config)) {
                    // 因为是模拟,所以不进行握手
                    // tls.handshake()
                    // 后续其他行为
                }
            }
        }
    }
    // 等待服务器启动
    sleep(Duration.second)

    // 客户端配置
    var config = TlsClientConfig()
    config.verifyMode = TrustAll

    // 连接服务器
    try (socket = TcpSocket("127.0.0.1", 8443)) {
        // 首先进行 TCP 连接
        socket.connect()
        // 创建 TLS 套接字并进行握手
        try (tls = TlsSocket.client(socket, clientConfig: config)) {
            // 因为是模拟,所以不进行握手
            // tls.handshake()
            // 后续其他行为
        }
    } catch (e: Exception) {
        println("client connection failed ${e}, retrying...")
    }
    removeIfExists(serverKey)
    removeIfExists(serverCrt)
    return 0
}

// 签名回调函数:接收待签名数据,调用第三方组件完成签名
public func keylessSignFunc(_: Array<Byte>): Array<Byte> {
    println("此处模拟调用外部密钥服务完成签名操作")
    return []
}

// 解密回调函数:接收加密数据,调用第三方组件完成解密
public func decryptCallback(_: Array<Byte>): Array<Byte> {
    println("此处模拟调用外部密钥服务完成解密操作")
    return []
}

static func server(StreamingSocket, ?TlsServerSession, TlsServerConfig)

public static func server(
    socket: StreamingSocket,
    session!: ?TlsServerSession = None,
    serverConfig!: TlsServerConfig
): TlsSocket

功能:根据传入的 StreamingSocket 实例创建指定地址的服务端 TLS 套接字,该套接字可用于服务端 TLS 握手及会话。

参数:

  • socket: StreamingSocket - TCP 连接建立完成后接受到套接字。
  • session!: ?TlsServerSession - TLS 会话 id, 若存在可用的 TLS 会话, 则可通过该 id 恢复历史 TLS 会话,省去 TLS 建立连接时间,但使用该会话依然可能协商失败。默认为 None。
  • serverConfig!: TlsServerConfig - 服务端配置,默认为 TlsServerConfig()。

返回值:

示例:

参见 static func client 示例。

func close()

public func close(): Unit

功能:关闭套接字。

异常:

  • SocketException - 底层连接无法关闭时,抛出异常。

示例:

import std.io.*
import std.fs.*
import std.net.*
import std.process.*
import stdx.net.tls.*
import stdx.crypto.x509.*
import stdx.crypto.keys.*
import stdx.net.tls.common.*

main() {
    // 定义证书和私钥文件路径
    let serverKey = "./server.key"
    let serverCrt = "./server.crt"

    // 启动服务器
    spawn {
        // OpenSSL 官方标准、无风险的测试命令用来本地生成证书和私钥
        let cmdStr = "openssl req -x509 -newkey rsa:2048 -nodes -keyout ${serverKey} -out ${serverCrt} -days 365 -subj \"/CN=localhost\""
        executeWithOutput("sh", ["-c", cmdStr])
        // 对证书以及私钥进行解析
        let pemString = String.fromUtf8(readToEnd(File(serverCrt, OpenMode.Read)))
        let keyString = String.fromUtf8(readToEnd(File(serverKey, OpenMode.Read)))

        let certificate = X509Certificate.decodeFromPem(pemString)
        let privateKey = GeneralPrivateKey.decodeFromPem(keyString)

        let config = TlsServerConfig(certificate, privateKey)

        // 启动 TCP 服务器
        try (server = TcpServerSocket(bindAt: 8443)) {
            // 绑定并监听
            server.bind()
            // 接受客户端连接,如果需要多次连接,可以使用循环,参考 samples
            try (clientSocket = server.accept()) {
                // 创建 TLS 套接字并进行握手
                let tls = TlsSocket.server(clientSocket, serverConfig: config)
                tls.handshake()
                // 读取数据并打印
                let buffer = Array<Byte>(39, repeat: 0)
                tls.read(buffer)
                println(String.fromUtf8(buffer))
                // 关闭连接,此处如果使用try-with-resources,可以省略
                tls.close()
            }
        }
    }
    // 等待服务器启动
    sleep(Duration.second)

    // 客户端配置
    var config = TlsClientConfig()
    config.verifyMode = TrustAll

    // 连接服务器
    try (socket = TcpSocket("127.0.0.1", 8443)) {
        // 首先进行 TCP 连接
        socket.connect()
        // 创建 TLS 套接字并进行握手
        let tls = TlsSocket.client(socket, clientConfig: config)
        tls.handshake()
        // 发送数据
        tls.write("这是一个由客户端发送的消息".toArray())

        // 关闭连接,此处如果使用try-with-resources,可以省略
        tls.close()
        println("客户端成功关闭连接: ${tls.isClosed()}")
    } catch (e: Exception) {
        println("client connection failed ${e}, retrying...")
    }
    removeIfExists(serverKey)
    removeIfExists(serverCrt)
    return 0
}

运行结果:

这是一个由客户端发送的消息
客户端成功关闭连接: true

func handshake(?Duration)

public func handshake(timeout!: ?Duration = None): TlsHandshakeResult

功能:TLS 握手。不支持重新协商握手,因此只能被调用一次。调用对象可以为客户端或者服务端的 TlsSocket

参数:

  • timeout!: ?Duration - 握手超时时间,默认为 None 不对超时时间进行设置,此时采用默认 30s 的超时时间。

返回值:

异常:

  • SocketException - 本端建连的底层 TCP 套接字关闭,抛出异常。
  • SocketTimeoutException - 底层 TCP 套接字连接超时时,抛出异常。
  • TlsException - 当握手已经开始或者已经结束,抛出异常;或当握手阶段出现系统错误时,抛出异常。
  • IllegalArgumentException - 设定的握手超时时间为负值时,抛出异常。

示例:

参见 static func client 示例。

func hashCode()

public override func hashCode(): Int64

功能:返回 TLS 套接字对象的哈希值。

返回值:

  • Int64 - 对 TLS 套接字对象进行哈希计算后得到的结果。

示例:

参见 func toString 示例。

func isClosed()

public func isClosed(): Bool

功能:返回套接字是否关闭的状态。

返回值:

  • Bool - 连接断开返回 true;否则,返回 false。

示例:

参见 func close 示例。

func read(Array<Byte>)

public override func read(buffer: Array<Byte>): Int64

功能:TlsSocket 读取数据。

参数:

  • buffer: Array<Byte> - 存储读取到的数据内容的数组。

返回值:

  • Int64 - 读取到的数据内容字节数。

异常:

  • SocketException - 本端建连的底层 TCP 套接字关闭,抛出异常。
  • TlsException - 当 buffer 为空,或者 TlsSocket 未连接,或读取数据出现系统错误等。

示例:

参见 static func client 示例。

func toString()

public func toString(): String

功能:套接字的字符串表示,字符串内容为当前套接字状态。

说明:

例如:当前套接字处于可开始进行握手状态时,该接口将返回字符串 "TlsSocket(TcpSocket(${本端地址} -> ${对端地址}), ready for handshake)"

返回值:

  • String - 该 TLS 连接字符串。

示例:

import std.io.*
import std.fs.*
import std.net.*
import std.process.*
import stdx.net.tls.*
import stdx.crypto.x509.*
import stdx.crypto.keys.*
import stdx.net.tls.common.*

main() {
    // 定义证书和私钥文件路径
    let serverKey = "./server.key"
    let serverCrt = "./server.crt"

    // 启动服务器
    spawn {
        // OpenSSL 官方标准、无风险的测试命令用来本地生成证书和私钥
        let cmdStr = "openssl req -x509 -newkey rsa:2048 -nodes -keyout ${serverKey} -out ${serverCrt} -days 365 -subj \"/CN=localhost\""
        executeWithOutput("sh", ["-c", cmdStr])
        // 对证书以及私钥进行解析
        let pemString = String.fromUtf8(readToEnd(File(serverCrt, OpenMode.Read)))
        let keyString = String.fromUtf8(readToEnd(File(serverKey, OpenMode.Read)))

        let certificate = X509Certificate.decodeFromPem(pemString)
        let privateKey = GeneralPrivateKey.decodeFromPem(keyString)

        let config = TlsServerConfig(certificate, privateKey)

        // 启动 TCP 服务器
        try (server = TcpServerSocket(bindAt: 8443)) {
            // 绑定并监听
            server.bind()
            // 接受客户端连接,如果需要多次连接,可以使用循环,参考 samples
            try (clientSocket = server.accept()) {
                // 创建 TLS 套接字并进行握手
                try (tls = TlsSocket.server(clientSocket, serverConfig: config)) {
                    tls.handshake()
                    // 读取数据并打印
                    let buffer = Array<Byte>(100, repeat: 0)
                    tls.read(buffer)
                    println(String.fromUtf8(buffer))

                    // 打印 TLS 套接字的字符串表示和哈希值
                    println("服务端 toString: ${tls}")
                    println("服务端 hashCode: ${tls.hashCode()}")
                }
            }
        }
    }
    // 等待服务器启动
    sleep(Duration.second)

    // 客户端配置
    var config = TlsClientConfig()
    config.verifyMode = TrustAll

    // 连接服务器
    try (socket = TcpSocket("127.0.0.1", 8443)) {
        // 首先进行 TCP 连接
        socket.connect()
        // 创建 TLS 套接字并进行握手
        try (tls = TlsSocket.client(socket, clientConfig: config)) {
            tls.handshake()
            // 发送数据
            tls.write("客户端发送: 这是一个由客户端发送的消息".toArray())

            // 打印 TLS 套接字的字符串表示和哈希值
            println("客户端 toString: ${tls}")
            println("客户端 hashCode: ${tls.hashCode()}")
        }
    } catch (e: Exception) {
        println("client connection failed ${e}, retrying...")
    }
    removeIfExists(serverKey)
    removeIfExists(serverCrt)
    return 0
}

可能的运行结果:

客户端 toString: TlsSocket(TcpSocket(127.0.0.1:35680 -> 127.0.0.1:8443), connected)
客户端 hashCode: 1
客户端发送: 这是一个由客户端发送的消息
服务端 toString: TlsSocket(TcpSocket(127.0.0.1:8443 -> 127.0.0.1:35680), connected)
服务端 hashCode: 2

func write(Array<Byte>)

public func write(buffer: Array<Byte>): Unit

功能:TlsSocket 发送数据。

参数:

  • buffer: Array<Byte> - 存储将要发送的数据内容数组。

异常:

  • SocketException - 本端建连的底层 TCP 套接字关闭,抛出异常。
  • TlsException - 当套接字已关闭,或者 TlsSocket 未连接,或写入数据出现系统错误等。

示例:

参见 static func client 示例。

operator func !=(TlsSocket)

public override operator func !=(other: TlsSocket): Bool

功能:判断两 TlsSocket 是否引用不同实例。

参数:

  • other: TlsSocket - 对比的 TLS 套接字。

返回值:

  • Bool - 对比的套接字不同返回 true;否则,返回 false

示例:

import std.io.*
import std.fs.*
import std.net.*
import std.process.*
import stdx.net.tls.*
import stdx.crypto.x509.*
import stdx.crypto.keys.*
import stdx.net.tls.common.*

main() {
    // 定义证书和私钥文件路径
    let serverKey = "./server.key"
    let serverCrt = "./server.crt"

    // 启动服务器
    spawn {
        // OpenSSL 官方标准、无风险的测试命令用来本地生成证书和私钥
        let cmdStr = "openssl req -x509 -newkey rsa:2048 -nodes -keyout ${serverKey} -out ${serverCrt} -days 365 -subj \"/CN=localhost\""
        executeWithOutput("sh", ["-c", cmdStr])
        // 对证书以及私钥进行解析
        let pemString = String.fromUtf8(readToEnd(File(serverCrt, OpenMode.Read)))
        let keyString = String.fromUtf8(readToEnd(File(serverKey, OpenMode.Read)))

        let certificate = X509Certificate.decodeFromPem(pemString)
        let privateKey = GeneralPrivateKey.decodeFromPem(keyString)

        let config = TlsServerConfig(certificate, privateKey)

        // 启动 TCP 服务器
        try (server = TcpServerSocket(bindAt: 8443)) {
            // 绑定并监听
            server.bind()
            // 接受客户端连接,如果需要多次连接,可以使用循环,参考 samples
            try (clientSocket = server.accept()) {
                // 创建 TLS 套接字并进行握手
                try (tls = TlsSocket.server(clientSocket, serverConfig: config)) {
                    tls.handshake()
                    // 读取数据并打印
                    let buffer = Array<Byte>(39, repeat: 0)
                    tls.read(buffer)
                    println(String.fromUtf8(buffer))
                    println("和自己对比相等: ${tls == tls}")
                    println("和自己对比不等: ${tls != tls}")
                }
            }
        }
    }
    // 等待服务器启动
    sleep(Duration.second)

    // 客户端配置
    var config = TlsClientConfig()
    config.verifyMode = TrustAll

    // 连接服务器
    try (socket = TcpSocket("127.0.0.1", 8443)) {
        // 首先进行 TCP 连接
        socket.connect()
        // 创建 TLS 套接字并进行握手
        try (tls = TlsSocket.client(socket, clientConfig: config)) {
            tls.handshake()
            // 发送数据
            tls.write("这是一个由客户端发送的消息".toArray())
        }
    } catch (e: Exception) {
        println("client connection failed ${e}, retrying...")
    }
    removeIfExists(serverKey)
    removeIfExists(serverCrt)
    return 0
}

运行结果:

这是一个由客户端发送的消息
和自己对比相等: true
和自己对比不等: false

operator func ==(TlsSocket)

public override operator func ==(other: TlsSocket): Bool

功能:判断两 TlsSocket 是否引用同一实例。

参数:

  • other: TlsSocket - 对比的 TLS 套接字。

返回值:

  • Bool - 对比的套接字相同返回 true;否则,返回 false

示例:

参见 operator func != 示例。

枚举

enum SignatureAlgorithm

public enum SignatureAlgorithm <: ToString & Equatable<SignatureAlgorithm> {
    | SignatureAndHashAlgorithm(SignatureType, HashType)
    | SignatureScheme(SignatureSchemeType)
}

功能:签名算法类型,签名算法用于确保传输数据的身份验证、完整性和真实性。

父类型:

SignatureAndHashAlgorithm(SignatureType, HashType)

SignatureAndHashAlgorithm(SignatureType, HashType)

功能:表明哪个签名和哈希算法对会被用于数字签名,自 TLS 1.2 及以后版本,包含签名和哈希算法类型。

SignatureScheme(SignatureSchemeType)

SignatureScheme(SignatureSchemeType)

功能:签名方案,自 TLS 1.3 及以后版本,业界更为推荐的指定签名算法的方式。

func toString()

public func toString():String

功能:转换签名算法的字符串表示。

返回值:

  • String - 签名算法名称。

示例:

import stdx.net.tls.*

main() {
    let sigAlg = SignatureAlgorithm.SignatureScheme(RSA_PKCS1_SHA256)
    let str = sigAlg.toString()
    println("签名算法的字符串表示: ${str}")
    return 0
}

运行结果:

签名算法的字符串表示: rsa_pkcs1_sha256

operator func !=(SignatureAlgorithm)

public operator func !=(other: SignatureAlgorithm): Bool

功能:判断签名算法类型是否不同。

参数:

返回值:

  • Bool - 不相同返回 true;否则,返回 false

示例:

import stdx.net.tls.*
import stdx.crypto.digest.*

main() {
    let sigAlg1 = SignatureAlgorithm.SignatureAndHashAlgorithm(SignatureType.RSA, HashType.SHA256)
    let sigAlg2 = SignatureAlgorithm.SignatureAndHashAlgorithm(SignatureType.ECDSA, HashType.SHA256)
    let isNotEqual = sigAlg1 != sigAlg2
    println("签名算法是否不同: ${isNotEqual}")
    return 0
}

运行结果:

签名算法是否不同: true

operator func ==(SignatureAlgorithm)

public operator func ==(other: SignatureAlgorithm): Bool

功能:判断签名算法类型是否相同。

参数:

返回值:

  • Bool - 相同返回 true;否则,返回 false

示例:

import stdx.net.tls.*
import stdx.crypto.digest.*

main() {
    let sigAlg1 = SignatureAlgorithm.SignatureAndHashAlgorithm(SignatureType.RSA, HashType.SHA256)
    let sigAlg2 = SignatureAlgorithm.SignatureAndHashAlgorithm(SignatureType.RSA, HashType.SHA256)
    let isEqual = sigAlg1 == sigAlg2
    println("签名算法是否相同: ${isEqual}")
    return 0
}

运行结果:

签名算法是否相同: true

enum SignatureSchemeType

public enum SignatureSchemeType <: ToString & Equatable<SignatureSchemeType> {
    | RSA_PKCS1_SHA256
    | RSA_PKCS1_SHA384
    | RSA_PKCS1_SHA512
    | ECDSA_SECP256R1_SHA256
    | ECDSA_SECP384R1_SHA384
    | ECDSA_SECP521R1_SHA512
    | RSA_PSS_RSAE_SHA256
    | RSA_PSS_RSAE_SHA384
    | RSA_PSS_RSAE_SHA512
    | ED25519
    | ED448
    | RSA_PSS_PSS_SHA256
    | RSA_PSS_PSS_SHA384
    | RSA_PSS_PSS_SHA512
}

功能:加密算法类型,用于保护网络通信的安全性和隐私性。

父类型:

ECDSA_SECP256R1_SHA256

ECDSA_SECP256R1_SHA256

功能:创建一个 ECDSA_SECP256R1_SHA256 类型的枚举实例,表示加密算法类型使用 ECDSA_SECP256R1_SHA256

ECDSA_SECP384R1_SHA384

ECDSA_SECP384R1_SHA384

功能:创建一个 ECDSA_SECP384R1_SHA384 类型的枚举实例,表示加密算法类型使用 ECDSA_SECP384R1_SHA384

ECDSA_SECP521R1_SHA512

ECDSA_SECP521R1_SHA512

功能:创建一个 ECDSA_SECP521R1_SHA512 类型的枚举实例,表示加密算法类型使用 ECDSA_SECP521R1_SHA512

ED25519

ED25519

功能:创建一个 ED25519 类型的枚举实例,表示加密算法类型使用 ED25519。

ED448

ED448

功能:创建一个 ED448 类型的枚举实例,表示加密算法类型使用 ED448。

RSA_PKCS1_SHA256

RSA_PKCS1_SHA256

功能:创建一个 RSA_PKCS1_SHA256 类型的枚举实例,表示加密算法类型使用 RSA_PKCS1_SHA256

RSA_PKCS1_SHA384

RSA_PKCS1_SHA384

功能:创建一个 RSA_PKCS1_SHA384 类型的枚举实例,表示加密算法类型使用 RSA_PKCS1_SHA384

RSA_PKCS1_SHA512

RSA_PKCS1_SHA512

功能:创建一个 RSA_PKCS1_SHA512 类型的枚举实例,表示加密算法类型使用 RSA_PKCS1_SHA512

RSA_PSS_PSS_SHA256

RSA_PSS_PSS_SHA256

功能:创建一个 RSA_PSS_PSS_SHA256 类型的枚举实例,表示加密算法类型使用 RSA_PSS_PSS_SHA256

RSA_PSS_PSS_SHA384

RSA_PSS_PSS_SHA384

功能:创建一个 RSA_PSS_PSS_SHA384 类型的枚举实例,表示加密算法类型使用 RSA_PSS_PSS_SHA384

RSA_PSS_PSS_SHA512

RSA_PSS_PSS_SHA512

功能:创建一个 RSA_PSS_PSS_SHA512 类型的枚举实例,表示加密算法类型使用 RSA_PSS_PSS_SHA512

RSA_PSS_RSAE_SHA256

RSA_PSS_RSAE_SHA256

功能:创建一个 RSA_PSS_RSAE_SHA256 类型的枚举实例,表示加密算法类型使用 RSA_PSS_RSAE_SHA256

RSA_PSS_RSAE_SHA384

RSA_PSS_RSAE_SHA384

功能:创建一个 RSA_PSS_RSAE_SHA384 类型的枚举实例,表示加密算法类型使用 RSA_PSS_RSAE_SHA384

RSA_PSS_RSAE_SHA512

RSA_PSS_RSAE_SHA512

功能:创建一个 RSA_PSS_RSAE_SHA512 类型的枚举实例,表示加密算法类型使用 RSA_PSS_RSAE_SHA384

func toString()

public func toString(): String

功能:加密算法类型的字符串表示。

RSA_PKCS1_SHA256 的字符串表示为 "rsa_pkcs1_sha256"。

返回值:

  • String - 加密算法类型的字符串表示。

示例:

import stdx.net.tls.*

main() {
    let schemeType = SignatureSchemeType.RSA_PKCS1_SHA256
    let str = schemeType.toString()
    println("签名方案类型的字符串表示: ${str}")
    return 0
}

运行结果:

签名方案类型的字符串表示: rsa_pkcs1_sha256

operator func !=(SignatureSchemeType)

public operator func !=(other: SignatureSchemeType): Bool

功能:判断两者是否为不同加密算法类型。

参数:

返回值:

  • Bool - 不相同返回 true;否则,返回 false。

示例:

import stdx.net.tls.*

main() {
    let schemeType1 = SignatureSchemeType.RSA_PKCS1_SHA256
    let schemeType2 = SignatureSchemeType.ECDSA_SECP256R1_SHA256
    let isNotEqual = schemeType1 != schemeType2
    println("签名方案类型是否不同: ${isNotEqual}")
    return 0
}

运行结果:

签名方案类型是否不同: true

operator func ==(SignatureSchemeType)

public operator func ==(other: SignatureSchemeType): Bool

功能:判断两者是否为同一加密算法类型。

参数:

返回值:

  • Bool - 相同返回 true;否则,返回 false。

示例:

import stdx.net.tls.*

main() {
    let schemeType1 = SignatureSchemeType.RSA_PKCS1_SHA256
    let schemeType2 = SignatureSchemeType.RSA_PKCS1_SHA256
    let isEqual = schemeType1 == schemeType2
    println("签名方案类型是否相同: ${isEqual}")
    return 0
}

运行结果:

签名方案类型是否相同: true

enum SignatureType

public enum SignatureType <: ToString & Equatable<SignatureType> {
    | DSA
    | ECDSA
    | RSA
}

功能:签名算法类型,用于认证真实性。参见 RFC5246 7.4.1.4.1 章节。

父类型:

DSA

DSA

功能:创建一个 DSA 类型的枚举实例,表示采用数字签名算法。

ECDSA

ECDSA

功能:创建一个 ECDSA 类型的枚举实例,表示采用椭圆曲线数字签名算法。

RSA

RSA

功能:创建一个 RSA 类型的枚举实例,表示采用 RSA 加密算法。

func toString()

public func toString(): String

功能:转换为签名算法的字符串表示。

返回值:

  • String - 签名算法的名称。

示例:

import stdx.net.tls.*

main() {
    let sigType = SignatureType.RSA
    let str = sigType.toString()
    println("签名类型的字符串表示: ${str}")
    return 0
}

运行结果:

签名类型的字符串表示: RSA

operator func !=(SignatureType)

public operator func !=(other: SignatureType): Bool

功能:判断两者是否为不同的签名算法。

参数:

返回值:

  • Bool - 不相同返回 true;否则,返回 false

示例:

import stdx.net.tls.*

main() {
    let sigType1 = SignatureType.RSA
    let sigType2 = SignatureType.ECDSA
    let isNotEqual = sigType1 != sigType2
    println("签名类型是否不同: ${isNotEqual}")
    return 0
}

运行结果:

签名类型是否不同: true

operator func ==(SignatureType)

public operator func ==(other: SignatureType): Bool

功能:判断两者是否为相同的签名算法。

参数:

返回值:

  • Bool - 相同返回 true;否则,返回 false

示例:

import stdx.net.tls.*

main() {
    let sigType1 = SignatureType.RSA
    let sigType2 = SignatureType.RSA
    let isEqual = sigType1 == sigType2
    println("签名类型是否相同: ${isEqual}")
    return 0
}

运行结果:

签名类型是否相同: true

enum TlsClientIdentificationMode

public enum TlsClientIdentificationMode {
    | Disabled
    | Optional
    | Required
}

功能:服务端对客户端证书的认证模式。

Disabled

Disabled

功能:表示服务端不校验客户端证书,客户端可以不发送证书和公钥,即单向认证。

Optional

Optional

功能:表示服务端校验客户端证书,但客户端可以不提供证书及公钥,不提供时则单向认证,提供时则为双向认证。

Required

Required

功能:表示服务端校验客户端证书,并且要求客户端必须提供证书和公钥,即双向认证。

结构体

struct CipherSuite

public struct CipherSuite <: ToString & Equatable<CipherSuite>

功能:TLS 中的密码套件。

父类型:

static prop allSupported

public static prop allSupported: Array<CipherSuite>

功能:返回所有支持的密码套件。

类型:Array<CipherSuite>

示例:

import stdx.net.tls.*

main() {
    let allSuites = CipherSuite.allSupported
    println("支持的密码套件数量: ${allSuites.size}")
    return 0
}

运行结果:

支持的密码套件数量: 60

func toString()

public func toString(): String

功能:返回密码套件名称。

返回值:

  • String - 密码套件名称。

示例:

import stdx.net.tls.*

main() {
    let suite = CipherSuite.allSupported[0]
    let name = suite.toString()
    println("密码套件名称: ${name}")
    return 0
}

运行结果:

密码套件名称: TLS_AES_256_GCM_SHA384

operator func !=(CipherSuite)

public operator func !=(that: CipherSuite): Bool

功能:判断两个密码套件是否不等。

参数:

  • that: CipherSuite - 被比较的密码套件对象。

返回值:

  • Bool - 若不等,则返回 true;反之,返回 false

示例:

import stdx.net.tls.*

main() {
    let suite1 = CipherSuite.allSupported[0]
    let suite2 = CipherSuite.allSupported[1]
    let isNotEqual = suite1 != suite2
    println("两个密码套件是否不等: ${isNotEqual}")
    return 0
}

运行结果:

两个密码套件是否不等: true

operator func ==(CipherSuite)

public operator func ==(that: CipherSuite): Bool

功能:判断两个密码套件是否相等。

参数:

  • that: CipherSuite - 被比较的密码套件对象。

返回值:

  • Bool - 若相等,则返回 true;反之,返回 false

示例:

import stdx.net.tls.*

main() {
    let suite1 = CipherSuite.allSupported[0]
    let suite2 = CipherSuite.allSupported[0] // 相同索引
    let isEqual = suite1 == suite2
    println("两个密码套件是否相等: ${isEqual}")
    return 0
}

运行结果:

两个密码套件是否相等: true

struct TlsClientConfig

public struct TlsClientConfig <: TlsConfig {
    public var keylogCallback: ?(TlsSocket, String) -> Unit = None
    public var verifyMode: CertificateVerifyMode = CertificateVerifyMode.Default
    public init()
}

功能:客户端配置。

父类型:

var keylogCallback

public var keylogCallback: ?(TlsSocket, String) -> Unit = None

功能:握手过程的回调函数,提供 TLS 初始秘钥数据,用于调试和解密记录使用。

类型:?(TlsSocket, String) -> Unit

prop certificate

public mut prop certificate: ?(Array<Certificate>, PrivateKey)

功能:设置或获取客户端证书和对应的私钥文件。其中证书必须为 X509Certificate 类型。

类型:?(Array<Certificate>, PrivateKey)

异常:

prop securityLevel

public mut prop securityLevel: Int32

功能:指定客户端的安全级别,默认值为 2,可选参数值在 0-5 内,参数值含义参见 openssl 的 SSL_CTX_set_security_level 说明。

类型:Int32

prop serverName

public mut prop serverName: ?String

功能:读写要求的服务端主机地址 (SNI), None 表示不要求。

类型:?String

异常:

  • IllegalArgumentException - 参数有 '\0' 字符时,抛出异常。

prop signatureAlgorithms

public mut prop signatureAlgorithms: ?Array<SignatureAlgorithm>

功能:指定保序的签名和哈希算法。在值为 None 或者列表为空时,客户端会使用默认的列表。指定列表后,客户端可能不会发送不合适的签名算法。 参见 RFC5246 7.4.1.4.1 (TLS 1.2) 章节, RFC8446 4.2.3. (TLS 1.3) 章节。

类型:?Array<SignatureAlgorithm>

prop supportedAlpnProtocols

public mut prop supportedAlpnProtocols: Array<String>

功能:应用层协商协议,若列表为空,则客户端将不协商应用层协议。

类型:Array<String>

异常:

  • IllegalArgumentException - 列表元素有 '\0' 字符时,抛出异常。

prop supportedCipherSuites

public mut prop supportedCipherSuites: Map<TlsVersion, Array<String>>

功能:设置或获取每个 TLS 版本对应的密码套件。

类型:Map<TlsVersion, Array<String>>

异常:

  • IllegalArgumentException - 通过传入 Map 设置密码套件时,某个 TLS 版本对应的密码套件字符串中包含空字符 \0,则抛出异常。

prop supportedVersions

public mut prop supportedVersions: Array<TlsVersion>

功能:设置或获取支持的 TLS 版本。

类型:Array<TlsVersion>

prop verifyMode

public mut prop verifyMode: CertificateVerifyMode

功能:设置或获取认证模式,默认值为 CertificateVerifyMode.Default,即认证系统证书。

类型:CertificateVerifyMode

init()

public init()

功能:构造 TlsClientConfig

示例:

import stdx.net.tls.*
import stdx.net.tls.common.*

main() {
    // 客户端配置
    var config = TlsClientConfig()
    config.verifyMode = TrustAll
    return 0
}

struct TlsServerConfig

public struct TlsServerConfig <: TlsConfig {
    public var keylogCallback: ?(TlsSocket, String) -> Unit = None
    public mut prop clientIdentityRequired: TlsClientIdentificationMode
    public mut prop verifyMode: CertificateVerifyMode
    public init(certChain: Array<X509Certificate>, certKey: PrivateKey)
}

父类型:

功能:服务端配置。

var keylogCallback

public var keylogCallback: ?(TlsSocket, String) -> Unit = None

功能:握手过程的回调函数,提供 TLS 初始秘钥数据,用于调试和解密记录使用。

类型:?(TlsSocket, String) -> Unit

prop certificate

public mut prop certificate: ?(Array<Certificate>, PrivateKey)

功能:设置或获取服务端证书和对应的私钥文件。其中证书必须为 X509Certificate 类型。不可设置为 None。

类型:?(Array<Certificate>, PrivateKey)

异常:

  • TlsException - 设置的服务端证书不是 X509Certificate 类型时,抛出异常;设置服务端证书和对应的私钥文件为 None 时,抛出异常。

prop clientIdentityRequired

public mut prop clientIdentityRequired: TlsClientIdentificationMode

功能:设置或获取服务端要求客户端的认证模式,默认值为 TlsClientIdentificationMode.Disable,即不要求客户端认证服务端证书,也不要求客户端发送本端证书。

类型:TlsClientIdentificationMode

prop dhParameters

public mut prop dhParameters: ?DHParameters

功能:指定服务端的 DH 密钥参数,默认为 None, 默认情况下使用 openssl 自动生成的参数值。

类型:?DHParameters

prop securityLevel

public mut prop securityLevel: Int32

功能:指定服务端的安全级别,默认值为 2,可选参数值在 [0,5] 内,参数值含义参见 openssl-SSL_CTX_set_security_level 说明。

类型:Int32

异常:

  • IllegalArgumentException - 当配置值不在 0-5 范围内时,抛出异常。

prop supportedAlpnProtocols

public mut prop supportedAlpnProtocols: Array<String>

功能:应用层协商协议,若客户端尝试协商该协议,服务端将与选取其中相交的协议名称。若客户端未尝试协商协议,则该配置将被忽略。

类型:Array<String>

异常:

  • IllegalArgumentException - 列表元素有 '\0' 字符时,抛出异常。

prop supportedCipherSuites

public mut prop supportedCipherSuites: Map<TlsVersion, Array<String>>

功能:设置或获取每个 TLS 版本对应的密码套件。

类型:Map<TlsVersion, Array<String>>

异常:

  • IllegalArgumentException - 通过传入 Map 设置密码套件时,某个 TLS 版本对应的密码套件字符串中包含空字符 \0,则抛出异常。

prop supportedVersions

public mut prop supportedVersions: Array<TlsVersion>

功能:设置或获取支持的 TLS 版本。

类型:Array<TlsVersion>

prop verifyMode

public mut prop verifyMode: CertificateVerifyMode

功能:设置或获取认证模式,默认值为 CertificateVerifyMode.Default,即认证系统证书。

类型:CertificateVerifyMode

init(Array<X509Certificate>, PrivateKey)

public init(certChain: Array<X509Certificate>, certKey: PrivateKey)

功能:构造 TlsServerConfig 对象。

参数:

示例:

import std.fs.*
import std.io.*
import std.process.*
import stdx.crypto.x509.*
import stdx.crypto.keys.*
import stdx.net.tls.*

main() {
    // 定义证书和私钥文件
    let serverKey = "./server.key"
    let serverCrt = "./server.crt"

    // OpenSSL 官方标准、无风险的测试用命令
    let cmdStr = "openssl req -x509 -newkey rsa:2048 -nodes -keyout ${serverKey} -out ${serverCrt} -days 365 -subj \"/CN=localhost\""
    executeWithOutput("sh", ["-c", cmdStr])

    // 获取证书和私钥内容
    let serverCrtContent = String.fromUtf8(readToEnd(File(serverCrt, Read)))
    let serverCertificate = X509Certificate.decodeFromPem(serverCrtContent)

    let serverKeyContent = String.fromUtf8(readToEnd(File(serverKey, Read)))
    let serverPrivateKey = GeneralPrivateKey.decodeFromPem(serverKeyContent)

    // 创建 TLS 服务器配置
    let _ = TlsServerConfig(serverCertificate, serverPrivateKey)

    // 删除证书和私钥文件
    removeIfExists(serverKey)
    removeIfExists(serverCrt)
    return 0
}

服务端证书及公钥在一份文件中

说明:

需要自行准备证书文件。

示例:

import std.io.*
import std.{fs.*, collection.*}
import stdx.net.tls.*
import stdx.crypto.x509.X509Certificate
import stdx.crypto.common.{PrivateKey, Pem, PemEntry, DerBlob}
import stdx.crypto.keys.GeneralPrivateKey

let certificatePath = "/etc/myserver/cert-and-key.pem"

func parsePem(text: String): (Array<X509Certificate>, PrivateKey) {
    let pem = Pem.decode(text)
    let chain = pem |> filter<PemEntry> {entry => entry.label == PemEntry.LABEL_CERTIFICATE} |>
        map<PemEntry, X509Certificate> {entry => X509Certificate.decodeFromDer(entry.body ?? DerBlob())} |> collectArray

    let key = (pem |> filter<PemEntry> {entry => entry.label == PemEntry.LABEL_PRIVATE_KEY} |>
        map<PemEntry, PrivateKey> {entry => GeneralPrivateKey.decodeDer(entry.body ?? DerBlob())} |> first) ?? throw Exception(
        "No private key found in the PEM file")

    if (chain.isEmpty()) {
        throw Exception("No certificates found in the PEM file")
    }

    return (chain, key)
}

func readTextFromFile(path: String): String {
    var fileString = ""
    try (file = File(path, Read)) {
        fileString = String.fromUtf8(readToEnd(file))
        ()
    }
    fileString
}

main() {
    // 对证书及私钥进行解析
    let pem = readTextFromFile(certificatePath)

    let (certificate, privateKey) = parsePem(pem)

    var _ = TlsServerConfig(certificate, privateKey)

    // 进行 https 服务,请参阅其他服务器示例
}

客户端示例

示例:

import std.net.TcpSocket
import stdx.crypto.x509.X509Certificate
import stdx.net.tls.*
import stdx.net.tls.common.*

main() {
    var config = TlsClientConfig()
    config.verifyMode = TrustAll
    config.supportedAlpnProtocols = ["h2"]

    // 用于恢复会话
    var lastSession: ?TlsClientSession = None
    // 重新连接环路
    while (true) {
        try (socket = TcpSocket("127.0.0.1", 8443)) {
            // 首先进行 TCP 连接
            socket.connect()
            try (tls = TlsSocket.client(socket, clientConfig: config, session: lastSession)) {
                try {
                    tls.handshake()
                    // 如果成功协商下一次重新连接,将记住会话
                    lastSession = match (tls.handshakeResult) {
                        case Some(r) => r.session as TlsClientSession
                        case None => None
                    }
                } catch (e: Exception) {
                    // 如果协商失败,将删除会话
                    lastSession = None
                    throw e
                }
                // tls 实例已完成
                tls.write("Hello, peer! Let's discuss our personal secrets.\n".toArray())
            }
        } catch (e: Exception) {
            println("client connection failed ${e}, retrying...")
        }
    }
}

证书热更新

示例:

import std.net.StreamingSocket
import stdx.crypto.common.{Certificate, PrivateKey}
import stdx.net.tls.*

class MyServer {
    private var currentConfig: TlsServerConfig

    init(initialConfig: TlsServerConfig) {
        currentConfig = initialConfig
    }

    // 更改带有密钥的证书只会影响新的连接
    public mut prop certificate: ?(Array<Certificate>, PrivateKey) {
        get() {
            currentConfig.certificate
        }
        set(newCertificate) {
            currentConfig.certificate = newCertificate
        }
    }

    public func onAcceptedConnection(client: StreamingSocket) {
        try (tls = TlsSocket.server(client, serverConfig: currentConfig)) {
            tls.handshake()
        }
    }
}

main() {}

服务端示例

说明:

需要自行准备证书文件。

示例:

import std.io.*
import std.fs.{File, OpenMode}
import std.net.{TcpServerSocket, TcpSocket}
import stdx.crypto.x509.X509Certificate
import stdx.crypto.keys.GeneralPrivateKey
import stdx.net.tls.*

// 证书及私钥路径,用户需自备
let certificatePath = "./files/apiserver.crt"
let certificateKeyPath = "./files/apiserver.key"

main() {
    // 对证书以及私钥进行解析
    let pem = readTextFromFile(certificatePath)
    let keyText = readTextFromFile(certificateKeyPath)

    let certificate = X509Certificate.decodeFromPem(pem)
    let privateKey = GeneralPrivateKey.decodeFromPem(keyText)

    let config = TlsServerConfig(certificate, privateKey)

    // 可选:允许恢复 TLS 会话
    let sessions = TlsServerSession.fromName("my-server")

    try (server = TcpServerSocket(bindAt: 8443)) {
        server.bind()

        server.acceptLoop {
            clientSocket => try (tls = TlsSocket.server(clientSocket, serverConfig: config, session: sessions)) {
                tls.handshake()
                let buffer = Array<Byte>(100, repeat: 0)
                tls.read(buffer)
                println(buffer)
            }
        }
    }
}

extend TcpServerSocket {
    func acceptLoop(handler: (TcpSocket) -> Unit) {
        while (true) {
            let client = accept()
            spawn {
                try {
                    handler(client)
                } finally {
                    client.close()
                }
            }
        }
    }
}

func readTextFromFile(path: String): String {
    var str = ""
    try (file = File(path, Read)) {
        str = String.fromUtf8(readToEnd(file))
    }
    str
}

自定义证书校验

TLS 配置的 verifyMode 使用 CustomVerify 模式。通过配置证书校验函数,使 TLS 握手时使用定制的证书校验流程。

注意:

以下示例仅用于展示客户端写法,可通过编译但无法运行成功。如需查看运行效果,需用户自行提供服务端和有效证书文件。

示例:

import std.net.TcpSocket
import stdx.crypto.x509.X509Certificate
import stdx.net.tls.*
import stdx.net.tls.common.*

main() {
    var config = TlsClientConfig()
    config.supportedAlpnProtocols = ["h2"]

    // 自定义校验逻辑
    config.verifyMode = CustomVerify({
        certificates =>
            if (certificates.size == 0) {
                return false
            }
            for (certificate in certificates) {
                match (certificate as X509Certificate) {
                    case Some(c) =>
                        if (c.issuer.organizationName != "example") {
                            return false
                        }
                    case None => return false
                }
            }
            return true
    })

    try (socket = TcpSocket("127.0.0.1", 8443)) {
        socket.connect()
        let client = TlsSocket.client(socket, clientConfig: config, session: None)
        client.handshake()
    }
}

stdx.net.tls.common

功能介绍

tls.common 包提供了 TLS 相关的抽象接口,用于适配多种 TLS 实现。

通过实现 TlsKit 及相关接口,可以自定义 stdx.net.http 包中所使用的 TLS 实现。

stdx.net.tls 包提供了一种基于 OpenSSL 的默认实现,详见 stdx.net.tls 包。若要使用默认实现,需要显式导入 stdx.net.tls 包。

API 列表

函数

函数名功能
getGlobalTlsKit()获取当前全局使用的 TLS 套件。
setGlobalTlsKit(TlsKit)设置全局使用的 TLS 套件。

接口

接口名功能
TlsConfigTLS 配置接口,用于适配不同的 TLS 实现。
TlsConnectionTLS 连接接口,用于适配不同的 TLS 实现。
TlsHandshakeResultTLS 握手结果接口。用于获取 TLS 握手过程中协商得到的信息。
TlsKitTLS 套件接口。由具体 TLS 实现提供,用于获取 TLS 服务端、客户端连接和服务端会话。
TlsSessionTLS 会话接口。用于记录 TLS 会话信息,由具体 TLS 实现提供和使用。

枚举

枚举名功能
CertificateVerifyMode对证书验证的处理模式。
TlsVersionTLS 协议版本。

异常类

类名功能
TlsExceptionTLS 处理出现错误时抛出的异常类型。

函数

func getGlobalTlsKit()

public func getGlobalTlsKit(): TlsKit

功能:获取当前全局使用的 TLS 套件。

返回值:

  • TlsKit - 当前全局使用的 TLS 套件。

异常:

  • TlsException - 若未设置全局 TLS 套件,则会抛出异常。

示例:

import stdx.net.tls.common.*

// 导入stdx.net.tls包,将使用默认 TLS 套件
import stdx.net.tls.*

main() {
    // 没有设置全局 TLS 套件将会抛出异常
    let tlsKit = getGlobalTlsKit()
    return 0
}

func setGlobalTlsKit(TlsKit)

public func setGlobalTlsKit(kit: TlsKit): Unit

功能:设置全局使用的 TLS 套件。

参数:

  • kit: TlsKit - 全局 TLS 套件。

示例:

import stdx.net.tls.common.*
import stdx.net.tls.*

main() {
    // 创建一个默认的 TLS 套件
    let defaultKit = DefaultTlsKit()

    // 设置全局 TLS 套件
    setGlobalTlsKit(defaultKit)
    return 0
}

接口

interface TlsConfig

public interface TlsConfig {
    mut prop verifyMode: CertificateVerifyMode
    mut prop supportedAlpnProtocols: Array<String>
    mut prop supportedVersions: Array<TlsVersion>
    mut prop supportedCipherSuites: Map<TlsVersion, Array<String>>
    mut prop certificate: ?(Array<Certificate>, PrivateKey)
}

功能:TLS 配置接口,用于适配不同的 TLS 实现。

prop certificate

mut prop certificate: ?(Array<Certificate>, PrivateKey)

功能:TLS 服务端或客户端的证书,包括证书链和私钥。

类型:?(Array<Certificate>, PrivateKey)

prop supportedAlpnProtocols

mut prop supportedAlpnProtocols: Array<String>

功能:支持的应用层协议列表。

类型:Array<String>

prop supportedCipherSuites

mut prop supportedCipherSuites: Map<TlsVersion, Array<String>>

功能:支持的加密套件。

类型:Map<TlsVersion, Array<String>>

prop supportedVersions

mut prop supportedVersions: Array<TlsVersion>

功能:支持的 TLS 版本。

类型:Array<TlsVersion>

prop verifyMode

mut prop verifyMode: CertificateVerifyMode

功能:证书认证模式。

类型:CertificateVerifyMode

interface TlsConnection

public interface TlsConnection <: StreamingSocket {
    func handshake(timeout!: ?Duration): TlsHandshakeResult
    prop handshakeResult: ?TlsHandshakeResult
}

功能:TLS 连接接口,用于适配不同的 TLS 实现。

父类型:

  • StreamingSocket

prop handshakeResult

prop handshakeResult: ?TlsHandshakeResult

功能:获取 TLS 握手结果。

类型:?TlsHandshakeResult

func handshake(?Duration)

func handshake(timeout!: ?Duration): TlsHandshakeResult

功能:进行 TLS 握手,返回握手结果。

参数:

  • timeout!: ?Duration - 握手超时时间。

返回值:

interface TlsHandshakeResult

public interface TlsHandshakeResult {
    prop version: TlsVersion
    prop cipherSuite: String
    prop peerCertificate: Array<Certificate>
    prop session: ?TlsSession
    prop alpnProtocol: String
    prop serverName: String
}

功能:TLS 握手结果接口。用于获取 TLS 握手过程中协商得到的信息。

prop alpnProtocol

prop alpnProtocol: String

功能:获取应用层协议。例如 “http/1.1"、"h2"。

类型:String

prop cipherSuite

prop cipherSuite: String

功能:获取 TLS 加密套件。

类型:String

prop peerCertificate

prop peerCertificate: Array<Certificate>

功能:获取对端证书。

类型:Array<Certificate>

prop serverName

prop serverName: String

功能:获取服务端主机名称。

类型:String

prop session

prop session: ?TlsSession

功能:获取 TLS 会话。客户端可在握手成功后捕获当前会话,后续可重用该会话。

类型:?TlsSession

prop version

prop version: TlsVersion

功能:获取 TLS 版本。

类型:TlsVersion

interface TlsKit

public interface TlsKit {
    func getTlsServer(socket: StreamingSocket, config: TlsConfig, session!: ?TlsSession): TlsConnection
    func getTlsClient(socket: StreamingSocket, config: TlsConfig, session!: ?TlsSession): TlsConnection
    func getTlsServerSession(name: String): TlsSession
}

功能:TLS 套件接口。由具体 TLS 实现提供,用于获取 TLS 服务端、客户端连接和服务端会话。

func getTlsClient(StreamingSocket, TlsConfig, ?TlsSession)

func getTlsClient(socket: StreamingSocket, config: TlsConfig, session!: ?TlsSession): TlsConnection

功能:根据传入的 StreamingSocket 实例创建客户端 TLS 连接,该连接可用于 TLS 握手。

参数:

  • socket: StreamingSocket - TCP 连接建立完成后得到的 socket。
  • config: TlsConfig - 客户端 TLS 配置。
  • session!: ?TlsSession - TLS 会话。若存在可用的 TLS 会话,则可通过该会话恢复,省去 TLS 建立连接时间。

返回值:

func getTlsServer(StreamingSocket, TlsConfig, ?TlsSession)

func getTlsServer(socket: StreamingSocket, config: TlsConfig, session!: ?TlsSession): TlsConnection

功能:根据传入的 StreamingSocket 实例创建服务端 TLS 连接,该连接可用于 TLS 握手。

参数:

  • socket: StreamingSocket - TCP 连接建立完成后得到的 socket。
  • config: TlsConfig - 服务端 TLS 配置。
  • session!: ?TlsSession - TLS 会话。若存在可用的 TLS 会话,则可通过该会话恢复,省去 TLS 建立连接时间。

返回值:

func getTlsServerSession(String)

func getTlsServerSession(name: String): TlsSession

功能:通过名称创建 TlsSession 实例,该名称用于区分 TLS 服务器。

参数:

  • name: String - 会话名称。

返回值:

interface TlsSession

public interface TlsSession {}

功能:TLS 会话接口。用于记录 TLS 会话信息,由具体 TLS 实现提供和使用。

枚举

enum CertificateVerifyMode

public enum CertificateVerifyMode {
    | Default
    | TrustAll
    | CustomCA(Array<Certificate>)
    | CustomVerify((Array<Certificate>) -> Bool)
}

功能:对证书验证的处理模式。

说明:

CustomCA 模式可使用用户配置的证书地址,适用于用户证书无法设置为系统证书的场景。

证书认证模式,TCP 连接建立成功后,客户端和服务端可交换证书,Default 模式使用系统证书。

在开发测试阶段,可使用 TrustAll 模式,该模式表示本端不作对对端证书的校验。此模式本端信任任意建立连接对象,一般仅在开发测试阶段使用。

CustomCA(Array<Certificate>)

CustomCA(Array<Certificate>)

功能:表示根据提供的 CA 列表与系统 CA 进行验证。

CustomVerify((Array<Certificate>) -> Bool)

CustomVerify((Array<Certificate>) -> Bool)

功能:表示自定义验证规则。需要提供一个证书校验函数,根据传入的证书返回是否校验通过。

Default

Default

功能:表示默认验证模式,根据系统 CA 验证证书。

TrustAll

TrustAll

功能:表示信任所有证书。

enum TlsVersion

public enum TlsVersion <: ToString & Hashable & Equatable<TlsVersion>{
    V1_2 | V1_3 | TLCP | ...
}

功能:TLS 协议版本。

父类型:

TLCP

TLCP

功能:表示 TLCP 版本。

V1_2

V1_2

功能:表示 TLS 1.2 版本。

V1_3

V1_3

功能:表示 TLS 1.3 版本。

func hashCode()

public func hashCode(): Int64

功能:返回当前 TlsVersion 的哈希值。

返回值:

示例:

import stdx.net.tls.common.*

main() {
    let tlsVersion = TlsVersion.V1_3
    let hashValue = tlsVersion.hashCode()
    println("TLS版本 ${tlsVersion} 的哈希值: ${hashValue}")

    return 0
}

运行结果:

TLS版本 TlsVersion.V1_3 的哈希值: -7046029254386353130

func toString()

public override func toString(): String

功能:返回当前 TlsVersion 的字符串表示。

返回值:

  • String - 当前 TlsVersion 的字符串表示。

示例:

import stdx.net.tls.common.*

main() {
    let tlsVersion = TlsVersion.V1_2
    let strValue = tlsVersion.toString()
    println("TLS版本的字符串表示: ${strValue}")

    return 0
}

运行结果:

TLS版本的字符串表示: TlsVersion.V1_2

operator func !=(TlsVersion)

public operator func !=(that: TlsVersion): Bool

功能:比较两个 TlsVersion 是否不等。

参数:

返回值:

  • Bool - 若不等返回 true,否则返回 false

示例:

import stdx.net.tls.common.*

main() {
    let tlsVersion1 = TlsVersion.V1_2
    let tlsVersion2 = TlsVersion.V1_3

    let isNotEqual = tlsVersion1 != tlsVersion2
    println("${tlsVersion1} != ${tlsVersion2}: ${isNotEqual}")

    let isEqual = tlsVersion1 != tlsVersion1
    println("${tlsVersion1} != ${tlsVersion1}: ${isEqual}")

    return 0
}

运行结果:

TlsVersion.V1_2 != TlsVersion.V1_3: true
TlsVersion.V1_2 != TlsVersion.V1_2: false

operator func ==(TlsVersion)

public operator func ==(that: TlsVersion): Bool

功能:比较两个 TlsVersion 是否相同。

参数:

返回值:

  • Bool - 相同时返回 true,否则返回 false

示例:

import stdx.net.tls.common.*

main() {
    let tlsVersion1 = TlsVersion.V1_2
    let tlsVersion2 = TlsVersion.V1_2
    let tlsVersion3 = TlsVersion.V1_3

    let isEqual = tlsVersion1 == tlsVersion2
    println("${tlsVersion1} == ${tlsVersion2}: ${isEqual}")

    let isNotEqual = tlsVersion1 == tlsVersion3
    println("${tlsVersion1} == ${tlsVersion3}: ${isNotEqual}")

    return 0
}

运行结果:

TlsVersion.V1_2 == TlsVersion.V1_2: true
TlsVersion.V1_2 == TlsVersion.V1_3: false

异常类

class TlsException

public class TlsException <: Exception {
    public init()
    public init(message: String)
}

功能:TLS 处理出现错误时抛出的异常。

父类型:

  • Exception

init()

public init()

功能:创建 TlsException 实例,异常提示消息为空。

示例:

import stdx.net.tls.common.*

main() {
    try {
        throw TlsException()
    } catch (e: TlsException) {
        println("异常信息: ${e.message}")
    }
}

运行结果:

异常信息: 

init(String)

public init(message: String)

功能:根据异常信息创建 TlsException 实例。

参数:

  • message: String - 异常信息。

示例:

import stdx.net.tls.common.*

main() {
    try {
        throw TlsException("TLS 处理错误")
    } catch (e: TlsException) {
        println("异常信息: ${e.message}")
    }
}

运行结果:

异常信息: TLS 处理错误

stdx.serialization.serialization

功能介绍

serialization 包提供了序列化和反序列化的能力。

序列化(serialization)是指将数据结构或对象状态转换成可取用格式(例如存成文件形式,存于缓冲,或经由网络中发送),以留待后续在相同或另一台计算机环境中,能恢复原先状态的过程。相对地,从一系列字节提取数据结构的反向操作,即反序列化(deserialization)。

用户定义的类型,可以通过实现 Serializable 接口,来支持序列化和反序列化。

API 列表

函数

函数名功能
field<T>(String, T)用于将一组数据 namedata 封装到 Field 对象中。

接口

接口名功能
Serializable用于规范序列化。

类名功能
DataModel中间数据层。
DataModelBool此类为 DataModel 的子类,实现对 Bool 类型数据的封装。
DataModelFloat此类为 DataModel 的子类,实现对 Float64 类型数据的封装。
DataModelInt此类为 DataModel 的子类,实现对 Int64 类型数据的封装。
DataModelNull此类为 DataModel 的子类,实现对 Null 类型数据的封装。
DataModelSeq此类为 DataModel 的子类,实现对 ArrayList<DataModel> 类型数据的封装。
DataModelString此类为 DataModel 的子类,实现对 String 类型数据的封装。
DataModelStruct此类为 DataModel 的子类,用来实现 class 对象到 DataModel 的转换。
Field用于存储 DataModelStruct 的元素。

异常类

异常类名功能
DataModelExceptionDataModel 的异常类。

函数

func field<T>(String, T) where T <: Serializable<T>

public func field<T>(name: String, data: T): Field where T <: Serializable<T>

功能:此函数用于将一组数据 namedata 封装到 Field 对象中。处理一组数据 namedata,将 data 序列化为 DataModel 类型,并将二者封装到 Field 对象中。

参数:

  • name: String - String 类型,name 字段为 "" 时行为与为其它字符串时一致。
  • data: T - T 类型,T 类型必须实现 Serializable<T> 接口。

返回值:

  • Field - 封装了 namedataField 对象。

示例:

import stdx.serialization.serialization.*

main() {
    // 使用field函数创建Field对象
    let fieldObj = field("username", "admin")

    // 使用Field对象的getName方法获取字段名
    let name = fieldObj.getName()
    println("Field getName: ${name}")
    return 0
}

运行结果:

Field getName: username

接口

interface Serializable

public interface Serializable<T> {
    func serialize(): DataModel
    static func deserialize(dm: DataModel): T
}

功能:用于规范序列化。

static func deserialize(DataModel)

static func deserialize(dm: DataModel): T

功能:将 DataModel 反序列化为对象。

说明:

支持实现 Serializable 的类型包括:

  • 基本数据类型:整数类型、浮点类型、布尔类型、字符类型、字符串类型。
  • Collection 类型:Array、ArrayList、HashSet、HashMap、Option。
  • 用户自定义的实现了 Serializable<T> 的类型。

参数:

  • dm: DataModel - 待反序列化的数据。

返回值:

  • T - 反序列化的对象。

异常:

  • DataModelException - 当 dm 的类型不支持反序列化到 T 类型时,抛出异常。

func serialize()

func serialize(): DataModel

功能:将自身序列化为 DataModel

返回值:

extend Bool <: Serializable

extend Bool <: Serializable<Bool>

功能:为 Bool 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

public static func deserialize(dm: DataModel): Bool

功能:将 DataModel 反序列化为 Bool。

参数:

返回值:

  • Bool - 反序列化后的 Bool。

异常:

示例:

import stdx.serialization.serialization.*

main() {
    // 先获得一个序列化后的DataModel
    let dataModel = true.serialize()

    // 使用Bool的deserialize方法反序列化
    let result = Bool.deserialize(dataModel)

    println("Bool反序列化成功: ${result}")
    return 0
}

运行结果:

Bool反序列化成功: true

func serialize()

public func serialize(): DataModel

功能:将 Bool 序列化为 DataModelBool

返回值:

示例:

import stdx.serialization.serialization.*

main() {
    let boolValue: Bool = true
    let dataModel = boolValue.serialize()
    return 0
}

extend Float16 <: Serializable

extend Float16 <: Serializable<Float16>

功能:为 Float16 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

public static func deserialize(dm: DataModel): Float16

功能:将 DataModel 反序列化为 Float16。

参数:

返回值:

  • Float16 - 反序列化后的 Float16。

异常:

示例:

import stdx.serialization.serialization.*

main() {
    // 先获得一个序列化后的DataModel
    let dataModel = 3.14f16.serialize()

    // 使用Float16的deserialize方法反序列化
    let result = Float16.deserialize(dataModel)

    println("Float16反序列化成功: ${result}")
    return 0
}

运行结果:

Float16反序列化成功: 3.140625

func serialize()

public func serialize(): DataModel

功能:将 Float16 序列化为 DataModelFloat

返回值:

示例:

import stdx.serialization.serialization.*

main() {
    let floatValue: Float16 = 3.14f16
    let dataModel = floatValue.serialize()
    return 0
}

extend Float32 <: Serializable

extend Float32 <: Serializable<Float32>

功能:为 Float32 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

public static func deserialize(dm: DataModel): Float32

功能:将 DataModel 反序列化为 Float32。

参数:

返回值:

  • Float32 - 反序列化后的 Float32。

异常:

示例:

import stdx.serialization.serialization.*

main() {
    // 先获得一个序列化后的DataModel
    let dataModel = 3.14f32.serialize()

    // 使用Float32的deserialize方法反序列化
    let result = Float32.deserialize(dataModel)

    println("Float32反序列化成功: ${result}")
    return 0
}

运行结果:

Float32反序列化成功: 3.140000

func serialize()

public func serialize(): DataModel

功能:将 Float32 序列化为 DataModelFloat

返回值:

示例:

import stdx.serialization.serialization.*

main() {
    let floatValue: Float32 = 3.14f32
    let dataModel = floatValue.serialize()
    return 0
}

extend Float64 <: Serializable

extend Float64 <: Serializable<Float64>

功能:为 Float64 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

public static func deserialize(dm: DataModel): Float64

功能:将 DataModel 反序列化为 Float64。

参数:

返回值:

  • Float64 - 反序列化后的 Float64。

异常:

示例:

import stdx.serialization.serialization.*

main() {
    // 先获得一个序列化后的DataModel
    let dataModel = 3.14.serialize()

    // 使用Float64的deserialize方法反序列化
    let result = Float64.deserialize(dataModel)

    println("Float64反序列化成功: ${result}")
    return 0
}

运行结果:

Float64反序列化成功: 3.140000

func serialize()

public func serialize(): DataModel

功能:将 Float64 序列化为 DataModelFloat

返回值:

示例:

import stdx.serialization.serialization.*

main() {
    let floatValue: Float64 = 3.14159f64
    let dataModel = floatValue.serialize()
    return 0
}

extend Int16 <: Serializable

extend Int16 <: Serializable<Int16>

功能:为 Int16 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

public static func deserialize(dm: DataModel): Int16

功能:将 DataModel 反序列化为 Int16。

参数:

返回值:

  • Int16 - 反序列化后的 Int16。

异常:

示例:

import stdx.serialization.serialization.*

main() {
    // 先获得一个序列化后的DataModel
    let dataModel = 123i16.serialize()

    // 使用Int16的deserialize方法反序列化
    let result = Int16.deserialize(dataModel)

    println("Int16反序列化成功: ${result}")
    return 0
}

运行结果:

Int16反序列化成功: 123

func serialize()

public func serialize(): DataModel

功能:将 Int16 序列化为 DataModelInt

返回值:

示例:

import stdx.serialization.serialization.*

main() {
    let intValue: Int16 = 123
    let dataModel = intValue.serialize()
    return 0
}

extend Int32 <: Serializable

extend Int32 <: Serializable<Int32>

功能:为 Int32 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

public static func deserialize(dm: DataModel): Int32

功能:将 DataModel 反序列化为 Int32。

参数:

返回值:

  • Int32 - 反序列化后的 Int32。

异常:

示例:

import stdx.serialization.serialization.*

main() {
    // 先获得一个序列化后的DataModel
    let dataModel = 123i32.serialize()

    // 使用Int32的deserialize方法反序列化
    let result = Int32.deserialize(dataModel)

    println("Int32反序列化成功: ${result}")
    return 0
}

运行结果:

Int32反序列化成功: 123

func serialize()

public func serialize(): DataModel

功能:将 Int32 序列化为 DataModelInt

返回值:

示例:

import stdx.serialization.serialization.*

main() {
    let intValue: Int32 = 123
    let dataModel = intValue.serialize()
    return 0
}

extend Int64 <: Serializable

extend Int64 <: Serializable<Int64>

功能:为 Int64 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

public static func deserialize(dm: DataModel): Int64

功能:将 DataModel 反序列化为 Int64。

参数:

返回值:

  • Int64 - 反序列化后的 Int64。

异常:

示例:

import stdx.serialization.serialization.*

main() {
    // 先获得一个序列化后的DataModel
    let dataModel = 123.serialize()

    // 使用Int64的deserialize方法反序列化
    let result = Int64.deserialize(dataModel)

    println("Int64反序列化成功: ${result}")
    return 0
}

运行结果:

Int64反序列化成功: 123

func serialize()

public func serialize(): DataModel

功能:将 Int64 序列化为 DataModelInt

返回值:

示例:

import stdx.serialization.serialization.*

main() {
    let intValue: Int64 = 123
    let dataModel = intValue.serialize()
    return 0
}

extend Int8 <: Serializable

extend Int8 <: Serializable<Int8>

功能:为 Int8 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

public static func deserialize(dm: DataModel): Int8

功能:将 DataModel 反序列化为 Int8。

参数:

返回值:

  • Int8 - 反序列化后的 Int8。

异常:

示例:

import stdx.serialization.serialization.*

main() {
    // 先获得一个序列化后的DataModel
    let dataModel = 123i8.serialize()

    // 使用Int8的deserialize方法反序列化
    let result = Int8.deserialize(dataModel)

    println("Int8反序列化成功: ${result}")
    return 0
}

运行结果:

Int8反序列化成功: 123

func serialize()

public func serialize(): DataModel

功能:将 Int8 序列化为 DataModelInt

返回值:

示例:

import stdx.serialization.serialization.*

main() {
    let intValue: Int8 = 123
    let dataModel = intValue.serialize()
    return 0
}

extend Rune <: Serializable

extend Rune <: Serializable<Rune>

功能:为 Rune 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

public static func deserialize(dm: DataModel): Rune

功能:将 DataModel 反序列化为 Rune。

参数:

返回值:

  • Rune - 反序列化后的字符。

异常:

示例:

import stdx.serialization.serialization.*

main() {
    // 先获得一个序列化后的DataModel
    let dataModel = r'A'.serialize()

    // 使用Rune的deserialize方法反序列化
    let result = Rune.deserialize(dataModel)

    println("Rune反序列化成功: ${result}")
    return 0
}

运行结果:

Rune反序列化成功: A

func serialize()

public func serialize(): DataModel

功能:将 Rune 序列化为 DataModelString

返回值:

示例:

import stdx.serialization.serialization.*

main() {
    let runeValue: Rune = 'A'
    let dataModel = runeValue.serialize()
    return 0
}

extend String <: Serializable

extend String <: Serializable<String>

功能:为 String 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

public static func deserialize(dm: DataModel): String

功能:将 DataModel 反序列化为 String。

参数:

返回值:

  • String - 反序列化后的 String。

异常:

示例:

import stdx.serialization.serialization.*

main() {
    // 先获得一个序列化后的DataModel
    let dataModel = ("测试字符串").serialize()

    // 使用String的deserialize方法反序列化
    let result = String.deserialize(dataModel)

    println("String反序列化成功: ${result}")
    return 0
}

运行结果:

String反序列化成功: 测试字符串

func serialize()

public func serialize(): DataModel

功能:将 String 序列化为 DataModelString

返回值:

示例:

import stdx.serialization.serialization.*

main() {
    let strValue: String = "测试字符串"
    let dataModel = strValue.serialize()
    return 0
}

extend UInt16 <: Serializable

extend UInt16 <: Serializable<UInt16>

功能:为 UInt16 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

public static func deserialize(dm: DataModel): UInt16

功能:将 DataModel 反序列化为 UInt16。

参数:

返回值:

  • UInt16 - 反序列化后的 UInt16。

异常:

示例:

import stdx.serialization.serialization.*

main() {
    // 先获得一个序列化后的DataModel
    let dataModel = 123u16.serialize()

    // 使用UInt16的deserialize方法反序列化
    let result = UInt16.deserialize(dataModel)

    println("UInt16反序列化成功: ${result}")
    return 0
}

运行结果:

UInt16反序列化成功: 123

func serialize()

public func serialize(): DataModel

功能:将 UInt16 序列化为 DataModelInt

返回值:

示例:

import stdx.serialization.serialization.*

main() {
    let uintValue: UInt16 = 123
    let dataModel = uintValue.serialize()
    return 0
}

extend UInt32 <: Serializable

extend UInt32 <: Serializable<UInt32>

功能:为 UInt32 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

public static func deserialize(dm: DataModel): UInt32

功能:将 DataModel 反序列化为 UInt32。

参数:

返回值:

  • UInt32 - 反序列化后的 UInt32。

异常:

示例:

import stdx.serialization.serialization.*

main() {
    // 先获得一个序列化后的DataModel
    let dataModel = 123u32.serialize()

    // 使用UInt32的deserialize方法反序列化
    let result = UInt32.deserialize(dataModel)

    println("UInt32反序列化成功: ${result}")
    return 0
}

运行结果:

UInt32反序列化成功: 123

func serialize()

public func serialize(): DataModel

功能:将 UInt32 序列化为 DataModelInt

返回值:

示例:

import stdx.serialization.serialization.*

main() {
    let uintValue: UInt32 = 123
    let dataModel = uintValue.serialize()
    return 0
}

extend UInt64 <: Serializable

extend UInt64 <: Serializable<UInt64>

功能:为 UInt64 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

public static func deserialize(dm: DataModel): UInt64

功能:将 DataModel 反序列化为 UInt64。

参数:

返回值:

  • UInt64 - 反序列化后的 UInt64。

异常:

示例:

import stdx.serialization.serialization.*

main() {
    // 先获得一个序列化后的DataModel
    let dataModel = 123u64.serialize()

    // 使用UInt64的deserialize方法反序列化
    let result = UInt64.deserialize(dataModel)

    println("UInt64反序列化成功: ${result}")
    return 0
}

运行结果:

UInt64反序列化成功: 123

func serialize()

public func serialize(): DataModel

功能:将 UInt64 序列化为 DataModelInt

返回值:

示例:

import stdx.serialization.serialization.*

main() {
    let uintValue: UInt64 = 123
    let dataModel = uintValue.serialize()
    return 0
}

extend UInt8 <: Serializable

extend UInt8 <: Serializable<UInt8>

功能:为 UInt8 类型实现 Serializable 接口。

父类型:

static func deserialize(DataModel)

public static func deserialize(dm: DataModel): UInt8

功能:将 DataModel 反序列化为 UInt8。

参数:

返回值:

  • UInt8 - 反序列化后的 UInt8。

异常:

示例:

import stdx.serialization.serialization.*

main() {
    // 先获得一个序列化后的DataModel
    let dataModel = 123u8.serialize()

    // 使用UInt8的deserialize方法反序列化
    let result = UInt8.deserialize(dataModel)

    println("UInt8反序列化成功: ${result}")
    return 0
}

运行结果:

UInt8反序列化成功: 123

func serialize()

public func serialize(): DataModel

功能:将 UInt8 序列化为 DataModelInt

返回值:

示例:

import stdx.serialization.serialization.*

main() {
    let uintValue: UInt8 = 123
    let dataModel = uintValue.serialize()
    return 0
}

extend<K, V> HashMap<K, V> <: Serializable<HashMap<K, V>> where K <: Serializable<K> & Hashable & Equatable<K>, V <: Serializable<V>

extend<K, V> HashMap<K, V> <: Serializable<HashMap<K, V>> where K <: Serializable<K> & Hashable & Equatable<K>, V <: Serializable<V>

功能:为 HashMap<K, V> 类型实现 Serializable<HashMap<K, V>> 接口。

父类型:

static func deserialize(DataModel)

public static func deserialize(dm: DataModel): HashMap<K, V>

功能:将 DataModel 反序列化为 HashMap<K, V>。

参数:

返回值:

  • HashMap<K, V> - 反序列化后的 HashMap<K, V>。

异常:

示例:

import stdx.serialization.serialization.*
import std.collection.*

main() {
    // 先获得一个序列化后的DataModel
    let map = HashMap<String, Int64>()
    map.add("key1", 100)
    map.add("key2", 200)
    let dataModel = map.serialize()

    // 使用HashMap的deserialize方法反序列化
    let result = HashMap<String, Int64>.deserialize(dataModel)

    println("HashMap反序列化成功: ${result}")
    return 0
}

运行结果:

HashMap反序列化成功: [(key1, 100), (key2, 200)]

func serialize()

public func serialize(): DataModel

功能:将 HashMap<K, V> 序列化为 DataModelSeq

返回值:

异常:

  • DataModelException - 当前 HashMap 实例中的 Key 不是 String 类型时,抛出异常。

示例:

import stdx.serialization.serialization.*
import std.collection.*

main() {
    let map = HashMap<String, Int64>()
    map.add("key1", 100)
    map.add("key2", 200)
    let dataModel = map.serialize()
    return 0
}

extend<T> Array<T> <: Serializable<Array<T>> where T <: Serializable<T>

extend<T> Array<T> <: Serializable<Array<T>> where T <: Serializable<T>

功能:为 Array<T> 类型实现 Serializable<Array<T>> 接口。

父类型:

static func deserialize(DataModel)

public static func deserialize(dm: DataModel): Array<T>

功能:将 DataModel 反序列化为 Array<T>。

参数:

返回值:

  • Array<T> - 反序列化后的 Array<T>。

异常:

示例:

import stdx.serialization.serialization.*

main() {
    // 先获得一个序列化后的DataModel
    let arr = [1, 2, 3]
    let dataModel = arr.serialize()

    // 使用Array的deserialize方法反序列化
    let result = Array<Int64>.deserialize(dataModel)

    println("Array反序列化成功: ${result}")
    return 0
}

运行结果:

Array反序列化成功: [1, 2, 3]

func serialize()

public func serialize(): DataModel

功能:将 Array<T> 序列化为 DataModelSeq

返回值:

示例:

import stdx.serialization.serialization.*

main() {
    let arr = [1, 2, 3]
    let dataModel = arr.serialize()
    return 0
}

extend<T> ArrayList<T> <: Serializable<ArrayList<T>> where T <: Serializable<T>

extend<T> ArrayList<T> <: Serializable<ArrayList<T>> where T <: Serializable<T>

功能:为 ArrayList<T> 类型实现 Serializable<ArrayList<T>> 接口。

父类型:

static func deserialize(DataModel)

public static func deserialize(dm: DataModel): ArrayList<T>

功能:将 DataModel 反序列化为 ArrayList<T>。

参数:

返回值:

  • ArrayList<T> - 反序列化后的 ArrayList<T>。

异常:

示例:

import stdx.serialization.serialization.*
import std.collection.*

main() {
    // 先获得一个序列化后的DataModel
    let arrayList = ArrayList<Int64>([100, 200])
    let dataModel = arrayList.serialize()

    // 使用ArrayList的deserialize方法反序列化
    let result = ArrayList<Int64>.deserialize(dataModel)

    println("ArrayList反序列化成功: ${result}")
    return 0
}

运行结果:

ArrayList反序列化成功: [100, 200]

func serialize()

public func serialize(): DataModel

功能:将 ArrayList<T> 序列化为 DataModelSeq

返回值:

示例:

import stdx.serialization.serialization.*
import std.collection.*

main() {
    let arrayList = ArrayList<Int64>([100, 200])
    let dataModel = arrayList.serialize()
    return 0
}

extend<T> HashSet<T> <: Serializable<HashSet<T>> where T <: Serializable<T> & Hashable & Equatable<T>

extend<T> HashSet<T> <: Serializable<HashSet<T>> where T <: Serializable<T> & Hashable & Equatable<T>

功能:为 HashSet<T> 类型实现 Serializable<HashSet<T>> 接口。

父类型:

static func deserialize(DataModel)

public static func deserialize(dm: DataModel): HashSet<T>

功能:将 DataModel 反序列化为 HashSet<T>。

参数:

返回值:

  • HashSet<T> - 反序列化后的 HashSet<T>。

异常:

示例:

import stdx.serialization.serialization.*
import std.collection.*

main() {
    // 先获得一个序列化后的DataModel
    let hashSet = HashSet<String>(["元素1", "元素2"])
    let dataModel = hashSet.serialize()

    // 使用HashSet的deserialize方法反序列化
    let result = HashSet<String>.deserialize(dataModel)

    println("HashSet反序列化成功: ${result}")
    return 0
}

运行结果:

HashSet反序列化成功: [元素1, 元素2]

func serialize()

public func serialize(): DataModel

功能:将 HashSet<T> 序列化为 DataModelSeq

返回值:

示例:

import stdx.serialization.serialization.*
import std.collection.*

main() {
    let hashSet = HashSet<String>(["元素1", "元素2"])
    let dataModel = hashSet.serialize()
    return 0
}

extend<T> Option<T> <: Serializable<Option<T>> where T <: Serializable<T>

extend<T> Option<T> <: Serializable<Option<T>> where T <: Serializable<T>

功能:为 Option<T> 类型实现 Serializable<Option<T>> 接口。

父类型:

static func deserialize(DataModel)

public static func deserialize(dm: DataModel): Option<T>

功能:将 DataModel 反序列化为 Option<T>。

参数:

返回值:

  • Option<T> - 反序列化后的 Option<T>。

异常:

  • DataModelException - 当 dm 的类型不支持反序列化到 T 类型时,抛出异常。

示例:

import stdx.serialization.serialization.*

main() {
    // 先获得一个序列化后的DataModel
    let option = Some(123)
    let dataModel = option.serialize()

    // 使用Option的deserialize方法反序列化
    let result = Option<Int64>.deserialize(dataModel)

    println("Option反序列化成功: ${result}")
    return 0
}

运行结果:

Option反序列化成功: Some(123)

func serialize()

public func serialize(): DataModel

功能:将 Option<T> 中的 T 序列化为 DataModel

返回值:

示例:

import stdx.serialization.serialization.*

main() {
    let option = Some(123)
    let dataModel = option.serialize()
    return 0
}

class DataModel

public abstract class DataModel

功能:此类为中间数据层。

class DataModelBool

public class DataModelBool <: DataModel {
    public init(bv: Bool)
}

功能:此类为 DataModel 的子类,实现对 Bool 类型数据的封装。

父类型:

init(Bool)

public init(bv: Bool)

功能:构造一个具有初始数据的 DataModelBool 实例。

参数:

  • bv: Bool - 传入的 Bool 类型的数据。

示例:

import stdx.serialization.serialization.*

main() {
    // 创建DataModelBool实例
    let dataModel = DataModelBool(true)
    return 0
}

func getValue()

public func getValue(): Bool

功能:获取 DataModelBool 中的数据。

返回值:

示例:

import stdx.serialization.serialization.*

main() {
    // 创建DataModelBool实例
    let dataModel = DataModelBool(false)

    // 获取布尔值
    let value = dataModel.getValue()

    println("获取到的布尔值: ${value}")

    return 0
}

运行结果:

获取到的布尔值: false

class DataModelFloat

public class DataModelFloat <: DataModel {
    public init(fv: Float64)
    public init(v: Int64)
}

功能:此类为 DataModel 的子类,实现对 Float64 类型数据的封装。

父类型:

init(Float64)

public init(fv: Float64)

功能:构造一个具有初始数据的 DataModelFloat 实例。

参数:

  • fv: Float64 - 传入的 Float64 类型的数据。

示例:

import stdx.serialization.serialization.*

main() {
    // 创建DataModelFloat实例
    let dataModel = DataModelFloat(3.14)
    return 0
}

init(Int64)

public init(v: Int64)

功能:构造一个具有初始数据的 DataModelFloat 实例。

参数:

  • v: Int64 - 传入的 Int64 类型的数据。

示例:

import stdx.serialization.serialization.*

main() {
    // 使用Int64参数创建DataModelFloat实例
    let dataModel = DataModelFloat(100)
    return 0
}

func getValue()

public func getValue(): Float64

功能:获取 DataModelFloat 中的数据。

返回值:

示例:

import stdx.serialization.serialization.*

main() {
    // 创建DataModelFloat实例,使用浮点数
    var dataModel = DataModelFloat(3.14)

    // 获取浮点数值
    let value = dataModel.getValue()

    println("获取到的浮点数值: ${value}")

    // 创建DataModelFloat实例,使用整数
    dataModel = DataModelFloat(3)

    println("获取到的浮点数值: ${dataModel.getValue()}")
    return 0
}

运行结果:

获取到的浮点数值: 3.140000
获取到的浮点数值: 3.000000

class DataModelInt

public class DataModelInt <: DataModel {
    public init(iv: Int64)
}

功能:此类为 DataModel 的子类,实现对 Int64 类型数据的封装。

父类型:

init(Int64)

public init(iv: Int64)

功能:构造一个具有初始数据的 DataModelInt 实例。

参数:

  • iv: Int64 - 传入的 Int64 类型的数据。

示例:

import stdx.serialization.serialization.*

main() {
    // 创建DataModelInt实例
    let dataModel = DataModelInt(42)
    return 0
}

func getValue()

public func getValue(): Int64

功能:获取 DataModelInt 中的数据。

返回值:

  • Int64 - DataModelInt 中类型为 Int64 的 value 数值。

示例:

import stdx.serialization.serialization.*

main() {
    // 创建DataModelInt实例
    let dataModel = DataModelInt(123)

    // 获取整数值
    let value = dataModel.getValue()

    println("获取到的整数值: ${value}")

    return 0
}

运行结果:

获取到的整数值: 123

class DataModelNull

public class DataModelNull <: DataModel

功能:此类为 DataModel 的子类,实现对 Null 类型数据的封装。

父类型:

class DataModelSeq

public class DataModelSeq <: DataModel {
    public init()
    public init(list: ArrayList<DataModel>)
}

功能:此类为 DataModel 的子类,实现对 ArrayList<DataModel> 类型数据的封装。

父类型:

init()

public init()

功能:构造一个参数为空的 DataModelSeq 实例。其中的数据默认为空的 ArrayList<DataModel>。

示例:

import stdx.serialization.serialization.*

main() {
    // 创建空参数的DataModelSeq实例
    let dataModel = DataModelSeq()
    return 0
}

init(ArrayList<DataModel>)

public init(list: ArrayList<DataModel>)

功能:构造一个具有初始数据的 DataModelSeq 实例。

参数:

示例:

import stdx.serialization.serialization.*
import std.collection.*

main() {
    // 创建一个ArrayList并添加一些DataModel
    let list = ArrayList<DataModel>()
    list.add(DataModelString("元素1"))
    list.add(DataModelString("元素2"))

    // 使用ArrayList创建DataModelSeq实例
    let dataModel = DataModelSeq(list)

    // 反序列化
    let array = Array<String>.deserialize(dataModel)
    println("查看数据: ${array}")
    return 0
}

运行结果:

查看数据: [元素1, 元素2]

func add(DataModel)

public func add(dm: DataModel): Unit 

功能:在 DataModelSeq 末尾增加一个 DataModel 数据。

参数:

示例:

import stdx.serialization.serialization.*
import std.collection.*

main() {
    // 创建DataModelSeq实例
    let dataModel = DataModelSeq()

    // 添加一些数据
    dataModel.add(DataModelString("字符串数据"))
    dataModel.add(DataModelInt(123))
    return 0
}

func getItems()

public func getItems(): ArrayList<DataModel>

功能:获取 DataModelSeq 中的数据。

返回值:

示例:

import stdx.serialization.serialization.*
import std.collection.*

main() {
    // 创建DataModelSeq实例并添加数据
    let dataModel = DataModelSeq()
    dataModel.add(DataModelString("字符串数据"))
    dataModel.add(DataModelInt(123))

    // 获取所有项目
    let items = dataModel.getItems()

    println("获取到的数据数量: ${items.size}")

    return 0
}

运行结果:

获取到的数据数量: 2

class DataModelString

public class DataModelString <: DataModel {
    public init(sv: String)
}

功能:此类为 DataModel 的子类,实现对 String 类型数据的封装。

父类型:

init(String)

public init(sv: String)

功能:构造一个具有初始数据的 DataModelString

参数:

  • sv: String - 传入的 String 类型。

示例:

import stdx.serialization.serialization.*

main() {
    // 创建DataModelString实例
    let dataModel = DataModelString("这是一个字符串")
    return 0
}

func getValue()

public func getValue(): String

功能:获取 DataModelString 中的数据。

返回值:

示例:

import stdx.serialization.serialization.*

main() {
    // 创建DataModelString实例
    let dataModel = DataModelString("测试字符串")

    // 获取字符串值
    let value = dataModel.getValue()

    println("获取到的字符串值: ${value}")

    return 0
}

运行结果:

获取到的字符串值: 测试字符串

class DataModelStruct

public class DataModelStruct <: DataModel {
    public init()
    public init(list: ArrayList<Field>)
}

功能:此类为 DataModel 的子类,用来实现 class 对象到 DataModel 的转换。

父类型:

init()

public init()

功能:构造一个空参的 DataModelStructfields 默认为空的 ArrayList<Field>。

示例:

import stdx.serialization.serialization.*

main() {
    // 创建空参数的DataModelStruct实例
    let dataModel = DataModelStruct()
    return 0
}

init(ArrayList<Field>)

public init(list: ArrayList<Field>)

功能:构造一个具有初始数据的 DataModelStruct

参数:

  • list: ArrayList<Field> - 传入的 ArrayList<Field> 类型的数据。

示例:

import stdx.serialization.serialization.*
import std.collection.*

main() {
    // 创建Field列表
    let fieldList = ArrayList<Field>()
    fieldList.add(Field("name", DataModelString("张三")))
    fieldList.add(Field("age", DataModelInt(25)))

    // 使用Field列表创建DataModelStruct实例
    let dataModel = DataModelStruct(fieldList)
    return 0
}

func add(Field)

public func add(fie: Field): DataModelStruct

功能:添加数据 fieDataModelStruct 中。

参数:

返回值:

示例:

import stdx.serialization.serialization.*

main() {
    // 创建DataModelStruct实例
    let dataModel = DataModelStruct()

    // 创建一个Field并添加到DataModelStruct
    let field = Field("name", DataModelString("李四"))
    let newDataModel = dataModel.add(field)
    return 0
}

func get(String)

public func get(key: String): DataModel

功能:获取 key 对应的数据。

参数:

  • key: String - 传入的 String 类型。

返回值:

示例:

import stdx.serialization.serialization.*

main() {
    // 创建DataModelStruct实例并添加数据
    let dataModel = DataModelStruct()
    let fieldName = Field("name", DataModelString("王五"))
    let fieldAge = Field("age", DataModelInt(18))
    dataModel.add(fieldName)
    dataModel.add(fieldAge)

    // 获取指定key的数据
    let dataModelString = dataModel.get("name")

    // 反序列化
    let data = String.deserialize(dataModelString)
    println("name: ${data}")
    return 0
}

运行结果:

name: 王五

func getFields()

public func getFields(): ArrayList<Field>

功能:获取 DataModelStruct 的数据集合。

返回值:

  • ArrayList<Field> - 类型为 ArrayList<Field> 的数据集合。

示例:

import stdx.serialization.serialization.*

main() {
    // 创建DataModelStruct实例并添加数据
    let dataModel = DataModelStruct()
    let fieldName = Field("name", DataModelString("赵六"))
    let fieldAge = Field("age", DataModelInt(18))
    dataModel.add(fieldName)
    dataModel.add(fieldAge)

    // 获取所有字段
    let fields = dataModel.getFields()

    println("数据大小: ${fields.size}")
    return 0
}

运行结果:

数据大小: 2

class Field

public class Field {
    public init(name: String, data: DataModel)
}

功能:用于存储 DataModelStruct 的元素。

init(String, DataModel)

public init(name: String, data: DataModel)

功能:Field 的构造函数。

参数:

  • name: String - name 字段值,name 字段为 "" 时行为与为其它字符串时一致。
  • data: DataModel - data 字段值。

示例:

import stdx.serialization.serialization.*

main() {
    // 创建Field实例
    let field = Field("age", DataModelInt(25))
    return 0
}

func getData()

public func getData(): DataModel

功能:获取 data 字段。

返回值:

示例:

import stdx.serialization.serialization.*

main() {
    // 创建Field实例
    let field = Field("score", DataModelFloat(95.5))

    // 获取data字段
    let data = field.getData()

    let score = Float64.deserialize(data)
    println("score: ${score}")

    return 0
}

运行结果:

score: 95.500000

func getName()

public func getName(): String

功能:获取 name 字段。

返回值:

  • String - 获取到的 name 字段,类型为 String。

示例:

import stdx.serialization.serialization.*

main() {
    // 创建Field实例
    let field = Field("username", DataModelString("admin"))

    // 获取name字段
    let name = field.getName()

    println("获取到的name字段: ${name}")

    return 0
}

运行结果:

获取到的name字段: username

异常类

class DataModelException

public class DataModelException <: Exception {
    public init()
    public init(message: String)
}

功能:DataModel 的异常类。

父类型:

  • Exception

init()

public init()

功能:创建 DataModelException 实例。

示例:

import stdx.serialization.serialization.*

main() {
    try {
        // 抛出无参异常
        throw DataModelException()
    } catch (e: DataModelException) {
        println("捕获到 DataModelException: ${e.message}")
    }

    return 0
}

运行结果:

捕获到 DataModelException: 

init(String)

public init(message: String)

功能:根据异常信息创建 DataModelException 实例。

参数:

  • message: String - 异常信息提示字符串。

示例:

import stdx.serialization.serialization.*

main() {
    try {
        // 抛出带消息的异常
        throw DataModelException("这是一个异常信息")
    } catch (e: DataModelException) {
        println("捕获到 DataModelException: ${e.message}")
    }
    return 0
}

运行结果:

捕获到 DataModelException: 这是一个异常信息

class 序列化和反序列化

import stdx.serialization.serialization.*
import std.math.*
import stdx.encoding.json.*

/* 通过实现 Serializable 接口,来实现对自定义类型的序列化和反序列化功能 */
class Abc <: Serializable<Abc> {
    var name: String = "Abcde"
    var age: Int64 = 555
    var loc: Option<Location> = Option<Location>.None

    /* 实现 Serializable 接口的序列化方法 */
    public func serialize(): DataModel {
        return DataModelStruct()
            .add(field<String>("name", name))
            .add(field<Int64>("age", age))
            .add(field<Option<Location>>("loc", loc))
    }

    /* 实现反序列化方法 */
    public static func deserialize(dm: DataModel): Abc {
        let dms = match (dm) {
            case data: DataModelStruct => data
            case _ => throw Exception("this data is not DataModelStruct")
        }
        let result = Abc()
        result.name = String.deserialize(dms.get("name"))
        result.age = Int64.deserialize(dms.get("age"))
        result.loc = Option<Location>.deserialize(dms.get("loc"))
        return result
    }
}

class Location <: Serializable<Location> {
    var time: Int64 = 666
    var heheh: Rune = 'T'

    /* 实现 Serializable 接口的序列化方法 */
    public func serialize(): DataModel {
        return DataModelStruct().add(field<Int64>("time", time)).add(field<Rune>("heheh", heheh))
    }

    /* 实现反序列化方法 */
    public static func deserialize(dm: DataModel): Location {
        let dms = match (dm) {
            case data: DataModelStruct => data
            case _ => throw Exception("this data is not DataModelStruct")
        }
        let result = Location()
        result.time = Int64.deserialize(dms.get("time"))
        result.heheh = Rune.deserialize(dms.get("heheh"))
        return result
    }
}

main(): Unit {
    let dd = Abc()
    let aa: JsonValue = dd.serialize().toJson()
    let bb: JsonObject = (aa as JsonObject).getOrThrow()
    let v1 = (bb.get("name").getOrThrow() as JsonString).getOrThrow()
    let v2 = (bb.get("age").getOrThrow() as JsonInt).getOrThrow()
    let v3 = bb.get("loc").getOrThrow()
    println(v1.getValue())
    println(v2.getValue())
    println(v3.toString())
    println("===========")
    let aaa = ##"{"age": 123, "loc": { "heheh": "H", "time": 45 }, "name": "zhangsan"}"##
    let bbb = JsonValue.fromStr(aaa)
    let ccc = (bbb as JsonObject).getOrThrow()
    let v4 = (ccc.get("name").getOrThrow() as JsonString).getOrThrow()
    let v5 = (ccc.get("age").getOrThrow() as JsonInt).getOrThrow()
    let v6 = (ccc.get("loc").getOrThrow() as JsonObject).getOrThrow()
    let v7 = (v6.get("time").getOrThrow() as JsonInt).getOrThrow()
    let v8 = (v6.get("heheh").getOrThrow() as JsonString).getOrThrow()
    println(v4.getValue())
    println(v5.getValue())
    println(v7.getValue())
    println(v8.getValue())
}

运行结果如下:

Abcde
555
null
===========
zhangsan
123
45
H

HashSet 和 HashMap 序列化

import std.collection.*
import stdx.serialization.serialization.*
import stdx.encoding.json.*

main(): Unit {
    let s: HashSet<Values> = HashSet<Values>([Values(3), Values(5), Values(7)])
    let seris: DataModel = s.serialize()
    println(seris.toJson().toJsonString())
    println("===========")
    let m: HashMap<String, Values> = HashMap<String, Values>([("1", Values(3)), ("2", Values(6)), ("3", Values(9))])
    let serim: DataModel = m.serialize()
    print(serim.toJson().toJsonString())
}

class Values <: Hashable & Equatable<Values> & Serializable<Values> {
    var m_data: Int64

    init(m_data: Int64) {
        this.m_data = m_data
    }

    public func hashCode(): Int64 {
        return this.m_data
    }

    public operator func ==(right: Values): Bool {
        return this.m_data == right.m_data
        
    }

    public operator func !=(right: Values): Bool {
        return this.m_data != right.m_data
    }

    /* 实现 Serializable 接口的序列化方法 */
    public func serialize(): DataModel {
        return DataModelStruct().add(field<Int64>("m_data", m_data))
    }

    /* 实现反序列化方法 */
    public static func deserialize(dm: DataModel): Values {
        let dms: DataModelStruct = match (dm) {
            case data: DataModelStruct => data
            case _ => throw Exception("this data is not DataModelStruct")
        }
        let result = Values(0)
        result.m_data = Int64.deserialize(dms.get("m_data"))
        return result
    }
}

运行结果如下:

[
  {
    "m_data": 3
  },
  {
    "m_data": 5
  },
  {
    "m_data": 7
  }
]
===========
{
  "1": {
    "m_data": 3
  },
  "2": {
    "m_data": 6
  },
  "3": {
    "m_data": 9
  }
}

stdx.string_intern

功能介绍

string_intern 包提供 string 对象的池化缓存能力。可以通过代码调用获取到被缓存起来的字符串对象,降低程序运行过程中,由于临时字符串过多导致的内存风险。

本功能需要构建两个全局字符串缓存池:

  1. 常量池:标准库默认实现,仅允许查询。

  2. 动态缓存池:通过代码启用,可以在运行时创建字符串对象并缓存起来。

本功能主要通过如下机制实现上述效果:

  1. 在编译阶段,将字符串常量缓存到常量池中。

  2. 在运行阶段,用户可以调用 String 的扩展方法(intern)来使用缓存好的字符串对象。

  3. 如果运行阶段用户还会产生无法被编译器识别的字符串,则需要手动开启运行时的字符串缓存,可以通过主动调用 String 的扩展方法(configInternPool)来开启该功能,并调用 intern 方法来创建(仅首次调用时)并获取已经缓存起来的字符串对象。

API 列表

接口

接口名功能
Internable为 String 扩展 intern、configInternPool 等函数接口。

接口

interface Internable

public interface Internable {
    static func configInternPool(capacity!: Int64, strMaxLength!: Int64): Unit
    static func intern(array: Array<Byte>): String
    static func intern(str: String): String
}

功能:用来为 String 类型提供池化缓存扩展。

static func configInternPool(Int64, Int64)

static func configInternPool(capacity!: Int64, strMaxLength!: Int64): Unit

功能:配置字符串缓存池的容量和所缓存的字符串的最大长度,如果不配置,调用 intern 方法时仅返回常量池的字符串对象,而不会缓存新的字符串对象。

参数:

  • capacity!: Int64 - 动态缓存池的容量。
  • strMaxLength!: Int64 - 动态缓存池中,每个字符串对象的最大长度,超出后不会缓存。

异常:

  • IllegalArgumentException - 当 capacitystrMaxLength 参数的值小于等于 0 时,抛出异常。

static func intern(Array<Byte>)

static func intern(array: Array<Byte>): String

功能:获取与输入数组内容一致的已经被缓存起来的字符串对象。

参数:

  • array: Array<Byte> - 运行时创建的 Byte 数组,该数组计划用于创建一个字符串。

返回值:

  • String - 在缓存池中的字符串对象,该字符串对象的 Byte 数组表示与入参一致。

static func intern(String)

static func intern(str: String): String

功能:获取与输入字符串内容一致的已经被缓存起来的字符串对象。

参数:

  • str: String - 运行时创建的字符串。

返回值:

  • String - 在缓存池中的字符串对象。

extend String <: Internable

extend String <: Internable

功能:为 String 扩展 Internable 接口,以实现将 String 池化缓存。

父类型:

static func configInternPool(Int64, Int64)

static func configInternPool(capacity!: Int64 = 8192, strMaxLength!: Int64 = 512): Unit

功能:配置字符串缓存池的容量和所缓存的字符串的最大长度,如果不配置,调用 intern 方法时仅返回常量池的字符串对象,而不会缓存新的字符串对象。

参数:

  • capacity!: Int64 - 动态缓存池的容量。默认值为 8192。
  • strMaxLength!: Int64 - 动态缓存池中,每个字符串对象的最大长度,超出后不会缓存。默认值为 512。

异常:

  • IllegalArgumentException - 当 capacitystrMaxLength 参数的值小于等于 0 时,抛出异常。

示例:

import stdx.string_intern.*

main(): Unit {
    // 配置字符串缓存池
    String.configInternPool(capacity: 10000, strMaxLength: 1000)
}

static func intern(Array<Byte>)

static func intern(array: Array<Byte>): String

功能:获取与输入数组内容一致的已经被缓存起来的字符串对象。

参数:

  • array: Array<Byte> - 运行时创建的 Byte 数组,该数组计划用于创建一个字符串。

返回值:

  • String - 在缓存池中的字符串对象,该字符串对象的 Byte 数组表示与入参一致。

示例:

import stdx.string_intern.*

main(): Unit {
    // 配置字符串缓存池
    String.configInternPool(capacity: 10000, strMaxLength: 1000)

    // 创建一个字节数组
    let byteArray: Array<Byte> = [104, 101, 108, 108, 111] // "hello"的ASCII码

    // 使用intern方法获取缓存的字符串
    let internedStr = String.intern(byteArray)

    println("字节数组池化缓存成功: ${internedStr}")
}

运行结果:

字节数组池化缓存成功: hello

static func intern(String)

static func intern(str: String): String

功能:获取与输入字符串内容一致的已经被缓存起来的字符串对象。

参数:

  • str: String - 运行时创建的字符串。

返回值:

  • String - 在缓存池中的字符串对象。

示例:

import stdx.string_intern.*

main(): Unit {
    String.configInternPool(capacity: 10000, strMaxLength: 1000)

    // 使用intern方法获取缓存的字符串
    let internedStr = String.intern("hello, 仓颉")

    println("字符串池化缓存成功: ${internedStr}")
}

运行结果:

字符串池化缓存成功: hello, 仓颉

字符串池化缓存示例

示例:

import stdx.string_intern.Internable

main(): Unit {
    String.configInternPool(capacity: 10000, strMaxLength: 1000)
    let intern1 = String.intern("hello, 仓颉")
    println(intern1)
    let intern2 = String.intern(unsafe { "hello, 仓颉".rawData() })
    println(intern2)
}

运行结果:

hello, 仓颉
hello, 仓颉

stdx.syntax

功能介绍

syntax 包主要包含了仓颉源码的语法解析器和仓颉语法树节点,提供语法解析函数。可以将指定路径的仓颉文件或包解析为抽象语法树(Abstract Syntax Tree)节点对象。

注意:

syntax 包需要依赖 cangjie/tools/lib 目录下的 libcangjie-lsp 动态库。

API 列表

函数

函数名功能
parseFile(String)  用于解析一个文本文件,获取一个符合仓颉语法的 SourceFile 类型的抽象语法树。
parsePackage(String)  用于解析一个文件目录,获取一个符合仓颉语法的 Package 类型的抽象语法树。
parseText(String)用于解析一个字符串文本,获取一个符合仓颉语法的抽象语法树节点。
parseTokens(Tokens, Bool)用于解析一组词法单元,获取一个符合仓颉语法的抽象语法树节点。

类名功能
Annotation表示编译器内置的注解节点。
Argument表示函数调用的实参节点。
ArrayLiteral表示 Array 字面量节点。
AsExpr表示一个类型转换表达式。
AssignExpr表示赋值表达式节点。
ASTRewriter语法树的通用重写器基类。
ASTVisitor语法树的通用访问器基类。
AtomicType表示一个基本类型节点。
BinaryExpr表示一个二元操作表达式节点。
Block表示块节点。
Body表示 Class 类型、 Struct 类型、 Interface 类型以及扩展中由 {} 和内部的一组声明节点组成的结构。
BreakExpr表示中断表达式。
CallExpr表示函数调用节点。
CatchPattern表示一个捕获模式。
ClassDecl表示一个类声明节点。
Comment表示一个注释节点。
CompositeType表示一个复合类型节点。
ConjunctionCondition表示原子条件的逻辑合取。
ConstPattern表示常量模式节点。
ContinueExpr表示继续表达式。
Decl所有声明节点的父类,继承自 SyntaxTreeNode 节点,提供了所有声明节点的通用接口。
Diagnostic表示仓颉语法树节点的诊断信息。
DisjunctionCondition表示合取条件的逻辑析取。
DoWhileExpr表示 do-while 表达式。
EnumConstructor表示一个枚举构造器。
EnumDecl表示一个 Enum 声明节点。
EnumPattern表示 enum 模式节点。
Expr所有表达式节点的父类,继承自 SyntaxTreeNode 节点。
ExtendDecl表示一个扩展声明节点。
FeatureId一个 feature 标识节点。
FeaturesDirective一个 features 声明节点。
FeaturesSet一个 feature set 节点。
ForInExpr表示 for-in 表达式。
FuncDecl表示一个函数声明节点。
FuncParam表示函数参数节点,包括非命名参数和命名参数。
FuncType表示函数类型节点。
GenericConstraint表示一个泛型约束节点。
GenericConstraints表示一组泛型约束。
GenericParam表示一个泛型参数节点。
IfExpr表示条件表达式。
ImportAlias表示一个别名导入的包导入声明节点的具体项目。
ImportAll表示一个全导入的包导入声明节点的具体项目。
ImportContent表示一个包导入声明节点的具体声明内容。
ImportList表示包导入节点。
ImportMulti表示一个多导入的包导入声明节点的具体项目。
ImportSingle表示一个单导入的包导入声明节点的具体项目。
IncOrDecExpr表示包含自增操作符(++)或自减操作符(--)的表达式。
InterfaceDecl表示接口声明节点。
IsExpr表示一个类型检查表达式。
Lambda表示 Lambda 表达式,是一个匿名的函数。
LambdaParam表示 Lambda 表达式的参数。
LetPattern表示一个 let 模式绑定表达式。
LitConstExpr表示一个字面量表达式节点。
LitConstRuneExpr表示一个字符字面量表达式节点。
LitConstStrExpr表示一个字符串字面量表达式节点。
MacroDecl表示一个宏定义节点。
MacroExpandDecl表示宏展开声明。
MacroExpandExpr表示宏展开表达式。
MacroExpandParam表示宏展开参数。
MainDecl表示一个 main 函数声明节点。
MatchCase表示 match 表达式中的一个 case 节点。
MatchExpr表示模式匹配表达式,用于实现模式匹配。
MemberAccess表示成员访问表达式。
Modifier表示某个声明的修饰符,通常放在声明处的最前端。
OptionalExpr表示一个带有问号操作符的表达式节点。
Package表示包节点。
PackageHeader表示包声明节点。
Parameter表示参数节点的父节点。
ParameterList表示参数列表节点。
ParenCondition表示一个括号条件节点,是指使用圆括号括起来的条件。
ParenExpr表示一个括号表达式节点,是指使用圆括号括起来的表达式。
ParenType表示括号类型节点。
ParsingResult<T> where T <: SyntaxTreeNode表示一个符合仓颉语法的抽象语法树。
Pattern所有模式匹配节点的父类,继承自 SyntaxTreeNode 节点。
PrefixType表示带前缀操作符的前缀类型节点。
PropDecl表示一个属性声明节点。
PropGetterOrSetter表示一个属性的 gettersetter 声明。
QuoteExpr表示 quote 表达式节点。
QuoteInterpolationExpr表示 QuoteExpr 中由 () 括起的内部引用表达式。
QuoteToken表示 quote 表达式节点内任意合法的 token
RangeExpr表示包含区间操作符的表达式。
ReturnExpr表示 return 表达式节点。
SourceFile表示一个仓颉源码文件节点。
SpawnExpr表示 Spawn 表达式。
StaticInit表示一个静态初始化器。
StrInterpolationContent表示字符串插值内容的节点。
StructDecl表示一个 Struct 声明节点。
SubscriptExpr表示索引访问表达式。
SymbolRef表示一个引用表达式节点。
SynchronizedExpr表示 synchronized 表达式。
SyntaxTreeNode所有仓颉语法树节点的父类。
ThrowExpr表示一个 throw 表达式。
TrailingClosureExpr表示尾随闭包表达式。
TryCatch表示 try-catch 表达式节点。
TupleLiteral表示元组字面量节点。
TuplePattern表示 Tuple 模式节点。
TupleType表示元组类型节点。
TypeAlias表示类型别名节点。
TypeAnnotation所有类型节点的父类,继承自 SyntaxTreeNode
TypeConvExpr表示类型转换表达式。
TypePattern表示类型模式节点。
UnaryExpr表示一个一元操作表达式节点。
UnsafeExpr表示一个不安全代码块。
VarDecl表示变量声明节点。
VarOrEnumPattern表示当模式的标识符为 Enum 构造器时的节点。
VarPattern表示绑定模式节点。
VArrayExpr表示 VArray 表达式的实例节点。
VArrayType表示 VArray 类型节点。
WhileExpr表示 while 表达式。
WildcardPattern表示通配符模式节点。

枚举

枚举名功能
AssignOpKind表示赋值操作符的类型,包括 +==-=!= 等。
AtomicCondition表示原子类型的条件或 let 声明的解构匹配,包括 let 声明、表达式类型、有括号修饰的条件等。
AtomicTypeKind表示原子类型的种类,包括布尔类型、整数类型、浮点类型、空类型等。
AtOpKind表示注解操作符的种类,包括 @@! 等。
BinaryOpKind表示二元操作符的类型,包括 +-*/ 等。
CommentKind表示注释的类型,包括块注释、文档注释、行注释等。
DiagnosticInfo表示语法树诊断信息的类型,包括 Warning, Error 等。
FuncKind表示声明函数的类型,包括外部函数、普通函数、构造器函数等。
ImportKind表示引用的类型,包括 AliasAllMultiSingle 等 。
IncOrDecOpKind表示自增自减表达式的操作符类型,包括 ++-- 两种类型。
LitConstKind表示字面量表达式的类型,包括 BoolLiteralFloatLiteralIntergerLiteralRuneLiteralStringLiteralUnitLiteral 六种类型。
LitConstStrKind表示字符串字面量表达式的类型,包括 JStringLiteralMultiLineStringMultiLineRawStringStringLiteral 四种类型。
MacroExpandInput表示宏展开的输入形式,区分不同的宏调用语法形式,包括无括号和有括号形式的宏输入。
ModifierKind表示修饰符的类型,包括 AbstractInternalMut 等。
PostActionMode表示控制 ASTVisitor 在访问节点完成后的行为策略,包括 ContinueStop 等。
PreActionMode表示控制 ASTVisitor 在访问节点前的行为策略,包括 ContinueSkipStop 等。
PrefixTypeOpKind表示前缀类型中的前缀操作符类型,包括 ? 等。
QuoteExprContent表示 quote 表达式中由 () 括起的内容类型,包括 QuoteTokenQuoteInterpolationExpr 两种。
RangeKind表示区间表达式的操作符类型,包括 ::= 两种。
StrLiteralPart表示字符串字面量的不同部分,包括常量部分和字符串插值部分。
UnaryOpKind表示一元表达式的操作符类型,包括 !- 两种。
VarKind表示变量声明表达式的类型,包括 ConstLetVar 三种。

结构体

结构体名功能
CodePositionRange表示节点位置信息。

函数

func parseFile(String)

public func parseFile(filePath: String): ParsingResult<SourceFile>

功能:用于解析一个文本文件,获取一个符合仓颉语法的 SourceFile 类型的抽象语法树。

参数:

  • filePath: String - 待解析文件的路径,可以是绝对路径或相对路径。

返回值:

  • ParsingResult<SourceFile> - 一个根节点为 SourceFile 类型的抽象语法树。

异常:

  • Exception - 当输入的 filePath 不是正确的仓颉源码路径时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 解析指定路径的文件,获取一个 SourceFile 类型的语法树
    if (let Some(node) <- parseFile("a.cj").node) {

        // 打印该语法树, 应与原文件中内容完全一致
        println(node.toString())
    }
}

func parsePackage(String)

public func parsePackage(dirPath: String): ParsingResult<Package>

功能:用于解析一个文件目录,获取一个符合仓颉语法的 Package 类型的抽象语法树。

参数:

  • dirPath: String - 待解析的文件目录,可以是绝对路径或相对路径。

返回值:

  • ParsingResult<Package> - 一个根节点为 Package 类型的抽象语法树。

异常:

  • Exception - 当输入的 dirPath 不是正确的仓颉包路径时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 解析指定路径的目录,获取一个 Package 类型的语法树
    if (let Some(pkg) <- parsePackage("/path/to/dir").node) {

        // 打印该语法树,包内的文件按文件名字母序排序,对每个文件依次打印文件名和文件内容
        println(pkg.toString())
    }
}

func parseText(String)

public func parseText(programText: String): ParsingResult<SyntaxTreeNode>

功能:用于解析一个字符串文本,获取一个符合仓颉语法的抽象语法树节点。

注意:

  • 此函数当前仅支持从文本解析出部分声明和大部分表达式节点,具体支持的节点如下:
  • 声明节点:VarDeclTypeAliasStructDeclStaticInitPropDeclMainDeclMacroDeclInterfaceDeclFuncDecl (类的主构造函数不支持),EnumDeclClassDecl
  • 表达式节点:除 OptionalExprMacroExpandExprStrInterpolationContent 外的所有表达式节点。

参数:

  • programText: String - 待解析的字符串文本。

返回值:

  • ParsingResult<SyntaxTreeNode> - 一个根节点为 SyntaxTreeNode 类型的抽象语法树节点。

异常:

  • Exception - 当根据输入文本无法正确解析出单个语法树节点时(包括解析出错和输入包含多个节点等情况),抛出异常,异常中包含报错提示消息。

示例:

import stdx.syntax.*

main() {
    // 解析字符串,获得一个语法树节点,示例中为 ClassDecl 类型节点
    if (let Some(node) <- parseText("class A {}").node) {

        // 输出该节点
        println("node is ClassDecl: ${node is ClassDecl}")
        println("node.toString(): ${node.toString()}")
    }
}

运行结果:

node is ClassDecl: true
node.toString(): class A {}

func parseTokens(Tokens, Bool)

public func parseTokens(tokens: Tokens, refreshPos!: Bool = true): ParsingResult<SyntaxTreeNode>

功能:用于解析一组词法单元,获取一个符合仓颉语法的抽象语法树节点。

注意:

  • 此函数当前仅支持从输入的一组词法单元解析出部分声明和大部分表达式节点,具体支持的节点如下:
  • 声明节点:VarDeclTypeAliasStructDeclStaticInitPropDeclMainDeclMacroDeclInterfaceDeclFuncDecl (类的主构造函数不支持),EnumDeclClassDecl
  • 表达式节点:除 OptionalExprMacroExpandExprStrInterpolationContent 外的所有表达式节点。

参数:

  • tokens: Tokens - 待解析的一组词法单元。
  • refreshPos!: Bool - 是否刷新输入词法单元的位置信息,true 表示刷新位置信息,false 表示不刷新,保留原始位置信息,默认 true

返回值:

  • ParsingResult<SyntaxTreeNode> - 一个根节点为 SyntaxTreeNode 类型的抽象语法树节点。

异常:

  • Exception - 当根据输入词法单元无法正确解析出单个语法树节点(包括解析出错和输入包含多个节点等情况)或输入词法单元的位置信息有误时,抛出异常,异常中包含报错提示消息。

示例:

import stdx.syntax.*

main() {
    let tokens = quote(
        class A      {let x=10}
    )
    
    // 解析 Tokens 获得一个语法树节点,示例中为 ClassDecl 类型节点
    // 默认刷新位置信息
    if (let Some(node) <- parseTokens(tokens).node) {

        // 输出该节点
        println("node is ClassDecl: ${node is ClassDecl}")
        println("node.toString(): ${node.toString()}")
    }

    // 设置不刷新位置信息
    if (let Some(node) <- parseTokens(tokens, refreshPos: false).node) {

        // 输出该节点
        println("node is ClassDecl: ${node is ClassDecl}")
        println("node.toString(): ${node.toString()}")
    }
}

运行结果:

node is ClassDecl: true
node.toString(): class A { let x = 10 }
node is ClassDecl: true
node.toString(): class A      {let x=10}

class Annotation

public class Annotation <: SyntaxTreeNode {
    public init(arguments: Array<Argument>, identifier: String, opKind: AtOpKind, comments!: Array<Comment> = [])
}

功能:表示编译器内置的注解节点。

一个 Annotation 节点:@CallingConv[xxx], @Attribute[xxx], @When[condition]等。

父类型:

prop arguments

public prop arguments: Array<Argument>

功能:获取 Annotation 中的参数序列,如 @CallingConv[xxx] 中的 xxx

类型:Array<Argument>

prop identifier

public prop identifier: String

功能:获取 Annotation 节点的标识符,如 @CallingConv[xxx] 中的 CallingConv

类型:String

prop opKind

public prop opKind: AtOpKind

功能:获取 Annotation 节点的操作符,如 @CallingConv[xxx] 中的 @

类型:AtOpKind

init(Array<Argument>, String, AtOpKind, Array<Comment>)

public init(arguments: Array<Argument>, identifier: String, opKind: AtOpKind, comments!: Array<Comment> = [])

功能:构造一个 Annotation 对象,表示语法树中的注解节点。

参数:

  • arguments: Array<Argument> - 注解的参数列表。
  • identifier: String - 注解的标识符名称,例如 MyAnnotation
  • opKind: AtOpKind - 注解操作符类型,如 @@!
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 identifier 不符合仓颉标识符规范时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 arguments
    let arguments = [Argument(
        "a1", 
        false, 
        LitConstExpr(LitConstKind.IntergerLiteral, "123")
    )]

    // 创建 identifier
    let identifier = "MyAnnotation"

    // 创建 opKind
    let opKind = AtOpKind.At

    // 创建 Annotation 实例
    let annotation = Annotation(
        arguments, 
        identifier, 
        opKind
    )

    println("annotation: ${annotation}")
}

运行结果:

annotation: @MyAnnotation[a1: 123]

func getAtOpPos()

public func getAtOpPos(): CodePositionRange

功能:获取 Annotation 节点中操作符 @@! 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 arguments
    let arguments = [Argument(
        "a1", 
        false, 
        LitConstExpr(LitConstKind.IntergerLiteral, "123")
    )]

    // 创建 identifier
    let identifier = "MyAnnotation"

    // 创建 opKind
    let opKind = AtOpKind.At

    // 创建 Annotation 实例
    let annotation = Annotation(
        arguments, 
        identifier, 
        opKind
    )
    let pos = annotation.getAtOpPos()

    // 输出 @ 或 @! 操作符位置
    println("annotation.getAtOpPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

annotation.getAtOpPos(): 1:1-1:2

func getCommasPos()

public func getCommasPos(): Array<CodePositionRange>

功能:获取 Annotation 节点中 , 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 arguments
    let arguments = [
        Argument("a1", false, LitConstExpr(LitConstKind.IntergerLiteral, "1")),
        Argument("a2", false, LitConstExpr(LitConstKind.IntergerLiteral, "2")),
        Argument("a3", false, LitConstExpr(LitConstKind.IntergerLiteral, "3"))
    ]

    // 创建 identifier
    let identifier = "MyAnnotation"

    // 创建 opKind
    let opKind = AtOpKind.At

    // 创建 Annotation 实例
    let annotation = Annotation(
        arguments, 
        identifier, 
        opKind
    )
    let posArr = annotation.getCommasPos()

    // 遍历输出逗号位置
    for (i in 0..posArr.size) {
        println("annotation.getCommasPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

annotation.getCommasPos()[0]: 1:20-1:21
annotation.getCommasPos()[1]: 1:27-1:28

func getIdentifierPos()

public func getIdentifierPos(): CodePositionRange

功能:获取 Annotation 节点中标识符的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 arguments
    let arguments = [Argument(
        "a1", 
        false, 
        LitConstExpr(LitConstKind.IntergerLiteral, "123")
    )]

    // 创建 identifier
    let identifier = "MyAnnotation"

    // 创建 opKind
    let opKind = AtOpKind.At

    // 创建 Annotation 实例
    let annotation = Annotation(
        arguments, 
        identifier, 
        opKind
    )
    let pos = annotation.getIdentifierPos()

    // 输出注解名位置
    println("annotation.getIdentifierPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

annotation.getIdentifierPos(): 1:2-1:14

func getLSquarePos()

public func getLSquarePos(): Option<CodePositionRange>

功能:获取 Annotation 节点中 [ 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 arguments
    let arguments = [Argument(
        "a1", 
        false, 
        LitConstExpr(LitConstKind.IntergerLiteral, "123")
    )]

    // 创建 identifier
    let identifier = "MyAnnotation"

    // 创建 opKind
    let opKind = AtOpKind.At

    // 创建 Annotation 实例
    let annotation = Annotation(
        arguments, 
        identifier, 
        opKind
    )

    if (let Some(pos) <- annotation.getLSquarePos()) {
        // 输出 [ 位置
        println("annotation.getLSquarePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

annotation.getLSquarePos(): 1:14-1:15

func getRSquarePos()

public func getRSquarePos(): Option<CodePositionRange>

功能:获取 Annotation 节点中 ] 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 arguments
    let arguments = [Argument(
        "a1", 
        false, 
        LitConstExpr(LitConstKind.IntergerLiteral, "123")
    )]

    // 创建 identifier
    let identifier = "MyAnnotation"

    // 创建 opKind
    let opKind = AtOpKind.At

    // 创建 Annotation 实例
    let annotation = Annotation(
        arguments, 
        identifier, 
        opKind
    )

    if (let Some(pos) <- annotation.getRSquarePos()) {
        // 输出 ] 位置
        println("annotation.getRSquarePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

annotation.getRSquarePos(): 1:22-1:23

class Argument

public class Argument <: SyntaxTreeNode {
    public init(identifier: Option<String>, isInOut: Bool, value: Expr, comments!: Array<Comment> = [])
}

功能:表示函数调用的实参节点。

例如 foo(arg:value) 中的 arg:value

父类型:

prop identifier

public prop identifier: Option<String>

功能:获取 Argument 节点中的标识符,如 arg:value 中的 arg(若不存在返回 None)。

类型:Option<String>

prop isInOut

public prop isInOut: Bool

功能:获取 Argument 节点是否有关键字 inout

类型:Bool

prop isNamed

public prop isNamed: Bool

功能:获取 Argument 节点是否为命名参数。

类型:Bool

prop value

public prop value: Expr

功能:获取 Argument 节点中的表达式,如 arg:value 中的 value

类型:Expr

init(Option<String>, Bool, Expr, Array<Comment>)

public init(identifier: Option<String>, isInOut: Bool, value: Expr, comments!: Array<Comment> = [])

功能:构造一个 Argument 对象,表示语法树中的参数节点。

参数:

  • identifier: Option<String> - 参数的可选标识符名称。
  • isInOut: Bool - 是否为 inout 参数。
  • value: Expr - 参数的值表达式。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 identifier 不为 None 且不符合仓颉标识符规范时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建参数标识符(可选)
    let identifier = "paramName"

    // 设置是否为 inout 参数
    let isInOut = false

    // 创建参数值
    let value = LitConstExpr(LitConstKind.IntergerLiteral, "123")

    // 创建 Argument 实例
    let argument = Argument(
        identifier, 
        isInOut, 
        value
    )

    println("argument: ${argument}")
}

运行结果:

argument: paramName: 123

func getColonPos()

public func getColonPos(): Option<CodePositionRange>

功能:获取当前 Argument: 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建参数标识符
    let identifier = "paramName"

    // 设置是否为 inout 参数
    let isInOut = false

    // 创建参数值
    let value = LitConstExpr(LitConstKind.IntergerLiteral, "123")

    // 创建 Argument 实例
    let argument = Argument(
        identifier, 
        isInOut, 
        value
    )

    if (let Some(pos) <- argument.getColonPos()) {
        // 输出冒号位置
        println("argument.getColonPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

argument.getColonPos(): 1:10-1:11

func getIdentifierPos()

public func getIdentifierPos(): Option<CodePositionRange>

功能:获取当前 Argument 中标识符的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回标识符的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建参数标识符
    let identifier = "paramName"

    // 设置是否为 inout 参数
    let isInOut = false

    // 创建参数值
    let value = LitConstExpr(LitConstKind.IntergerLiteral, "123")

    // 创建 Argument 实例
    let argument = Argument(
        identifier, 
        isInOut, 
        value
    )

    if (let Some(pos) <- argument.getIdentifierPos()) {
        // 输出标识符位置
        println("argument.getIdentifierPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

argument.getIdentifierPos(): 1:1-1:10

func getInoutKeyWordPos()

public func getInoutKeyWordPos(): Option<CodePositionRange>

功能:获取当前 Argumentinout 关键字的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回 inout 关键字的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建参数标识符
    let identifier = "paramName"

    // 设置为 inout 参数
    let isInOut = true

    // 创建参数值
    let value = LitConstExpr(LitConstKind.IntergerLiteral, "123")

    // 创建 Argument 实例
    let argument = Argument(
        identifier, 
        isInOut, 
        value
    )

    if (let Some(pos) <- argument.getInoutKeyWordPos()) {
        // 输出 inout 关键字位置
        println("argument.getInoutKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

argument.getInoutKeyWordPos(): 1:12-1:17

class ArrayLiteral

public class ArrayLiteral <: Expr {
    public init(elements: Array<Expr>, comments!: Array<Comment> = [])
}

功能:表示 Array 字面量节点。

ArrayLiteral 节点:使用格式 [element1, element2, ... , elementN] 表示, 每个 element 是一个表达式。

父类型:

prop elements

public prop elements: Array<Expr>

功能:获取 ArrayLiteral 中的表达式列表。

类型:Array<Expr>

init(Array<Expr>, Array<Comment>)

public init(elements: Array<Expr>, comments!: Array<Comment> = [])

功能:构造一个 ArrayLiteral 对象,表示数组字面量表达式,如 [1, 2, 3]

参数:

  • elements: Array<Expr> - 数组元素表达式列表。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建 elements
    let elements: Array<Expr> = [
        LitConstExpr(LitConstKind.IntergerLiteral, "123"),
        LitConstExpr(LitConstKind.BoolLiteral, "true")
    ]

    // 创建 ArrayLiteral 实例
    let arrayLiteral = ArrayLiteral(
        elements
    )

    println("arrayLiteral: ${arrayLiteral}")
}

运行结果:

arrayLiteral: [123, true]

func getCommasPos()

public func getCommasPos(): Array<CodePositionRange>

功能:获取当前 ArrayLiteral 中所有 , 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 elements
    let elements: Array<Expr> = [
        LitConstExpr(LitConstKind.IntergerLiteral, "1"),
        LitConstExpr(LitConstKind.IntergerLiteral, "2"),
        LitConstExpr(LitConstKind.IntergerLiteral, "3")
    ]

    // 创建 ArrayLiteral 实例
    let arrayLiteral = ArrayLiteral(elements)
    let posArr = arrayLiteral.getCommasPos()

    // 遍历输出逗号位置
    for (i in 0..posArr.size) {
        println("arrayLiteral.getCommasPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

arrayLiteral.getCommasPos()[0]: 1:3-1:4
arrayLiteral.getCommasPos()[1]: 1:6-1:7

func getLSquarePos()

public func getLSquarePos(): CodePositionRange

功能:获取当前 ArrayLiteral[ 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 elements
    let elements: Array<Expr> = [
        LitConstExpr(LitConstKind.IntergerLiteral, "1"),
        LitConstExpr(LitConstKind.IntergerLiteral, "2")
    ]

    // 创建 ArrayLiteral 实例
    let arrayLiteral = ArrayLiteral(elements)
    let pos = arrayLiteral.getLSquarePos()

    // 输出左方括号位置
    println("arrayLiteral.getLSquarePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

arrayLiteral.getLSquarePos(): 1:1-1:2

func getRSquarePos()

public func getRSquarePos(): CodePositionRange

功能:获取当前 ArrayLiteral] 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 elements
    let elements: Array<Expr> = [
        LitConstExpr(LitConstKind.IntergerLiteral, "1"),
        LitConstExpr(LitConstKind.IntergerLiteral, "2")
    ]

    // 创建 ArrayLiteral 实例
    let arrayLiteral = ArrayLiteral(elements)
    let pos = arrayLiteral.getRSquarePos()

    // 输出右方括号位置
    println("arrayLiteral.getRSquarePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

arrayLiteral.getRSquarePos(): 1:6-1:7

class AsExpr

public class AsExpr <: Expr {
    public init(srcVal: Expr, targetTypeAnnotation: TypeAnnotation, comments!: Array<Comment> = [])
}

功能:表示一个类型转换表达式。

一个 AsExpr 表达式:e as T,类型为 Option<T>。其中 e 可以是任何类型的表达式,T 可以是任何类型。

父类型:

prop srcVal

public prop srcVal: Expr

功能:获取 AsExpr 节点中的源表达式节点。

类型:Expr

prop targetTypeAnnotation

public prop targetTypeAnnotation: TypeAnnotation

功能:获取 AsExpr 节点中的目标类型。

类型:TypeAnnotation

init(Expr, TypeAnnotation, Array<Comment>)

public init(srcVal: Expr, targetTypeAnnotation: TypeAnnotation, comments!: Array<Comment> = [])

功能:构造一个 AsExpr 对象,表示类型转换表达式,如 x as Int32

参数:

  • srcVal: Expr - 被转换的源表达式。
  • targetTypeAnnotation: TypeAnnotation - 目标类型。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建 srcVal
    let srcVal = SymbolRef("x", [])

    // 创建 targetTypeAnnotation
    let targetTypeAnnotation = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 AsExpr 实例
    let asExpr = AsExpr(
        srcVal, 
        targetTypeAnnotation
    )

    println("asExpr: ${asExpr}")
}

运行结果:

asExpr: x as Int64

func getAsKeyWordPos()

public func getAsKeyWordPos(): CodePositionRange

功能:获取 as 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 srcVal
    let srcVal = SymbolRef("x", [])

    // 创建 targetTypeAnnotation
    let targetTypeAnnotation = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 AsExpr 实例
    let asExpr = AsExpr(srcVal, targetTypeAnnotation)
    let pos = asExpr.getAsKeyWordPos()

    // 输出 as 关键字位置
    println("asExpr.getAsKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

asExpr.getAsKeyWordPos(): 1:3-1:5

class AssignExpr

public class AssignExpr <: Expr {
    public init(assignOpKind: AssignOpKind, lhs: SyntaxTreeNode, rhs: Expr, comments!: Array<Comment> = [])
}

功能:表示赋值表达式节点。

用于将左操作数的值修改为右操作数的值。一个 AssignExpr 节点:a = b

父类型:

prop assignOpKind

public prop assignOpKind: AssignOpKind

功能:获取 AssignExpr 节点中的赋值操作符类型(如 = 等)。

类型:AssignOpKind

prop lhs

public prop lhs: SyntaxTreeNode

功能:获取 AssignExpr 节点中的左操作数。

类型:SyntaxTreeNode

prop rhs

public prop rhs: Expr

功能:获取 AssignExpr 节点中的右操作数。

类型:Expr

init(AssignOpKind, SyntaxTreeNode, Expr, Array<Comment>)

public init(assignOpKind: AssignOpKind, lhs: SyntaxTreeNode, rhs: Expr, comments!: Array<Comment> = [])

功能:构造一个 AssignExpr 对象,表示赋值表达式。

参数:

  • assignOpKind: AssignOpKind - 赋值操作符类型。
  • lhs: SyntaxTreeNode - 左操作数节点。
  • rhs: Expr - 右操作数表达式。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建 assignOpKind
    let assignOpKind = AssignOpKind.Assign

    // 创建 lhs
    let lhs = SymbolRef("a", [])

    // 创建 rhs
    let rhs = LitConstExpr(LitConstKind.IntergerLiteral, "3")

    // 创建 AssignExpr 实例
    let assignExpr = AssignExpr(
        assignOpKind, 
        lhs, 
        rhs
    )

    println("assignExpr: ${assignExpr}")
}

运行结果:

assignExpr: a = 3

func getAssignOpPos()

public func getAssignOpPos(): CodePositionRange

功能:获取赋值操作符的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 assignOpKind
    let assignOpKind = AssignOpKind.Assign

    // 创建 lhs
    let lhs = SymbolRef("a", [])

    // 创建 rhs
    let rhs = LitConstExpr(LitConstKind.IntergerLiteral, "3")

    // 创建 AssignExpr 实例
    let assignExpr = AssignExpr(assignOpKind, lhs, rhs)
    let pos = assignExpr.getAssignOpPos()

    // 输出赋值操作符位置
    println("assignExpr.getAssignOpPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

assignExpr.getAssignOpPos(): 1:3-1:4

class ASTRewriter

public open class ASTRewriter {}

功能:语法树的重写器基类,提供对语法树节点的遍历时重写节点内容的能力。

说明:

  • 通过 walk 方法自顶向下遍历语法树,并在遍历过程中调用 rewrite 方法对节点进行重写;
  • 支持对任意语法树节点进行遍历及重写;
  • 重写过程中会保持节点类型一致性,若重写后节点类型发生变化将抛出异常。

func rewrite(SyntaxTreeNode)

public open func rewrite(node: SyntaxTreeNode): SyntaxTreeNode

功能:重写单个语法树节点,默认实现为直接返回原节点,子类可重写此方法以实现自定义的节点替换逻辑。

参数:

返回值:

示例:

import stdx.syntax.*
import std.collection.ArrayList

// 继承 ASTRewriter
class DocStubGenerator <: ASTRewriter {
    public override func rewrite(node: SyntaxTreeNode): SyntaxTreeNode {
        match (node) {
            case fn: FuncDecl =>
                let comment = Comment(
                    "// @brief describe ${fn.name}"
                )
                let newComments = ArrayList<Comment>(fn.comments)
                newComments.add(comment)
                // 2. 修改 FuncDecl 中的 comments 属性
                let f = FuncDecl(
                    fn.body,
                    fn.genericConstraints,
                    fn.genericParams,
                    fn.kind,
                    fn.name,
                    fn.params,
                    fn.retTyAnnotation,
                    annotations: fn.annotations,
                    modifiers: fn.modifiers,
                    comments: newComments.toArray()
                )
                return f
            case _ => return node
        }
    }
}

main() {
    let root = parseFile("path/to/source/main.cj")

    // 利用实现的 DocStubGenerator 重写节点
    let generator = DocStubGenerator()
    let newNode = generator.walk(root.node.getOrThrow(), detach: true)

    println(newNode)
}

func walk(SyntaxTreeNode, Bool)

public func walk(startPoint: SyntaxTreeNode, detach!: Bool = false): SyntaxTreeNode

功能:对指定的语法树节点进行遍历与重写。

说明:

  • detachtrue,遍历后产生一颗独立的新树,新树的父节点为空;若 detachfalse,会向上刷新父节点中的内容。

参数:

  • startPoint: SyntaxTreeNode - 起始节点,可以是任意语法树节点或整包节点。
  • detach!: Bool - 是否断开与父节点的关联,默认为 false

返回值:

异常:

  • Exception - 当重写后的节点类型与原始节点类型不一致时,抛出异常。

示例:

import stdx.syntax.*
import std.collection.ArrayList

// 继承 ASTRewriter
class DocStubGenerator <: ASTRewriter {
    public override func rewrite(node: SyntaxTreeNode): SyntaxTreeNode {
        match (node) {
            case fn: FuncDecl =>
                let comment = Comment(
                    "// @brief describe ${fn.name}"
                )
                let newComments = ArrayList<Comment>(fn.comments)
                newComments.add(comment)
                // 2. 修改 FuncDecl 中的 comments 属性
                let f = FuncDecl(
                    fn.body,
                    fn.genericConstraints,
                    fn.genericParams,
                    fn.kind,
                    fn.name,
                    fn.params,
                    fn.retTyAnnotation,
                    annotations: fn.annotations,
                    modifiers: fn.modifiers,
                    comments: newComments.toArray()
                )
                return f
            case _ => return node
        }
    }
}

main() {
    let root = parseFile("path/to/source/main.cj")

    // 利用实现的 DocStubGenerator 重写节点
    let generator = DocStubGenerator()
    let newNode = generator.walk(root.node.getOrThrow(), detach: true)

    println(newNode)
}

class ASTVisitor

public open class ASTVisitor {}

功能:语法树的通用访问器基类。开发者可以通过遍历 SyntaxTreeNode 及其子类,实现对 Cangjie 源代码结构的统一访问与处理。

func postAction(SyntaxTreeNode)

public open func postAction(node: SyntaxTreeNode): PostActionMode

功能:在离开节点后执行的钩子函数,用于决定是否继续或停止遍历,当 preAction 停止时, postAction 也会立即停止。

参数:

返回值:

示例:

import stdx.syntax.*

// 继承 ASTVisitor
public class BinaryCounter <: ASTVisitor {
    public var count = 0

    // 重写 postAction,在进入节点后做判断
    public override func postAction(node: SyntaxTreeNode): PostActionMode {
        match (node) {
            // 遇到 BinaryExpr 时计数 +1 并继续
            case _: BinaryExpr =>
                count += 1
                return PostActionMode.Continue

            // 遇到 CallExpr 停止整个遍历
            case _: CallExpr =>
                println("Found CallExpr, stop traversal")
                return PostActionMode.Stop

            // 其它节点保持默认行为
            case _ => PostActionMode.Continue
        }
    }
}

main() {
    let root = parseFile("path/to/source/main.cj")

    let counter = BinaryCounter()
    if (let Some(node) <- root.node) {
        // 进行遍历
        counter.walk(node)
    }

    println("Total BinaryExpr count: ${counter.count}")
}

func preAction(SyntaxTreeNode)

public open func preAction(node: SyntaxTreeNode): PreActionMode

功能:在进入节点前执行的钩子函数,用于决定是否继续、跳过或停止遍历。

参数:

返回值:

示例:

import stdx.syntax.*

//继承 ASTVisitor
public class BinaryCounter <: ASTVisitor {
    public var count = 0

    // 重写 preAction,只在进入节点前做判断
    public override func preAction(node: SyntaxTreeNode): PreActionMode {
        match (node) {
            // 遇到 BinaryExpr 时计数 +1 并继续
            case _: BinaryExpr =>
                count += 1
                return PreActionMode.Continue

            // 遇到 CallExpr 立即停止整个遍历
            case _: CallExpr =>
                println("Found CallExpr, stop traversal")
                return PreActionMode.Stop

            // 其它节点保持默认行为
            case _ => PreActionMode.Continue
        }
    }
}

main() {
    let root = parseFile("path/to/source/main.cj")

    let counter = BinaryCounter()
    if (let Some(node) <- root.node) {
        // 进行遍历
        counter.walk(node)
    }

    println("Total BinaryExpr count: ${counter.count}")
}

func walk(SyntaxTreeNode)

public func walk(root: SyntaxTreeNode): Unit

功能:从指定节点开始深度优先遍历 AST

参数:

示例:

import stdx.syntax.*

//继承 ASTVisitor
public class BinaryCounter <: ASTVisitor {
    public var count = 0

    // 重写 preAction,只在进入节点前做判断
    public override func preAction(node: SyntaxTreeNode): PreActionMode {
        match (node) {
            // 遇到 BinaryExpr 时计数 +1 并继续
            case _: BinaryExpr =>
                count += 1
                return PreActionMode.Continue

            // 遇到 CallExpr 立即停止整个遍历
            case _: CallExpr =>
                println("Found CallExpr, stop traversal")
                return PreActionMode.Stop

            // 其它节点保持默认行为
            case _ => PreActionMode.Continue
        }
    }
}

main() {
    let root = parseFile("path/to/source/main.cj")

    let counter = BinaryCounter()
    if (let Some(node) <- root.node) {
        // 进行遍历
        counter.walk(node)
    }

    println("Total BinaryExpr count: ${counter.count}")
}

class AtomicType

public class AtomicType <: TypeAnnotation {
    public init(kind: AtomicTypeKind, comments!: Array<Comment> = [])
}

功能:表示一个基本类型节点。

例如数值类型,字符类型,布尔类型等。

父类型:

prop kind

public prop kind: AtomicTypeKind

功能:获取 AtomicType 的具体类型。

类型:AtomicTypeKind

init(AtomicTypeKind, Array<Comment>)

public init(kind: AtomicTypeKind, comments!: Array<Comment> = [])

功能:构造一个 AtomicType 对象,表示原子类型,如 Int64Bool 等。

参数:

  • kind: AtomicTypeKind - 原子类型种类。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建 kind
    let kind = AtomicTypeKind.UInt32Type

    // 创建 AtomicType 实例
    let atomicType = AtomicType(
        kind
    )

    println("atomicType: ${atomicType}")
}

运行结果:

atomicType: UInt32

class BinaryExpr

public class BinaryExpr <: Expr {
    public init(lhs: Expr, opKind: BinaryOpKind, rhs: Expr, comments!: Array<Comment> = [])
}

功能:表示一个二元操作表达式节点。

一个 BinaryExpr 节点:1 + 2

父类型:

prop lhs

public prop lhs: Expr

功能:获取 BinaryExpr 节点中操作符左侧的表达式节点。

类型:Expr

prop opKind

public prop opKind: BinaryOpKind

功能:获取 BinaryExpr 节点中的二元操作符类型。

类型:BinaryOpKind

prop rhs

public prop rhs: Expr

功能:获取 BinaryExpr 节点中操作符右侧的表达式节点。

类型:Expr

init(Expr, BinaryOpKind, Expr, Array<Comment>)

public init(lhs: Expr, opKind: BinaryOpKind, rhs: Expr, comments!: Array<Comment> = [])

功能:构造一个 BinaryExpr 对象,表示二元运算表达式,如 x + y

参数:

  • lhs: Expr - 左操作数表达式。
  • opKind: BinaryOpKind - 二元操作符类型。
  • rhs: Expr - 右操作数表达式。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建 lhs
    let lhs = SymbolRef("x", [])

    // 创建 opKind
    let opKind = BinaryOpKind.Add

    // 创建 rhs
    let rhs = SymbolRef("y", [])

    // 创建 BinaryExpr 实例
    let binaryExpr = BinaryExpr(
        lhs, 
        opKind, 
        rhs
    )

    println("binaryExpr: ${binaryExpr}")
}

运行结果:

binaryExpr: x + y

func getOperatorPos()

public func getOperatorPos(): CodePositionRange

功能:获取二元操作符的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 lhs
    let lhs = SymbolRef("x", [])

    // 创建 opKind
    let opKind = BinaryOpKind.Add

    // 创建 rhs
    let rhs = SymbolRef("y", [])

    // 创建 BinaryExpr 实例
    let binaryExpr = BinaryExpr(lhs, opKind, rhs)
    let pos = binaryExpr.getOperatorPos()

    // 输出操作符位置
    println("binaryExpr.getOperatorPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

binaryExpr.getOperatorPos(): 1:3-1:4

class Block

public class Block <: SyntaxTreeNode {
    public init(nodes: Array<SyntaxTreeNode>, comments!: Array<Comment> = [])
}

功能:表示一个块节点。

父类型:

prop nodes

public prop nodes: Array<SyntaxTreeNode>

功能:获取 Block 中的表达式或声明序列。

类型:Array<SyntaxTreeNode>

init(Array<SyntaxTreeNode>, Array<Comment>)

public init(nodes: Array<SyntaxTreeNode>, comments!: Array<Comment> = [])

功能:构造一个 Block 对象,表示语法树中的代码块节点。

参数:

  • nodes: Array<SyntaxTreeNode> - 块内的子节点列表。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当 nodes 中的节点不是表达式类型、函数声明或变量声明时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 nodes
    let nodes: Array<SyntaxTreeNode> = [
        LitConstExpr(LitConstKind.IntergerLiteral, "123")
    ]

    // 创建 Block 实例
    let block = Block(
        nodes
    )

    println("block: ${block}")
}

运行结果:

block: {
    123
}

func getLCurlPos()

public func getLCurlPos(): CodePositionRange

功能:获取 Block 节点中 { 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 nodes
    let nodes: Array<SyntaxTreeNode> = [
        LitConstExpr(LitConstKind.IntergerLiteral, "123")
    ]

    // 创建 Block 实例
    let block = Block(nodes)
    let pos = block.getLCurlPos()

    // 输出左花括号位置
    println("block.getLCurlPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

block.getLCurlPos(): 1:1-1:2

func getRCurlPos()

public func getRCurlPos(): CodePositionRange

功能:获取 Block 节点中 } 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 nodes
    let nodes: Array<SyntaxTreeNode> = [
        LitConstExpr(LitConstKind.IntergerLiteral, "123")
    ]

    // 创建 Block 实例
    let block = Block(nodes)
    let pos = block.getRCurlPos()

    // 输出右花括号位置
    println("block.getRCurlPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

block.getRCurlPos(): 3:1-3:2

class Body

public class Body <: SyntaxTreeNode {
    public init(memberDecls: Array<Decl>, comments!: Array<Comment> = [])
}

功能:表示 Class 类型、 Struct 类型、 Interface 类型以及扩展中由 {} 和内部的一组声明节点组成的结构。

父类型:

prop memberDecls

public prop memberDecls: Array<Decl>

功能:获取 Body 内的声明节点集合。

类型:Array<Decl>

init(Array<Decl>, Array<Comment>)

public init(memberDecls: Array<Decl>, comments!: Array<Comment> = [])

功能:构造一个 Body 对象,表示语法树中的声明体节点。

参数:

  • memberDecls: Array<Decl> - 成员声明列表。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建一个变量声明
    let initializer = LitConstExpr(LitConstKind.IntergerLiteral, "1")
    let varDecl = VarDecl(initializer, VarKind.Let, "x", VarPattern("x"), AtomicType(AtomicTypeKind.Int64Type))
    
    // 创建成员声明列表
    let memberDecls: Array<Decl> = [varDecl]
    
    // 创建 Body 实例
    let body = Body(memberDecls)
    
    println("body: ${body}")
}

运行结果:

body: {
    let x: Int64 = 1
}

func getLCurlPos()

public func getLCurlPos(): CodePositionRange

功能:获取 Body 节点中 { 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建一个变量声明
    let initializer = LitConstExpr(LitConstKind.IntergerLiteral, "1")
    let varDecl = VarDecl(initializer, VarKind.Let, "x", VarPattern("x"), AtomicType(AtomicTypeKind.Int64Type))
    
    // 创建成员声明列表
    let memberDecls: Array<Decl> = [varDecl]
    
    // 创建 Body 实例
    let body = Body(memberDecls)
    
    // 获取左花括号位置
    let pos = body.getLCurlPos()
    
    // 输出左花括号位置
    println("body.getLCurlPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

body.getLCurlPos(): 1:1-1:2

func getRCurlPos()

 public func getRCurlPos(): CodePositionRange

功能:获取 Body 节点中 } 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建一个变量声明
    let initializer = LitConstExpr(LitConstKind.IntergerLiteral, "1")
    let varDecl = VarDecl(initializer, VarKind.Let, "x", VarPattern("x"), AtomicType(AtomicTypeKind.Int64Type))
    
    // 创建成员声明列表
    let memberDecls: Array<Decl> = [varDecl]
    
    // 创建 Body 实例
    let body = Body(memberDecls)
    
    // 获取右花括号位置
    let pos = body.getRCurlPos()
    
    // 输出右花括号位置
    println("body.getRCurlPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

body.getRCurlPos(): 3:1-3:2

class BreakExpr

public class BreakExpr <: Expr {
    public init(comments!: Array<Comment> = [])
}

功能:表示中断表达式。

用于终止当前循环语句,并将控制权转移到外层代码。BreakExpr 节点以 break 关键字表示,通常用于循环体内部,以提前退出循环。

父类型:

init(Array<Comment>)

public init(comments!: Array<Comment> = [])

功能:构造一个 BreakExpr 对象,表示 break 表达式。

参数:

  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建 BreakExpr 实例
    let breakexpr = BreakExpr()

    println("breakexpr: ${breakexpr}")
}

运行结果:

breakexpr: break

class CallExpr

public class CallExpr <: Expr {
    public init(callee: Expr, arguments: Array<Argument>, comments!: Array<Comment> = [])
}

功能:表示函数调用节点。

一个 CallExpr 节点包括一个表达式,后面紧跟参数列表,例如 foo(100)

父类型:

prop arguments

public prop arguments: Array<Argument>

功能:获取 CallExpr 节点中的函数参数。

类型:Array<Argument>

prop callee

public prop callee: Expr

功能:获取 CallExpr 节点中的函数调用节点。

类型:Expr

init(Expr, Array<Argument>, Array<Comment>)

public init(callee: Expr, arguments: Array<Argument>, comments!: Array<Comment> = [])

功能:构造一个 CallExpr 对象,表示函数调用表达式,如 f(x, y)

参数:

  • callee: Expr - 被调用的函数表达式。
  • arguments: Array<Argument> - 实参列表。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当调用表达式不是成员访问或引用表达式时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 callee
    let callee = SymbolRef("foo", [])

    // 创建 arguments
    let arguments = [Argument(
        "a1", 
        false, 
        LitConstExpr(LitConstKind.IntergerLiteral, "123")
    )]

    // 创建 CallExpr 实例
    let callExpr = CallExpr(
        callee, 
        arguments
    )

    println("callExpr: ${callExpr}")
}

运行结果:

callExpr: foo(a1: 123)

func getCommasPos()

public func getCommasPos(): Array<CodePositionRange>

功能:获取 CallExpr 节点中 , 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 callee
    let callee = SymbolRef("foo", [])

    // 创建 arguments
    let arguments = [
        Argument("a1", false, LitConstExpr(LitConstKind.IntergerLiteral, "1")),
        Argument("a2", false, LitConstExpr(LitConstKind.IntergerLiteral, "2")),
        Argument("a3", false, LitConstExpr(LitConstKind.IntergerLiteral, "3"))
    ]

    // 创建 CallExpr 实例
    let callExpr = CallExpr(callee, arguments)
    let posArr = callExpr.getCommasPos()

    // 遍历输出逗号位置
    for (i in 0..posArr.size) {
        println("callExpr.getCommasPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

callExpr.getCommasPos()[0]: 1:10-1:11
callExpr.getCommasPos()[1]: 1:17-1:18

func getLParenPos()

public func getLParenPos(): CodePositionRange

功能:获取当前 CallExpr( 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 callee
    let callee = SymbolRef("foo", [])

    // 创建 arguments
    let arguments = [Argument("a1", false, LitConstExpr(LitConstKind.IntergerLiteral, "123"))]

    // 创建 CallExpr 实例
    let callExpr = CallExpr(callee, arguments)
    let pos = callExpr.getLParenPos()

    // 输出左括号位置
    println("callExpr.getLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

callExpr.getLParenPos(): 1:4-1:5

func getRParenPos()

public func getRParenPos(): CodePositionRange

功能:获取当前 CallExpr) 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 callee
    let callee = SymbolRef("foo", [])

    // 创建 arguments
    let arguments = [Argument("a1", false, LitConstExpr(LitConstKind.IntergerLiteral, "123"))]

    // 创建 CallExpr 实例
    let callExpr = CallExpr(callee, arguments)
    let pos = callExpr.getRParenPos()

    // 输出右括号位置
    println("callExpr.getRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

callExpr.getRParenPos(): 1:12-1:13

class CatchPattern

public class CatchPattern <: SyntaxTreeNode {
    public init(pattern: Pattern, exceptionType: Array<TypeAnnotation>, comments!: Array<Comment> = [])
}

功能:表示一个捕获模式。

用于获取 TryCatch 中通过模式匹配的方式匹配待捕获的异常序列。

父类型:

prop exceptionType

public prop exceptionType: Array<TypeAnnotation>

功能:获取当前捕获模式的异常类型列表。

类型:Array<TypeAnnotation>

prop pattern

public prop pattern: Pattern

功能:获取当前捕获模式的模式。

类型:Pattern

init(Pattern, Array<TypeAnnotation>, Array<Comment>)

public init(pattern: Pattern, exceptionType: Array<TypeAnnotation>, comments!: Array<Comment> = [])

功能:构造一个 CatchPattern 对象,表示 catch 子句中的异常捕获模式。

参数:

  • pattern: Pattern - 用于绑定异常的模式。
  • exceptionType: Array<TypeAnnotation> - 可捕获的异常类型列表。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 pattern 不为 WildcardPatternVarPattern,或当 patternVarPatternexceptionType 为空时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 pattern
    let pattern = VarPattern("x")

    // 创建 exceptionType
    let exceptionType: Array<TypeAnnotation> = [CompositeType("I1", [], []), CompositeType("I2", [], [])]

    // 创建 CatchPattern 实例
    let catchPattern = CatchPattern(
        pattern, 
        exceptionType
    )

    println("catchPattern: ${catchPattern}")
}

运行结果:

catchPattern: x: I1 | I2

func getBitOrsPos()

public func getBitOrsPos(): Array<CodePositionRange>

功能:获取 CatchPattern 节点中 | 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 pattern
    let pattern = VarPattern("x")

    // 创建 exceptionType
    let exceptionType: Array<TypeAnnotation> = [
        CompositeType("I1", [], []),
        CompositeType("I2", [], []),
        CompositeType("I3", [], [])
    ]

    // 创建 CatchPattern 实例
    let catchPattern = CatchPattern(pattern, exceptionType)
    let posArr = catchPattern.getBitOrsPos()

    // 遍历输出竖线位置
    for (i in 0..posArr.size) {
        println("catchPattern.getBitOrsPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

catchPattern.getBitOrsPos()[0]: 1:7-1:8
catchPattern.getBitOrsPos()[1]: 1:12-1:13

func getColonPos()

public func getColonPos(): Option<CodePositionRange>

功能:获取 CatchPattern 节点中 : 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 pattern
    let pattern = VarPattern("x")

    // 创建 exceptionType
    let exceptionType: Array<TypeAnnotation> = [CompositeType("I1", [], []), CompositeType("I2", [], [])]

    // 创建 CatchPattern 实例
    let catchPattern = CatchPattern(pattern, exceptionType)

    if (let Some(pos) <- catchPattern.getColonPos()) {
        // 输出冒号位置
        println("catchPattern.getColonPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

catchPattern.getColonPos(): 1:2-1:3

class ClassDecl

public class ClassDecl <: Decl {
    public init(body: Body, genericConstraints: Option<GenericConstraints>, genericParams: Array<GenericParam>,
        name: String, superTyAnnotations: Array<TypeAnnotation>, annotations!: Array<Annotation> = [],
        modifiers!: Array<Modifier> = [], comments!: Array<Comment> = [])
}

功能:表示一个类声明节点。

类的声明使用 class 关键字,声明依次为:可缺省的修饰符、class 关键字、class 名、可选的类型参数、是否指定父类或父接口、可选的泛型约束、类体的声明。

父类型:

prop body

public prop body: Body

功能:获取当前类声明的主体部分。

类型:Body

prop genericConstraints

public prop genericConstraints: Option<GenericConstraints>

功能:获取当前类声明的泛型约束(若不存在返回 None)。

类型:Option<GenericConstraints>

prop genericParams

public prop genericParams: Array<GenericParam>

功能:获取当前类声明的泛型参数列表。

类型:Array<GenericParam>

prop name

public prop name: String

功能:获取当前类声明的名称。

类型:String

prop superTyAnnotations

public prop superTyAnnotations: Array<TypeAnnotation>

功能:获取当前类声明的父类类型标注列表。

类型:Array<TypeAnnotation>

init(Body, Option<GenericConstraints>, Array<GenericParam>, String, Array<TypeAnnotation>, Array<Annotation>, Array<Modifier>, Array<Comment>)

public init(body: Body, genericConstraints: Option<GenericConstraints>, genericParams: Array<GenericParam>,
    name: String, superTyAnnotations: Array<TypeAnnotation>, annotations!: Array<Annotation> = [],
    modifiers!: Array<Modifier> = [], comments!: Array<Comment> = [])

功能:构造一个 ClassDecl 对象,表示类声明节点。

参数:

  • body: Body - 类体,包含成员声明。
  • genericConstraints: Option<GenericConstraints> - 可选的泛型约束。
  • genericParams: Array<GenericParam> - 泛型参数列表。
  • name: String - 类名。
  • superTyAnnotations: Array<TypeAnnotation> - 父类类型标注列表。
  • annotations!: Array<Annotation> - 附加的注解列表,默认为空数组。
  • modifiers!: Array<Modifier> - 修饰符列表,默认为空数组。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 body 中有除静态初始化器、函数声明、变量声明、宏展开声明和属性声明外的声明或当泛型约束与泛型参数不对应,或输入的 name 不符合仓颉标识符规范时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 body
    let body = Body([])
    
    // 创建 genericConstraints
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])
    
    // 创建 genericParams
    let genericParams = [GenericParam("T")]
    
    // 创建 name
    let name = "A"
    
    // 创建 superTyAnnotations
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    
    // 创建 annotations
    let annotations = [Annotation([Argument(None, false, LitConstExpr(LitConstKind.IntergerLiteral, "123"))], "MyAnno", AtOpKind.At)]
    
    // 创建 modifiers
    let modifiers = [Modifier(ModifierKind.Public)]
    
    // 创建 ClassDecl 实例
    let classDecl = ClassDecl(
        body, 
        genericConstraints, 
        genericParams, 
        name, 
        superTyAnnotations, 
        annotations: annotations, 
        modifiers: modifiers
    )
    
    println("classDecl: ${classDecl}")
}

运行结果:

classDecl: @MyAnno[123]
public class A<T> <: I1 where T<:I1 {
}

func getClassKeyWordPos()

public func getClassKeyWordPos(): CodePositionRange

功能:获取 ClassDecl 节点中 class 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 body
    let body = Body([])
    
    // 创建 genericConstraints
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])
    
    // 创建 genericParams
    let genericParams = [GenericParam("T")]
    
    // 创建 name
    let name = "A"
    
    // 创建 superTyAnnotations
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    
    // 创建 ClassDecl 实例
    let classDecl = ClassDecl(
        body, 
        genericConstraints, 
        genericParams, 
        name, 
        superTyAnnotations
    )
    
    // 获取 class 关键字位置
    let pos = classDecl.getClassKeyWordPos()
    
    // 输出 class 关键字位置
    println("classDecl.getClassKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

classDecl.getClassKeyWordPos(): 1:1-1:6

func getGenericParamsCommasPos()

public func getGenericParamsCommasPos(): Array<CodePositionRange>

功能:获取 ClassDecl 节点中泛型参数中 , 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 body
    let body = Body([])
    
    // 创建 genericConstraints
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])
    
    // 创建 genericParams
    let genericParams = [GenericParam("T"), GenericParam("U"), GenericParam("V")]
    
    // 创建 name
    let name = "A"
    
    // 创建 superTyAnnotations
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    
    // 创建 ClassDecl 实例
    let classDecl = ClassDecl(
        body, 
        genericConstraints, 
        genericParams, 
        name, 
        superTyAnnotations
    )
    
    // 获取泛型参数中逗号的位置
    let posArr = classDecl.getGenericParamsCommasPos()
    
    // 遍历输出逗号位置
    for (i in 0..posArr.size) {
        println("classDecl.getGenericParamsCommasPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

classDecl.getGenericParamsCommasPos()[0]: 1:10-1:11
classDecl.getGenericParamsCommasPos()[1]: 1:13-1:14

func getGenericParamsLAnglePos()

public func getGenericParamsLAnglePos(): Option<CodePositionRange>

功能:获取 ClassDecl 节点中泛型参数的 < 的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回泛型参数的 < 的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 body
    let body = Body([])
    
    // 创建 genericConstraints
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])
    
    // 创建 genericParams
    let genericParams = [GenericParam("T")]
    
    // 创建 name
    let name = "A"
    
    // 创建 superTyAnnotations
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    
    // 创建 ClassDecl 实例
    let classDecl = ClassDecl(
        body, 
        genericConstraints, 
        genericParams, 
        name, 
        superTyAnnotations
    )
    
    // 获取泛型参数左尖括号的位置
    if (let Some(pos) <- classDecl.getGenericParamsLAnglePos()) {
        // 输出左尖括号位置
        println("classDecl.getGenericParamsLAnglePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    } else {
        println("No left angle bracket found")
    }
}

运行结果:

classDecl.getGenericParamsLAnglePos(): 1:8-1:9

func getGenericParamsRAnglePos()

public func getGenericParamsRAnglePos(): Option<CodePositionRange>

功能:获取 ClassDecl 节点中泛型参数的 > 的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回泛型参数的 > 的位置(若不存在返回 None

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 body
    let body = Body([])
    
    // 创建 genericConstraints
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])
    
    // 创建 genericParams
    let genericParams = [GenericParam("T")]
    
    // 创建 name
    let name = "A"
    
    // 创建 superTyAnnotations
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    
    // 创建 ClassDecl 实例
    let classDecl = ClassDecl(
        body, 
        genericConstraints, 
        genericParams, 
        name, 
        superTyAnnotations
    )
    
    // 获取泛型参数右尖括号的位置
    if (let Some(pos) <- classDecl.getGenericParamsRAnglePos()) {
        // 输出右尖括号位置
        println("classDecl.getGenericParamsRAnglePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    } else {
        println("No right angle bracket found")
    }
}

运行结果:

classDecl.getGenericParamsRAnglePos(): 1:10-1:11

func getIdentifierPos()

public func getIdentifierPos(): CodePositionRange

功能:获取 ClassDecl 节点中标识符的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 body
    let body = Body([])
    
    // 创建 genericConstraints
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])
    
    // 创建 genericParams
    let genericParams = [GenericParam("T")]
    
    // 创建 name
    let name = "A"
    
    // 创建 superTyAnnotations
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    
    // 创建 ClassDecl 实例
    let classDecl = ClassDecl(
        body, 
        genericConstraints, 
        genericParams, 
        name, 
        superTyAnnotations
    )
    
    // 获取标识符的位置
    let pos = classDecl.getIdentifierPos()
    
    // 输出标识符位置
    println("classDecl.getIdentifierPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

classDecl.getIdentifierPos(): 1:7-1:8

func getSuperTyAnnotationsBitAndsPos()

public func getSuperTyAnnotationsBitAndsPos(): Array<CodePositionRange>

功能:获取 ClassDecl 节点中父类型中 & 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 body
    let body = Body([])
    
    // 创建 genericConstraints
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])
    
    // 创建 genericParams
    let genericParams = [GenericParam("T")]
    
    // 创建 name
    let name = "A"
    
    // 创建多个父类型(使用 & 连接)
    let superTyAnnotations: Array<TypeAnnotation> = [
        CompositeType("I1", [], []),
        CompositeType("I2", [], []),
        CompositeType("I3", [], [])
    ]
    
    // 创建 ClassDecl 实例
    let classDecl = ClassDecl(
        body, 
        genericConstraints, 
        genericParams, 
        name, 
        superTyAnnotations
    )
    
    // 获取父类型中 & 的位置
    let posArr = classDecl.getSuperTyAnnotationsBitAndsPos()
    
    // 遍历输出 & 位置
    for (i in 0..posArr.size) {
        println("classDecl.getSuperTyAnnotationsBitAndsPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

classDecl.getSuperTyAnnotationsBitAndsPos()[0]: 1:18-1:19
classDecl.getSuperTyAnnotationsBitAndsPos()[1]: 1:23-1:24

func getUpperBoundPos()

public func getUpperBoundPos(): Option<CodePositionRange>

功能:获取 ClassDecl 节点中 <: 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 body
    let body = Body([])
    
    // 创建 genericConstraints
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])
    
    // 创建 genericParams
    let genericParams = [GenericParam("T")]
    
    // 创建 name
    let name = "A"
    
    // 创建 superTyAnnotations
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    
    // 创建 ClassDecl 实例
    let classDecl = ClassDecl(
        body, 
        genericConstraints, 
        genericParams, 
        name, 
        superTyAnnotations
    )
    
    // 获取 <: 位置
    if (let Some(pos) <- classDecl.getUpperBoundPos()) {
        // 输出 <: 位置
        println("classDecl.getUpperBoundPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    } else {
        println("No upper bound found")
    }
}

运行结果:

classDecl.getUpperBoundPos(): 1:12-1:14

class Comment

public class Comment <: SyntaxTreeNode {
    public init(content: String)
}

功能:表示一个注释信息节点。例如 // comment

父类型:

prop content

public prop content: String

功能:表示注释信息的内容。

类型:String

prop kind

public prop kind: CommentKind

功能:表示注释的类型。

类型:CommentKind

init(String)

public init(content: String)

功能:构造一个 Comment 对象,表示语法树中的注释节点。

参数:

  • content: String - 注释内容。

示例:

import stdx.syntax.*

main() {
    // 创建注释内容
    let content = "// This is a comment"

    // 创建 Comment 实例
    let comment = Comment(
        content
    )

    println("comment: ${comment}")
}

运行结果:

comment: // This is a comment

class CompositeType

public class CompositeType <: TypeAnnotation {
    public init(name: String, prefixes: Array<String>, typeArguments: Array<TypeAnnotation>, comments!: Array<Comment> = [])
}

功能:表示一个复合类型节点。例如 p1.p0.A<Int64>

父类型:

prop name

public prop name: String

功能:表示复合类型的名称。

类型:String

prop prefixes

public prop prefixes: Array<String>

功能:表示复合类型的所有前缀类型。

类型:Array<String>

prop typeArguments

public prop typeArguments: Array<TypeAnnotation>

功能:表示复合类型的所有类型参数。

类型:Array<TypeAnnotation>

init(String, Array<String>, Array<TypeAnnotation>, Array<Comment>)

public init(name: String, prefixes: Array<String>, typeArguments: Array<TypeAnnotation>, comments!: Array<Comment> = [])

功能:构造一个 CompositeType 对象,表示如 p1.p0.A<Int64> 这样的复合类型。

参数:

  • name: String - 复合类型的主名称,例如 A
  • prefixes: Array<String> - 复合类型的前缀路径,例如 ["p1", "p0"]
  • typeArguments: Array<TypeAnnotation> - 类型参数列表,例如 [Int64]
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 name 不符合仓颉标识符规范时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 name
    let name = "A"

    // 创建 prefixes
    let prefixes = ["p0"]

    // 创建 typeArguments
    let typeArguments : Array<TypeAnnotation> = [CompositeType("I1", [], [])]

    // 创建 CompositeType 实例
    let compositeType = CompositeType(
        name, 
        prefixes, 
        typeArguments
    )

    println("compositeType: ${compositeType}")
}

运行结果:

compositeType: p0.A<I1>

func getCommasPos()

public func getCommasPos(): Array<CodePositionRange>

功能:获取 , 的位置序列。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 CompositeType 实例
    let typeArguments: Array<TypeAnnotation> = [CompositeType("I1", [], []), CompositeType("I2", [], [])]
    let compositeType = CompositeType("A", ["p0"], typeArguments)
    let posArr = compositeType.getCommasPos()

    // 遍历输出逗号位置
    for (i in 0..posArr.size) {
        println("compositeType.getCommasPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

compositeType.getCommasPos()[0]: 1:8-1:9

func getDotsPos()

public func getDotsPos(): Array<CodePositionRange>

功能:获取 . 的位置序列。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 CompositeType 实例
    let compositeType = CompositeType("A", ["p0", "p1"], [])
    let posArr = compositeType.getDotsPos()

    // 遍历输出点位置
    for (i in 0..posArr.size) {
        println("compositeType.getDotsPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

compositeType.getDotsPos()[0]: 1:3-1:4
compositeType.getDotsPos()[1]: 1:6-1:7

func getLAnglePos()

public func getLAnglePos(): Option<CodePositionRange>

功能:获取 < 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 CompositeType 实例
    let typeArguments: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    let compositeType = CompositeType("A", [], typeArguments)

    if (let Some(pos) <- compositeType.getLAnglePos()) {
        // 输出左尖括号位置
        println("compositeType.getLAnglePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

compositeType.getLAnglePos(): 1:2-1:3

func getRAnglePos()

public func getRAnglePos(): Option<CodePositionRange>

功能:获取 > 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 CompositeType 实例
    let typeArguments: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    let compositeType = CompositeType("A", [], typeArguments)

    if (let Some(pos) <- compositeType.getRAnglePos()) {
        // 输出右尖括号位置
        println("compositeType.getRAnglePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

compositeType.getRAnglePos(): 1:5-1:6

class ConjunctionCondition

public class ConjunctionCondition <: SyntaxTreeNode {
    public init(cond: Array<AtomicCondition>, comments!: Array<Comment> = [])
}

功能:表示原子条件的逻辑合取。

该节点聚合了多个原子条件,只有当所有原子条件的求值结果都为 true 时,该合取条件才会被满足。它对其包含的原子条件之间的关系建模为逻辑 AND 运算。

父类型:

-SyntaxTreeNode

prop cond

public prop cond: Array<AtomicCondition>

功能:表示该模式节点中的原子条件列表。

类型:Array<AtomicCondition>

init(Array<AtomicCondition>, Array<Comment>)

public init(cond: Array<AtomicCondition>, comments!: Array<Comment> = [])

功能:构造一个 ConjunctionCondition 对象,表示原子条件的逻辑合取。

参数:

  • cond: Array<AtomicCondition> - 原子条件列表。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 cond 为空时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 cond
    let cond = [
            AtomicCondition.Expression(BinaryExpr(SymbolRef("x", []),BinaryOpKind.Equal, SymbolRef("y", []))), 
            AtomicCondition.Expression(BinaryExpr(SymbolRef("a", []),BinaryOpKind.Gt, SymbolRef("b", [])))
        ]

    // 创建 ConjunctionCondition 实例
    let conjunctionCondition = ConjunctionCondition(
        cond
    )

    println("conjunctionCondition: ${conjunctionCondition}")
}

运行结果:

conjunctionCondition: x == y && a > b

func getAndsPos()

public func getAndsPos(): Array<CodePositionRange>

功能:获取 ConjunctionCondition 节点中 && 的位置序列。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 cond
    let cond = [
        AtomicCondition.Expression(BinaryExpr(SymbolRef("x", []), BinaryOpKind.Equal, SymbolRef("y", []))),
        AtomicCondition.Expression(BinaryExpr(SymbolRef("a", []), BinaryOpKind.Gt, SymbolRef("b", []))),
        AtomicCondition.Expression(BinaryExpr(SymbolRef("m", []), BinaryOpKind.Lt, SymbolRef("n", [])))
    ]

    // 创建 ConjunctionCondition 实例
    let conjunctionCondition = ConjunctionCondition(cond)
    let posArr = conjunctionCondition.getAndsPos()

    // 遍历输出 && 位置
    for (i in 0..posArr.size) {
        println("conjunctionCondition.getAndsPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

conjunctionCondition.getAndsPos()[0]: 1:8-1:10
conjunctionCondition.getAndsPos()[1]: 1:17-1:19

class ConstPattern

public class ConstPattern <: Pattern {
    public init(litConstExpr: LitConstExpr, comments!: Array<Comment> = [])
}

功能:表示常量模式节点。

常量模式可以是整数字面量、浮点数字面量、字符字面量、布尔字面量、字符串字面量等字面量,如 case 1 => 0 中的 1

父类型:

prop litConstExpr

public prop litConstExpr: LitConstExpr

功能:表示该模式节点中的常量表达式节点。

类型:LitConstExpr

init(LitConstExpr, Array<Comment>)

public init(litConstExpr: LitConstExpr, comments!: Array<Comment> = [])

功能:构造一个 ConstPattern 对象,表示常量模式,如 42"hello"

参数:

  • litConstExpr: LitConstExpr - 字面量常量表达式。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建 litConstExpr
    let litConstExpr = LitConstExpr(LitConstKind.BoolLiteral, "true")

    // 创建 ConstPattern 实例
    let constPattern = ConstPattern(
        litConstExpr
    )

    println("constPattern: ${constPattern}")
}

运行结果:

constPattern: true

class ContinueExpr

public class ContinueExpr <: Expr {
    public init(comments!: Array<Comment> = [])
}

功能:表示继续表达式。

用于跳过当前循环迭代,直接进入下一次循环迭代。ContinueExpr 节点以 continue 关键字表示,通常用于循环体内部,以跳过当前迭代的剩余部分。

父类型:

init(Array<Comment>)

public init(comments!: Array<Comment> = [])

功能:构造一个 ContinueExpr 对象,表示 continue 表达式。

参数:

  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建 ContinueExpr 实例
    let continueexpr = ContinueExpr()

    println("continueexpr: ${continueexpr}")
}

运行结果:

continueexpr: continue

class Decl

sealed abstract class Decl <: SyntaxTreeNode {}

功能:所有声明节点的父类,继承自 SyntaxTreeNode 节点,提供了所有声明节点的通用接口。

父类型:

prop annotations

public prop annotations: Array<Annotation>

功能:获取当前声明的注解列表。

类型:Array<Annotation>

prop modifiers

public prop modifiers: Array<Modifier>

功能:获取当前声明的修饰符列表。

类型:Array<Modifier>

class Diagnostic

public class Diagnostic {
    public let codePos: CodePositionRange
    public let diagInfo: DiagnosticInfo
}

功能:表示仓颉语法树的一个诊断信息。

let codePos

public let codePos: CodePositionRange

功能:获取当前代码诊断信息的位置信息。

类型:CodePositionRange

let diagInfo

public let diagInfo: DiagnosticInfo

功能:获取当前代码诊断信息的具体诊断信息,包括 Warning, Error 类型等。

类型:DiagnosticInfo

class DisjunctionCondition

public class DisjunctionCondition <: SyntaxTreeNode {
    public init(cond: Array<ConjunctionCondition>, comments!: Array<Comment> = [])
}

功能:表示合取条件的逻辑析取。

该节点聚合了多个合取条件,只要其中至少一个合取条件的求值结果为 true,该析取条件就会被满足。它对其包含的合取条件之间的关系建模为逻辑 OR 运算,形成一个析取范式的逻辑表达式。

父类型:

-SyntaxTreeNode

prop cond

public prop cond: Array<ConjunctionCondition>

功能:表示该模式节点中的合取条件列表。

类型:Array<ConjunctionCondition>

init(Array<ConjunctionCondition>, Array<Comment>)

public init(cond: Array<ConjunctionCondition>, comments!: Array<Comment> = [])

功能:构造一个 DisjunctionCondition 对象,表示逻辑析取条件。

参数:

异常:

  • Exception - 当输入的 cond 为空时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 cond
    let cond = [
            ConjunctionCondition(AtomicCondition.Expression(BinaryExpr(SymbolRef("x", []),BinaryOpKind.Equal, SymbolRef("y", [])))), 
            ConjunctionCondition(AtomicCondition.Expression(BinaryExpr(SymbolRef("a", []),BinaryOpKind.Equal, SymbolRef("b", []))))
        ]

    // 创建 DisjunctionCondition 实例
    let disjunctionCondition = DisjunctionCondition(
        cond
    )

    println("disjunctionCondition: ${disjunctionCondition}")
}

运行结果:

disjunctionCondition: x == y || a == b

func getOrsPos()

public func getOrsPos(): Array<CodePositionRange>

功能:获取 DisjunctionCondition 节点中 || 的位置序列。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 cond
    let cond = [
        ConjunctionCondition(AtomicCondition.Expression(BinaryExpr(SymbolRef("x", []), BinaryOpKind.Equal, SymbolRef("y", [])))),
        ConjunctionCondition(AtomicCondition.Expression(BinaryExpr(SymbolRef("a", []), BinaryOpKind.Equal, SymbolRef("b", [])))),
        ConjunctionCondition(AtomicCondition.Expression(BinaryExpr(SymbolRef("m", []), BinaryOpKind.Equal, SymbolRef("n", []))))
    ]

    // 创建 DisjunctionCondition 实例
    let disjunctionCondition = DisjunctionCondition(cond)
    let posArr = disjunctionCondition.getOrsPos()

    // 遍历输出 || 位置
    for (i in 0..posArr.size) {
        println("disjunctionCondition.getOrsPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

disjunctionCondition.getOrsPos()[0]: 1:8-1:10
disjunctionCondition.getOrsPos()[1]: 1:18-1:20

class DoWhileExpr

public class DoWhileExpr <: Expr {
    public init(body: Block, condition: Expr, comments!: Array<Comment> = [])
}

功能:表示 do-while 表达式。

父类型:

prop body

public prop body: Block

功能:获取当前 do-while 语句的循环体代码块。

类型:Block

prop condition

public prop condition: Expr

功能:获取当前 do-while 语句的继续条件表达式。

类型:Expr

init(Block, Expr, Array<Comment>)

public init(body: Block, condition: Expr, comments!: Array<Comment> = [])

功能:构造一个 DoWhileExpr 对象,表示 do-while 循环表达式。

参数:

  • body: Block - 循环体代码块。
  • condition: Expr - 循环继续条件表达式。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建循环体
    let body = Block([])

    // 创建循环条件
    let condition = BinaryExpr(SymbolRef("x", []),BinaryOpKind.Gt, SymbolRef("y", []))

    // 创建 DoWhileExpr 实例
    let doWhileExpr = DoWhileExpr(
        body, 
        condition
    )

    println("doWhileExpr: ${doWhileExpr}")
}

运行结果:

doWhileExpr: do {
} while (x > y)

func getCondLParenPos()

public func getCondLParenPos(): CodePositionRange

功能:获取 DoWhileExpr 节点中条件的 ( 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建循环体
    let body = Block([])

    // 创建循环条件
    let condition = BinaryExpr(SymbolRef("x", []), BinaryOpKind.Gt, SymbolRef("y", []))

    // 创建 DoWhileExpr 实例
    let doWhileExpr = DoWhileExpr(body, condition)
    let pos = doWhileExpr.getCondLParenPos()

    // 输出条件左括号位置
    println("doWhileExpr.getCondLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

doWhileExpr.getCondLParenPos(): 2:9-2:10

func getCondRParenPos()

public func getCondRParenPos(): CodePositionRange

功能:获取 DoWhileExpr 节点中条件的 ) 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建循环体
    let body = Block([])

    // 创建循环条件
    let condition = BinaryExpr(SymbolRef("x", []), BinaryOpKind.Gt, SymbolRef("y", []))

    // 创建 DoWhileExpr 实例
    let doWhileExpr = DoWhileExpr(body, condition)
    let pos = doWhileExpr.getCondRParenPos()

    // 输出条件右括号位置
    println("doWhileExpr.getCondRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

doWhileExpr.getCondRParenPos(): 2:15-2:16

func getDoKeyWordPos()

public func getDoKeyWordPos(): CodePositionRange

功能:获取 DoWhileExpr 节点中 do 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建循环体
    let body = Block([])

    // 创建循环条件
    let condition = BinaryExpr(SymbolRef("x", []), BinaryOpKind.Gt, SymbolRef("y", []))

    // 创建 DoWhileExpr 实例
    let doWhileExpr = DoWhileExpr(body, condition)
    let pos = doWhileExpr.getDoKeyWordPos()

    // 输出 do 关键字位置
    println("doWhileExpr.getDoKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

doWhileExpr.getDoKeyWordPos(): 1:1-1:3

func getWhileKeyWordPos()

public func getWhileKeyWordPos(): CodePositionRange

功能:获取 DoWhileExpr 节点中 while 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建循环体
    let body = Block([])

    // 创建循环条件
    let condition = BinaryExpr(SymbolRef("x", []), BinaryOpKind.Gt, SymbolRef("y", []))

    // 创建 DoWhileExpr 实例
    let doWhileExpr = DoWhileExpr(body, condition)
    let pos = doWhileExpr.getWhileKeyWordPos()

    // 输出 while 关键字位置
    println("doWhileExpr.getWhileKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

doWhileExpr.getWhileKeyWordPos(): 2:3-2:8

class EnumConstructor

public class EnumConstructor <: Decl {
    public init(name: String, paramTyAnnotations: Array<TypeAnnotation>, annotations!: Array<Annotation> = [],
        comments!: Array<Comment> = [])
}

功能:表示一个枚举构造器。

EnumConstructor 类用于在枚举类型中声明一个构造器,name 表示构造器的名称,paramTyAnnotations 表示构造器参数的类型标注列表。

父类型:

prop name

public prop name: String

功能:获取当前枚举构造器的名称。

类型:String

prop paramTyAnnotations

public prop paramTyAnnotations: Array<TypeAnnotation>

功能:获取当前枚举构造器参数的类型标注列表。

类型:Array<TypeAnnotation>

init(String, Array<TypeAnnotation>, Array<Annotation>, Array<Comment>)

public init(name: String, paramTyAnnotations: Array<TypeAnnotation>, annotations!: Array<Annotation> = [],
    comments!: Array<Comment> = [])

功能:构造一个 EnumConstructor 对象,表示枚举构造器节点。

参数:

  • name: String - 构造器名称。
  • paramTyAnnotations: Array<TypeAnnotation> - 参数类型注解列表。
  • annotations!: Array<Annotation> - 附加的注解列表,默认为空数组。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 name 不符合仓颉标识符规范时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 name
    let name = "EnumA"

    // 创建 paramTyAnnotations
    let paramTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]

    // 创建 annotations
    let annotations = [Annotation([Argument(None, false, LitConstExpr(LitConstKind.IntergerLiteral, "123"))], "MyAnno", AtOpKind.At)]

    // 创建 EnumConstructor 实例
    let enumConstructor = EnumConstructor(
        name, 
        paramTyAnnotations, 
        annotations: annotations
    )

    println("enumConstructor: ${enumConstructor}")
}

运行结果:

enumConstructor: @MyAnno[123]
EnumA(I1)

func getIdentifierPos()

public func getIdentifierPos(): CodePositionRange

功能:获取 EnumConstructor 节点中标识符的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 EnumConstructor 实例
    let enumConstructor = EnumConstructor("EnumA", [])
    let pos = enumConstructor.getIdentifierPos()

    // 输出标识符位置
    println("enumConstructor.getIdentifierPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

enumConstructor.getIdentifierPos(): 1:1-1:6

func getParamsCommasPos()

public func getParamsCommasPos(): Array<CodePositionRange>

功能:获取 EnumConstructor 节点中参数间的 , 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 EnumConstructor 实例
    let paramTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], []), CompositeType("I2", [], [])]
    let enumConstructor = EnumConstructor("EnumA", paramTyAnnotations)
    let posArr = enumConstructor.getParamsCommasPos()

    // 遍历输出逗号位置
    for (i in 0..posArr.size) {
        println("enumConstructor.getParamsCommasPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

enumConstructor.getParamsCommasPos()[0]: 1:9-1:10

func getParamsLParenPos()

public func getParamsLParenPos(): Option<CodePositionRange>

功能:获取 EnumConstructor 节点中参数的 ( 的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回参数的 ( 的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 EnumConstructor 实例
    let paramTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    let enumConstructor = EnumConstructor("EnumA", paramTyAnnotations)

    if (let Some(pos) <- enumConstructor.getParamsLParenPos()) {
        // 输出参数左括号位置
        println("enumConstructor.getParamsLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

enumConstructor.getParamsLParenPos(): 1:6-1:7

func getParamsRParenPos()

public func getParamsRParenPos(): Option<CodePositionRange>

功能:获取 EnumConstructor 节点中参数的 ) 的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回参数的 ) 的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 EnumConstructor 实例
    let paramTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    let enumConstructor = EnumConstructor("EnumA", paramTyAnnotations)

    if (let Some(pos) <- enumConstructor.getParamsRParenPos()) {
        // 输出参数右括号位置
        println("enumConstructor.getParamsRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

enumConstructor.getParamsRParenPos(): 1:9-1:10

class EnumDecl

public class EnumDecl <: Decl {
    public init(body: Body, constructors: Array<EnumConstructor>, genericConstraints: Option<GenericConstraints>, genericParams: Array<GenericParam>,
        isNonExhaustive: Bool, name: String, superTyAnnotations: Array<TypeAnnotation>,
        annotations!: Array<Annotation> = [], modifiers!: Array<Modifier> = [], comments!: Array<Comment> = [])
}

功能:表示一个 Enum 声明节点。

Enum 的声明使用 enum 关键字,声明依次为:可缺省的修饰符、enum 关键字、enum 名、可选的类型参数、是否指定父接口、可选的泛型约束、enum 体的声明。

父类型:

prop body

public prop body: Body

功能:获取当前枚举声明的主体部分。

类型:Body

prop genericConstraints

public prop genericConstraints: Option<GenericConstraints>

功能:获取当前枚举声明的泛型约束(若不存在返回 None)。

类型:Option<GenericConstraints>

prop genericParams

public prop genericParams: Array<GenericParam>

功能:获取当前枚举声明的泛型参数列表。

类型:Array<GenericParam>

prop isNonExhaustive

public prop isNonExhaustive: Bool

功能:判断当前枚举声明是否为 non-exhaustive enum

类型:Bool

prop name

public prop name: String

功能:获取当前枚举声明的名称。

类型:String

prop superTyAnnotations

public prop superTyAnnotations: Array<TypeAnnotation>

功能:获取当前枚举声明的父类类型标注列表。

类型:Array<TypeAnnotation>

init(Body, Array<EnumConstructor>, Option<GenericConstraints>, Array<GenericParam>, Bool, String, Array<TypeAnnotation>, Array<Annotation>, Array<Modifier>, Array<Comment>)

public init(body: Body, constructors: Array<EnumConstructor>, genericConstraints: Option<GenericConstraints>,
    genericParams: Array<GenericParam>, isNonExhaustive: Bool, name: String, superTyAnnotations: Array<TypeAnnotation>,
    annotations!: Array<Annotation> = [], modifiers!: Array<Modifier> = [], comments!: Array<Comment> = [])

功能:构造一个 EnumDecl 对象,表示枚举声明节点。

参数:

  • body: Body - 枚举体,包含除枚举构造器外其他成员声明。
  • constructors: Array<EnumConstructor> - 枚举构造器列表。
  • genericConstraints: Option<GenericConstraints> - 可选的泛型约束。
  • genericParams: Array<GenericParam> - 泛型参数列表。
  • isNonExhaustive: Bool - 是否为非穷举枚举。
  • name: String - 枚举名。
  • superTyAnnotations: Array<TypeAnnotation> - 父类类型标注列表。
  • annotations!: Array<Annotation> - 附加的注解列表,默认为空数组。
  • modifiers!: Array<Modifier> - 修饰符列表,默认为空数组。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 constructors 为空,或输入的 body 中的节点不是函数声明、属性声明及宏展开声明,或当泛型约束与泛型参数不对应,或输入的 name 不符合仓颉标识符规范时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 body
    let body = Body([])

    // 创建 constructor
    let constructor = [EnumConstructor("EnumA", [])]

    // 创建 genericConstraints
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])

    // 创建 genericParams
    let genericParams = [GenericParam("T")]

    // 创建 isNonExhaustive
    let isNonExhaustive = true

    // 创建 name
    let name = "A"

    // 创建 superTyAnnotations
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]

    // 创建 EnumDecl 实例
    let enumDecl = EnumDecl(
        body, 
        constructor, 
        genericConstraints, 
        genericParams, 
        isNonExhaustive, 
        name, 
        superTyAnnotations
    )

    println("enumDecl: ${enumDecl}")
}

运行结果:

enumDecl: enum A<T> <: I1 where T<:I1 {
    | EnumA
    | ...
}

func getCaseSeparatorsPos()

public func getCaseSeparatorsPos(): Array<CodePositionRange>

功能:获取 EnumDecl 节点中 | 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 EnumDecl 实例
    let constructors = [EnumConstructor("A", []), EnumConstructor("B", [])]
    let enumDecl = EnumDecl(Body([]), constructors, None, [], false, "MyEnum", [])
    let posArr = enumDecl.getCaseSeparatorsPos()

    // 遍历输出竖线位置
    for (i in 0..posArr.size) {
        println("enumDecl.getCaseSeparatorsPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

enumDecl.getCaseSeparatorsPos()[0]: 2:5-2:6
enumDecl.getCaseSeparatorsPos()[1]: 3:5-3:6

func getEnumKeyWordPos()

public func getEnumKeyWordPos(): CodePositionRange

功能:获取 EnumDecl 节点中 enum 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 EnumDecl 实例
    let constructors = [EnumConstructor("A", [])]
    let enumDecl = EnumDecl(Body([]), constructors, None, [], false, "MyEnum", [])
    let pos = enumDecl.getEnumKeyWordPos()

    // 输出 enum 关键字位置
    println("enumDecl.getEnumKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

enumDecl.getEnumKeyWordPos(): 1:1-1:5

func getGenericParamsCommasPos()

public func getGenericParamsCommasPos(): Array<CodePositionRange>

功能:获取 EnumDecl 节点中泛型参数中 , 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 EnumDecl 实例
    let genericParams = [GenericParam("T"), GenericParam("U")]
    let constructors = [EnumConstructor("A", [])]
    let enumDecl = EnumDecl(Body([]), constructors, None, genericParams, false, "MyEnum", [])
    let posArr = enumDecl.getGenericParamsCommasPos()

    // 遍历输出逗号位置
    for (i in 0..posArr.size) {
        println("enumDecl.getGenericParamsCommasPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

enumDecl.getGenericParamsCommasPos()[0]: 1:14-1:15

func getGenericParamsLAnglePos()

public func getGenericParamsLAnglePos(): Option<CodePositionRange>

功能:获取 EnumDecl 节点中泛型参数的 < 的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回泛型参数的 < 的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 EnumDecl 实例
    let genericParams = [GenericParam("T")]
    let constructors = [EnumConstructor("A", [])]
    let enumDecl = EnumDecl(Body([]), constructors, None, genericParams, false, "MyEnum", [])

    if (let Some(pos) <- enumDecl.getGenericParamsLAnglePos()) {
        // 输出泛型参数左尖括号位置
        println("enumDecl.getGenericParamsLAnglePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

enumDecl.getGenericParamsLAnglePos(): 1:12-1:13

func getGenericParamsRAnglePos()

public func getGenericParamsRAnglePos(): Option<CodePositionRange>

功能:获取 EnumDecl 节点中泛型参数的 > 的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回泛型参数的 > 的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 EnumDecl 实例
    let genericParams = [GenericParam("T")]
    let constructors = [EnumConstructor("A", [])]
    let enumDecl = EnumDecl(Body([]), constructors, None, genericParams, false, "MyEnum", [])

    if (let Some(pos) <- enumDecl.getGenericParamsRAnglePos()) {
        // 输出泛型参数右尖括号位置
        println("enumDecl.getGenericParamsRAnglePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

enumDecl.getGenericParamsRAnglePos(): 1:14-1:15

func getIdentifierPos()

public func getIdentifierPos(): CodePositionRange

功能:获取 EnumDecl 节点中标识符的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 EnumDecl 实例
    let constructors = [EnumConstructor("A", [])]
    let enumDecl = EnumDecl(Body([]), constructors, None, [], false, "MyEnum", [])
    let pos = enumDecl.getIdentifierPos()

    // 输出标识符位置
    println("enumDecl.getIdentifierPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

enumDecl.getIdentifierPos(): 1:6-1:12

func getNonExhaustiveTripleDotPos()

public func getNonExhaustiveTripleDotPos(): Option<CodePositionRange>

功能:获取 EnumDecl 节点中 ... 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 EnumDecl 实例
    let constructors = [EnumConstructor("A", [])]
    let enumDecl = EnumDecl(Body([]), constructors, None, [], true, "MyEnum", [])

    if (let Some(pos) <- enumDecl.getNonExhaustiveTripleDotPos()) {
        // 输出三点位置
        println("enumDecl.getNonExhaustiveTripleDotPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

enumDecl.getNonExhaustiveTripleDotPos(): 3:7-3:10

func getSuperTyAnnotationsBitAndsPos()

public func getSuperTyAnnotationsBitAndsPos(): Array<CodePositionRange>

功能:获取 EnumDecl 节点的父类型中 & 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 EnumDecl 实例
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], []), CompositeType("I2", [], [])]
    let constructors = [EnumConstructor("A", [])]
    let enumDecl = EnumDecl(Body([]), constructors, None, [], false, "MyEnum", superTyAnnotations)
    let posArr = enumDecl.getSuperTyAnnotationsBitAndsPos()

    // 遍历输出&位置
    for (i in 0..posArr.size) {
        println("enumDecl.getSuperTyAnnotationsBitAndsPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

enumDecl.getSuperTyAnnotationsBitAndsPos()[0]: 1:19-1:20

func getUpperBoundPos()

public func getUpperBoundPos(): Option<CodePositionRange>

功能:获取 EnumDecl 节点中 <: 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 EnumDecl 实例
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    let constructors = [EnumConstructor("A", [])]
    let enumDecl = EnumDecl(Body([]), constructors, None, [], false, "MyEnum", superTyAnnotations)

    if (let Some(pos) <- enumDecl.getUpperBoundPos()) {
        // 输出 <: 位置
        println("enumDecl.getUpperBoundPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

enumDecl.getUpperBoundPos(): 1:13-1:15

class EnumPattern

public class EnumPattern <: Pattern {
    public init(enumConstructor: SymbolRef, enumType: Option<CompositeType>, subPatterns: Array<Pattern>, 
        comments!: Array<Comment> = [])
}

功能:表示 enum 模式节点。

用于匹配 enumconstructor, 如 case Year(n) => 1 中的 Year(n)

父类型:

prop enumConstructor

public prop enumConstructor: SymbolRef

功能:表示 enum 构造器。

类型:SymbolRef

prop enumType

public prop enumType: Option<CompositeType>

功能:表示该 enum 模式节点中的前缀类型,例如,p1.p0.E<Int64> 是模式 p1.p0.E<Int64>.C0(x)enumType

类型:Option<CompositeType>

prop subPatterns

public prop subPatterns: Array<Pattern>

功能:表示该模式节点中有参构造器内的模式节点列表。

类型:Array<Pattern>

init(SymbolRef, Option<CompositeType>, Array<Pattern>, Array<Comment>)

public init(enumConstructor: SymbolRef, enumType: Option<CompositeType>, subPatterns: Array<Pattern>, comments!: Array<Comment> = [])

功能:构造一个 EnumPattern 对象,表示枚举模式。

参数:

  • enumConstructor: SymbolRef - 枚举构造器引用。
  • enumType: Option<CompositeType> - 可选的枚举类型前缀,如 Result
  • subPatterns: Array<Pattern> - 子模式列表。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建 enumConstructor
    let enumConstructor = SymbolRef("A", [])

    // 创建 enumType
    let enumType = CompositeType("C1", [], [])

    // 创建 subPatterns
    let subPatterns: Array<Pattern> = [VarPattern("x")]

    // 创建 EnumPattern 实例
    let enumPattern = EnumPattern(
        enumConstructor, 
        enumType, 
        subPatterns
    )

    println("enumPattern: ${enumPattern}")
}

运行结果:

enumPattern: C1.A(x)

func getCommasPos()

public func getCommasPos(): Array<CodePositionRange>

功能:获取 EnumPattern 节点中 , 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 EnumPattern 实例
    let enumConstructor = SymbolRef("A", [])
    let subPatterns: Array<Pattern> = [VarPattern("x"), VarPattern("y")]
    let enumPattern = EnumPattern(enumConstructor, None, subPatterns)
    let posArr = enumPattern.getCommasPos()

    // 遍历输出逗号位置
    for (i in 0..posArr.size) {
        println("enumPattern.getCommasPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

enumPattern.getCommasPos()[0]: 1:4-1:5

func getDotPos()

public func getDotPos(): Option<CodePositionRange>

功能:获取 EnumPattern 节点中 . 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 EnumPattern 实例
    let enumConstructor = SymbolRef("A", [])
    let enumType = CompositeType("C1", [], [])
    let subPatterns: Array<Pattern> = [VarPattern("x")]
    let enumPattern = EnumPattern(enumConstructor, enumType, subPatterns)

    if (let Some(pos) <- enumPattern.getDotPos()) {
        // 输出点位置
        println("enumPattern.getDotPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

enumPattern.getDotPos(): 1:3-1:4

func getLParenPos()

public func getLParenPos(): Option<CodePositionRange>

功能:获取 EnumPattern 节点中 ( 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 EnumPattern 实例
    let enumConstructor = SymbolRef("A", [])
    let subPatterns: Array<Pattern> = [VarPattern("x")]
    let enumPattern = EnumPattern(enumConstructor, None, subPatterns)

    if (let Some(pos) <- enumPattern.getLParenPos()) {
        // 输出左括号位置
        println("enumPattern.getLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

enumPattern.getLParenPos(): 1:2-1:3

func getRParenPos()

public func getRParenPos(): Option<CodePositionRange>

功能:获取 EnumPattern 节点中 ) 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 EnumPattern 实例
    let enumConstructor = SymbolRef("A", [])
    let subPatterns: Array<Pattern> = [VarPattern("x")]
    let enumPattern = EnumPattern(enumConstructor, None, subPatterns)

    if (let Some(pos) <- enumPattern.getRParenPos()) {
        // 输出右括号位置
        println("enumPattern.getRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

enumPattern.getRParenPos(): 1:4-1:5

class Expr

sealed abstract class Expr <: SyntaxTreeNode {}

功能:表示一个表达式节点。

父类型:

class ExtendDecl

public class ExtendDecl <: Decl {
    public init(body: Body, extendedTyAnnotation: TypeAnnotation, genericConstraints: Option<GenericConstraints>,
        genericParams: Array<GenericParam>, superTyAnnotations: Array<TypeAnnotation>,
        annotations!: Array<Annotation> = [], comments!: Array<Comment> = [])
}

功能:表示一个扩展声明节点。

扩展的声明使用 extend 关键字,扩展声明依次为:extend 关键字、扩展类型、是否指定父接口、可选的泛型约束、扩展体的声明。

父类型:

prop body

public prop body: Body

功能:获取当前扩展声明的主体部分。

类型:Body

prop extendedTyAnnotation

public prop extendedTyAnnotation: TypeAnnotation

功能:获取当前扩展声明的被扩展类型标注。

类型:TypeAnnotation

prop genericConstraints

public prop genericConstraints: Option<GenericConstraints>

功能:获取当前扩展声明的泛型约束(若不存在返回 None)。

类型:Option<GenericConstraints>

prop genericParams

public prop genericParams: Array<GenericParam>

功能:获取当前扩展声明的泛型参数列表。

类型:Array<GenericParam>

prop superTyAnnotations

public prop superTyAnnotations: Array<TypeAnnotation>

功能:获取当前扩展声明的父类类型标注列表。

类型:Array<TypeAnnotation>

init(Body, TypeAnnotation, Option<GenericConstraints>, Array<GenericParam>, Array<TypeAnnotation>, Array<Annotation>, Array<Comment>)

public init(body: Body, extendedTyAnnotation: TypeAnnotation, genericConstraints: Option<GenericConstraints>,
    genericParams: Array<GenericParam>, superTyAnnotations: Array<TypeAnnotation>,
    annotations!: Array<Annotation> = [], comments!: Array<Comment> = [])

功能:构造一个 ExtendDecl 对象,表示扩展声明节点。

参数:

  • body: Body - 扩展体,包含成员声明。
  • extendedTyAnnotation: TypeAnnotation - 被扩展的类型注解。
  • genericConstraints: Option<GenericConstraints> - 可选的泛型约束。
  • genericParams: Array<GenericParam> - 泛型参数列表。
  • superTyAnnotations: Array<TypeAnnotation> - 父类类型标注列表。
  • annotations!: Array<Annotation> - 附加的注解列表,默认为空数组。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 body 中有除函数声明、宏展开声明和属性声明外的声明或当泛型约束与泛型参数不对应时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建扩展体,包含一些成员声明
    let body = Body([])

    // 设置被扩展的类型注解
    let extendedTyAnnotation = CompositeType("C1", [], [])

    // 创建泛型约束(无)
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])

    // 创建泛型参数
    let genericParams = [GenericParam("T")]

    // 设置父类型注解
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]

    // 创建注解
    let annotations = [Annotation([Argument(None, false, LitConstExpr(LitConstKind.IntergerLiteral, "123"))], "MyAnno", AtOpKind.At)]

    // 创建 ExtendDecl 实例
    let extendDecl = ExtendDecl(
        body, 
        extendedTyAnnotation, 
        genericConstraints, 
        genericParams, 
        superTyAnnotations, 
        annotations: annotations
    )

    println("extendDecl: ${extendDecl}")
}

运行结果:

extendDecl: @MyAnno[123]
extend<T> C1 <: I1 where T<:I1 {
}

func getExtendKeyWordPos()

public func getExtendKeyWordPos(): CodePositionRange

功能:获取 ExtendDecl 节点中 extend 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建扩展体
    let body = Body([])

    // 设置被扩展的类型注解
    let extendedTyAnnotation = CompositeType("C1", [], [])

    // 创建泛型约束(无)
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])

    // 创建泛型参数
    let genericParams = [GenericParam("T")]

    // 设置父类型注解
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    
    // 创建 ExtendDecl 实例
    let extendDecl = ExtendDecl(
        body, 
        extendedTyAnnotation, 
        genericConstraints, 
        genericParams, 
        superTyAnnotations
    )
    
    // 获取 extend 关键字位置
    let pos = extendDecl.getExtendKeyWordPos()
    
    // 输出 extend 关键字位置
    println("extendDecl.getExtendKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

extendDecl.getExtendKeyWordPos(): 1:1-1:7

func getGenericParamsCommasPos()

public func getGenericParamsCommasPos(): Array<CodePositionRange>

功能:获取 ExtendDecl 节点中泛型参数中 , 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建扩展体
    let body = Body([])

    // 设置被扩展的类型注解
    let extendedTyAnnotation = CompositeType("C1", [], [])

    // 创建泛型约束(无)
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])

    // 创建泛型参数
    let genericParams = [GenericParam("T"), GenericParam("U"), GenericParam("V")]

    // 设置父类型注解
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    
    // 创建 ExtendDecl 实例
    let extendDecl = ExtendDecl(
        body, 
        extendedTyAnnotation, 
        genericConstraints, 
        genericParams, 
        superTyAnnotations
    )
    
    // 获取泛型参数中逗号的位置
    let posArr = extendDecl.getGenericParamsCommasPos()
    
    // 遍历输出逗号位置
    for (i in 0..posArr.size) {
        println("extendDecl.getGenericParamsCommasPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

extendDecl.getGenericParamsCommasPos()[0]: 1:9-1:10
extendDecl.getGenericParamsCommasPos()[1]: 1:12-1:13

func getGenericParamsLAnglePos()

public func getGenericParamsLAnglePos(): Option<CodePositionRange>

功能:获取 ExtendDecl 节点中泛型参数的 < 的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回泛型参数中 < 的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建扩展体
    let body = Body([])

    // 设置被扩展的类型注解
    let extendedTyAnnotation = CompositeType("C1", [], [])

    // 创建泛型约束(无)
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])

    // 创建泛型参数
    let genericParams = [GenericParam("T")]

    // 设置父类型注解
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    
    // 创建 ExtendDecl 实例
    let extendDecl = ExtendDecl(
        body, 
        extendedTyAnnotation, 
        genericConstraints, 
        genericParams, 
        superTyAnnotations
    )
    
    // 获取泛型参数左尖括号的位置
    if (let Some(pos) <- extendDecl.getGenericParamsLAnglePos()) {
        // 输出左尖括号位置
        println("extendDecl.getGenericParamsLAnglePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    } else {
        println("No left angle bracket found")
    }
}

运行结果:

extendDecl.getGenericParamsLAnglePos(): 1:7-1:8

func getGenericParamsRAnglePos()

public func getGenericParamsRAnglePos(): Option<CodePositionRange>

功能:获取 ExtendDecl 节点中泛型参数的 > 的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回泛型参数中 > 的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建扩展体
    let body = Body([])

    // 设置被扩展的类型注解
    let extendedTyAnnotation = CompositeType("C1", [], [])

    // 创建泛型约束(无)
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])

    // 创建泛型参数
    let genericParams = [GenericParam("T")]

    // 设置父类型注解
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    
    // 创建 ExtendDecl 实例
    let extendDecl = ExtendDecl(
        body, 
        extendedTyAnnotation, 
        genericConstraints, 
        genericParams, 
        superTyAnnotations
    )
    
    // 获取泛型参数右尖括号的位置
    if (let Some(pos) <- extendDecl.getGenericParamsRAnglePos()) {
        // 输出右尖括号位置
        println("extendDecl.getGenericParamsRAnglePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    } else {
        println("No right angle bracket found")
    }
}

运行结果:

extendDecl.getGenericParamsRAnglePos(): 1:9-1:10

func getSuperTyAnnotationsBitAndsPos()

public func getSuperTyAnnotationsBitAndsPos(): Array<CodePositionRange>

功能:获取 ExtendDecl 节点中父类型中 & 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建扩展体
    let body = Body([])

    // 设置被扩展的类型注解
    let extendedTyAnnotation = CompositeType("C1", [], [])

    // 创建泛型约束(无)
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])

    // 创建泛型参数
    let genericParams = [GenericParam("T")]
    
    // 创建多个父类型(使用 & 连接)
    let superTyAnnotations: Array<TypeAnnotation> = [
        CompositeType("I1", [], []),
        CompositeType("I2", [], []),
        CompositeType("I3", [], [])
    ]
    
    // 创建 ExtendDecl 实例
    let extendDecl = ExtendDecl(
        body, 
        extendedTyAnnotation, 
        genericConstraints, 
        genericParams, 
        superTyAnnotations
    )
    
    // 获取父类型中 & 的位置
    let posArr = extendDecl.getSuperTyAnnotationsBitAndsPos()
    
    // 遍历输出 & 位置
    for (i in 0..posArr.size) {
        println("extendDecl.getSuperTyAnnotationsBitAndsPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

extendDecl.getSuperTyAnnotationsBitAndsPos()[0]: 1:20-1:21
extendDecl.getSuperTyAnnotationsBitAndsPos()[1]: 1:25-1:26

func getUpperBoundPos()

public func getUpperBoundPos(): Option<CodePositionRange>

功能:获取 ExtendDecl 节点中 <: 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建扩展体
    let body = Body([])

    // 设置被扩展的类型注解
    let extendedTyAnnotation = CompositeType("C1", [], [])

    // 创建泛型约束(无)
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])

    // 创建泛型参数
    let genericParams = [GenericParam("T")]

    // 设置父类型注解
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    
    // 创建 ExtendDecl 实例
    let extendDecl = ExtendDecl(
        body, 
        extendedTyAnnotation, 
        genericConstraints, 
        genericParams, 
        superTyAnnotations
    )
    
    // 获取 <: 位置
    if (let Some(pos) <- extendDecl.getUpperBoundPos()) {
        // 输出 <: 位置
        println("extendDecl.getUpperBoundPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    } else {
        println("No upper bound found")
    }
}

运行结果:

extendDecl.getUpperBoundPos(): 1:14-1:16

class FeatureId

public class FeatureId <: SyntaxTreeNode {
    public init(identifiers: Array<String>, comments!: Array<Comment> = [])
}

功能:一个 feature 标识节点。

父类型:

prop featureNameIdentifiers

public prop featureNameIdentifiers: Array<String> 

功能:获取 feature 名称中的标识符。

类型:Array<String>

init(Array<String>, Array<Comment>)

public init(identifiers: Array<String>, comments!: Array<Comment> = [])

功能:构造一个对象。

参数:

  • features: Array<String> - feature 名称数组。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当数组为空或包含空字符串时抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 identifiers
    let identifiers = ["std", "core", "feature"]

    // 创建 FeatureId 实例
    let featureId = FeatureId(
        identifiers
    )

    println("featureId: ${featureId}")
}

运行结果:

featureId: std.core.feature

func getDotPoses()

public func getDotPoses(): Array<CodePositionRange>

功能:获取 feature 名称中的 . 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 identifiers
    let identifiers = ["std", "core", "feature"]

    // 创建 FeatureId 实例
    let featureId = FeatureId(identifiers)
    
    // 获取点的位置
    let posArr = featureId.getDotPoses()
    
    // 遍历输出点的位置
    for (i in 0..posArr.size) {
        println("featureId.getDotPoses()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

featureId.getDotPoses()[0]: 1:4-1:5
featureId.getDotPoses()[1]: 1:9-1:10

func getIdentifierPos()

public func getIdentifierPos(): Array<CodePositionRange> 

功能:获取 feature 名称中的标识符位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 identifiers
    let identifiers = ["std", "core", "feature"]

    // 创建 FeatureId 实例
    let featureId = FeatureId(identifiers)
    
    // 获取标识符的位置
    let posArr = featureId.getIdentifierPos()
    
    // 遍历输出标识符位置
    for (i in 0..posArr.size) {
        println("featureId.getIdentifierPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

featureId.getIdentifierPos()[0]: 1:1-1:4
featureId.getIdentifierPos()[1]: 1:5-1:9
featureId.getIdentifierPos()[2]: 1:10-1:17

class FeaturesDirective

public class FeaturesDirective <: SyntaxTreeNode {
    public init(annotations: Array<Annotation>, set: FeaturesSet, comments!: Array<Comment> = [])
}

功能:一个 features 声明节点。

父类型:

prop annotations

public prop annotations: Array<Annotation>

功能:获取当前声明的注解列表。

类型:Array<Annotation>

prop featuresSet

public prop featuresSet: FeaturesSet

功能:获取当前声明的 features set。

类型:FeaturesSet

init(Array<Annotation>, FeaturesSet, Array<Comment>)

public init(annotations: Array<Annotation>, set: FeaturesSet, comments!: Array<Comment> = [])

功能:构造一个 FeatureId 对象。

参数:

  • annotations: Array<Annotation> - 一组在 feature directive 声明节点上的注解。
  • set: FeaturesSet - 一组 features 名称。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当 featureId 无法构造时抛出异常。

示例:

import stdx.syntax.*

main() {
    // 创建注解
    let annotations: Array<Annotation> = []

    // 创建 FeatureId
    let featureId1 = FeatureId(["std", "core", "feature1"])
    let featureId2 = FeatureId(["std", "core", "feature2"])

    // 创建 FeaturesSet
    let featuresSet = FeaturesSet([featureId1, featureId2])

    // 创建 FeaturesDirective 实例
    let featuresDirective = FeaturesDirective(
        annotations, 
        featuresSet
    )

    println("featuresDirective: ${featuresDirective}")
}

运行结果:

featuresDirective: features {std.core.feature1, std.core.feature2}

func getFeaturesKeywordPos()

public func getFeaturesKeywordPos(): CodePositionRange    

功能:获取声明中的关键字 features 的位置信息。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建注解
    let annotations: Array<Annotation> = []

    // 创建 FeatureId
    let featureId = FeatureId(["std", "core", "feature"])

    // 创建 FeaturesSet
    let featuresSet = FeaturesSet([featureId])

    // 创建 FeaturesDirective 实例
    let featuresDirective = FeaturesDirective(
        annotations, 
        featuresSet
    )

    // 获取 features 关键字的位置
    let pos = featuresDirective.getFeaturesKeywordPos()

    // 输出关键字位置
    println("featuresDirective.getFeaturesKeywordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

featuresDirective.getFeaturesKeywordPos(): 1:1-1:9

class FeaturesSet

public class FeaturesSet <: SyntaxTreeNode {
    public init(features: Array<FeatureId>, comments!: Array<Comment> = [])
}

功能:一个 feature set 节点。

父类型:

prop content

public prop content: Array<FeatureId>

功能:获取 features set 内包含的一组 featureId。

类型:Array<FeatureId>

init(Array<FeatureId>, Array<Comment>)

public init(features: Array<FeatureId>, comments!: Array<Comment> = [])

功能:创建一个 FeaturesSet 对象。

参数:

  • features: Array<FeatureId> - 一组定义在 features set 中的 feature id。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建 FeatureId
    let featureId1 = FeatureId(["std", "core", "feature1"])
    let featureId2 = FeatureId(["std", "core", "feature2"])

    // 创建 FeaturesSet 实例
    let featuresSet = FeaturesSet([featureId1, featureId2])

    println("featuresSet: ${featuresSet}")
}

运行结果:

featuresSet: {std.core.feature1, std.core.feature2}

func getLCurlPos()

public func getLCurlPos(): CodePositionRange 

功能:获取 '{' 的位置信息。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 FeatureId
    let featureId = FeatureId(["std", "core", "feature"])

    // 创建 FeaturesSet 实例
    let featuresSet = FeaturesSet([featureId])

    // 获取左花括号的位置
    let pos = featuresSet.getLCurlPos()

    // 输出左花括号位置
    println("featuresSet.getLCurlPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

featuresSet.getLCurlPos(): 1:1-1:2

func getRCurlPos()

public func getRCurlPos(): CodePositionRange

功能:获取 '}' 的位置信息。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 FeatureId
    let featureId = FeatureId(["std", "core", "feature"])

    // 创建 FeaturesSet 实例
    let featuresSet = FeaturesSet([featureId])

    // 获取右花括号的位置
    let pos = featuresSet.getRCurlPos()

    // 输出右花括号位置
    println("featuresSet.getRCurlPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

featuresSet.getRCurlPos(): 1:18-1:19

func getCommaPoses()

public func getCommaPoses(): Array<CodePositionRange>

功能:获取 ',' 的位置信息。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建多个 FeatureId
    let featureId1 = FeatureId(["std", "core", "feature1"])
    let featureId2 = FeatureId(["std", "core", "feature2"])
    let featureId3 = FeatureId(["std", "core", "feature3"])

    // 创建 FeaturesSet 实例
    let featuresSet = FeaturesSet([featureId1, featureId2, featureId3])

    // 获取逗号的位置
    let posArr = featuresSet.getCommaPoses()

    // 输出逗号位置
    for (i in 0..posArr.size) {
        println("featuresSet.getCommaPoses()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

featuresSet.getCommaPoses()[0]: 1:19-1:20
featuresSet.getCommaPoses()[1]: 1:38-1:39

class ForInExpr

public class ForInExpr <: Expr {
    public init(body: Block, expr: Expr, pattern: Pattern, patternGuard: Option<Expr>, comments!: Array<Comment> = [])
}

功能:表示 for-in 表达式。

ForInExpr 类型中,关键字 for 之后是 Pattern, 此后是一个 in 关键字和表达式节点,最后是一个执行循环体 Block

父类型:

prop body

public prop body: Block

功能:获取当前 for-in 语句的循环体代码块。

类型:Block

prop expr

public prop expr: Expr

功能:获取当前 for-in 语句的集合表达式,即要遍历的对象。

类型:Expr

prop pattern

public prop pattern: Pattern

功能:获取当前 for-in 语句的迭代变量模式。

类型:Pattern

prop patternGuard

public prop patternGuard: Option<Expr>

功能:获取当前 for-in 语句中用于迭代的条件表达式(若不存在返回 None)。

类型:Option<Expr>

init(Block, Expr, Pattern, Option<Expr>, Array<Comment>)

public init(body: Block, expr: Expr, pattern: Pattern, patternGuard: Option<Expr>, comments!: Array<Comment> = [])

功能:构造一个 ForInExpr 对象,表示 for-in 循环表达式。

参数:

  • body: Block - 循环体代码块。
  • expr: Expr - 被迭代的集合表达式。
  • pattern: Pattern - 用于解构每次迭代值的绑定模式。
  • patternGuard: Option<Expr> - 可选的模式守卫表达式。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当 pattern 不是通配符模式、变量绑定模式、元组模式或枚举模式时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 body
    let body = Block([])

    // 创建 expr
    let expr = LitConstExpr(LitConstKind.IntergerLiteral, "10")

    // 创建 pattern
    let pattern = VarPattern("x")

    // 创建 patternGuard
    let patternGuard = BinaryExpr(SymbolRef("x", []),BinaryOpKind.NotEq, LitConstExpr(LitConstKind.IntergerLiteral, "5"))

    // 创建 ForInExpr 实例
    let forInExpr = ForInExpr(
        body, 
        expr, 
        pattern, 
        patternGuard
    )

    println("forInExpr: ${forInExpr}")
}

运行结果:

forInExpr: for (x in 10 where x != 5) {
}

func getForKeyWordPos()

public func getForKeyWordPos(): CodePositionRange

功能:获取 ForInExpr 节点中 for 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 ForInExpr 实例
    let forInExpr = ForInExpr(Block([]), LitConstExpr(LitConstKind.IntergerLiteral, "10"), VarPattern("x"), None)
    let pos = forInExpr.getForKeyWordPos()

    // 输出 for 关键字位置
    println("forInExpr.getForKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

forInExpr.getForKeyWordPos(): 1:1-1:4

func getInKeyWordPos()

public func getInKeyWordPos(): CodePositionRange

功能:获取 ForInExpr 节点中 in 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 ForInExpr 实例
    let forInExpr = ForInExpr(Block([]), LitConstExpr(LitConstKind.IntergerLiteral, "10"), VarPattern("x"), None)
    let pos = forInExpr.getInKeyWordPos()

    // 输出 in 关键字位置
    println("forInExpr.getInKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

forInExpr.getInKeyWordPos(): 1:8-1:10

func getLParenPos()

public func getLParenPos(): CodePositionRange

功能:获取 ForInExpr 节点中的 ( 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 ForInExpr 实例
    let forInExpr = ForInExpr(Block([]), LitConstExpr(LitConstKind.IntergerLiteral, "10"), VarPattern("x"), None)
    let pos = forInExpr.getLParenPos()

    // 输出左括号位置
    println("forInExpr.getLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

forInExpr.getLParenPos(): 1:5-1:6

func getRParenPos()

public func getRParenPos(): CodePositionRange

功能:获取 ForInExpr 节点中的 ) 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 ForInExpr 实例
    let forInExpr = ForInExpr(Block([]), LitConstExpr(LitConstKind.IntergerLiteral, "10"), VarPattern("x"), None)
    let pos = forInExpr.getRParenPos()

    // 输出右括号位置
    println("forInExpr.getRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

forInExpr.getRParenPos(): 1:13-1:14

func getWhereKeyWordPos()

public func getWhereKeyWordPos(): Option<CodePositionRange>

功能:获取 ForInExpr 节点中 where 关键字的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回 where 关键字的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 patternGuard
    let patternGuard = BinaryExpr(SymbolRef("x", []), BinaryOpKind.NotEq, LitConstExpr(LitConstKind.IntergerLiteral, "5"))

    // 创建 ForInExpr 实例
    let forInExpr = ForInExpr(Block([]), LitConstExpr(LitConstKind.IntergerLiteral, "10"), VarPattern("x"), patternGuard)

    if (let Some(pos) <- forInExpr.getWhereKeyWordPos()) {
        // 输出 where 关键字位置
        println("forInExpr.getWhereKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

forInExpr.getWhereKeyWordPos(): 1:14-1:19

class FuncDecl

public class FuncDecl <: Decl {
    public init(body: Option<Block>, genericConstraints: Option<GenericConstraints>, genericParams: Array<GenericParam>,
        kind: FuncKind, name: String, params: ParameterList, retTyAnnotation: Option<TypeAnnotation>,
        annotations!: Array<Annotation> = [], modifiers!: Array<Modifier> = [], comments!: Array<Comment> = [])
}

功能:表示一个函数声明节点。

由可选的函数修饰符,关键字 func,函数名,可选的泛型约束列表,可选的类型形参列表,函数参数,可选的函数体,可缺省的函数返回类型来声明一个函数。

父类型:

prop body

public prop body: Option<Block>

功能:获取当前函数声明的主体部分(若不存在返回 None)。

类型:Option<Block>

prop genericConstraints

public prop genericConstraints: Option<GenericConstraints>

功能:获取当前函数声明的泛型约束(若不存在返回 None)。

类型:Option<GenericConstraints>

prop genericParams

public prop genericParams: Array<GenericParam>

功能:获取当前函数声明的泛型参数列表。

类型:Array<GenericParam>

prop kind

public prop kind: FuncKind

功能:获取当前函数声明的种类。

类型:FuncKind

prop name

public prop name: String

功能:获取当前函数声明的名称。

类型:String

prop params

public prop params: ParameterList

功能:获取当前函数声明的参数列表。

类型:ParameterList

prop retTyAnnotation

public prop retTyAnnotation: Option<TypeAnnotation>

功能:获取当前函数声明的返回类型标注(若不存在返回 None)。

类型:Option<TypeAnnotation>

init(Option<Block>, Option<GenericConstraints>, Array<GenericParam>, FuncKind, String, ParameterList, Option<TypeAnnotation>, Array<Annotation>, Array<Modifier>, Array<Comment>)

public init(body: Option<Block>, genericConstraints: Option<GenericConstraints>, genericParams: Array<GenericParam>,
    kind: FuncKind, name: String, params: ParameterList, retTyAnnotation: Option<TypeAnnotation>,
    annotations!: Array<Annotation> = [], modifiers!: Array<Modifier> = [], comments!: Array<Comment> = [])

功能:构造一个 FuncDecl 对象,表示函数声明节点。

参数:

  • body: Option<Block> - 可选的函数体。
  • genericConstraints: Option<GenericConstraints> - 可选的泛型约束。
  • genericParams: Array<GenericParam> - 泛型参数列表。
  • kind: FuncKind - 函数种类。
  • name: String - 函数名。
  • params: ParameterList - 参数列表。
  • retTyAnnotation: Option<TypeAnnotation> - 可选的返回类型注解。
  • annotations!: Array<Annotation> - 附加的注解列表,默认为空数组。
  • modifiers!: Array<Modifier> - 修饰符列表,默认为空数组。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当函数种类和修饰符不对应,或输入的 name 不符合仓颉标识符规范时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 body
    let body = Block([ReturnExpr(None)])

    // 创建 genericConstraints
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])

    // 创建 genericParams
    let genericParams = [GenericParam("T")]

    // 创建 kind
    let kind = FuncKind.Normal

    // 创建 name
    let name = "foo"

    // 创建 params
    let params = ParameterList([])

    // 创建 retTyAnnotation
    let retTyAnnotation = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 FuncDecl 实例
    let funcDecl = FuncDecl(
        body, 
        genericConstraints, 
        genericParams, 
        kind, 
        name, 
        params, 
        retTyAnnotation
    )

    println("funcDecl: ${funcDecl}")
}

运行结果:

funcDecl: func foo<T>(): Int64 where T<:I1 {
    return
}

func getFuncKeyWordPos()

public func getFuncKeyWordPos(): Option<CodePositionRange>

功能:获取 FuncDecl 节点中 func 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 FuncDecl 实例
    let funcDecl = FuncDecl(
        Block([ReturnExpr(None)]),
        None,
        [],
        FuncKind.Normal,
        "foo",
        ParameterList([]),
        AtomicType(AtomicTypeKind.Int64Type)
    )

    if (let Some(pos) <- funcDecl.getFuncKeyWordPos()) {
        // 输出 func 关键字位置
        println("funcDecl.getFuncKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

funcDecl.getFuncKeyWordPos(): 1:1-1:5

func getFuncKindKeyWordPos()

public func getFuncKindKeyWordPos(): Option<CodePositionRange>

功能:获取 FuncDecl 节点中 FuncKind 关键字的位置。

返回值:

注意:

kindFinalizer 时,返回 ~ 的位置,kindOperator 时,返回 operator 的位置,kindForeign 时,返回 foriegn 的位置。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 Operator 类型的 FuncDecl 实例
    let operatorFuncDecl = FuncDecl(
        Block([ReturnExpr(None)]),
        None,
        [],
        FuncKind.Operator,
        "+",
        ParameterList([]),
        AtomicType(AtomicTypeKind.Int64Type),
        modifiers: [Modifier(ModifierKind.Operator)]
    )

    if (let Some(pos) <- operatorFuncDecl.getFuncKindKeyWordPos()) {
        // 输出 operator 关键字位置
        println("operatorFuncDecl.getFuncKindKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

operatorFuncDecl.getFuncKindKeyWordPos(): 1:1-1:9

func getGenericParamsCommasPos()

public func getGenericParamsCommasPos(): Array<CodePositionRange>

功能:获取 FuncDecl 节点中泛型参数间 , 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建带有多个泛型参数的 FuncDecl 实例
    let funcDecl = FuncDecl(
        Block([ReturnExpr(None)]),
        None,
        [GenericParam("T"), GenericParam("U"), GenericParam("V")],
        FuncKind.Normal,
        "foo",
        ParameterList([]),
        AtomicType(AtomicTypeKind.Int64Type)
    )

    // 获取泛型参数间逗号的位置
    let posArr = funcDecl.getGenericParamsCommasPos()

    // 输出逗号位置
    for (i in 0..posArr.size) {
        println("funcDecl.getGenericParamsCommasPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

funcDecl.getGenericParamsCommasPos()[0]: 1:11-1:12
funcDecl.getGenericParamsCommasPos()[1]: 1:14-1:15

func getGenericParamsLAnglePos()

public func getGenericParamsLAnglePos(): Option<CodePositionRange>

功能:获取 FuncDecl 节点中泛型参数 < 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建带有泛型参数的 FuncDecl 实例
    let funcDecl = FuncDecl(
        Block([ReturnExpr(None)]),
        None,
        [GenericParam("T")],
        FuncKind.Normal,
        "foo",
        ParameterList([]),
        AtomicType(AtomicTypeKind.Int64Type)
    )

    if (let Some(pos) <- funcDecl.getGenericParamsLAnglePos()) {
        // 输出左尖括号位置
        println("funcDecl.getGenericParamsLAnglePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

funcDecl.getGenericParamsLAnglePos(): 1:9-1:10

func getGenericParamsRAnglePos()

public func getGenericParamsRAnglePos(): Option<CodePositionRange>

功能:获取 FuncDecl 节点中泛型参数 > 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建带有泛型参数的 FuncDecl 实例
    let funcDecl = FuncDecl(
        Block([ReturnExpr(None)]),
        None,
        [GenericParam("T")],
        FuncKind.Normal,
        "foo",
        ParameterList([]),
        AtomicType(AtomicTypeKind.Int64Type)
    )

    if (let Some(pos) <- funcDecl.getGenericParamsRAnglePos()) {
        // 输出右尖括号位置
        println("funcDecl.getGenericParamsRAnglePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

funcDecl.getGenericParamsRAnglePos(): 1:11-1:12

func getIdentifierPos()

public func getIdentifierPos(): CodePositionRange

功能:获取 FuncDecl 节点中标识符的位置。

返回值:

注意:

kindFinalizer 时,返回 init 的位置。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 FuncDecl 实例
    let funcDecl = FuncDecl(
        Block([ReturnExpr(None)]),
        None,
        [],
        FuncKind.Normal,
        "foo",
        ParameterList([]),
        AtomicType(AtomicTypeKind.Int64Type)
    )

    // 获取标识符位置
    let pos = funcDecl.getIdentifierPos()

    // 输出标识符位置
    println("funcDecl.getIdentifierPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

funcDecl.getIdentifierPos(): 1:6-1:9

func getRetTyAnnotationColonPos()

public func getRetTyAnnotationColonPos(): Option<CodePositionRange>

功能:获取 FuncDecl 节点中类型前 : 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建带有返回类型注解的 FuncDecl 实例
    let funcDecl = FuncDecl(
        Block([ReturnExpr(None)]),
        None,
        [],
        FuncKind.Normal,
        "foo",
        ParameterList([]),
        AtomicType(AtomicTypeKind.Int64Type)
    )

    if (let Some(pos) <- funcDecl.getRetTyAnnotationColonPos()) {
        // 输出冒号位置
        println("funcDecl.getRetTyAnnotationColonPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

funcDecl.getRetTyAnnotationColonPos(): 1:11-1:12

class FuncParam

public open class FuncParam <: Parameter {
    public init(defaultValue: Option<Expr>, kind: Option<VarKind>, name: String, typeAnnotation: TypeAnnotation,
        isNamed!: Bool = false, annotations!: Array<Annotation> = [], modifiers!: Array<Modifier> = [],
        comments!: Array<Comment> = [])
}

功能:表示一个函数参数。

FuncParam 类用于在程序中声明一个新的函数参数,defaultValue 表示参数的默认值,name 表示参数的名称,typeAnnotation 表示参数的类型标注。

父类型:

prop defaultValue

public prop defaultValue: Option<Expr>

功能:获取当前函数参数的默认值(若不存在返回 None)。

类型:Option<Expr>

prop kind

public prop kind: Option<VarKind>

功能:获取当前函数参数的种类(若不存在返回 None)。

类型:Option<VarKind>

prop name

public prop name: String

功能:获取当前函数参数的名称。

类型:String

prop typeAnnotation

public prop typeAnnotation: TypeAnnotation

功能:获取当前函数参数的类型标注。

类型:TypeAnnotation

init(Option<Expr>, Option<VarKind>, String, TypeAnnotation, Bool, Array<Annotation>, Array<Modifier>, Array<Comment>)

public init(defaultValue: Option<Expr>, kind: Option<VarKind>, name: String, typeAnnotation: TypeAnnotation,
    isNamed!: Bool = false, annotations!: Array<Annotation> = [], modifiers!: Array<Modifier> = [],
    comments!: Array<Comment> = [])

功能:构造一个 FuncParam 对象,表示函数参数节点。

参数:

  • defaultValue: Option<Expr> - 可选的默认值表达式。
  • kind: Option<VarKind> - 可选的变量种类。
  • name: String - 参数名。
  • typeAnnotation: TypeAnnotation - 类型注解。
  • isNamed!: Bool - 是否为命名参数,默认为 false
  • annotations!: Array<Annotation> - 附加的注解列表,默认为空数组。
  • modifiers!: Array<Modifier> - 修饰符列表,默认为空数组。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当 kind 不代表 varlet,或 kind 为空但 modifiers 不为空,或没有传入参数名却为命名参数,或输入的 name 不符合仓颉标识符规范时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 defaultValue
    let defaultValue = LitConstExpr(LitConstKind.IntergerLiteral, "1")

    // 创建 kind
    let kind = VarKind.Let

    // 创建 name
    let name = "x"

    // 创建 typeAnnotation
    let typeAnnotation = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 isNamed
    let isNamed = true

    // 创建 FuncParam 实例
    let funcParam = FuncParam(
        defaultValue, 
        kind, 
        name, 
        typeAnnotation, 
        isNamed: isNamed
    )

    println("funcParam: ${funcParam}")
}

运行结果:

funcParam: let x!: Int64 = 1

func getAssignPos()

public func getAssignPos(): Option<CodePositionRange>

功能:获取 FuncParam 节点中 = 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 FuncParam 实例
    let defaultValue = LitConstExpr(LitConstKind.IntergerLiteral, "1")
    let funcParam = FuncParam(defaultValue, VarKind.Let, "x", AtomicType(AtomicTypeKind.Int64Type), isNamed: true)

    if (let Some(pos) <- funcParam.getAssignPos()) {
        // 输出等号位置
        println("funcParam.getAssignPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

funcParam.getAssignPos(): 1:15-1:16

func getIdentifierPos()

public func getIdentifierPos(): CodePositionRange

功能:获取 FuncParam 节点中标识符的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 FuncParam 实例
    let funcParam = FuncParam(None, VarKind.Let, "x", AtomicType(AtomicTypeKind.Int64Type))
    let pos = funcParam.getIdentifierPos()

    // 输出标识符位置
    println("funcParam.getIdentifierPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

funcParam.getIdentifierPos(): 1:5-1:6

func getNotPos()

public func getNotPos(): Option<CodePositionRange>

功能:获取 FuncParam 节点中 ! 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 FuncParam 实例
    let funcParam = FuncParam(None, VarKind.Let, "x", AtomicType(AtomicTypeKind.Int64Type), isNamed: true)

    if (let Some(pos) <- funcParam.getNotPos()) {
        // 输出感叹号位置
        println("funcParam.getNotPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

funcParam.getNotPos(): 1:6-1:7

func getTypeAnnotationColonPos()

public func getTypeAnnotationColonPos(): CodePositionRange

功能:获取 FuncParam 节点中 : 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 FuncParam 实例
    let funcParam = FuncParam(None, VarKind.Let, "x", AtomicType(AtomicTypeKind.Int64Type))
    let pos = funcParam.getTypeAnnotationColonPos()

    // 输出冒号位置
    println("funcParam.getTypeAnnotationColonPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

funcParam.getTypeAnnotationColonPos(): 1:6-1:7

func getVarKindKeyWordPos()

public func getVarKindKeyWordPos(): Option<CodePositionRange>

功能:获取 FuncParam 节点中关键字 letvar 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 FuncParam 实例
    let funcParam = FuncParam(None, VarKind.Let, "x", AtomicType(AtomicTypeKind.Int64Type))

    if (let Some(pos) <- funcParam.getVarKindKeyWordPos()) {
        // 输出 let/var 关键字位置
        println("funcParam.getVarKindKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

funcParam.getVarKindKeyWordPos(): 1:1-1:4

class FuncType

public class FuncType <: TypeAnnotation {
    public init(paramTypes: Array<TypeAnnotation>, labels: Array<String>, retType: TypeAnnotation, comments!: Array<Comment> = [])
}

功能:表示函数类型节点。

由函数的参数类型和返回类型组成,参数类型与返回类型之间用 -> 分隔,如:(Int32) -> Unit

父类型:

prop labels

public prop labels: Array<String>

功能:获取 FuncType 节点中的类型参数名,例如 (name: String, age: Int64) -> Unit 中的 nameage

类型:Array<String>

prop paramTypes

public prop paramTypes: Array<TypeAnnotation>

功能:获取 FuncType 节点中函数的参数类型列表。

类型:Array<TypeAnnotation>

prop retType

public prop retType: TypeAnnotation

功能:获取 FuncType 的返回类型节点。

类型:TypeAnnotation

init(Array<TypeAnnotation>, Array<String>, TypeAnnotation, Array<Comment>)

public init(paramTypes: Array<TypeAnnotation>, labels: Array<String>, retType: TypeAnnotation, comments!: Array<Comment> = [])

功能:构造一个 FuncType 对象,表示函数类型,如 (a: Int64, b: String) -> Bool

参数:

  • paramTypes: Array<TypeAnnotation> - 参数类型列表。
  • labels: Array<String> - 参数标签列表。
  • retType: TypeAnnotation - 返回类型。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当参数类型列表和参数名列表长度不一样时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 paramTypes
    let paramTypes: Array<TypeAnnotation> = [CompositeType("I1", [], [])]

    // 创建 labels
    let labels = ["x"]

    // 创建 retType
    let retType = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 FuncType 实例
    let funcType = FuncType(
        paramTypes, 
        labels, 
        retType
    )

    println("funcType: ${funcType}")
}

运行结果:

funcType: (x: I1) -> Int64

func getArrowPos()

public func getArrowPos(): CodePositionRange

功能:获取 -> 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 FuncType 实例
    let funcType = FuncType(
        [AtomicType(AtomicTypeKind.Int64Type), AtomicType(Int32Type)],
        ["a", "b"],
        AtomicType(BoolType)
    )

    // 获取箭头位置
    let pos = funcType.getArrowPos()

    // 输出箭头位置
    println("funcType.getArrowPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

funcType.getArrowPos(): 1:22-1:24

func getColonsPos()

public func getColonsPos(): Array<CodePositionRange>

功能:获取 : 的位置序列。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 FuncType 实例
    let funcType = FuncType(
        [AtomicType(AtomicTypeKind.Int64Type), AtomicType(Int32Type)],
        ["a", "b"],
        AtomicType(BoolType)
    )

    // 获取冒号位置
    let posArr = funcType.getColonsPos()

    // 输出冒号位置
    for (i in 0..posArr.size) {
        println("funcType.getColonsPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

funcType.getColonsPos()[0]: 1:3-1:4
funcType.getColonsPos()[1]: 1:13-1:14

func getCommasPos()

public func getCommasPos(): Array<CodePositionRange>

功能:获取 , 的位置序列。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 FuncType 实例
    let funcType = FuncType(
        [AtomicType(AtomicTypeKind.Int64Type), AtomicType(Int32Type), AtomicType(BoolType)],
        ["a", "b", "c"],
        AtomicType(UnitType)
    )

    // 获取逗号位置
    let posArr = funcType.getCommasPos()

    // 输出逗号位置
    for (i in 0..posArr.size) {
        println("funcType.getCommasPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

funcType.getCommasPos()[0]: 1:10-1:11
funcType.getCommasPos()[1]: 1:20-1:21

func getLabelsPos()

public func getLabelsPos(): Array<CodePositionRange>

功能:获取标签的位置序列。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 FuncType 实例
    let funcType = FuncType(
        [AtomicType(AtomicTypeKind.Int64Type), AtomicType(Int32Type)],
        ["a", "b"],
        AtomicType(BoolType)
    )

    // 获取标签位置
    let posArr = funcType.getLabelsPos()

    // 输出标签位置
    for (i in 0..posArr.size) {
        println("funcType.getLabelsPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

funcType.getLabelsPos()[0]: 1:2-1:3
funcType.getLabelsPos()[1]: 1:12-1:13

func getLParenPos()

public func getLParenPos(): CodePositionRange

功能:获取 ( 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 FuncType 实例
    let funcType = FuncType(
        [AtomicType(AtomicTypeKind.Int64Type)],
        ["a"],
        AtomicType(BoolType)
    )

    // 获取左括号位置
    let pos = funcType.getLParenPos()

    // 输出左括号位置
    println("funcType.getLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

funcType.getLParenPos(): 1:1-1:2

func getRParenPos()

public func getRParenPos(): CodePositionRange

功能:获取 ) 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 FuncType 实例
    let funcType = FuncType(
        [AtomicType(AtomicTypeKind.Int64Type)],
        ["a"],
        AtomicType(BoolType)
    )

    // 获取右括号位置
    let pos = funcType.getRParenPos()

    // 输出右括号位置
    println("funcType.getRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

funcType.getRParenPos(): 1:10-1:11

class GenericConstraint

public class GenericConstraint <: SyntaxTreeNode {
    public init(typeArgument: TypeAnnotation, upperBounds: Array<TypeAnnotation>, comments!: Array<Comment> = [])
}

功能:表示一个泛型约束节点。

一个 GenericConstraint 节点:interface Enumerable<T> where T <: Interface & Class {} 中的 where T <: Interface & Class

说明:

通过 where 之后的 <: 符号来声明,其中 <: 左边称为类型变元,<: 右边称为约束上界,约束上界可以为类型或接口。

父类型:

prop typeArgument

public prop typeArgument: TypeAnnotation

功能:获取 GenericConstraint 节点中的类型变元。

类型:TypeAnnotation

prop upperBounds

public prop upperBounds: Array<TypeAnnotation>

功能:获取 GenericConstraint 节点约束上界的 TypeAnnotation 类型节点的集合。

类型:Array<TypeAnnotation>

init(TypeAnnotation, Array<TypeAnnotation>, Array<Comment>)

public init(typeArgument: TypeAnnotation, upperBounds: Array<TypeAnnotation>, comments!: Array<Comment> = [])

功能:构造一个 GenericConstraint 对象,表示泛型约束。

参数:

  • typeArgument: TypeAnnotation - 被约束的类型参数。
  • upperBounds: Array<TypeAnnotation> - 上界类型列表。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 upperBounds 为空时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 typeArgument
    let typeArgument = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 upperBounds
    let upperBounds: Array<TypeAnnotation> = [CompositeType("I1", [], [])]

    // 创建 GenericConstraint 实例
    let genericConstraint = GenericConstraint(
        typeArgument, 
        upperBounds
    )

    println("genericConstraint: ${genericConstraint}")
}

运行结果:

genericConstraint: Int64<:I1

func getBitAndsPos()

public func getBitAndsPos(): Array<CodePositionRange>

功能:获取 GenericConstraint 节点中 & 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 GenericConstraint 实例
    let typeArgument = AtomicType(AtomicTypeKind.Int64Type)
    let upperBounds: Array<TypeAnnotation> = [CompositeType("I1", [], []), CompositeType("I2", [], [])]
    let genericConstraint = GenericConstraint(typeArgument, upperBounds)
    let posArr = genericConstraint.getBitAndsPos()

    // 遍历输出&位置
    for (i in 0..posArr.size) {
        println("genericConstraint.getBitAndsPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

genericConstraint.getBitAndsPos()[0]: 1:11-1:12

func getUpperBoundPos()

public func getUpperBoundPos(): CodePositionRange

功能:获取 GenericConstraint 节点中 <: 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 GenericConstraint 实例
    let typeArgument = AtomicType(AtomicTypeKind.Int64Type)
    let upperBounds: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    let genericConstraint = GenericConstraint(typeArgument, upperBounds)
    let pos = genericConstraint.getUpperBoundPos()

    // 输出 <: 位置
    println("genericConstraint.getUpperBoundPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

genericConstraint.getUpperBoundPos(): 1:6-1:8

class GenericConstraints

public class GenericConstraints <: SyntaxTreeNode {
    public init(constraints: Array<GenericConstraint>, comments!: Array<Comment> = [])
}

功能:表示一组泛型约束。

一个 GenericConstraints 节点:interface Enumerable<T1, T2> where T1 <: I1 & I2, T2 <: I3 & I4 中的 where T1 <: I1 & I2, T2 <: I3 & I4

父类型:

prop constraints

public prop constraints: Array<GenericConstraint>

功能:获取 GenericConstraints 节点中的所有约束。

类型:Array<GenericConstraint>

init(Array<GenericConstraint>, Array<Comment>)

public init(constraints: Array<GenericConstraint>, comments!: Array<Comment> = [])

功能:构造一个 GenericConstraints 对象,表示一组泛型约束。

参数:

  • constraints: Array<GenericConstraint> - 泛型约束列表。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 constraints 为空时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 constraints
    let constraints = [
        GenericConstraint(CompositeType("I1", [], []), [CompositeType("T", [], [])]), 
        GenericConstraint(CompositeType("I2", [], []), [CompositeType("T", [], []), CompositeType("U", [], [])])
    ]

    // 创建 GenericConstraints 实例
    let genericConstraints = GenericConstraints(
        constraints
    )

    println("genericConstraints: ${genericConstraints}")
}

运行结果:

genericConstraints: where I1<:T, I2<:T & U

func getCommasPos()

public func getCommasPos(): Array<CodePositionRange>

功能:获取 GenericConstraints 节点中 , 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 GenericConstraints 实例
    let constraints = [
        GenericConstraint(CompositeType("I1", [], []), [CompositeType("T", [], [])]),
        GenericConstraint(CompositeType("I2", [], []), [CompositeType("T", [], []), CompositeType("U", [], [])])
    ]
    let genericConstraints = GenericConstraints(constraints)
    let posArr = genericConstraints.getCommasPos()

    // 遍历输出逗号位置
    for (i in 0..posArr.size) {
        println("genericConstraints.getCommasPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

genericConstraints.getCommasPos()[0]: 1:12-1:13

func getWhereKeyWordPos()

public func getWhereKeyWordPos(): CodePositionRange

功能:获取 GenericConstraints 节点中 where 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 GenericConstraints 实例
    let constraints = [
        GenericConstraint(CompositeType("I1", [], []), [CompositeType("T", [], [])])
    ]
    let genericConstraints = GenericConstraints(constraints)
    let pos = genericConstraints.getWhereKeyWordPos()

    // 输出 where 关键字位置
    println("genericConstraints.getWhereKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

genericConstraints.getWhereKeyWordPos(): 1:1-1:6

class GenericParam

public class GenericParam <: Decl {
    public init(name: String, comments!: Array<Comment> = [])
}

功能:表示一个泛型参数节点。

一个 GenericParam 节点:<T1, T2, T3> 中的 T1

父类型:

prop name

public prop name: String

功能:获取当前型参的名称。

类型:String

init(String, Array<Comment>)

public init(name: String, comments!: Array<Comment> = [])

功能:构造一个 GenericParam 对象,表示泛型参数节点。

参数:

  • name: String - 泛型参数名。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 name 不符合仓颉标识符规范时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 name
    let name = "T"

    // 创建 GenericParam 实例
    let genericParam = GenericParam(
        name
    )

    println("genericParam: ${genericParam}")
}

运行结果:

genericParam: T

class IfExpr

public class IfExpr <: Expr {
    public init(condition: DisjunctionCondition, elseBlock: Option<Block>, elseIf: Option<IfExpr>, ifBlock: Block, comments!: Array<Comment> = [])
}

功能:表示条件表达式。

可以根据判定条件是否成立来决定执行哪条代码分支。一个 IfExpr 节点中 if 是关键字,if 之后是一个小括号,小括号内可以是一个表达式或者一个 let 声明的解构匹配,接着是一个 BlockBlock 之后是可选的 else 分支。 else 分支以 else 关键字开始,后接新的 if 表达式或一个 Block

父类型:

prop condition

public prop condition: DisjunctionCondition

功能:获取当前 if 语句的条件表达式。

类型:DisjunctionCondition

prop elseBlock

public prop elseBlock: Option<Block>

功能:获取当前 if 语句的 else 分支代码块(若不存在返回 None)。

类型:Option<Block>

prop elseIf

public prop elseIf: Option<IfExpr>

功能:获取当前 if 语句的 else if 分支(若不存在返回 None)。

类型:Option<IfExpr>

prop ifBlock

public prop ifBlock: Block

功能:获取当前 if 语句的 if 分支代码块。

类型:Block

init(DisjunctionCondition, Option<Block>, Option<IfExpr>, Block, Array<Comment>)

public init(condition: DisjunctionCondition, elseBlock: Option<Block>, elseIf: Option<IfExpr>, ifBlock: Block, comments!: Array<Comment> = [])

功能:构造一个 IfExpr 对象,表示 if 条件表达式。

参数:

  • condition: DisjunctionCondition - 条件表达式。
  • elseBlock: Option<Block> - 可选的 else 分支代码块。
  • elseIf: Option<IfExpr> - 可选的 else if 分支。
  • ifBlock: Block - if 分支代码块。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入中存在多个 elseBlock 时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 condition
    let cond = [
        ConjunctionCondition(AtomicCondition.Expression(SymbolRef("x", [])))
    ]

    // 创建 DisjunctionCondition 实例
    let condition = DisjunctionCondition(cond)

    // 创建 elseBlock
    let elseBlock = Block([ReturnExpr(LitConstExpr(LitConstKind.IntergerLiteral, "100"))])

    // 创建 ifBlock
    let ifBlock = Block([ReturnExpr(LitConstExpr(LitConstKind.IntergerLiteral, "10"))])

    // 创建 IfExpr 实例
    let ifExpr = IfExpr(
        condition, 
        elseBlock, 
        None, 
        ifBlock
    )

    println("ifExpr: ${ifExpr}")
}

运行结果:

ifExpr: if (x) {
    return 10
} else {
    return 100
}

func getCondLParenPos()

public func getCondLParenPos(): CodePositionRange

功能:获取 IfExpr 节点中条件的 ( 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 condition
    let condition = DisjunctionCondition([ConjunctionCondition(AtomicCondition.Expression(SymbolRef("x", [])))])

    // 创建 ifBlock
    let ifBlock = Block([ReturnExpr(LitConstExpr(LitConstKind.IntergerLiteral, "10"))])

    // 创建 IfExpr 实例
    let ifExpr = IfExpr(condition, None, None, ifBlock)
    let pos = ifExpr.getCondLParenPos()

    // 输出条件左括号位置
    println("ifExpr.getCondLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

ifExpr.getCondLParenPos(): 1:4-1:5

func getCondRParenPos()

public func getCondRParenPos(): CodePositionRange

功能:获取 IfExpr 节点中条件的 ) 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 condition
    let condition = DisjunctionCondition([ConjunctionCondition(AtomicCondition.Expression(SymbolRef("x", [])))])

    // 创建 ifBlock
    let ifBlock = Block([ReturnExpr(LitConstExpr(LitConstKind.IntergerLiteral, "10"))])

    // 创建 IfExpr 实例
    let ifExpr = IfExpr(condition, None, None, ifBlock)
    let pos = ifExpr.getCondRParenPos()

    // 输出条件右括号位置
    println("ifExpr.getCondRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

ifExpr.getCondRParenPos(): 1:6-1:7

func getElseKeyWordPos()

public func getElseKeyWordPos(): Option<CodePositionRange>

功能:获取 IfExpr 节点中 else 关键字的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回 else 关键字的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 condition
    let condition = DisjunctionCondition([ConjunctionCondition(AtomicCondition.Expression(SymbolRef("x", [])))])

    // 创建 elseBlock
    let elseBlock = Block([ReturnExpr(LitConstExpr(LitConstKind.IntergerLiteral, "100"))])

    // 创建 ifBlock
    let ifBlock = Block([ReturnExpr(LitConstExpr(LitConstKind.IntergerLiteral, "10"))])

    // 创建 IfExpr 实例
    let ifExpr = IfExpr(condition, elseBlock, None, ifBlock)

    if (let Some(pos) <- ifExpr.getElseKeyWordPos()) {
        // 输出 else 关键字位置
        println("ifExpr.getElseKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

ifExpr.getElseKeyWordPos(): 3:3-3:7

func getIfKeyWordPos()

public func getIfKeyWordPos(): CodePositionRange

功能:获取 IfExpr 节点中 if 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 condition
    let condition = DisjunctionCondition([ConjunctionCondition(AtomicCondition.Expression(SymbolRef("x", [])))])

    // 创建 ifBlock
    let ifBlock = Block([ReturnExpr(LitConstExpr(LitConstKind.IntergerLiteral, "10"))])

    // 创建 IfExpr 实例
    let ifExpr = IfExpr(condition, None, None, ifBlock)
    let pos = ifExpr.getIfKeyWordPos()

    // 输出 if 关键字位置
    println("ifExpr.getIfKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

ifExpr.getIfKeyWordPos(): 1:1-1:3

class ImportAlias

public class ImportAlias <: ImportContent {
    public init(prefixes: Array<String>, identifier: String, alias: String, comments!: Array<Comment> = [])
}

功能:表示一个别名导入的包导入声明节点的具体项目,如 import pkg.a.b as p 中的 pkg.a.b as p

父类型:

prop aliasName

public prop aliasName: String

功能:表示该包导入节点中的别名,如 pkg.a.b as p 中的 p

类型:String

prop identifier

public prop identifier: String

功能:表示该包导入节点中的被导入的项,它可能是包中的顶层声明或声明,也可能是子包的名字,如 pkg.a.b as a 中的 b

类型:String

init(Array<String>, String, String, Array<Comment>)

public init(prefixes: Array<String>, identifier: String, alias: String, comments!: Array<Comment> = [])

功能:构造一个 ImportAlias 对象,表示带别名的导入项。

参数:

  • prefixes: Array<String> - 导入路径的前缀列表,如 ["pkg"]
  • identifier: String - 被导入的标识符名称,如 A
  • alias: String - 别名名称,如 B
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 identifier 不符合仓颉标识符规范时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 prefixes
    let prefixes = ["pkg"]

    // 创建 identifier
    let identifier = "a"

    // 创建 alias
    let alias = "p"

    // 创建 ImportAlias 实例
    let importAlias = ImportAlias(
        prefixes, 
        identifier, 
        alias
    )

    println("importAlias: ${importAlias}")
}

运行结果:

importAlias: pkg.a as p

func getAliasNamePos()

public func getAliasNamePos(): CodePositionRange

功能:获取当前 ImportAlias 中包的别名的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 ImportAlias 实例
    let importAlias = ImportAlias(["pkg"], "a", "p")
    let pos = importAlias.getAliasNamePos()

    // 输出别名位置
    println("importAlias.getAliasNamePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

importAlias.getAliasNamePos(): 1:10-1:11

func getAsPos()

public func getAsPos(): CodePositionRange

功能:获取当前 ImportAliasas 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 ImportAlias 实例
    let importAlias = ImportAlias(["pkg"], "a", "p")
    let pos = importAlias.getAsPos()

    // 输出 as 关键字位置
    println("importAlias.getAsPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

importAlias.getAsPos(): 1:7-1:9

func getIdentifierPos()

public func getIdentifierPos(): CodePositionRange

功能:获取当前 ImportAlias 中原始包名的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 ImportAlias 实例
    let importAlias = ImportAlias(["pkg"], "a", "p")
    let pos = importAlias.getIdentifierPos()

    // 输出原始包名位置
    println("importAlias.getIdentifierPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

importAlias.getIdentifierPos(): 1:5-1:6

class ImportAll

public class ImportAll <: ImportContent {
    public init(prefixes: Array<String>, comments!: Array<Comment> = [])
}

功能:表示一个全导入的包导入声明节点的具体项目,如 import pkg.* 中的 pkg.*

父类型:

init(Array<String>, Array<Comment>)

public init(prefixes: Array<String>, comments!: Array<Comment> = [])

功能:构造一个 ImportAll 对象,表示通配符导入。

参数:

  • prefixes: Array<String> - 导入路径的前缀列表,如 ["pkg"]
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建 prefixes
    let prefixes = ["pkg"]

    // 创建 ImportAll 实例
    let importAll = ImportAll(
        prefixes
    )

    println("importAll: ${importAll}")
}

运行结果:

importAll: pkg.*

func getMulPos()

public func getMulPos(): CodePositionRange

功能:获取当前 ImportAll* 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 ImportAll 实例
    let importAll = ImportAll(["pkg"])
    let pos = importAll.getMulPos()

    // 输出星号位置
    println("importAll.getMulPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

importAll.getMulPos(): 1:5-1:6

class ImportContent

public open class ImportContent <: SyntaxTreeNode {}

功能:表示一个包导入声明节点的具体声明内容,如 import pkg.a.b 中的 pkg.a.b

父类型:

prop prefixes

public prop prefixes: Array<String>

功能:表示该包导入节点中完整包名的前缀列表,如 pkg.a.b 中的 [pkg, a]

类型:Array<String>

func getDotsPos()

public func getDotsPos(): Array<CodePositionRange>

功能:获取当前 ImportContent 中所有 . 分隔符的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 使用 ImportSingle 子类来演示
    let importSingle = ImportSingle(["pkg", "a"], "b")
    let posArr = importSingle.getDotsPos()

    // 输出点号位置
    for (i in 0..posArr.size) {
        println("importSingle.getDotsPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

importSingle.getDotsPos()[0]: 1:4-1:5
importSingle.getDotsPos()[1]: 1:6-1:7

func getPrefixesPos()

public func getPrefixesPos(): Array<CodePositionRange>

功能:获取当前 ImportMulti 中所有前缀包名的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 使用 ImportSingle 子类来演示
    let importSingle = ImportSingle(["pkg", "a"], "b")
    let posArr = importSingle.getPrefixesPos()

    // 输出前缀包名位置
    for (i in 0..posArr.size) {
        println("importSingle.getPrefixesPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

importSingle.getPrefixesPos()[0]: 1:1-1:4
importSingle.getPrefixesPos()[1]: 1:5-1:6

class ImportList

public class ImportList <: SyntaxTreeNode {
    public init(contents: ImportContent, modifier: Option<Modifier>, comments!: Array<Comment> = [])
}

功能:表示包导入节点。

一个 ImportList 节点:import pkg.a.bimport pkg.a.b as p 等。

父类型:

prop contents

public prop contents: ImportContent

功能:表示该包导入节点中的导入内容。

类型:ImportContent

prop kind

public prop kind: ImportKind

功能:表示该包导入节点的类型。

类型:ImportKind

prop modifier

public prop modifier: Option<Modifier>

功能:表示该包导入节点中的修饰符。

类型:Option<Modifier>

init(ImportContent, Option<Modifier>, Array<Comment>)

public init(contents: ImportContent, modifier: Option<Modifier>, comments!: Array<Comment> = [])

功能:构造一个 ImportList 对象,表示一条导入语句,如 import pkg.A

参数:

  • contents: ImportContent - 导入内容。
  • modifier: Option<Modifier> - 修饰符,可选。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

示例:

import stdx.syntax.*

main() {
    // 创建 contents
    let contents = ImportSingle(["pkg"], "a")

    // 创建 modifier
    let modifier = Modifier(ModifierKind.Public)

    // 创建 ImportList 实例
    let importList = ImportList(
        contents, 
        modifier
    )

    println("importList: ${importList}")
}

运行结果:

importList: public import pkg.a

func getImportKeyWordPos()

public func getImportKeyWordPos(): CodePositionRange

功能:获取当前 ImportListimport 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 ImportList 实例
    let contents = ImportSingle(["pkg"], "a")
    let importList = ImportList(contents, None)
    let pos = importList.getImportKeyWordPos()

    // 输出 import 关键字位置
    println("importList.getImportKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

importList.getImportKeyWordPos(): 1:1-1:7

class ImportMulti

public class ImportMulti <: ImportContent {
    public init(prefixes: Array<String>, contents: Array<ImportContent>, comments!: Array<Comment> = [])
}

功能:表示一个多导入的包导入声明节点的具体项目,如 import pkg.{a.*, b.c, d as p} 中的 pkg.{a.*, b.c, d as p}

父类型:

prop contents

public prop contents: Array<ImportContent>

功能:表示该包导入节点中的多个导入项的列表,如 pkg.{a.*, b.c, d as p} 中的 [a.*, b.c, d as p]

类型:Array<ImportContent>

init(Array<String>, Array<ImportContent>, Array<Comment>)

public init(prefixes: Array<String>, contents: Array<ImportContent>, comments!: Array<Comment> = [])

功能:构造一个 ImportMulti 对象,表示多导入项。

参数:

  • prefixes: Array<String> - 导入路径的前缀列表,如 ["pkg"]
  • contents: Array<ImportContent> - 导入内容列表。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 contents 为空时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 prefixes
    let prefixes = ["pkg"]

    // 创建 contents
    let contents: Array<ImportContent> = [ImportSingle([], "a"), ImportSingle([], "b")]

    // 创建 ImportMulti 实例
    let importMulti = ImportMulti(
        prefixes, 
        contents
    )

    println("importMulti: ${importMulti}")
}

运行结果:

importMulti: pkg.{a, b}

func getCommasPos()

public func getCommasPos(): Array<CodePositionRange>

功能:获取当前 ImportMulti 中所有 , 分隔符的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 ImportMulti 实例
    let contents: Array<ImportContent> = [ImportSingle([], "a"), ImportSingle([], "b")]
    let importMulti = ImportMulti(["pkg"], contents)
    let posArr = importMulti.getCommasPos()

    // 遍历输出逗号位置
    for (i in 0..posArr.size) {
        println("importMulti.getCommasPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

importMulti.getCommasPos()[0]: 1:7-1:8

func getLCurlPos()

public func getLCurlPos(): CodePositionRange

功能:获取当前 ImportMulti{ 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 ImportMulti 实例
    let contents: Array<ImportContent> = [ImportSingle([], "a")]
    let importMulti = ImportMulti(["pkg"], contents)
    let pos = importMulti.getLCurlPos()

    // 输出左花括号位置
    println("importMulti.getLCurlPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

importMulti.getLCurlPos(): 1:5-1:6

func getRCurlPos()

public func getRCurlPos(): CodePositionRange

功能:获取当前 ImportMulti} 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 ImportMulti 实例
    let contents: Array<ImportContent> = [ImportSingle([], "a")]
    let importMulti = ImportMulti(["pkg"], contents)
    let pos = importMulti.getRCurlPos()

    // 输出右花括号位置
    println("importMulti.getRCurlPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

importMulti.getRCurlPos(): 1:7-1:8

class ImportSingle

public class ImportSingle <: ImportContent {
    public init(prefixes: Array<String>, identifier: String, comments!: Array<Comment> = [])
}

功能:表示一个单导入的包导入声明节点的具体项目,如 import pkg.a 中的 pkg.a

父类型:

prop identifier

public prop identifier: String

功能:表示该包导入节点中的被导入的项,它可能是包中的顶层声明或声明,也可能是子包的名字,如 pkg.a 中的 a

类型:String

init(Array<String>, String, Array<Comment>)

public init(prefixes: Array<String>, identifier: String, comments!: Array<Comment> = [])

功能:构造一个 ImportSingle 对象,表示单导入项。

参数:

  • prefixes: Array<String> - 导入路径的前缀列表,如 ["pkg"]
  • identifier: String - 被导入的标识符名称,如 A
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 identifier 不符合仓颉标识符规范时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 prefixes
    let prefixes = ["pkg"]

    // 创建 identifier
    let identifier = "a"

    // 创建 ImportSingle 实例
    let importSingle = ImportSingle(
        prefixes, 
        identifier
    )

    println("importSingle: ${importSingle}")
}

运行结果:

importSingle: pkg.a

func getIdentifierPos()

public func getIdentifierPos(): CodePositionRange

功能:获取当前 ImportSingle 中具体包名的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 ImportSingle 实例
    let importSingle = ImportSingle(["pkg"], "a")
    let pos = importSingle.getIdentifierPos()

    // 输出标识符位置
    println("importSingle.getIdentifierPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

importSingle.getIdentifierPos(): 1:5-1:6

class IncOrDecExpr

public class IncOrDecExpr <: Expr {
    public init(kind: IncOrDecOpKind, operand: Expr, comments!: Array<Comment> = [])
}

功能:表示包含自增操作符(++)或自减操作符(--)的表达式。

父类型:

prop kind

public prop kind: IncOrDecOpKind

功能:获取当前自增自减表达式的操作符类型。

类型:IncOrDecOpKind

prop operand

public prop operand: Expr

功能:获取 IncOrDecExpr 中的表达式。

类型:Expr

init(IncOrDecOpKind, Expr, Array<Comment>)

public init(kind: IncOrDecOpKind, operand: Expr, comments!: Array<Comment> = [])

功能:构造一个 IncOrDecExpr 对象,表示自增或自减表达式。

参数:

  • kind: IncOrDecOpKind - 自增或自减操作类型。
  • operand: Expr - 被操作的表达式。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建 kind
    let kind = IncOrDecOpKind.Incr

    // 创建 operand
    let operand = SymbolRef("x", [])

    // 创建 IncOrDecExpr 实例
    let incOrDecExpr = IncOrDecExpr(
        kind, 
        operand
    )

    println("incOrDecExpr: ${incOrDecExpr}")
}

运行结果:

incOrDecExpr: x++

func getOperatorPos()

public func getOperatorPos(): CodePositionRange

功能:获取操作符的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 kind
    let kind = IncOrDecOpKind.Incr

    // 创建 operand
    let operand = SymbolRef("x", [])

    // 创建 IncOrDecExpr 实例
    let incOrDecExpr = IncOrDecExpr(kind, operand)
    let pos = incOrDecExpr.getOperatorPos()

    // 输出操作符位置
    println("incOrDecExpr.getOperatorPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

incOrDecExpr.getOperatorPos(): 1:2-1:4

class InterfaceDecl

public class InterfaceDecl <: Decl {
    public init(body: Body, genericConstraints: Option<GenericConstraints>, genericParams: Array<GenericParam>,
        name: String, superTyAnnotations: Array<TypeAnnotation>, annotations!: Array<Annotation> = [],
        modifiers!: Array<Modifier> = [], comments!: Array<Comment> = [])
}

功能:表示接口声明节点。

接口的声明使用 interface 关键字,接口声明依次为:可缺省的修饰符、interface 关键字、接口名、可选的类型参数、是否指定父接口、可选的泛型约束、接口体的声明。

父类型:

prop body

public prop body: Body

功能:获取当前接口声明的主体部分。

类型:Body

prop genericConstraints

public prop genericConstraints: Option<GenericConstraints>

功能:获取当前接口声明的泛型约束(若不存在返回 None)。

类型:Option<GenericConstraints>

prop genericParams

public prop genericParams: Array<GenericParam>

功能:获取当前接口声明的泛型参数列表。

类型:Array<GenericParam>

prop name

public prop name: String

功能:获取当前接口声明的名称。

类型:String

prop superTyAnnotations

public prop superTyAnnotations: Array<TypeAnnotation>

功能:获取当前接口声明的父类类型标注列表。

类型:Array<TypeAnnotation>

init(Body, Option<GenericConstraints>, Array<GenericParam>, String, Array<TypeAnnotation>, Array<Annotation>, Array<Modifier>, Array<Comment>)

public init(body: Body, genericConstraints: Option<GenericConstraints>, genericParams: Array<GenericParam>,
    name: String, superTyAnnotations: Array<TypeAnnotation>, annotations!: Array<Annotation> = [],
    modifiers!: Array<Modifier> = [], comments!: Array<Comment> = [])

功能:构造一个 InterfaceDecl 对象,表示接口声明节点。

参数:

  • body: Body - 接口体,包含成员声明。
  • genericConstraints: Option<GenericConstraints> - 可选的泛型约束。
  • genericParams: Array<GenericParam> - 泛型参数列表。
  • name: String - 接口名。
  • superTyAnnotations: Array<TypeAnnotation> - 父类类型标注列表。
  • annotations!: Array<Annotation> - 附加的注解列表,默认为空数组。
  • modifiers!: Array<Modifier> - 修饰符列表,默认为空数组。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 body 中有除函数声明和宏展开声明外的声明,或泛型约束与泛型参数不对应,或输入的 name 不符合仓颉标识符规范时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 body
    let body = Body([])

    // 创建 genericConstraints
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])

    // 创建 genericParams
    let genericParams = [GenericParam("T")]

    // 创建 name
    let name = "foo"

    // 创建 superTyAnnotations
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]

    // 创建 InterfaceDecl 实例
    let interfaceDecl = InterfaceDecl(
        body, 
        genericConstraints, 
        genericParams, 
        name, 
        superTyAnnotations
    )

    println("interfaceDecl: ${interfaceDecl}")
}

运行结果:

interfaceDecl: interface foo<T> <: I1 where T<:I1 {
}

func getGenericParamsCommasPos()

public func getGenericParamsCommasPos(): Array<CodePositionRange>

功能:获取 InterfaceDecl 节点中泛型参数中 , 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 InterfaceDecl 实例
    let body = Body([])
    let genericParams = [GenericParam("T"), GenericParam("U"), GenericParam("V")]
    let interfaceDecl = InterfaceDecl(body, None, genericParams, "MyInterface", [])

    // 获取泛型参数中逗号的位置
    let commaPoses = interfaceDecl.getGenericParamsCommasPos()

    // 输出逗号位置
    for (i in 0..commaPoses.size) {
        println("interfaceDecl.getGenericParamsCommasPos()[${i}]: ${commaPoses[i].beginLine}:${commaPoses[i].beginColumn}-${commaPoses[i].endLine}:${commaPoses[i].endColumn}")
    }
}

运行结果:

interfaceDecl.getGenericParamsCommasPos()[0]: 1:24-1:25
interfaceDecl.getGenericParamsCommasPos()[1]: 1:27-1:28

func getGenericParamsLAnglePos()

public func getGenericParamsLAnglePos(): Option<CodePositionRange>

功能:获取 InterfaceDecl 节点中泛型参数的 < 的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回泛型参数的 < 的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 InterfaceDecl 实例
    let body = Body([])
    let genericParams = [GenericParam("T")]
    let interfaceDecl = InterfaceDecl(body, None, genericParams, "MyInterface", [])

    if (let Some(pos) <- interfaceDecl.getGenericParamsLAnglePos()) {
        // 输出左尖括号位置
        println("interfaceDecl.getGenericParamsLAnglePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

interfaceDecl.getGenericParamsLAnglePos(): 1:22-1:23

func getGenericParamsRAnglePos()

public func getGenericParamsRAnglePos(): Option<CodePositionRange>

功能:获取 InterfaceDecl 节点中泛型参数的 > 的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回泛型参数的 > 的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 InterfaceDecl 实例
    let body = Body([])
    let genericParams = [GenericParam("T")]
    let interfaceDecl = InterfaceDecl(body, None, genericParams, "MyInterface", [])

    if (let Some(pos) <- interfaceDecl.getGenericParamsRAnglePos()) {
        // 输出右尖括号位置
        println("interfaceDecl.getGenericParamsRAnglePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

interfaceDecl.getGenericParamsRAnglePos(): 1:24-1:25

func getIdentifierPos()

public func getIdentifierPos(): CodePositionRange

功能:获取 InterfaceDecl 节点中标识符的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 InterfaceDecl 实例
    let body = Body([])
    let interfaceDecl = InterfaceDecl(body, None, [], "MyInterface", [])

    // 获取标识符位置
    let pos = interfaceDecl.getIdentifierPos()

    // 输出标识符位置
    println("interfaceDecl.getIdentifierPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

interfaceDecl.getIdentifierPos(): 1:11-1:22

func getInterfaceKeyWordPos()

public func getInterfaceKeyWordPos(): CodePositionRange

功能:获取 InterfaceDecl 节点中 interface 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 InterfaceDecl 实例
    let body = Body([])
    let interfaceDecl = InterfaceDecl(body, None, [], "MyInterface", [])

    // 获取 interface 关键字位置
    let pos = interfaceDecl.getInterfaceKeyWordPos()

    // 输出 interface 关键字位置
    println("interfaceDecl.getInterfaceKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

interfaceDecl.getInterfaceKeyWordPos(): 1:1-1:10

func getSuperTyAnnotationsBitAndsPos()

public func getSuperTyAnnotationsBitAndsPos(): Array<CodePositionRange>

功能:获取 InterfaceDecl 节点中父类型中 & 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 InterfaceDecl 实例
    let body = Body([])
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], []), CompositeType("I2", [], [])]
    let interfaceDecl = InterfaceDecl(body, None, [], "MyInterface", superTyAnnotations)

    // 获取父类型中 & 的位置
    let bitAndsPoses = interfaceDecl.getSuperTyAnnotationsBitAndsPos()

    // 输出 & 位置
    for (i in 0..bitAndsPoses.size) {
        println("interfaceDecl.getSuperTyAnnotationsBitAndsPos()[${i}]: ${bitAndsPoses[i].beginLine}:${bitAndsPoses[i].beginColumn}-${bitAndsPoses[i].endLine}:${bitAndsPoses[i].endColumn}")
    }
}

运行结果:

interfaceDecl.getSuperTyAnnotationsBitAndsPos()[0]: 1:29-1:30

func getUpperBoundPos()

public func getUpperBoundPos(): Option<CodePositionRange>

功能:获取 InterfaceDecl 节点中 <: 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 InterfaceDecl 实例
    let body = Body([])
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    let interfaceDecl = InterfaceDecl(body, None, [], "MyInterface", superTyAnnotations)

    if (let Some(pos) <- interfaceDecl.getUpperBoundPos()) {
        // 输出 <: 位置
        println("interfaceDecl.getUpperBoundPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

interfaceDecl.getUpperBoundPos(): 1:23-1:25

class IsExpr

public class IsExpr <: Expr {
    public init(srcVal: Expr, targetTypeAnnotation: TypeAnnotation, comments!: Array<Comment> = [])
}

功能:表示一个类型检查表达式。

一个 IsExpr 表达式:e is T,类型为 Bool 。其中 e 可以是任何类型的表达式,T 可以是任何类型。

父类型:

prop srcVal

public prop srcVal: Expr

功能:获取 IsExpr 节点中的源表达式节点。

类型:Expr

prop targetTypeAnnotation

public prop targetTypeAnnotation: TypeAnnotation

功能:获取 IsExpr 节点中的目标类型。

类型:TypeAnnotation

init(Expr, TypeAnnotation, Array<Comment>)

public init(srcVal: Expr, targetTypeAnnotation: TypeAnnotation, comments!: Array<Comment> = [])

功能:构造一个 IsExpr 对象,表示类型判断表达式,如 x is Int64

参数:

  • srcVal: Expr - 被判断的源表达式。
  • targetTypeAnnotation: TypeAnnotation - 目标类型。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建 srcVal
    let srcVal = SymbolRef("x", [])

    // 创建 targetTypeAnnotation
    let targetTypeAnnotation = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 IsExpr 实例
    let isExpr = IsExpr(
        srcVal, 
        targetTypeAnnotation
    )

    println("isExpr: ${isExpr}")
}

运行结果:

isExpr: x is Int64

func getIsKeyWordPos()

public func getIsKeyWordPos(): CodePositionRange

功能:获取 is 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 srcVal
    let srcVal = SymbolRef("x", [])

    // 创建 targetTypeAnnotation
    let targetTypeAnnotation = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 IsExpr 实例
    let isExpr = IsExpr(srcVal, targetTypeAnnotation)
    let pos = isExpr.getIsKeyWordPos()

    // 输出 is 关键字位置
    println("isExpr.getIsKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

isExpr.getIsKeyWordPos(): 1:3-1:5

class Lambda

public class Lambda <: Expr {
    public init(body: Array<SyntaxTreeNode>, params: ParameterList, comments!: Array<Comment> = [])
}

功能:表示 Lambda 表达式,是一个匿名的函数。

一个 Lambda 节点有两种形式,一种是有形参的,例如 {a: Int64 => e1; e2 },另一种是无形参的,例如 { => e1; e2 }

父类型:

prop body

public prop body: Array<SyntaxTreeNode>

功能:获取当前 Lambda 表达式的主体代码块。

类型:Array<SyntaxTreeNode>

prop params

public prop params: ParameterList

功能:获取当前 Lambda 表达式的参数列表。

类型:ParameterList

init(Array<SyntaxTreeNode>, ParameterList, Array<Comment>)

public init(body: Array<SyntaxTreeNode>, params: ParameterList, comments!: Array<Comment> = [])

功能:构造一个 Lambda 对象,表示匿名函数(lambda)表达式,如 { x => x + 1 }

参数:

  • body: Array<SyntaxTreeNode> - lambda 体中的语法节点列表。
  • params: ParameterList - 参数列表。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建 body
    let body: Array<SyntaxTreeNode> = [BinaryExpr(SymbolRef("x", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))]

    // 创建 params
    let params = ParameterList(LambdaParam("x", None), hasParen:false)

    // 创建 Lambda 实例
    let lambda = Lambda(
        body, 
        params
    )

    println("lambda: ${lambda}")
}

运行结果:

lambda: { x => x + 1 }

func getDoubleArrowPos()

public func getDoubleArrowPos(): Option<CodePositionRange>

功能:获取当前 Lambda=> 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 Lambda 实例
    let body: Array<SyntaxTreeNode> = [BinaryExpr(SymbolRef("x", []), BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))]
    let params = ParameterList(LambdaParam("x", None), hasParen: false)
    let lambda = Lambda(body, params)

    if (let Some(pos) <- lambda.getDoubleArrowPos()) {
        // 输出双箭头位置
        println("lambda.getDoubleArrowPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

lambda.getDoubleArrowPos(): 1:5-1:7

func getLCurlPos()

public func getLCurlPos(): CodePositionRange

功能:获取当前 Lambda{ 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 Lambda 实例
    let body: Array<SyntaxTreeNode> = [BinaryExpr(SymbolRef("x", []), BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))]
    let params = ParameterList(LambdaParam("x", None), hasParen: false)
    let lambda = Lambda(body, params)
    let pos = lambda.getLCurlPos()

    // 输出左花括号位置
    println("lambda.getLCurlPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

lambda.getLCurlPos(): 1:1-1:2

func getRCurlPos()

public func getRCurlPos(): CodePositionRange

功能:获取当前 Lambda} 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 Lambda 实例
    let body: Array<SyntaxTreeNode> = [BinaryExpr(SymbolRef("x", []), BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))]
    let params = ParameterList(LambdaParam("x", None), hasParen: false)
    let lambda = Lambda(body, params)
    let pos = lambda.getRCurlPos()

    // 输出右花括号位置
    println("lambda.getRCurlPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

lambda.getRCurlPos(): 1:14-1:15

class LambdaParam

public open class LambdaParam <: Parameter {
    public init(name: String, typeAnnotation: Option<TypeAnnotation>, comments!: Array<Comment> = [])
}

功能:表示一个 lambda 参数。

LambdaParam 类用于在程序中声明一个新的 lambda 参数,name 表示参数的名称,typeAnnotation 表示参数的类型标注。

父类型:

prop name

public prop name: String

功能:获取当前 lambda 参数的名称。

类型:String

prop typeAnnotation

public prop typeAnnotation: Option<TypeAnnotation>

功能:获取 LambdaParam 节点中的类型标注(若不存在返回 None)。

类型:Option<TypeAnnotation>

init(String, Option<TypeAnnotation>, Array<Comment>)

public init(name: String, typeAnnotation: Option<TypeAnnotation>, comments!: Array<Comment> = [])

功能:构造一个 LambdaParam 对象,表示 lambda 参数节点。

参数:

  • name: String - 参数名。
  • typeAnnotation: Option<TypeAnnotation> - 可选的类型注解。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 name 不符合仓颉标识符规范时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 name
    let name = "x"

    // 创建 typeAnnotation
    let typeAnnotation = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 LambdaParam 实例
    let lambdaParam = LambdaParam(
        name, 
        typeAnnotation
    )

    println("lambdaParam: ${lambdaParam}")
}

运行结果:

lambdaParam: x: Int64

func getIdentifierPos()

public func getIdentifierPos(): CodePositionRange

功能:获取 LambdaParam 节点中标识符的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 LambdaParam 实例
    let lambdaParam = LambdaParam("x", AtomicType(AtomicTypeKind.Int64Type))
    let pos = lambdaParam.getIdentifierPos()

    // 输出标识符位置
    println("lambdaParam.getIdentifierPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

lambdaParam.getIdentifierPos(): 1:1-1:2

func getTypeAnnotationColonPos()

public func getTypeAnnotationColonPos(): Option<CodePositionRange>

功能:获取 LambdaParam 节点中 : 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 LambdaParam 实例
    let lambdaParam = LambdaParam("x", AtomicType(AtomicTypeKind.Int64Type))

    if (let Some(pos) <- lambdaParam.getTypeAnnotationColonPos()) {
        // 输出冒号位置
        println("lambdaParam.getTypeAnnotationColonPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

lambdaParam.getTypeAnnotationColonPos(): 1:2-1:3

class LetPattern

public class LetPattern <: SyntaxTreeNode {
    public init(expr: Expr, patterns: Array<Pattern>, comments!: Array<Comment> = [])
}

功能:表示一个 let 模式绑定表达式。

它将一个表达式绑定到一个或多个模式以进行解构。

父类型:

prop expr

public prop expr: Expr

功能:需要解构的表达式。

类型:Expr

prop patterns

public prop patterns: Array<Pattern>

功能:绑定表达式的模式列表。

类型:Array<Pattern>

init(Expr, Array<Pattern>, Array<Comment>)

public init(expr: Expr, patterns: Array<Pattern>, comments!: Array<Comment> = [])

功能:构造一个 LetPattern 对象,表示 let 模式绑定表达式。

参数:

  • expr: Expr - 被绑定的表达式。
  • patterns: Array<Pattern> - 用于解构的模式列表。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 patterns 为空时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 expr
    let expr = SymbolRef("y", [])

    // 创建 patterns
    let patterns: Array<Pattern> = [VarPattern("x")]

    // 创建 LetPattern 实例
    let letPattern = LetPattern(
        expr, 
        patterns
    )

    println("letPattern: ${letPattern}")
}

运行结果:

letPattern: let x <- y

func getBackArrowPos()

public func getBackArrowPos(): CodePositionRange

功能:获取 LetPattern 节点中 <- 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 expr
    let expr = SymbolRef("y", [])

    // 创建 patterns
    let patterns: Array<Pattern> = [VarPattern("x")]

    // 创建 LetPattern 实例
    let letPattern = LetPattern(expr, patterns)
    let pos = letPattern.getBackArrowPos()

    // 输出后箭头位置
    println("letPattern.getBackArrowPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

letPattern.getBackArrowPos(): 1:7-1:9

func getBitOrsPos()

public func getBitOrsPos(): Array<CodePositionRange>

功能:获取 LetPattern 节点中 | 的位置序列。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 expr
    let expr = SymbolRef("y", [])

    // 创建 patterns
    let patterns: Array<Pattern> = [
        VarPattern("x1"),
        VarPattern("x2"),
        VarPattern("x3")
    ]

    // 创建 LetPattern 实例
    let letPattern = LetPattern(expr, patterns)
    let posArr = letPattern.getBitOrsPos()

    // 遍历输出竖线位置
    for (i in 0..posArr.size) {
        println("letPattern.getBitOrsPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

letPattern.getBitOrsPos()[0]: 1:8-1:9
letPattern.getBitOrsPos()[1]: 1:13-1:14

func getLetKeyWordPos()

public func getLetKeyWordPos(): CodePositionRange

功能:获取 LetPattern 节点中 let 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 expr
    let expr = SymbolRef("y", [])

    // 创建 patterns
    let patterns: Array<Pattern> = [VarPattern("x")]

    // 创建 LetPattern 实例
    let letPattern = LetPattern(expr, patterns)
    let pos = letPattern.getLetKeyWordPos()

    // 输出 let 关键字位置
    println("letPattern.getLetKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

letPattern.getLetKeyWordPos(): 1:1-1:4

class LitConstExpr

public open class LitConstExpr <: Expr {
    public init(kind: LitConstKind, rawValue: String, comments!: Array<Comment> = [])
}

功能:表示一个字面量表达式节点。

一个 LitConstExpr 表达式:1.0123 等。

父类型:

prop kind

public prop kind: LitConstKind

功能:获取当前字面量表达式的类型。

类型:LitConstKind

prop rawValue

public prop rawValue: String

功能:获取当前字面量表达式的原始值。

类型:String

init(LitConstKind, String, Array<Comment>)

public init(kind: LitConstKind, rawValue: String, comments!: Array<Comment> = [])

功能:构造一个 LitConstExpr 对象,表示字面量常量表达式。

参数:

  • kind: LitConstKind - 字面量类型。
  • rawValue: String - 字面量的原始字符串值。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当 kindRuneLiteralStringLiteral 时,或 rawValue 无法用于构建对应类型字面量时,抛出异常,异常中包含报错提示信息。

注意:

不支持构造字符类型和字符串类型的字面量表达式节点,字符类型的字面量表达式节点通过 LitConstRuneExpr 构造,字符串类型的字面量表达式节点通过 LitConstStrExpr 构造。

示例:

import stdx.syntax.*

main() {
    // 设置字面量类型
    let kind = LitConstKind.BoolLiteral

    // 设置原始值
    let rawValue = "true"

    // 创建 LitConstExpr 实例
    let litConstExpr = LitConstExpr(
        kind, 
        rawValue
    )

    println("litConstExpr: ${litConstExpr}")
}

运行结果:

litConstExpr: true

class LitConstRuneExpr

public class LitConstRuneExpr <: LitConstExpr {
    public init(kind: LitConstKind, rawValue: String, isSingleQuote: Bool, comments!: Array<Comment> = [])
}

功能:表示一个字符类型的字面量表达式节点。

一个 LitConstRuneExpr 表达式:r'a'

父类型:

注意:

syntax 库不支持字符字节字面量,即形如 b'x' 的字面量。

prop isSingleQuote

public prop isSingleQuote: Bool

功能:表示当前字符字面量表达式是否为单引号引用。

类型:Bool

init(LitConstKind, String, Bool, Array<Comment>)

public init(kind: LitConstKind, rawValue: String, isSingleQuote: Bool, comments!: Array<Comment> = [])

功能:构造一个 LitConstRuneExpr 对象,表示字符字面量表达式。

参数:

  • kind: LitConstKind - 字面量类型,固定为 RuneLiteral
  • rawValue: String - 字面量的原始字符串值。
  • isSingleQuote: Bool - 是否使用单引号包裹。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当 kind 不是字符字面量类型时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 设置字面量类型
    let kind = LitConstKind.RuneLiteral

    // 设置原始值
    let rawValue = "a"

    // 设置是否为单引号
    let isSingleQuote = true

    // 创建 LitConstRuneExpr 实例
    let litConstRuneExpr = LitConstRuneExpr(
        kind, 
        rawValue, 
        isSingleQuote
    )

    println("litConstRuneExpr: ${litConstRuneExpr}")
}

运行结果:

litConstRuneExpr: r'a'

class LitConstStrExpr

public class LitConstStrExpr <: LitConstExpr {
    public init(kind: LitConstKind, rawValue: String, delimiterNum: Int64, isSingleQuote: Bool, strKind: LitConstStrKind, strPartExprs: Array<StrLiteralPart>,
        comments!: Array<Comment> = [])
}

功能:表示一个字符串类型的字面量表达式节点。

一个 LitConstStrExpr 表达式:"me"#"hi"# 等。

父类型:

prop delimiterNum

public prop delimiterNum: Int64

功能:表示当前 LitConstStrExpr 前后成对出现的 # 分隔符数。例如 ##'\n'##delimiterNum = 2

类型:Int64

prop isSingleQuote

public prop isSingleQuote: Bool

功能:表示当前 LitConstStrExpr 是否为单引号引用。

类型:Bool

prop strKind

public prop strKind: LitConstStrKind

功能:获取当前 LitConstStrExpr 的类型

类型:LitConstStrKind

prop strPartExprs

public prop strPartExprs: Array<StrLiteralPart>

功能:获取当前 LitConstStrExpr 中的各个字符串部分,分为字面量表达式和插值字符串表达式两种。

类型:Array<StrLiteralPart>

init(LitConstKind, String, Int64, Bool, LitConstStrKind, Array<StrLiteralPart>, Array<Comment>)

public init(kind: LitConstKind, rawValue: String, delimiterNum: Int64, isSingleQuote: Bool, strKind: LitConstStrKind, strPartExprs: Array<StrLiteralPart>, comments!: Array<Comment> = [])

功能:构造一个 LitConstStrExpr 对象,表示字符串字面量表达式,支持插值。

参数:

  • kind: LitConstKind - 字面量类型。
  • rawValue: String - 字面量的原始字符串值。
  • delimiterNum: Int64 - 分隔符数量。
  • isSingleQuote: Bool - 是否使用单引号包裹。
  • strKind: LitConstStrKind - 字符串字面量种类。
  • strPartExprs: Array<StrLiteralPart> - 字符串片段列表,可包含插值。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当 strKindMultiLineRawStringdelimiterNum0 时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 kind
    let kind = LitConstKind.StringLiteral

    // 创建 rawValue
    let rawValue = "abc"

    // 创建 delimiterNum
    let delimiterNum = 0

    // 创建 isSingleQuote
    let isSingleQuote = true

    // 创建 strKind
    let strKind = LitConstStrKind.StringLiteral

    // 创建 strPartExprs
    let strPartExprs: Array<StrLiteralPart> = []

    // 创建 LitConstStrExpr 实例
    let litConstStrExpr = LitConstStrExpr(
        kind, 
        rawValue, 
        delimiterNum, 
        isSingleQuote, 
        strKind, 
        strPartExprs
    )

    println("litConstStrExpr: ${litConstStrExpr}")
}

运行结果:

litConstStrExpr: 'abc'

func hasInterpolation()

public func hasInterpolation(): Bool

功能:表示当前 LitConstStrExpr 是否存在插值。

返回值:

  • Bool - 返回是否存在插值。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 LitConstStrExpr 实例
    let litConstStrExpr = LitConstStrExpr(LitConstKind.StringLiteral, "abc", 0, true, LitConstStrKind.StringLiteral, [])
    let hasInterp = litConstStrExpr.hasInterpolation()

    // 输出是否存在插值
    println("litConstStrExpr.hasInterpolation(): ${hasInterp}")
}

运行结果:

litConstStrExpr.hasInterpolation(): false

class MacroDecl

public class MacroDecl <: Decl {
    public init(body: Block, name: String, params: ParameterList, retTyAnnotation: Option<TypeAnnotation>,
        annotations!: Array<Annotation> = [], modifiers!: Array<Modifier> = [], comments!: Array<Comment> = [])
}

功能:表示一个宏定义节点。

一个 MacroDecl 节点:public macro M(input: Tokens): Tokens {...}

父类型:

prop body

public prop body: Block

功能:获取 MacroDecl 节点的函数体。

类型:Block

prop name

public prop name: String

功能:获取 MacroDecl 节点的名称。

类型:String

prop params

public prop params: ParameterList

功能:获取 MacroDecl 节点的的参数列表。

类型:ParameterList

prop retTyAnnotation

public prop retTyAnnotation: Option<TypeAnnotation>

功能:获取 MacroDecl 节点的函数返回类型。

类型:Option<TypeAnnotation>

init(Block, String, ParameterList, Option<TypeAnnotation>, Array<Annotation>, Array<Modifier>, Array<Comment>)

public init(body: Block, name: String, params: ParameterList, retTyAnnotation: Option<TypeAnnotation>,
    annotations!: Array<Annotation> = [], modifiers!: Array<Modifier> = [], comments!: Array<Comment> = [])

功能:构造一个 MacroDecl 对象,表示宏声明节点,如 macro myMacro(input: Tokens): Tokens {...}

参数:

  • body: Block - 宏体。
  • name: String - 宏名。
  • params: ParameterList - 参数列表。
  • retTyAnnotation: Option<TypeAnnotation> - 可选的返回类型注解。
  • annotations!: Array<Annotation> - 附加的注解列表,默认为空数组。
  • modifiers!: Array<Modifier> - 修饰符列表,默认为空数组。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 name 不符合仓颉标识符规范时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 body
    let body = Block([])

    // 创建 name
    let name = "foo"

    // 创建 params
    let params = ParameterList([])

    // 创建 retTyAnnotation
    let retTyAnnotation = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 MacroDecl 实例
    let macroDecl = MacroDecl(
        body, 
        name, 
        params, 
        retTyAnnotation
    )

    println("macroDecl: ${macroDecl}")
}

运行结果:

macroDecl: macro foo(): Int64 {
}

func getIdentifierPos()

public func getIdentifierPos(): CodePositionRange

功能:获取 MacroDecl 节点中标识符的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 MacroDecl 实例
    let body = Block([])
    let params = ParameterList([])
    let macroDecl = MacroDecl(body, "foo", params, None)
    let pos = macroDecl.getIdentifierPos()

    // 输出标识符位置
    println("macroDecl.getIdentifierPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

macroDecl.getIdentifierPos(): 1:7-1:10

func getMacroKeyWordPos()

public func getMacroKeyWordPos(): CodePositionRange

功能:获取 MacroDecl 节点中 macro 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 MacroDecl 实例
    let body = Block([])
    let params = ParameterList([])
    let macroDecl = MacroDecl(body, "foo", params, None)
    let pos = macroDecl.getMacroKeyWordPos()

    // 输出 macro 关键字位置
    println("macroDecl.getMacroKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

macroDecl.getMacroKeyWordPos(): 1:1-1:6

func getRetTyAnnotationColonPos()

public func getRetTyAnnotationColonPos(): Option<CodePositionRange>

功能:获取 MacroDecl 节点中返回类型的冒号的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回返回类型的冒号的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 MacroDecl 实例
    let body = Block([])
    let params = ParameterList([])
    let retTyAnnotation = AtomicType(AtomicTypeKind.Int64Type)
    let macroDecl = MacroDecl(body, "foo", params, retTyAnnotation)

    if (let Some(pos) <- macroDecl.getRetTyAnnotationColonPos()) {
        // 输出冒号位置
        println("macroDecl.getRetTyAnnotationColonPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

macroDecl.getRetTyAnnotationColonPos(): 1:12-1:13

class MacroExpandDecl

public class MacroExpandDecl <: Decl {
    public init(calleeMacro: Expr, macroAttrs: Tokens, macroInputs: MacroExpandInput,
        annotations!: Array<Annotation> = [], comments!: Array<Comment> = [])
}

功能:表示宏展开声明。

用于在编译时执行宏并将其展开为具体代码,实现元编程能力。

父类型:

prop calleeMacro

public prop calleeMacro: Expr

功能:获取被调用的宏表达式。

类型:Expr

prop macroAttrs

public prop macroAttrs: Tokens

功能:获取宏的属性标记集合,用于传递编译时元数据。

类型:Tokens

prop macroInputs

public prop macroInputs: MacroExpandInput

功能:获取宏展开的输入声明,定义宏执行所需的上下文。

类型:MacroExpandInput

init(Expr, Tokens, MacroExpandInput, Array<Annotation>, Array<Comment>)

public init(calleeMacro: Expr, macroAttrs: Tokens, macroInputs: MacroExpandInput,
    annotations!: Array<Annotation> = [], comments!: Array<Comment> = [])

功能:构造一个 MacroExpandDecl 对象,表示宏展开声明节点。

参数:

  • calleeMacro: Expr - 被调用的宏表达式。
  • macroAttrs: Tokens - 宏的属性标记序列,会被格式化。
  • macroInputs: MacroExpandInput - 宏输入,会被格式化。
  • annotations!: Array<Annotation> - 附加的注解列表,默认为空数组。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当宏调用表达式不是成员访问或引用表达式时,格式化过程中内存分配失败,或 macroInputs 不在 MacroExpandInput 中时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 calleeMacro
    let calleeMacro = SymbolRef(
        "testMacro",
        []
    )

    // 创建 macroAttrs
    let macroAttrs = quote(123)

    // 创建 EnumConstructor 实例
    let enumConstructor = EnumConstructor(
        "EnumA",
        [AtomicType(AtomicTypeKind.Int64Type)]
    )

    // 创建 macroInputs
    let macroInputs = MacroExpandInput.WithoutParens(enumConstructor)

    // 创建 MacroExpandDecl 实例
    let macroExpandDecl = MacroExpandDecl(
        calleeMacro,
        macroAttrs,
        macroInputs
    )

    println("macroExpandDecl: ${macroExpandDecl}")
}

运行结果:

macroExpandDecl: @testMacro[123]
EnumA(Int64)

func getAtPos()

public func getAtPos(): CodePositionRange

功能:获取 MacroExpandDecl 节点中 @ 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 calleeMacro
    let calleeMacro = SymbolRef(
        "testMacro",
        []
    )

    // 创建 macroAttrs
    let macroAttrs = quote(123)

    // 创建 EnumConstructor 实例
    let enumConstructor = EnumConstructor(
        "EnumA",
        [AtomicType(AtomicTypeKind.Int64Type)]
    )

    // 创建 macroInputs
    let macroInputs = MacroExpandInput.WithoutParens(enumConstructor)

    // 创建 MacroExpandDecl 实例
    let macroExpandDecl = MacroExpandDecl(
        calleeMacro,
        macroAttrs,
        macroInputs
    )

    let pos = macroExpandDecl.getAtPos()
    // 输出 @ 位置
    println("macroExpandDecl.getAtPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

macroExpandDecl.getAtPos(): 1:1-1:2

func getLParenPos()

public func getLParenPos(): Option<CodePositionRange>

功能:获取 MacroExpandDecl 节点中 ( 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 calleeMacro
    let calleeMacro = SymbolRef(
        "testMacro",
        []
    )

    // 创建 macroAttrs
    let macroAttrs = quote(123)

    // 创建 EnumConstructor 实例
    let enumConstructor = EnumConstructor(
        "EnumA",
        [AtomicType(AtomicTypeKind.Int64Type)]
    )

    // 创建 macroInputs
    let macroInputs = MacroExpandInput.WithoutParens(enumConstructor)

    // 创建 MacroExpandDecl 实例
    let macroExpandDecl = MacroExpandDecl(
        calleeMacro,
        macroAttrs,
        macroInputs
    )

    // 实际上所创建的 MacroExpandDecl 节点中不存在 ( 子节点,因此 getLParenPos() 会返回 None
    if (let Some(pos) <- macroExpandDecl.getLParenPos()) {
        // 输出 ( 位置
        println("macroExpandDecl.getLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    } else {
        println("macroExpandDecl.getLParenPos(): None")
    }
}

运行结果:

macroExpandDecl.getLParenPos(): None

func getLSquarePos()

public func getLSquarePos(): Option<CodePositionRange>

功能:获取 MacroExpandDecl 节点中 [ 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 calleeMacro
    let calleeMacro = SymbolRef(
        "testMacro",
        []
    )

    // 创建 macroAttrs
    let macroAttrs = quote(123)

    // 创建 EnumConstructor 实例
    let enumConstructor = EnumConstructor(
        "EnumA",
        [AtomicType(AtomicTypeKind.Int64Type)]
    )

    // 创建 macroInputs
    let macroInputs = MacroExpandInput.WithoutParens(enumConstructor)

    // 创建 MacroExpandDecl 实例
    let macroExpandDecl = MacroExpandDecl(
        calleeMacro,
        macroAttrs,
        macroInputs
    )

    if (let Some(pos) <- macroExpandDecl.getLSquarePos()) {
        // 输出 [ 位置
        println("macroExpandDecl.getLSquarePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

macroExpandDecl.getLSquarePos(): 1:11-1:12

func getRParenPos()

public func getRParenPos(): Option<CodePositionRange>

功能:获取 MacroExpandDecl 节点中 ) 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 calleeMacro
    let calleeMacro = SymbolRef(
        "testMacro",
        []
    )

    // 创建 macroAttrs
    let macroAttrs = quote(123)

    // 创建 EnumConstructor 实例
    let enumConstructor = EnumConstructor(
        "EnumA",
        [AtomicType(AtomicTypeKind.Int64Type)]
    )

    // 创建 macroInputs
    let macroInputs = MacroExpandInput.WithoutParens(enumConstructor)

    // 创建 MacroExpandDecl 实例
    let macroExpandDecl = MacroExpandDecl(
        calleeMacro,
        macroAttrs,
        macroInputs
    )

    // 实际上所创建的 MacroExpandDecl 节点中不存在 ( 子节点,因此 getLParenPos() 会返回 None
    if (let Some(pos) <- macroExpandDecl.getRParenPos()) {
        // 输出 ) 位置
        println("macroExpandDecl.getRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    } else {
        println("macroExpandDecl.getRParenPos(): None")
    }
}

运行结果:

macroExpandDecl.getRParenPos(): None

func getRSquarePos()

public func getRSquarePos(): Option<CodePositionRange>

功能:获取 MacroExpandDecl 节点中 ] 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 calleeMacro
    let calleeMacro = SymbolRef(
        "testMacro",
        []
    )

    // 创建 macroAttrs
    let macroAttrs = quote(123)

    // 创建 EnumConstructor 实例
    let enumConstructor = EnumConstructor(
        "EnumA",
        [AtomicType(AtomicTypeKind.Int64Type)]
    )

    // 创建 macroInputs
    let macroInputs = MacroExpandInput.WithoutParens(enumConstructor)

    // 创建 MacroExpandDecl 实例
    let macroExpandDecl = MacroExpandDecl(
        calleeMacro,
        macroAttrs,
        macroInputs
    )

    if (let Some(pos) <- macroExpandDecl.getRSquarePos()) {
        // 输出 ] 位置
        println("macroExpandDecl.getRSquarePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

macroExpandDecl.getRSquarePos(): 1:15-1:16

class MacroExpandExpr

public class MacroExpandExpr <: Expr {
    public init(calleeMacro: Expr, macroAttrs: Tokens, macroInputs: MacroExpandInput, comments!: Array<Comment> = [])
}

功能:表示宏展开表达式。

用于在表达式上下文中执行编译时宏,将宏调用展开为具体的表达式代码。

父类型:

prop calleeMacro

public prop calleeMacro: Expr

功能:获取被调用的宏表达式。

类型:Expr

prop macroAttrs

public prop macroAttrs: Tokens

功能:获取宏的属性标记集合,用于传递编译时元数据。

类型:Tokens

prop macroInputs

public prop macroInputs: MacroExpandInput

功能:获取宏展开的输入声明,定义宏执行所需的上下文。

类型:MacroExpandInput

init(Expr, Tokens, MacroExpandInput, Array<Comment>)

public init(calleeMacro: Expr, macroAttrs: Tokens, macroInputs: MacroExpandInput, comments!: Array<Comment> = [])

功能:构造一个 MacroExpandExpr 对象,表示宏展开表达式节点。

参数:

  • calleeMacro: Expr - 被调用的宏表达式。
  • macroAttrs: Tokens - 宏的属性标记序列。
  • macroInputs: MacroExpandInput - 宏输入,可以是带括号的 Tokens 或不带括号的 Decl。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当宏调用表达式不是成员访问或引用表达式时,格式化过程中内存分配失败,或 macroInputs 不在 MacroExpandInput 中时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 calleeMacro
    let calleeMacro = SymbolRef(
        "testMacro",
        []
    )

    // 创建 macroAttrs
    let macroAttrs = quote(123)

    // 创建 EnumConstructor 实例
    let enumConstructor = EnumConstructor(
        "EnumA",
        [AtomicType(AtomicTypeKind.Int64Type)]
    )

    // 创建 macroInputs
    let macroInputs = MacroExpandInput.WithParens(quote(1 + 1))

    // 创建 MacroExpandExpr 实例
    let macroExpandExpr = MacroExpandExpr(
        calleeMacro,
        macroAttrs,
        macroInputs
    )

    println("macroExpandExpr: ${macroExpandExpr}")
}

运行结果:

macroExpandExpr: @testMacro[123](1 + 1)

func getAtPos()

public func getAtPos(): CodePositionRange

功能:获取 MacroExpandExpr 节点中 @ 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 calleeMacro
    let calleeMacro = SymbolRef(
        "testMacro",
        []
    )

    // 创建 macroAttrs
    let macroAttrs = quote(123)

    // 创建 macroInputs
    let macroInputs = MacroExpandInput.WithParens(quote(1 + 1))

    // 创建 MacroExpandExpr 实例
    let macroExpandExpr = MacroExpandExpr(
        calleeMacro,
        macroAttrs,
        macroInputs
    )

    let pos = macroExpandExpr.getAtPos()
    // 输出 @ 位置
    println("macroExpandExpr.getAtPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

macroExpandExpr.getAtPos(): 1:1-1:2

func getLParenPos()

public func getLParenPos(): Option<CodePositionRange>

功能:获取 MacroExpandExpr 节点中 ( 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 calleeMacro
    let calleeMacro = SymbolRef(
        "testMacro",
        []
    )

    // 创建 macroAttrs
    let macroAttrs = quote(123)

    // 创建 macroInputs
    let macroInputs = MacroExpandInput.WithParens(quote(1 + 1))

    // 创建 MacroExpandExpr 实例
    let macroExpandExpr = MacroExpandExpr(
        calleeMacro,
        macroAttrs,
        macroInputs
    )

    if (let Some(pos) <- macroExpandExpr.getLParenPos()) {
        // 输出 ( 位置
        println("macroExpandExpr.getLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

macroExpandExpr.getLParenPos(): 1:16-1:17

func getLSquarePos()

public func getLSquarePos(): Option<CodePositionRange>

功能:获取 MacroExpandExpr 节点中 [ 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 calleeMacro
    let calleeMacro = SymbolRef(
        "testMacro",
        []
    )

    // 创建 macroAttrs
    let macroAttrs = quote(123)

    // 创建 macroInputs
    let macroInputs = MacroExpandInput.WithParens(quote(1 + 1))

    // 创建 MacroExpandExpr 实例
    let macroExpandExpr = MacroExpandExpr(
        calleeMacro,
        macroAttrs,
        macroInputs
    )

    if (let Some(pos) <- macroExpandExpr.getLSquarePos()) {
        // 输出 [ 位置
        println("macroExpandExpr.getLSquarePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

macroExpandExpr.getLSquarePos(): 1:11-1:12

func getRParenPos()

public func getRParenPos(): Option<CodePositionRange>

功能:获取 MacroExpandExpr 节点中 ) 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 calleeMacro
    let calleeMacro = SymbolRef(
        "testMacro",
        []
    )

    // 创建 macroAttrs
    let macroAttrs = quote(123)

    // 创建 macroInputs
    let macroInputs = MacroExpandInput.WithParens(quote(1 + 1))

    // 创建 MacroExpandExpr 实例
    let macroExpandExpr = MacroExpandExpr(
        calleeMacro,
        macroAttrs,
        macroInputs
    )

    if (let Some(pos) <- macroExpandExpr.getRParenPos()) {
        // 输出 ) 位置
        println("macroExpandExpr.getRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

macroExpandExpr.getRParenPos(): 1:22-1:23

func getRSquarePos()

public func getRSquarePos(): Option<CodePositionRange>

功能:获取 MacroExpandExpr 节点中 ] 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 calleeMacro
    let calleeMacro = SymbolRef(
        "testMacro",
        []
    )

    // 创建 macroAttrs
    let macroAttrs = quote(123)

    // 创建 macroInputs
    let macroInputs = MacroExpandInput.WithParens(quote(1 + 1))

    // 创建 MacroExpandExpr 实例
    let macroExpandExpr = MacroExpandExpr(
        calleeMacro,
        macroAttrs,
        macroInputs
    )

    if (let Some(pos) <- macroExpandExpr.getRSquarePos()) {
        // 输出 ] 位置
        println("macroExpandExpr.getRSquarePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

macroExpandExpr.getRSquarePos(): 1:15-1:16

class MacroExpandParam

public class MacroExpandParam <: Parameter {
    public init(calleeMacro: Expr, macroAttrs: Tokens, macroInputs: MacroExpandInput,
        annotations!: Array<Annotation> = [], comments!: Array<Comment> = [])
}

功能:表示宏展开参数。

用于在函数参数定义中应用编译时宏,将宏逻辑应用于参数处理。

父类型:

prop calleeMacro

public prop calleeMacro: Expr

功能:获取被调用的宏表达式。

类型:Expr

prop macroAttrs

public prop macroAttrs: Tokens

功能:获取宏的属性标记集合,用于传递编译时元数据。

类型:Tokens

prop macroInputs

public prop macroInputs: MacroExpandInput

功能:获取宏展开的输入声明,定义宏执行所需的上下文。

类型:MacroExpandInput

init(Expr, Tokens, MacroExpandInput, Array<Annotation>, Array<Comment>)

public init(calleeMacro: Expr, macroAttrs: Tokens, macroInputs: MacroExpandInput,
    annotations!: Array<Annotation> = [], comments!: Array<Comment> = [])

功能:构造一个 MacroExpandParam 对象,表示宏展开参数节点,用于函数参数中嵌入宏调用。

参数:

  • calleeMacro: Expr - 被调用的宏表达式。
  • macroAttrs: Tokens - 宏的属性标记序列。
  • macroInputs: MacroExpandInput - 宏输入,可以是带括号的 Tokens 或不带括号的 Decl。
  • annotations!: Array<Annotation> - 附加的注解列表,默认为空数组。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当宏调用表达式不是成员访问或引用表达式时,格式化过程中内存分配失败,或 macroInputs 不在 MacroExpandInput 中时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 calleeMacro
    let calleeMacro = SymbolRef(
        "testMacro",
        []
    )

    // 创建 macroAttrs
    let macroAttrs = quote(123)

    // 创建 EnumConstructor 实例
    let enumConstructor = EnumConstructor(
        "EnumA",
        [AtomicType(AtomicTypeKind.Int64Type)]
    )

    // 创建 macroInputs
    let macroInputs = MacroExpandInput.WithParens(quote(a: Int64))

    // 创建 MacroExpandParam 实例
    let macroExpandParam = MacroExpandParam(
        calleeMacro,
        macroAttrs,
        macroInputs
    )

    println("macroExpandParam: ${macroExpandParam}")
}

运行结果:

macroExpandParam: @testMacro[123](a: Int64)

func getAtPos()

public func getAtPos(): CodePositionRange

功能:获取 MacroExpandParam 节点中 @ 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 calleeMacro
    let calleeMacro = SymbolRef(
        "testMacro",
        []
    )

    // 创建 macroAttrs
    let macroAttrs = quote(123)

    // 创建 macroInputs
    let macroInputs = MacroExpandInput.WithParens(quote(a: Int64))

    // 创建 MacroExpandParam 实例
    let macroExpandParam = MacroExpandParam(
        calleeMacro,
        macroAttrs,
        macroInputs
    )
    let pos = macroExpandParam.getAtPos()

    // 输出 @ 位置
    println("macroExpandParam.getAtPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

macroExpandParam.getAtPos(): 1:1-1:2

func getLParenPos()

public func getLParenPos(): Option<CodePositionRange>

功能:获取 MacroExpandParam 节点中 ( 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 calleeMacro
    let calleeMacro = SymbolRef(
        "testMacro",
        []
    )

    // 创建 macroAttrs
    let macroAttrs = quote(123)

    // 创建 macroInputs
    let macroInputs = MacroExpandInput.WithParens(quote(a: Int64))

    // 创建 MacroExpandParam 实例
    let macroExpandParam = MacroExpandParam(
        calleeMacro,
        macroAttrs,
        macroInputs
    )
    if (let Some(pos) <- macroExpandParam.getLParenPos()) {
        // 输出 ( 位置
        println("macroExpandParam.getLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

macroExpandParam.getLParenPos(): 1:16-1:17

func getLSquarePos()

public func getLSquarePos(): Option<CodePositionRange>

功能:获取 MacroExpandParam 节点中 [ 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 calleeMacro
    let calleeMacro = SymbolRef(
        "testMacro",
        []
    )

    // 创建 macroAttrs
    let macroAttrs = quote(123)

    // 创建 macroInputs
    let macroInputs = MacroExpandInput.WithParens(quote(a: Int64))

    // 创建 MacroExpandParam 实例
    let macroExpandParam = MacroExpandParam(
        calleeMacro,
        macroAttrs,
        macroInputs
    )
    if (let Some(pos) <- macroExpandParam.getLSquarePos()) {
        // 输出 [ 位置
        println("macroExpandParam.getLSquarePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

macroExpandParam.getLSquarePos(): 1:11-1:12

func getRParenPos()

public func getRParenPos(): Option<CodePositionRange>

功能:获取 MacroExpandParam 节点中 ) 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 calleeMacro
    let calleeMacro = SymbolRef(
        "testMacro",
        []
    )

    // 创建 macroAttrs
    let macroAttrs = quote(123)

    // 创建 macroInputs
    let macroInputs = MacroExpandInput.WithParens(quote(a: Int64))

    // 创建 MacroExpandParam 实例
    let macroExpandParam = MacroExpandParam(
        calleeMacro,
        macroAttrs,
        macroInputs
    )
    if (let Some(pos) <- macroExpandParam.getRParenPos()) {
        // 输出 ) 位置
        println("macroExpandParam.getRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

macroExpandParam.getRParenPos(): 1:25-1:26

func getRSquarePos()

public func getRSquarePos(): Option<CodePositionRange>

功能:获取 MacroExpandParam 节点中 ] 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 calleeMacro
    let calleeMacro = SymbolRef(
        "testMacro",
        []
    )

    // 创建 macroAttrs
    let macroAttrs = quote(123)

    // 创建 macroInputs
    let macroInputs = MacroExpandInput.WithParens(quote(a: Int64))

    // 创建 MacroExpandParam 实例
    let macroExpandParam = MacroExpandParam(
        calleeMacro,
        macroAttrs,
        macroInputs
    )
    if (let Some(pos) <- macroExpandParam.getRSquarePos()) {
        // 输出 ] 位置
        println("macroExpandParam.getRSquarePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

macroExpandParam.getRSquarePos(): 1:15-1:16

class MainDecl

public class MainDecl <: Decl {
    public init(body: Block, params: ParameterList, retTyAnnotation: Option<TypeAnnotation>, comments!: Array<Comment> = [])
}

功能:表示一个 main 函数声明节点。

一个 MainDecl 节点:main() {}

父类型:

prop body

public prop body: Block

功能:获取当前主函数声明的主体部分。

类型:Block

prop params

public prop params: ParameterList

功能:获取当前主函数声明的参数列表。

类型:ParameterList

prop retTyAnnotation

public prop retTyAnnotation: Option<TypeAnnotation>

功能:获取当前主函数声明的返回类型标注(若不存在返回 None)。

类型:Option<TypeAnnotation>

init(Block, ParameterList, Option<TypeAnnotation>, Array<Comment>)

public init(body: Block, params: ParameterList, retTyAnnotation: Option<TypeAnnotation>, comments!: Array<Comment> = [])

功能:构造一个 MainDecl 对象,表示主函数声明节点。

参数:

  • body: Block - 主函数体。
  • params: ParameterList - 参数列表。
  • retTyAnnotation: Option<TypeAnnotation> - 可选的返回类型注解。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建 body
    let body = Block([ReturnExpr(None)])

    // 创建 params
    let params = ParameterList([])

    // 创建 retTyAnnotation
    let retTyAnnotation = AtomicType(UnitType)

    // 创建 MainDecl 实例
    let mainDecl = MainDecl(
        body, 
        params, 
        retTyAnnotation
    )

    println("mainDecl: ${mainDecl}")
}

运行结果:

mainDecl: main(): Unit {
    return
}

func getMainKeyWordPos()

public func getMainKeyWordPos(): CodePositionRange

功能:获取 MainDecl 节点中 main 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 MainDecl 实例
    let body = Block([ReturnExpr(None)])
    let params = ParameterList([])
    let mainDecl = MainDecl(body, params, None)
    let pos = mainDecl.getMainKeyWordPos()

    // 输出 main 关键字位置
    println("mainDecl.getMainKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

mainDecl.getMainKeyWordPos(): 1:1-1:5

func getRetTyAnnotationColonPos()

public func getRetTyAnnotationColonPos(): Option<CodePositionRange>

功能:获取 MainDecl 节点中类型前 : 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 MainDecl 实例
    let body = Block([ReturnExpr(None)])
    let params = ParameterList([])
    let retTyAnnotation = AtomicType(UnitType)
    let mainDecl = MainDecl(body, params, retTyAnnotation)

    if (let Some(pos) <- mainDecl.getRetTyAnnotationColonPos()) {
        // 输出冒号位置
        println("mainDecl.getRetTyAnnotationColonPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

mainDecl.getRetTyAnnotationColonPos(): 1:7-1:8

class MatchCase

public class MatchCase <: SyntaxTreeNode {
    public init(patterns: Array<Pattern>, patternGuardCond: Option<Expr>, caseCond: Option<Expr>, body: Array<SyntaxTreeNode>, comments!: Array<Comment> = [])
}

功能:表示 match 表达式中的一个 case 节点。

一个 MatchCase 节点:case failScore where score > 0 => 0

父类型:

prop body

public prop body: Array<SyntaxTreeNode>

功能:获取当前匹配条件满足时执行的代码块。

类型:Array<SyntaxTreeNode>

prop caseCond

public prop caseCond: Option<Expr>

功能:获取当前匹配条件的表达式(若不存在返回 None)。

类型:Option<Expr>

prop patternGuardCond

public prop patternGuardCond: Option<Expr>

功能:获取当前匹配条件的模式守卫表达式(若不存在返回 None)。

类型:Option<Expr>

prop patterns

public prop patterns: Array<Pattern>

功能:获取当前匹配条件的模式列表。

类型:Array<Pattern>

init(Array<Pattern>, Option<Expr>, Option<Expr>, Array<SyntaxTreeNode>, Array<Comment>)

public init(patterns: Array<Pattern>, patternGuardCond: Option<Expr>, caseCond: Option<Expr>, body: Array<SyntaxTreeNode>, comments!: Array<Comment> = [])

功能:构造一个 MatchCase 对象,表示 match 表达式中的分支 case。

参数:

  • patterns: Array<Pattern> - 匹配模式列表。
  • patternGuardCond: Option<Expr> - 可选的模式守卫条件。
  • caseCond: Option<Expr> - 可选的 case 条件表达式。
  • body: Array<SyntaxTreeNode> - case 体中的语法节点列表。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当 body 中的节点不是表达式类型、函数声明或变量声明时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 patterns
    let patterns: Array<Pattern> = [VarPattern("x"), VarPattern("y")]

    // 创建 patternGuardCond
    let patternGuardCond = BinaryExpr(SymbolRef("x", []),BinaryOpKind.Lt, LitConstExpr(LitConstKind.IntergerLiteral, "5"))

    // 创建 body
    let body: Array<SyntaxTreeNode> = [BinaryExpr(SymbolRef("x", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))]

    // 创建 MatchCase 实例
    let matchCase = MatchCase(
        patterns, 
        patternGuardCond, 
        None, 
        body
    )

    println("matchCase: ${matchCase}")
}

运行结果:

matchCase: case x | y where x < 5 => x + 1

func getBitOrsPos()

public func getBitOrsPos(): Array<CodePositionRange>

功能:获取当前 MatchCase 中所有 | 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 patterns
    let patterns: Array<Pattern> = [VarPattern("x"), VarPattern("y"), VarPattern("z")]

    // 创建 body
    let body: Array<SyntaxTreeNode> = [BinaryExpr(SymbolRef("x", []), BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))]

    // 创建 MatchCase 实例
    let matchCase = MatchCase(patterns, None, None, body)
    let posArr = matchCase.getBitOrsPos()

    // 遍历输出竖线位置
    for (i in 0..posArr.size) {
        println("matchCase.getBitOrsPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

matchCase.getBitOrsPos()[0]: 1:8-1:9
matchCase.getBitOrsPos()[1]: 1:12-1:13

func getCasePos()

public func getCasePos(): CodePositionRange

功能:获取当前 MatchCasecase 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 patterns
    let patterns: Array<Pattern> = [VarPattern("x")]

    // 创建 body
    let body: Array<SyntaxTreeNode> = [BinaryExpr(SymbolRef("x", []), BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))]

    // 创建 MatchCase 实例
    let matchCase = MatchCase(patterns, None, None, body)
    let pos = matchCase.getCasePos()

    // 输出 case 关键字位置
    println("matchCase.getCasePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

matchCase.getCasePos(): 1:1-1:5

func getDoubleArrowPos()

public func getDoubleArrowPos(): CodePositionRange

功能:获取当前 MatchCase=> 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 patterns
    let patterns: Array<Pattern> = [VarPattern("x")]

    // 创建 body
    let body: Array<SyntaxTreeNode> = [BinaryExpr(SymbolRef("x", []), BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))]

    // 创建 MatchCase 实例
    let matchCase = MatchCase(patterns, None, None, body)
    let pos = matchCase.getDoubleArrowPos()

    // 输出双箭头位置
    println("matchCase.getDoubleArrowPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

matchCase.getDoubleArrowPos(): 1:8-1:10

func getWherePos()

public func getWherePos(): Option<CodePositionRange>

功能:获取当前 MatchCasewhere 关键字的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回 where 关键字的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 patterns
    let patterns: Array<Pattern> = [VarPattern("x")]

    // 创建 patternGuardCond
    let patternGuardCond = BinaryExpr(SymbolRef("x", []), BinaryOpKind.Lt, LitConstExpr(LitConstKind.IntergerLiteral, "5"))

    // 创建 body
    let body: Array<SyntaxTreeNode> = [BinaryExpr(SymbolRef("x", []), BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))]

    // 创建 MatchCase 实例
    let matchCase = MatchCase(patterns, patternGuardCond, None, body)

    if (let Some(pos) <- matchCase.getWherePos()) {
        // 输出 where 关键字位置
        println("matchCase.getWherePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

matchCase.getWherePos(): 1:8-1:13

class MatchExpr

public class MatchExpr <: Expr {
    public init(matchCases: Array<MatchCase>, selector: Option<Expr>, comments!: Array<Comment> = [])
}

功能:表示模式匹配表达式,用于实现模式匹配。

模式匹配表达式分为带 selectormatch 表达式和不带 selectormatch 表达式。

父类型:

prop matchCases

public prop matchCases: Array<MatchCase>

功能:获取当前 match 语句的所有匹配条件和对应的代码块。

类型:Array<MatchCase>

prop selector

public prop selector: Option<Expr>

功能:获取当前 match 语句的要匹配的表达式。

类型:Option<Expr>

init(Array<MatchCase>, Option<Expr>, Array<Comment>)

public init(matchCases: Array<MatchCase>, selector: Option<Expr>, comments!: Array<Comment> = [])

功能:构造一个 MatchExpr 对象,表示 match 表达式。

参数:

  • matchCases: Array<MatchCase> - 分支 case 列表。
  • selector: Option<Expr> - 可选的被匹配表达式。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建 matchCases
    let matchCases = [MatchCase([VarPattern("x"), VarPattern("y")], None, None, [BinaryExpr(SymbolRef("x", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))])]

    // 创建 selector
    let selector = SymbolRef("x", [])

    // 创建 MatchExpr 实例
    let matchExpr = MatchExpr(
        matchCases, 
        selector
    )

    println("matchExpr: ${matchExpr}")
}

运行结果:

matchExpr: match (x) {
    case x | y => x + 1
}

func getMatchCasesLCurlPos()

public func getMatchCasesLCurlPos(): CodePositionRange

功能:获取当前 MatchExpr{ 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 matchCases
    let matchCases = [MatchCase([VarPattern("x")], None, None, [BinaryExpr(SymbolRef("x", []), BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))])]

    // 创建 MatchExpr 实例
    let matchExpr = MatchExpr(matchCases, SymbolRef("x", []))
    let pos = matchExpr.getMatchCasesLCurlPos()

    // 输出左花括号位置
    println("matchExpr.getMatchCasesLCurlPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

matchExpr.getMatchCasesLCurlPos(): 1:11-1:12

func getMatchCasesRCurlPos()

public func getMatchCasesRCurlPos(): CodePositionRange

功能:获取当前 MatchExpr} 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 matchCases
    let matchCases = [MatchCase([VarPattern("x")], None, None, [BinaryExpr(SymbolRef("x", []), BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))])]

    // 创建 MatchExpr 实例
    let matchExpr = MatchExpr(matchCases, SymbolRef("x", []))
    let pos = matchExpr.getMatchCasesRCurlPos()

    // 输出右花括号位置
    println("matchExpr.getMatchCasesRCurlPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

matchExpr.getMatchCasesRCurlPos(): 3:1-3:2

func getMatchKeyWordPos()

public func getMatchKeyWordPos(): CodePositionRange

功能:获取当前 MatchExprmatch 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 matchCases
    let matchCases = [MatchCase([VarPattern("x")], None, None, [BinaryExpr(SymbolRef("x", []), BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))])]

    // 创建 MatchExpr 实例
    let matchExpr = MatchExpr(matchCases, SymbolRef("x", []))
    let pos = matchExpr.getMatchKeyWordPos()

    // 输出 match 关键字位置
    println("matchExpr.getMatchKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

matchExpr.getMatchKeyWordPos(): 1:1-1:6

func getSelectorLParenPos()

public func getSelectorLParenPos(): Option<CodePositionRange>

功能:获取当前 MatchExpr 的选择器中的 ( 的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回选择器中的 ( 的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 matchCases
    let matchCases = [MatchCase([VarPattern("x")], None, None, [BinaryExpr(SymbolRef("x", []), BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))])]

    // 创建 MatchExpr 实例
    let matchExpr = MatchExpr(matchCases, SymbolRef("x", []))

    if (let Some(pos) <- matchExpr.getSelectorLParenPos()) {
        // 输出选择器左括号位置
        println("matchExpr.getSelectorLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

matchExpr.getSelectorLParenPos(): 1:7-1:8

func getSelectorRParenPos()

public func getSelectorRParenPos(): Option<CodePositionRange>

功能:获取当前 MatchExpr 的选择器中的 ) 的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回选择器中的 ) 的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 matchCases
    let matchCases = [MatchCase([VarPattern("x")], None, None, [BinaryExpr(SymbolRef("x", []), BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))])]

    // 创建 MatchExpr 实例
    let matchExpr = MatchExpr(matchCases, SymbolRef("x", []))

    if (let Some(pos) <- matchExpr.getSelectorRParenPos()) {
        // 输出选择器右括号位置
        println("matchExpr.getSelectorRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

matchExpr.getSelectorRParenPos(): 1:9-1:10

class MemberAccess

public class MemberAccess <: Expr {
    public init(base: SyntaxTreeNode, field: SymbolRef, comments!: Array<Comment> = [])
}

功能:表示成员访问表达式。

可以用于访问 classinterfacestruct 等类型的成员。一个 MemberAccess 节点的形式为 p.ap 为成员访问表达式的主体,a 表示成员的名字。

父类型:

prop base

public prop base: SyntaxTreeNode

功能:获取当前成员访问表达式的基节点,即被访问的对象或结构体。

类型:SyntaxTreeNode

prop field

public prop field: SymbolRef

功能:获取当前成员访问表达式中要访问的成员字段。

类型:SymbolRef

init(SyntaxTreeNode, SymbolRef, Array<Comment>)

public init(base: SyntaxTreeNode, field: SymbolRef, comments!: Array<Comment> = [])

功能:构造一个 MemberAccess 对象,表示成员访问表达式。

参数:

  • base: SyntaxTreeNode - 被访问的对象表达式或类型标注。
  • field: SymbolRef - 成员字段引用。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当 base 节点不是表达式或类型标注时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 base
    let base = SymbolRef("p", [])

    // 创建 field
    let field = SymbolRef("A", [])

    // 创建 MemberAccess 实例
    let memberAccess = MemberAccess(
        base, 
        field
    )

    println("memberAccess: ${memberAccess}")
}

运行结果:

memberAccess: p.A

func getDotPos()

public func getDotPos(): CodePositionRange

功能:获取当前 MemberAccess. 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 base
    let base = SymbolRef("p", [])

    // 创建 field
    let field = SymbolRef("A", [])

    // 创建 MemberAccess 实例
    let memberAccess = MemberAccess(base, field)
    let pos = memberAccess.getDotPos()

    // 输出点号位置
    println("memberAccess.getDotPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

memberAccess.getDotPos(): 1:2-1:3

class Modifier

public class Modifier <: SyntaxTreeNode {
    public init(kind: ModifierKind, comments!: Array<Comment> = [])
}

功能:表示某个声明的修饰符,通常放在声明处的最前端。

一个 Modifier 节点:public func foo() 中的 public

父类型:

prop kind

public prop kind: ModifierKind

功能:获取 Modifier 节点的修饰符种类。

类型:ModifierKind

init(ModifierKind, Array<Comment>)

public init(kind: ModifierKind, comments!: Array<Comment> = [])

功能:构造一个 Modifier 对象,表示语法树中的修饰符节点,如 publicstatic 等。

参数:

  • kind: ModifierKind - 修饰符类型。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建 ModifierKind
    let kind = ModifierKind.Public

    // 创建 Modifier 实例
    let modifier = Modifier(
        kind
    )

    println("modifier: ${modifier}")
}

运行结果:

modifier: public

class OptionalExpr

public class OptionalExpr <: Expr {
    public init(base: Expr, comments!: Array<Comment> = [])
}

功能:表示一个带有问号操作符的表达式节点。

一个 OptionalExpr 节点:a?.b, a?(b), a?[b] 中的 a?

父类型:

prop base

public prop base: Expr

功能:获取 OptionalExpr 的表达式节点。

类型:Expr

init(Expr, Array<Comment>)

public init(base: Expr, comments!: Array<Comment> = [])

功能:构造一个 OptionalExpr 对象,表示带问号操作符的表达式节点。

参数:

  • base: Expr - 基础表达式。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建 SymbolRef 实例
    let symbolRef = SymbolRef("a", [])

    // 创建 OptionalExpr 实例
    let optionalExpr = OptionalExpr(symbolRef)

    println("optionalExpr: ${optionalExpr}")
}

运行结果:

optionalExpr: a?

func getQuestionPos()

public func getQuestionPos(): CodePositionRange

功能:获取 ? 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 SymbolRef 实例
    let symbolRef = SymbolRef("a", [])

    // 创建 OptionalExpr 实例
    let optionalExpr = OptionalExpr(symbolRef)
    
    let pos = optionalExpr.getQuestionPos()
    
    // 输出 ? 位置
    println("optionalExpr.getQuestionPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

optionalExpr.getQuestionPos(): 1:2-1:3

class Package

public class Package <: SyntaxTreeNode {
    public init(isMacroPkg: Bool, name: String, srcFile: Array<SourceFile>)
}

功能:表示包节点。

父类型:

prop isMacroPkg

public prop isMacroPkg: Bool

功能:表示当前包是否为宏包。

类型:Bool

prop name

public prop name: String

功能:表示当前包的包名。

类型:String

prop srcFile

public prop srcFile: Array<SourceFile>

功能:表示当前包的源码文件列表。

类型:Array<SourceFile>

init(Bool, String, Array<SourceFile>)

public init(isMacroPkg: Bool, name: String, srcFile: Array<SourceFile>)

功能:构造一个 Package 对象,表示整个包节点,包含多个源文件。

参数:

  • isMacroPkg: Bool - 是否为宏包。
  • name: String - 包名。
  • srcFile: Array<SourceFile> - 源文件列表。

异常:

  • Exception - 当输入的 name 不符合仓颉标识符规范时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    let contents = ImportSingle(["pkg"], "a")

    // 创建 ImportList 实例
    let importList = ImportList(
        contents, 
        None
    )

    let body = Block([ReturnExpr(None)])
    let params = ParameterList([])
    let retTyAnnotation = AtomicType(UnitType)

    // 创建 MainDecl 实例
    let mainDecl = MainDecl(
        body, 
        params, 
        retTyAnnotation
    )

    let name = "sourceFile.cj"
    let path = "/path/to/sourceFile.cj"

    // 创建 SourceFile 实例
    let sourceFile = SourceFile(
        [importList],
        name,
        path,
        None,
        [mainDecl]
    )

    let isMacroPkg = false
    let pkgName = "default"

    // 创建 Package 实例
    let pkg = Package(
        isMacroPkg,
        pkgName,
        [sourceFile]
    )

    println("pkg: ${pkg}")
}

运行结果:

pkg: // sourceFile.cj
import pkg.a
main(): Unit {
    return
}

func toString()

public func toString(): String

功能:将包节点作为字符串打印出来,包内的文件按文件名字母序排序,对每个文件依次打印文件名和文件内容。

返回值:

  • String - 返回包节点作为字符串打印的结果。

示例:

import stdx.syntax.*

main() {
    let contents = ImportSingle(["pkg"], "a")

    // 创建 ImportList 实例
    let importList = ImportList(
        contents, 
        None
    )

    let body = Block([ReturnExpr(None)])
    let params = ParameterList([])
    let retTyAnnotation = AtomicType(UnitType)

    // 创建 MainDecl 实例
    let mainDecl = MainDecl(
        body, 
        params, 
        retTyAnnotation
    )

    let name = "sourceFile.cj"
    let path = "/path/to/sourceFile.cj"

    // 创建 SourceFile 实例
    let sourceFile = SourceFile(
        [importList],
        name,
        path,
        None,
        [mainDecl]
    )

    let isMacroPkg = false
    let pkgName = "default"

    // 创建 Package 实例
    let pkg = Package(
        isMacroPkg,
        pkgName,
        [sourceFile]
    )

    println("pkg.toString(): ${pkg.toString()}")
}

运行结果:

pkg.toString(): // sourceFile.cj
import pkg.a
main(): Unit {
    return
}

func toTokens()

public func toTokens(): Tokens

功能:将包节点转换为一组词法单元,包内的文件按文件名字典序排序,在每个文件对应的词法单元之前加上一个注释类型的 Token, 内容为该文件的文件名。

返回值:

  • Tokens - 返回包节点转换为一组词法单元的结果。

示例:

import stdx.syntax.*

main() {
    let contents = ImportSingle(["pkg"], "a")

    // 创建 ImportList 实例
    let importList = ImportList(
        contents, 
        None
    )

    let body = Block([ReturnExpr(None)])
    let params = ParameterList([])
    let retTyAnnotation = AtomicType(UnitType)

    // 创建 MainDecl 实例
    let mainDecl = MainDecl(
        body, 
        params, 
        retTyAnnotation
    )

    let name = "sourceFile.cj"
    let path = "/path/to/sourceFile.cj"

    // 创建 SourceFile 实例
    let sourceFile = SourceFile(
        [importList],
        name,
        path,
        None,
        [mainDecl]
    )

    let isMacroPkg = false
    let pkgName = "default"

    // 创建 Package 实例
    let pkg = Package(
        isMacroPkg,
        pkgName,
        [sourceFile]
    )

    println("pkg.toTokens(): ${pkg.toTokens()}")
}

运行结果:

pkg.toTokens(): 
// sourceFile.cj
 import pkg.a
main(): Unit {
    return
}

class PackageHeader

public class PackageHeader <: SyntaxTreeNode {
    public init(accessModifier: Option<Modifier>, isMacroPkg: Bool, packageNameIdentifiers: Array<String>, comments!: Array<Comment> = [])
}

功能:表示包声明节点。

父类型:

prop accessModifier

public prop accessModifier: Option<Modifier>

功能:表示当前包声明的可见性修饰符。

类型:Option<Modifier>

prop isMacroPkg

public prop isMacroPkg: Bool

功能:表示当前包是否为宏包。

类型:Bool

prop packageNameIdentifiers

public prop packageNameIdentifiers: Array<String>

功能:获取 PackageHeader 节点中当前包的包名列表,包含 root 包到当前子包的各级包名。

类型:Array<String>

init(Option<Modifier>, Bool, Array<String>, Array<Comment>)

public init(accessModifier: Option<Modifier>, isMacroPkg: Bool, packageNameIdentifiers: Array<String>, comments!: Array<Comment> = [])

功能:构造一个 PackageHeader 对象,表示包声明头。

参数:

  • accessModifier: Option<Modifier> - 访问修饰符,可选。
  • isMacroPkg: Bool - 是否为宏包。
  • packageNameIdentifiers: Array<String> - 包名标识符列表,如 ["stdx", "syntax"]
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当修饰符不是 publicinternalprotected,或 packageNameIdentifiers 为空时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 accessModifier
    let accessModifier = Modifier(ModifierKind.Public)

    // 创建 isMacroPkg
    let isMacroPkg = true

    // 创建 packageNameIdentifiers
    let packageNameIdentifiers = ["A"]

    // 创建 PackageHeader 实例
    let packageHeader = PackageHeader(
        accessModifier, 
        isMacroPkg, 
        packageNameIdentifiers
    )

    println("packageHeader: ${packageHeader}")
}

运行结果:

packageHeader: public macro package A

func getDotsPos()

public func getDotsPos(): Array<CodePositionRange>

功能:获取 PackageHeader 节点中 . 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 PackageHeader 实例
    let packageNameIdentifiers = ["syntax"]
    let packageHeader = PackageHeader(None, false, packageNameIdentifiers)
    let posArr = packageHeader.getDotsPos()

    // 遍历输出点位置
    for (i in 0..posArr.size) {
        println("packageHeader.getDotsPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

func getMacroKeyWordPos()

public func getMacroKeyWordPos(): Option<CodePositionRange>

功能:获取 PackageHeader 节点中 macro 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 PackageHeader 实例
    let packageHeader = PackageHeader(None, true, ["A"])

    if (let Some(pos) <- packageHeader.getMacroKeyWordPos()) {
        // 输出 macro 关键字位置
        println("packageHeader.getMacroKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

packageHeader.getMacroKeyWordPos(): 1:1-1:6

func getPackageIdentifiersPos()

public func getPackageIdentifiersPos(): Array<CodePositionRange>

功能:获取 PackageHeader 节点中包标识符的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 PackageHeader 实例
    let packageNameIdentifiers = ["std"]
    let packageHeader = PackageHeader(None, false, packageNameIdentifiers)
    let posArr = packageHeader.getPackageIdentifiersPos()

    // 遍历输出包标识符位置
    for (i in 0..posArr.size) {
        println("packageHeader.getPackageIdentifiersPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

packageHeader.getPackageIdentifiersPos()[0]: 1:9-1:12

func getPackageKeyWordPos()

public func getPackageKeyWordPos(): CodePositionRange

功能:获取 PackageHeader 节点中 package 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 PackageHeader 实例
    let packageHeader = PackageHeader(None, false, ["A"])
    let pos = packageHeader.getPackageKeyWordPos()

    // 输出 package 关键字位置
    println("packageHeader.getPackageKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

packageHeader.getPackageKeyWordPos(): 1:1-1:8

func getPackageName()

public func getPackageName(): String

功能:获取 PackageHeader 节点中的包名。

返回值:

  • String - 返回包名。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 PackageHeader 实例
    let packageNameIdentifiers = ["syntax"]
    let packageHeader = PackageHeader(None, false, packageNameIdentifiers)
    let name = packageHeader.getPackageName()

    // 输出包名
    println("packageHeader.getPackageName(): ${name}")
}

运行结果:

packageHeader.getPackageName(): syntax

func getParentPackageName()

public func getParentPackageName(): String

功能:获取 PackageHeader 节点中所有父包的包名。

返回值:

  • String - 返回所有父包的包名。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 PackageHeader 实例
    let packageNameIdentifiers = ["std", "syntax"]
    let packageHeader = PackageHeader(None, false, packageNameIdentifiers)
    let parentName = packageHeader.getParentPackageName()

    // 输出父包名
    println("packageHeader.getParentPackageName(): ${parentName}")
}

运行结果:

packageHeader.getParentPackageName(): std

class Parameter

sealed abstract class Parameter <: Decl {}

功能:参数节点的父类,继承自 Decl 节点。

父类型:

class ParameterList

public class ParameterList <: SyntaxTreeNode {
    public init(parameters: Array<Parameter>, hasParen!: Bool = true, comments!: Array<Comment> = [])
}

功能:参数列表节点。

父类型:

prop params

public prop params: Array<Parameter>

功能:获取全部参数。

类型:Array<Parameter>

init(Array<Parameter>, Bool, Array<Comment>)

public init(parameters: Array<Parameter>, hasParen!: Bool = true, comments!: Array<Comment> = [])

功能:构造一个 ParameterList 对象,表示参数列表。

参数:

  • parameters: Array<Parameter> - 参数列表。
  • hasParen!: Bool - 是否带有括号,默认为 true
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    let name0 = "x"
    let typeAnnotation0 = AtomicType(Int64Type)
    let name1 = "y"
    let typeAnnotation1 = AtomicType(Int64Type)

    // 创建 LambdaParam 实例
    let lambdaParam0 = LambdaParam(
        name0, 
        typeAnnotation0
    )
    let lambdaParam1 = LambdaParam(
        name1, 
        typeAnnotation1
    )

    // 创建 ParameterList 实例
    let parameterList = ParameterList(
        [lambdaParam0, lambdaParam1],
        hasParen: false
    )

    println("parameterList: ${parameterList}")
}

运行结果:

parameterList: x: Int64, y: Int64

func getParamsCommasPos()

public func getParamsCommasPos(): Array<CodePositionRange>

功能:获取参数间 , 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let name0 = "x"
    let typeAnnotation0 = AtomicType(Int64Type)
    let name1 = "y"
    let typeAnnotation1 = AtomicType(Int64Type)

    // 创建 LambdaParam 实例
    let lambdaParam0 = LambdaParam(
        name0, 
        typeAnnotation0
    )
    let lambdaParam1 = LambdaParam(
        name1, 
        typeAnnotation1
    )

    // 创建 ParameterList 实例
    let parameterList = ParameterList(
        [lambdaParam0, lambdaParam1],
        hasParen: false
    )

    let commasPos = parameterList.getParamsCommasPos()
    
    // 输出参数间逗号位置
    for (i in 0..commasPos.size) {
        println("parameterList.getParamsCommasPos()[${i}]: ${commasPos[i].beginLine}:${commasPos[i].beginColumn}-${commasPos[i].endLine}:${commasPos[i].endColumn}")
    }
}

运行结果:

parameterList.getParamsCommasPos()[0]: 1:9-1:10

func getParamsLParenPos()

public func getParamsLParenPos(): Option<CodePositionRange>

功能:获取参数前 ( 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main() {
    let name0 = "x"
    let typeAnnotation0 = AtomicType(Int64Type)
    let name1 = "y"
    let typeAnnotation1 = AtomicType(Int64Type)

    // 创建 LambdaParam 实例
    let lambdaParam0 = LambdaParam(
        name0, 
        typeAnnotation0
    )
    let lambdaParam1 = LambdaParam(
        name1, 
        typeAnnotation1
    )

    // 创建 ParameterList 实例
    let parameterList = ParameterList(
        [lambdaParam0, lambdaParam1],
        hasParen: true
    )

    if (let Some(pos) <- parameterList.getParamsLParenPos()) {
        // 输出 ( 位置
        println("parameterList.getParamsLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

parameterList.getParamsLParenPos(): 1:1-1:2

func getParamsRParenPos()

public func getParamsRParenPos(): Option<CodePositionRange>

功能:获取参数后 ) 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main() {
    let name0 = "x"
    let typeAnnotation0 = AtomicType(Int64Type)
    let name1 = "y"
    let typeAnnotation1 = AtomicType(Int64Type)

    // 创建 LambdaParam 实例
    let lambdaParam0 = LambdaParam(
        name0, 
        typeAnnotation0
    )
    let lambdaParam1 = LambdaParam(
        name1, 
        typeAnnotation1
    )

    // 创建 ParameterList 实例
    let parameterList = ParameterList(
        [lambdaParam0, lambdaParam1],
        hasParen: true
    )

    if (let Some(pos) <- parameterList.getParamsRParenPos()) {
        // 输出 ) 位置
        println("parameterList.getParamsRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

parameterList.getParamsRParenPos(): 1:20-1:21

class ParenCondition

public class ParenCondition <: SyntaxTreeNode {
    public init(cond: DisjunctionCondition, comments!: Array<Comment> = [])
}

功能:表示一个括号条件节点,是指使用圆括号括起来的条件。

父类型:

prop cond

public prop cond: DisjunctionCondition

功能:获取 ParenCondition 节点中由圆括号括起来的条件。

类型:DisjunctionCondition

init(DisjunctionCondition, Array<Comment>)

public init(cond: DisjunctionCondition, comments!: Array<Comment> = [])

功能:构造一个 ParenCondition 对象,表示括号包裹的逻辑条件。

参数:

  • cond: DisjunctionCondition - 被括号包裹的析取条件。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    let symbolRef0 = SymbolRef("x", [])
    let symbolRef1 = SymbolRef("y", [])
    let symbolRef2 = SymbolRef("a", [])
    let symbolRef3 = SymbolRef("b", [])

    let binaryExpr0 = BinaryExpr(symbolRef0, BinaryOpKind.Equal, symbolRef1)
    let binaryExpr1 = BinaryExpr(symbolRef2, BinaryOpKind.Equal, symbolRef3)

    // 创建 ConjunctionCondition 实例
    let cond0 = ConjunctionCondition(AtomicCondition.Expression(binaryExpr0))
    let cond1 = ConjunctionCondition(AtomicCondition.Expression(binaryExpr1))

    // 创建 DisjunctionCondition 实例
    let disjunctionCondition = DisjunctionCondition(
        [cond0, cond1]
    )

    // 创建 ParenCondition 实例
    let parenCondition = ParenCondition(disjunctionCondition)

    println("parenCondition: ${parenCondition}")
}

运行结果:

parenCondition: (x == y || a == b)

func getLParenPos()

public func getLParenPos(): CodePositionRange

功能:获取 ParenCondition 节点中的 ( 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let symbolRef0 = SymbolRef("x", [])
    let symbolRef1 = SymbolRef("y", [])
    let symbolRef2 = SymbolRef("a", [])
    let symbolRef3 = SymbolRef("b", [])

    let binaryExpr0 = BinaryExpr(symbolRef0, BinaryOpKind.Equal, symbolRef1)
    let binaryExpr1 = BinaryExpr(symbolRef2, BinaryOpKind.Equal, symbolRef3)

    // 创建 ConjunctionCondition 实例
    let cond0 = ConjunctionCondition(AtomicCondition.Expression(binaryExpr0))
    let cond1 = ConjunctionCondition(AtomicCondition.Expression(binaryExpr1))

    // 创建 DisjunctionCondition 实例
    let disjunctionCondition = DisjunctionCondition(
        [cond0, cond1]
    )

    // 创建 ParenCondition 实例
    let parenCondition = ParenCondition(disjunctionCondition)
    
    let pos = parenCondition.getLParenPos()
    // 输出 ( 位置
    println("parenCondition.getLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

parenCondition.getLParenPos(): 1:1-1:2

func getRParenPos()

public func getRParenPos(): CodePositionRange

功能:获取 ParenCondition 节点中的 ) 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let symbolRef0 = SymbolRef("x", [])
    let symbolRef1 = SymbolRef("y", [])
    let symbolRef2 = SymbolRef("a", [])
    let symbolRef3 = SymbolRef("b", [])

    let binaryExpr0 = BinaryExpr(symbolRef0, BinaryOpKind.Equal, symbolRef1)
    let binaryExpr1 = BinaryExpr(symbolRef2, BinaryOpKind.Equal, symbolRef3)

    // 创建 ConjunctionCondition 实例
    let cond0 = ConjunctionCondition(AtomicCondition.Expression(binaryExpr0))
    let cond1 = ConjunctionCondition(AtomicCondition.Expression(binaryExpr1))

    // 创建 DisjunctionCondition 实例
    let disjunctionCondition = DisjunctionCondition(
        [cond0, cond1]
    )

    // 创建 ParenCondition 实例
    let parenCondition = ParenCondition(disjunctionCondition)
    
    let pos = parenCondition.getRParenPos()
    // 输出 ) 位置
    println("parenCondition.getRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

parenCondition.getRParenPos(): 1:18-1:19

class ParenExpr

public class ParenExpr <: Expr {
    public init(subExpr: Expr, comments!: Array<Comment> = [])
}

功能:表示一个括号表达式节点,是指使用圆括号括起来的表达式。

父类型:

prop subExpr

public prop subExpr: Expr

功能:获取 ParenExpr 节点中由圆括号括起来的子表达式。

类型:Expr

init(Expr, Array<Comment>)

public init(subExpr: Expr, comments!: Array<Comment> = [])

功能:构造一个 ParenExpr 对象,表示括号表达式,如 (x + 1)

参数:

  • subExpr: Expr - 被括号包裹的子表达式。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    let srcVal = SymbolRef("a", [])
    let targetTypeAnnotation = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 AsExpr 实例
    let asExpr = AsExpr(
        srcVal, 
        targetTypeAnnotation
    )

    // 创建 ParenExpr 实例
    let parenExpr = ParenExpr(asExpr)

    println("parenExpr: ${parenExpr}")
}

运行结果:

parenExpr: (a as Int64)

func getLParenPos()

public func getLParenPos(): CodePositionRange

功能:获取 ( 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let srcVal = SymbolRef("a", [])
    let targetTypeAnnotation = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 AsExpr 实例
    let asExpr = AsExpr(
        srcVal, 
        targetTypeAnnotation
    )

    // 创建 ParenExpr 实例
    let parenExpr = ParenExpr(asExpr)
    
    let pos = parenExpr.getLParenPos()
    // 输出 ( 位置
    println("parenExpr.getLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

parenExpr.getLParenPos(): 1:1-1:2

func getRParenPos()

public func getRParenPos(): CodePositionRange

功能:获取 ) 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let srcVal = SymbolRef("a", [])
    let targetTypeAnnotation = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 AsExpr 实例
    let asExpr = AsExpr(
        srcVal, 
        targetTypeAnnotation
    )

    // 创建 ParenExpr 实例
    let parenExpr = ParenExpr(asExpr)
    
    let pos = parenExpr.getRParenPos()
    // 输出 ) 位置
    println("parenExpr.getRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

parenExpr.getRParenPos(): 1:12-1:13

class ParenType

public class ParenType <: TypeAnnotation {
    public init(subType: TypeAnnotation, comments!: Array<Comment> = [])
}

功能:表示括号类型节点。

例如 var a: (Int64) 中的 (Int64)

父类型:

prop subType

public prop subType: TypeAnnotation

功能:获取 ParenType 节点中括起来的类型,如 (Int64) 中的 Int64

类型:TypeAnnotation

init(TypeAnnotation, Array<Comment>)

public init(subType: TypeAnnotation, comments!: Array<Comment> = [])

功能:构造一个 ParenType 对象,表示括号包裹的类型,如 (T)

参数:

  • subType: TypeAnnotation - 被括号包裹的子类型。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    
    let subType = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 ParenType 实例
    let parenType = ParenType(subType)

    println("parenType: ${parenType}")
}

运行结果:

parenType: (Int64)

func getLParenPos()

public func getLParenPos(): CodePositionRange

功能:获取 ( 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let subType = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 ParenType 实例
    let parenType = ParenType(subType)
    
    let pos = parenType.getLParenPos()
    // 输出 ( 位置
    println("parenType.getLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

parenType.getLParenPos(): 1:1-1:2

func getRParenPos()

public func getRParenPos(): CodePositionRange

功能:获取 ) 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let subType = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 ParenType 实例
    let parenType = ParenType(subType)
    
    let pos = parenType.getRParenPos()
    // 输出 ) 位置
    println("parenType.getRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

parenType.getRParenPos(): 1:7-1:8

class ParsingResult<T> where T <: SyntaxTreeNode

public class ParsingResult<T> where T <: SyntaxTreeNode {
    public let diags: Array<Diagnostic>
    public let node: Option<T>
}

功能:表示一个符合仓颉语法的抽象语法树。

let diags

public let diags: Array<Diagnostic>

功能:获取当前抽象语法树的全部诊断信息。

类型:Array<Diagnostic>

let node

public let node: Option<T>

功能:获取当前抽象语法树的节点(若不存在返回 None)。

类型:Option<T>,其中 TSyntaxTreeNode 的子类型 T

class Pattern

sealed abstract class Pattern <: SyntaxTreeNode {}

功能:表示一个模式匹配节点。

父类型:

class PrefixType

public class PrefixType <: TypeAnnotation {
    public init(base: TypeAnnotation, prefixOp: PrefixTypeOpKind, comments!: Array<Comment> = [])
}

功能:表示带前缀操作符的前缀类型节点。

例如 var a : ?A 中的 ?A

父类型:

prop base

public prop base: TypeAnnotation

功能:获取 PrefixType 节点中的类型节点,如 var a: ?A 中的 A

类型:TypeAnnotation

prop prefixTypeOpKind

public prop prefixTypeOpKind: PrefixTypeOpKind

功能:获取 PrefixType 节点中的前缀操作符类型。

类型:PrefixTypeOpKind

init(TypeAnnotation, PrefixTypeOpKind, Array<Comment>)

public init(base: TypeAnnotation, prefixOp: PrefixTypeOpKind, comments!: Array<Comment> = [])

功能:构造一个 PrefixType 对象,表示带前缀的类型,如 ?T

参数:

示例:

import stdx.syntax.*

main() {
    let base = AtomicType(AtomicTypeKind.Int64Type)
    let prefixOp = PrefixTypeOpKind.Quest

    // 创建 PrefixType 实例
    let prefixType = PrefixType(
        base,
        prefixOp
    )

    println("prefixType: ${prefixType}")
}

运行结果:

prefixType: ?Int64

func getOperatorPos()

public func getOperatorPos(): CodePositionRange

功能:获取前缀操作符的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let base = AtomicType(AtomicTypeKind.Int64Type)
    let prefixOp = PrefixTypeOpKind.Quest

    // 创建 PrefixType 实例
    let prefixType = PrefixType(
        base,
        prefixOp
    )
    
    let pos = prefixType.getOperatorPos()
    // 输出前缀操作符位置
    println("prefixType.getOperatorPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

prefixType.getOperatorPos(): 1:1-1:2

class PropDecl

public class PropDecl <: Decl {
    public init(getter: Option<PropGetterOrSetter>, name: String, setter: Option<PropGetterOrSetter>,
        tyAnnotation: TypeAnnotation, annotations!: Array<Annotation> = [], modifiers!: Array<Modifier> = [],
        comments!: Array<Comment> = [])
}

功能:表示一个属性声明节点。

一个 PropDecl 节点:prop X: Int64 { get() { 0 } }

父类型:

prop getter

public prop getter: Option<PropGetterOrSetter>

功能:获取当前属性声明的 getter 方法(若不存在返回 None)。

类型:Option<PropGetterOrSetter>

prop isMut

public prop isMut: Bool

功能:判断当前属性声明是否可变。

类型:Bool

prop name

public prop name: String

功能:获取当前属性声明的名称。

类型:String

prop setter

public prop setter: Option<PropGetterOrSetter>

功能:获取当前属性声明的 setter 方法(若不存在返回 None)。

类型:Option<PropGetterOrSetter>

prop tyAnnotation

public prop tyAnnotation: TypeAnnotation

功能:获取当前属性声明的类型标注。

类型:TypeAnnotation

init(Option<PropGetterOrSetter>, String, Option<PropGetterOrSetter>, TypeAnnotation, Array<Annotation>, Array<Modifier>, Array<Comment>)

public init(getter: Option<PropGetterOrSetter>, name: String, setter: Option<PropGetterOrSetter>,
    tyAnnotation: TypeAnnotation, annotations!: Array<Annotation> = [], modifiers!: Array<Modifier> = [],
    comments!: Array<Comment> = [])

功能:构造一个 PropDecl 对象,表示属性声明节点。

参数:

  • getter: Option<PropGetterOrSetter> - 可选的 getter。
  • name: String - 属性名。
  • setter: Option<PropGetterOrSetter> - 可选的 setter。
  • tyAnnotation: TypeAnnotation - 类型注解。
  • annotations!: Array<Annotation> - 附加的注解列表,默认为空数组。
  • modifiers!: Array<Modifier> - 修饰符列表,默认为空数组。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当 setter 存在但 getter 不存在,或输入的 name 不符合仓颉标识符规范时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 getter
    let getter = PropGetterOrSetter(Block([]), None, true)

    // 创建 name
    let name = "x"

    // 创建 setter
    let setter = PropGetterOrSetter(Block([]), "v", false)

    // 创建 tyAnnotation
    let tyAnnotation = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 PropDecl 实例
    let propDecl = PropDecl(
        getter, 
        name, 
        setter, 
        tyAnnotation
    )

    println("propDecl: ${propDecl}")
}

运行结果:

propDecl: prop x: Int64 {
    get() {
}
    set(v) {
}
}

func getIdentifierPos()

public func getIdentifierPos(): CodePositionRange

功能:获取 PropDecl 节点中标识符的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 PropDecl 实例
    let getter = PropGetterOrSetter(Block([]), None, true)
    let propDecl = PropDecl(getter, "x", None, AtomicType(AtomicTypeKind.Int64Type))
    let pos = propDecl.getIdentifierPos()

    // 输出标识符位置
    println("propDecl.getIdentifierPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

propDecl.getIdentifierPos(): 1:6-1:7

func getLCurlPos()

public func getLCurlPos(): Option<CodePositionRange>

功能:获取 PropDecl 节点中 { 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 PropDecl 实例
    let getter = PropGetterOrSetter(Block([]), None, true)
    let propDecl = PropDecl(getter, "x", None, AtomicType(AtomicTypeKind.Int64Type))

    if (let Some(pos) <- propDecl.getLCurlPos()) {
        // 输出左花括号位置
        println("propDecl.getLCurlPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

propDecl.getLCurlPos(): 1:15-1:16

func getPropKeyWordPos()

public func getPropKeyWordPos(): CodePositionRange

功能:获取 PropDecl 节点中 prop 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 PropDecl 实例
    let getter = PropGetterOrSetter(Block([]), None, true)
    let propDecl = PropDecl(getter, "x", None, AtomicType(AtomicTypeKind.Int64Type))
    let pos = propDecl.getPropKeyWordPos()

    // 输出 prop 关键字位置
    println("propDecl.getPropKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

propDecl.getPropKeyWordPos(): 1:1-1:5

func getRCurlPos()

public func getRCurlPos(): Option<CodePositionRange>

功能:获取 PropDecl 节点中 } 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 PropDecl 实例
    let getter = PropGetterOrSetter(Block([]), None, true)
    let propDecl = PropDecl(getter, "x", None, AtomicType(AtomicTypeKind.Int64Type))

    if (let Some(pos) <- propDecl.getRCurlPos()) {
        // 输出右花括号位置
        println("propDecl.getRCurlPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

propDecl.getRCurlPos(): 5:1-5:2

func getTyAnnotationColonPos()

public func getTyAnnotationColonPos(): CodePositionRange

功能:获取 PropDecl 节点中返回类型前的 : 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 PropDecl 实例
    let getter = PropGetterOrSetter(Block([]), None, true)
    let propDecl = PropDecl(getter, "x", None, AtomicType(AtomicTypeKind.Int64Type))
    let pos = propDecl.getTyAnnotationColonPos()

    // 输出冒号位置
    println("propDecl.getTyAnnotationColonPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

propDecl.getTyAnnotationColonPos(): 1:7-1:8

class PropGetterOrSetter

public class PropGetterOrSetter <: Decl {
    public init(block: Block, identifier: Option<String>, isGetter: Bool, annotations!: Array<Annotation> = [],
        comments!: Array<Comment> = [])
}

功能:表示一个属性的 gettersetter 声明。

父类型:

prop block

public prop block: Block

功能:获取当前属性 gettersetter 方法的主体部分。

类型:Block

prop identifier

public prop identifier: Option<String>

功能:若为 setter 方法,则获取当前方法的输入参数,否则返回 None。

类型:Option<String>

prop isGetter

public prop isGetter: Bool

功能:判断当前属性方法是否为 getter 方法。

类型:Bool

init(Block, Option<String>, Bool, Array<Annotation>, Array<Comment>)

public init(block: Block, identifier: Option<String>, isGetter: Bool, annotations!: Array<Annotation> = [],
    comments!: Array<Comment> = [])

功能:构造一个 PropGetterOrSetter 对象,表示属性 getter 或 setter 节点。

参数:

  • block: Block - 代码块。
  • identifier: Option<String> - 可选的标识符。
  • isGetter: Bool - 是否为 getter。
  • annotations!: Array<Annotation> - 附加的注解列表,默认为空数组。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当 isGettertrueannotations 不为空或 identifier 不为空,或 isGetterfalseidentifier 为空或不符合仓颉标识符规范时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    let assignOpKind = AssignOpKind.Assign
    let lhs = SymbolRef("variable_", [])
    let rhs = SymbolRef("v", [])

    // 创建 AssignExpr 实例
    let assignExpr = AssignExpr(
        assignOpKind, 
        lhs, 
        rhs
    )

    let nodes: Array<SyntaxTreeNode> = [assignExpr]

    // 创建 Block 实例
    let block = Block(
        nodes
    )

    // 创建 PropGetterOrSetter 实例
    let propSetter = PropGetterOrSetter(
        block,
        Some("v"),
        false
    )

    println("propSetter: ${propSetter}")
}

运行结果:

propSetter: set(v) {
    variable_ = v
}

func getGetKeyWordPos()

public func getGetKeyWordPos(): Option<CodePositionRange>

功能:获取 PropGetterOrSetter 节点中 get 关键字的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回 get 关键字的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main() {
    let assignOpKind = AssignOpKind.Assign
    let lhs = SymbolRef("variable_", [])
    let rhs = SymbolRef("v", [])

    // 创建 AssignExpr 实例
    let assignExpr = AssignExpr(
        assignOpKind, 
        lhs, 
        rhs
    )

    let nodes: Array<SyntaxTreeNode> = [assignExpr]

    // 创建 Block 实例
    let block = Block(
        nodes
    )

    // 创建 PropGetterOrSetter 实例
    let propGetter = PropGetterOrSetter(
        block,
        None, 
        true
    )

    if (let Some(pos) <- propGetter.getGetKeyWordPos()) {
        // 输出 get 关键字位置
        println("propGetter.getGetKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

propGetter.getGetKeyWordPos(): 1:1-1:4

func getIdentifierPos()

public func getIdentifierPos(): Option<CodePositionRange>

功能:获取 PropGetterOrSetter 节点中标识符的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回标识符的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main() {
    let assignOpKind = AssignOpKind.Assign
    let lhs = SymbolRef("variable_", [])
    let rhs = SymbolRef("v", [])

    // 创建 AssignExpr 实例
    let assignExpr = AssignExpr(
        assignOpKind, 
        lhs, 
        rhs
    )

    let nodes: Array<SyntaxTreeNode> = [assignExpr]

    // 创建 Block 实例
    let block = Block(
        nodes
    )

    // 创建 PropGetterOrSetter 实例
    let propSetter = PropGetterOrSetter(
        block,
        Some("v"),
        false
    )

    if (let Some(pos) <- propSetter.getIdentifierPos()) {
        // 输出 setter 中标识符位置
        println("propSetter.getIdentifierPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

propSetter.getIdentifierPos(): 1:5-1:6

func getLParenPos()

public func getLParenPos(): CodePositionRange

功能:获取 PropGetterOrSetter 节点中 ( 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let assignOpKind = AssignOpKind.Assign
    let lhs = SymbolRef("variable_", [])
    let rhs = SymbolRef("v", [])

    // 创建 AssignExpr 实例
    let assignExpr = AssignExpr(
        assignOpKind, 
        lhs, 
        rhs
    )

    let nodes: Array<SyntaxTreeNode> = [assignExpr]

    // 创建 Block 实例
    let block = Block(
        nodes
    )

    // 创建 PropGetterOrSetter 实例
    let propSetter = PropGetterOrSetter(
        block,
        Some("v"),
        false
    )

    let pos = propSetter.getLParenPos()
    // 输出 ( 位置
    println("propSetter.getLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

propSetter.getLParenPos(): 1:4-1:5

func getRParenPos()

public func getRParenPos(): CodePositionRange

功能:获取 PropGetterOrSetter 节点中 ) 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let assignOpKind = AssignOpKind.Assign
    let lhs = SymbolRef("variable_", [])
    let rhs = SymbolRef("v", [])

    // 创建 AssignExpr 实例
    let assignExpr = AssignExpr(
        assignOpKind, 
        lhs, 
        rhs
    )

    let nodes: Array<SyntaxTreeNode> = [assignExpr]

    // 创建 Block 实例
    let block = Block(
        nodes
    )

    // 创建 PropGetterOrSetter 实例
    let propSetter = PropGetterOrSetter(
        block,
        Some("v"),
        false
    )

    let pos = propSetter.getRParenPos()
    // 输出 ) 位置
    println("propSetter.getRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

propSetter.getRParenPos(): 1:6-1:7

func getSetKeyWordPos()

public func getSetKeyWordPos(): Option<CodePositionRange>

功能:获取 PropGetterOrSetter 节点中 set 关键字的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回 set 关键字的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main() {
    let assignOpKind = AssignOpKind.Assign
    let lhs = SymbolRef("variable_", [])
    let rhs = SymbolRef("v", [])

    // 创建 AssignExpr 实例
    let assignExpr = AssignExpr(
        assignOpKind, 
        lhs, 
        rhs
    )

    let nodes: Array<SyntaxTreeNode> = [assignExpr]

    // 创建 Block 实例
    let block = Block(
        nodes
    )

    // 创建 PropGetterOrSetter 实例
    let propSetter = PropGetterOrSetter(
        block,
        Some("v"),
        false
    )

    if (let Some(pos) <- propSetter.getSetKeyWordPos()) {
        // 输出 set 关键字位置
        println("propSetter.getSetKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

propSetter.getSetKeyWordPos(): 1:1-1:4

class QuoteExpr

public class QuoteExpr <: Expr {
    public init(tokensOrRefExpr: Array<QuoteExprContent>, comments!: Array<Comment> = [])
}

功能:表示 quote 表达式节点。

一个 QuoteExpr 节点: quote(var ident = 0)

父类型:

prop tokensOrRefExpr

public prop tokensOrRefExpr: Array<QuoteExprContent>

功能:获取 QuoteExpr 中由 () 括起的内部引用表达式或 QuoteToken 节点。

类型:Array<QuoteExprContent>

init(Array<QuoteExprContent>, Array<Comment>)

public init(tokensOrRefExpr: Array<QuoteExprContent>, comments!: Array<Comment> = [])

功能:构造一个 QuoteExpr 对象,表示引用表达式,如 quote( ... ),内部可混合 Tokens 和插值表达式。

参数:

  • tokensOrRefExpr: Array<QuoteExprContent> - 引用内容列表。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建 QuoteToken 实例
    let quoteToken = QuoteToken(quote(hello world))

    // 创建 QuoteExpr 实例
    let quoteExpr = QuoteExpr(
        QuoteExprContent.TokenPart(quoteToken)
    )

    println("quoteExpr: ${quoteExpr}")
}

运行结果:

quoteExpr: quote(hello world)

func getLParenPos()

public func getLParenPos(): CodePositionRange

功能:获取当前 QuoteExpr( 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 QuoteToken 实例
    let quoteToken = QuoteToken(quote(hello world))

    // 创建 QuoteExpr 实例
    let quoteExpr = QuoteExpr(
        QuoteExprContent.TokenPart(quoteToken)
    )
    
    let pos = quoteExpr.getLParenPos()
    // 输出 ( 位置
    println("quoteExpr.getLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

quoteExpr.getLParenPos(): 1:6-1:7

func getQuoteKeyWordPos()

public func getQuoteKeyWordPos(): CodePositionRange

功能:获取当前 QuoteExprquote 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 QuoteToken 实例
    let quoteToken = QuoteToken(quote(hello world))

    // 创建 QuoteExpr 实例
    let quoteExpr = QuoteExpr(
        QuoteExprContent.TokenPart(quoteToken)
    )
    
    let pos = quoteExpr.getQuoteKeyWordPos()
    // 输出 quote 关键字位置
    println("quoteExpr.getQuoteKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

quoteExpr.getQuoteKeyWordPos(): 1:1-1:6

func getRParenPos()

public func getRParenPos(): CodePositionRange

功能:获取当前 QuoteExpr) 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 QuoteToken 实例
    let quoteToken = QuoteToken(quote(hello world))

    // 创建 QuoteExpr 实例
    let quoteExpr = QuoteExpr(
        QuoteExprContent.TokenPart(quoteToken)
    )
    
    let pos = quoteExpr.getRParenPos()
    // 输出 ) 位置
    println("quoteExpr.getRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

quoteExpr.getRParenPos(): 1:18-1:19

class QuoteInterpolationExpr

public class QuoteInterpolationExpr <: Expr {
    public init(expr: Expr, hasParen!: Bool = false, comments!: Array<Comment> = [])
}

功能:表示 QuoteExpr 中由 () 括起的内部引用表达式, 例如 $(A.a)$a

父类型:

prop expr

public prop expr: Expr

功能:获取 QuoteInterpolationExpr 中被引用的表达式。

类型:Expr

init(Expr, Bool, Array<Comment>)

public init(expr: Expr, hasParen!: Bool = false, comments!: Array<Comment> = [])

功能:构造一个 QuoteInterpolationExpr 对象,表示 quote 中的插值表达式。

参数:

  • expr: Expr - 被插值的表达式。
  • hasParen!: Bool - 是否带有括号,默认为 false
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    let symbolRef = SymbolRef("a", [])

    // 创建 QuoteInterpolationExpr 实例
    let quoteInterpolationExpr = QuoteInterpolationExpr(
        symbolRef,
        hasParen: false
    )

    println("quoteInterpolationExpr: ${quoteInterpolationExpr}")
}

运行结果:

quoteInterpolationExpr: $a

func getDollarPos()

public func getDollarPos(): CodePositionRange

功能:获取当前 QuoteInterpolationExpr$ 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let symbolRef = SymbolRef("a", [])

    // 创建 QuoteInterpolationExpr 实例
    let quoteInterpolationExpr = QuoteInterpolationExpr(
        symbolRef,
        hasParen: false
    )
    
    let pos = quoteInterpolationExpr.getDollarPos()
    // 输出 $ 位置
    println("quoteInterpolationExpr.getDollarPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

quoteInterpolationExpr.getDollarPos(): 1:1-1:2

func getLParenPos()

public func getLParenPos(): Option<CodePositionRange>

功能:获取当前 QuoteInterpolationExpr( 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main() {
    let symbolRef = SymbolRef("a", [])

    // 创建 QuoteInterpolationExpr 实例
    let quoteInterpolationExpr = QuoteInterpolationExpr(
        symbolRef,
        hasParen: true
    )
    
    if (let Some(pos) <- quoteInterpolationExpr.getLParenPos()) {
        // 输出 ( 位置
        println("quoteInterpolationExpr.getLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

quoteInterpolationExpr.getLParenPos(): 1:2-1:3

func getRParenPos()

public func getRParenPos(): Option<CodePositionRange>

功能:获取当前 QuoteInterpolationExpr) 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main() {
    let symbolRef = SymbolRef("a", [])

    // 创建 QuoteInterpolationExpr 实例
    let quoteInterpolationExpr = QuoteInterpolationExpr(
        symbolRef,
        hasParen: true
    )
    
    if (let Some(pos) <- quoteInterpolationExpr.getRParenPos()) {
        // 输出 ) 位置
        println("quoteInterpolationExpr.getRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

quoteInterpolationExpr.getRParenPos(): 1:4-1:5

class QuoteToken

public class QuoteToken <: SyntaxTreeNode {
    public init(content: Tokens, comments!: Array<Comment> = [])
}

功能:表示 quote 表达式节点内任意合法的 token

父类型:

prop content

public prop content: Tokens

功能:获取 QuoteToken 内的 Tokens。

类型:Tokens

init(Tokens, Array<Comment>)

public init(content: Tokens, comments!: Array<Comment> = [])

功能:构造一个 QuoteToken 对象,表示 quote 表达式节点内任意合法的 token

参数:

  • content: Tokens - 被引用的标记序列,会被格式化。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当格式化过程中内存分配失败时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    let tokens = quote(hello world)
    
    // 创建 QuoteToken 实例
    let quoteToken = QuoteToken(tokens)

    println("quoteToken: ${quoteToken}")
}

运行结果:

quoteToken: hello world

class RangeExpr

public class RangeExpr <: Expr {
    public init(start: Option<Expr>, kind: RangeKind, end: Option<Expr>, step: Option<Expr>, comments!: Array<Comment> = [])
}

功能:表示包含区间操作符的表达式。

RangeExpr 节点:存在两种 Range 操作符:....=,分别用于创建左闭右开和左闭右闭的 Range 实例。它们的使用方式分别为 start..end:stepstart..=end:step

父类型:

prop end

public prop end: Option<Expr>

功能:获取 RangeExpr 中的终止值。

类型:Option<Expr>

prop kind

public prop kind: RangeKind

功能:获取 RangeExpr 的类型。

类型:RangeKind

prop start

public prop start: Option<Expr>

功能:获取 RangeExpr 中的起始值。

类型:Option<Expr>

prop step

public prop step: Option<Expr>

功能:获取 RangeExpr 中的步长表达式。

类型:Option<Expr>

init(Option<Expr>, RangeKind, Option<Expr>, Option<Expr>, Array<Comment>)

public init(start: Option<Expr>, kind: RangeKind, end: Option<Expr>, step: Option<Expr>, comments!: Array<Comment> = [])

功能:构造一个 RangeExpr 对象,表示区间表达式,如 1..101..=10

参数:

  • start: Option<Expr> - 区间起始表达式。
  • kind: RangeKind - 区间类型(开区间或闭区间)。
  • end: Option<Expr> - 区间结束表达式。
  • step: Option<Expr> - 可选的步长表达式。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    let kind = LitConstKind.IntergerLiteral
    let rawValue0 = "1"
    let rawValue1 = "100"
    let rawValue2 = "2"

    // 创建 LitConstExpr 实例
    let litConstExpr0 = LitConstExpr(
        kind, 
        rawValue0
    )
    let litConstExpr1 = LitConstExpr(
        kind, 
        rawValue1
    )
    let litConstExpr2 = LitConstExpr(
        kind, 
        rawValue2
    )

    let rangeKind = RangeKind.ClosedRangeOp

    // 创建 RangeExpr 实例
    let rangeExpr = RangeExpr(
        litConstExpr0,
        rangeKind,
        litConstExpr1,
        litConstExpr2
    )

    println("rangeExpr: ${rangeExpr}")
}

运行结果:

rangeExpr: 1..=100 : 2

func getColonPos()

public func getColonPos(): Option<CodePositionRange>

功能:获取 : 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main() {
    let kind = LitConstKind.IntergerLiteral
    let rawValue0 = "1"
    let rawValue1 = "100"
    let rawValue2 = "2"

    // 创建 LitConstExpr 实例
    let litConstExpr0 = LitConstExpr(
        kind, 
        rawValue0
    )
    let litConstExpr1 = LitConstExpr(
        kind, 
        rawValue1
    )
    let litConstExpr2 = LitConstExpr(
        kind, 
        rawValue2
    )

    let rangeKind = RangeKind.ClosedRangeOp

    // 创建 RangeExpr 实例
    let rangeExpr = RangeExpr(
        litConstExpr0,
        rangeKind,
        litConstExpr1,
        litConstExpr2
    )

    if (let Some(pos) <- rangeExpr.getColonPos()) {
        // 输出 : 位置
        println("rangeExpr.getColonPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

rangeExpr.getColonPos(): 1:9-1:10

func getRangeOpPos()

public func getRangeOpPos(): CodePositionRange

功能:获取 ....= 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let kind = LitConstKind.IntergerLiteral
    let rawValue0 = "1"
    let rawValue1 = "100"
    let rawValue2 = "2"

    // 创建 LitConstExpr 实例
    let litConstExpr0 = LitConstExpr(
        kind, 
        rawValue0
    )
    let litConstExpr1 = LitConstExpr(
        kind, 
        rawValue1
    )
    let litConstExpr2 = LitConstExpr(
        kind, 
        rawValue2
    )

    let rangeKind = RangeKind.ClosedRangeOp

    // 创建 RangeExpr 实例
    let rangeExpr = RangeExpr(
        litConstExpr0,
        rangeKind,
        litConstExpr1,
        litConstExpr2
    )

    let pos = rangeExpr.getRangeOpPos()
    // 输出 .. 位置
    println("rangeExpr.getRangeOpPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

rangeExpr.getRangeOpPos(): 1:2-1:5

class ReturnExpr

public class ReturnExpr <: Expr {
    public init(retVal: Option<Expr>, comments!: Array<Comment> = [])
}

功能:表示 return 表达式节点。

一个 ReturnExpr 节点:return 1

父类型:

prop retVal

public prop retVal: Option<Expr>

功能:获取当前 return 语句的返回值表达式(若不存在返回 None)。

类型:Option<Expr>

init(Option<Expr>, Array<Comment>)

public init(retVal: Option<Expr>, comments!: Array<Comment> = [])

功能:构造一个 ReturnExpr 对象,表示 return 表达式,可带返回值。

参数:

  • retVal: Option<Expr> - 可选的返回值表达式。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    let kind = LitConstKind.FloatLiteral
    let rawValue = "3.14"

    // 创建 LitConstExpr 实例
    let litConstExpr = LitConstExpr(
        kind, 
        rawValue
    )

    // 创建 ReturnExpr 实例
    let returnExpr = ReturnExpr(
        Some(litConstExpr)
    )

    println("returnExpr: ${returnExpr}")
}

运行结果:

returnExpr: return 3.14

func getReturnKeyWordPos()

public func getReturnKeyWordPos(): CodePositionRange

功能:获取 return 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let kind = LitConstKind.FloatLiteral
    let rawValue = "3.14"

    // 创建 LitConstExpr 实例
    let litConstExpr = LitConstExpr(
        kind, 
        rawValue
    )

    // 创建 ReturnExpr 实例
    let returnExpr = ReturnExpr(
        Some(litConstExpr)
    )
    
    let pos = returnExpr.getReturnKeyWordPos()
    // 输出 return 关键字位置
    println("returnExpr.getReturnKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

returnExpr.getReturnKeyWordPos(): 1:1-1:7

class SourceFile

public class SourceFile <: SyntaxTreeNode {
    public init(importLists: Array<ImportList>, name: String, path: String, pkgHeader: Option<PackageHeader>, topLevelDecls: Array<Decl>,
        ftrDirective!: Option<FeaturesDirective> = None, comments!: Array<Comment> = [])
}

功能:表示单个仓颉源码文件的语法树节点。

一个仓颉源码文件节点主要包括包声明节点,包导入节点和 TopLevel 作用域内的所有声明节点。

父类型:

prop ftrDirective

public prop ftrDirective: Option<FeaturesDirective> 

功能:在源码文件节点中找到 FeaturesDirective 节点。

类型: Option<FeaturesDirective>

prop importLists

public prop importLists: Array<ImportList>

功能:获取仓颉源码文件中包导入节点 ImportList 的列表。

类型:Array<ImportList>

prop name

public prop name: String

功能:获取仓颉源码文件的名称。

类型:String

prop path

public prop path: String

功能:获取仓颉源码文件的绝对路径。

类型:String

prop pkgHeader

public prop pkgHeader: Option<PackageHeader>

功能:获取仓颉源码文件中包的声明节点 PackageHeader

类型:Option<PackageHeader>

prop topLevelDecls

public prop topLevelDecls: Array<Decl>

功能:获取仓颉源码文件中 TopLevel 作用域内声明的声明节点列表。

类型:Array<Decl>

init(Array<ImportList>, String, String, Option<PackageHeader>, Array<Decl>, Option<FeaturesDirective>, Array<Comment>)

public init(importLists: Array<ImportList>, name: String, path: String, pkgHeader: Option<PackageHeader>, topLevelDecls: Array<Decl>,
    ftrDirective!: Option<FeaturesDirective> = None, comments!: Array<Comment> = [])

功能:构造一个 SourceFile 对象,表示语法树中的源文件节点。

参数:

  • importLists: Array<ImportList> - 导入列表。
  • name: String - 源文件名。
  • path: String - 源文件路径。
  • pkgHeader: Option<PackageHeader> - 包声明头,可选。
  • topLevelDecls: Array<Decl> - 顶层声明列表。
  • ftrDirective!: Option<FeaturesDirective> - 特性指令,默认为 None
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 name 不符合仓颉标识符规范时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    let contents = ImportSingle(["pkg"], "a")

    // 创建 ImportList 实例
    let importList = ImportList(
        contents, 
        None
    )

    let isMacroPkg = false
    let packageNameIdentifiers = ["A"]

    // 创建 PackageHeader 实例
    let packageHeader = PackageHeader(
        None, 
        isMacroPkg,
        packageNameIdentifiers
    )

    let body = Block([ReturnExpr(None)])
    let params = ParameterList([])
    let retTyAnnotation = AtomicType(UnitType)

    // 创建 MainDecl 实例
    let mainDecl = MainDecl(
        body, 
        params, 
        retTyAnnotation
    )

    let name = "sourceFile.cj"
    let path = "/path/to/sourceFile.cj"

    // 创建 SourceFile 实例
    let sourceFile = SourceFile(
        [importList],
        name,
        path,
        Some(packageHeader),
        [mainDecl]
    )

    println("sourceFile: ${sourceFile}")
}

运行结果:

sourceFile: package A
import pkg.a
main(): Unit {
    return
}

class SpawnExpr

public class SpawnExpr <: Expr {
    public init(threadContext: Option<Expr>, trailingLambdaExpr: Lambda, comments!: Array<Comment> = [])
}

功能:表示 Spawn 表达式。

一个 SpawnExpr 节点由 spawn 关键字和一个不包含形参的闭包组成,例如:spawn { add(1, 2) }

父类型:

prop threadContext

public prop threadContext: Option<Expr>

功能:获取当前 Spawn 语句的线程执行上下文(若不存在返回 None)。

类型:Option<Expr>

prop trailingLambdaExpr

public prop trailingLambdaExpr: Lambda

功能:获取当前 Spawn 语句的线程执行代码块。

类型:Lambda

init(Option<Expr>, Lambda, Array<Comment>)

public init(threadContext: Option<Expr>, trailingLambdaExpr: Lambda, comments!: Array<Comment> = [])

功能:构造一个 SpawnExpr 对象,表示 spawn 表达式,用于创建线程。

参数:

  • threadContext: Option<Expr> - 可选的线程上下文表达式。
  • trailingLambdaExpr: Lambda - 线程体 lambda 表达式。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建 LitConstExpr 实例
    let litConstExpr = LitConstExpr(
        LitConstKind.FloatLiteral, 
        "3.14"
    )

    // 创建 Lambda 实例
    let lambda = Lambda(
        [litConstExpr],
        ParameterList([], hasParen: false)
    )

    let symbolRef = SymbolRef("context", [])

    // 创建 SpawnExpr 实例
    let spawnExpr = SpawnExpr(
        Some(symbolRef),
        lambda
    )

    println("spawnExpr: ${spawnExpr}")
}

运行结果:

spawnExpr: spawn (context) {  => 3.14 }

func getSpawnKeyWordPos()

public func getSpawnKeyWordPos(): CodePositionRange

功能:获取 SpawnExpr 节点中 spawn 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 LitConstExpr 实例
    let litConstExpr = LitConstExpr(
        LitConstKind.FloatLiteral, 
        "3.14"
    )

    // 创建 Lambda 实例
    let lambda = Lambda(
        [litConstExpr],
        ParameterList([], hasParen: false)
    )

    let symbolRef = SymbolRef("context", [])

    // 创建 SpawnExpr 实例
    let spawnExpr = SpawnExpr(
        Some(symbolRef),
        lambda
    )
    
    let pos = spawnExpr.getSpawnKeyWordPos()
    // 输出 spawn 关键字位置
    println("spawnExpr.getSpawnKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

spawnExpr.getSpawnKeyWordPos(): 1:1-1:6

func getThreadContextLParenPos()

public func getThreadContextLParenPos(): Option<CodePositionRange>

功能:获取 SpawnExpr 节点中线程上下文的 ( 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 LitConstExpr 实例
    let litConstExpr = LitConstExpr(
        LitConstKind.FloatLiteral, 
        "3.14"
    )

    // 创建 Lambda 实例
    let lambda = Lambda(
        [litConstExpr],
        ParameterList([], hasParen: false)
    )

    let symbolRef = SymbolRef("context", [])

    // 创建 SpawnExpr 实例
    let spawnExpr = SpawnExpr(
        Some(symbolRef),
        lambda
    )
    
    if (let Some(pos) <- spawnExpr.getThreadContextLParenPos()) {
        // 输出线程上下文参数 ( 位置
        println("spawnExpr.getThreadContextLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

spawnExpr.getThreadContextLParenPos(): 1:7-1:8

func getThreadContextRParenPos()

public func getThreadContextRParenPos(): Option<CodePositionRange>

功能:获取 SpawnExpr 节点中线程上下文的 ) 的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回线程上下文的 ) 的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main() {
    // 创建 LitConstExpr 实例
    let litConstExpr = LitConstExpr(
        LitConstKind.FloatLiteral, 
        "3.14"
    )

    // 创建 Lambda 实例
    let lambda = Lambda(
        [litConstExpr],
        ParameterList([], hasParen: false)
    )

    let symbolRef = SymbolRef("context", [])

    // 创建 SpawnExpr 实例
    let spawnExpr = SpawnExpr(
        Some(symbolRef),
        lambda
    )
    
    if (let Some(pos) <- spawnExpr.getThreadContextRParenPos()) {
        // 输出线程上下文参数 ) 位置
        println("spawnExpr.getThreadContextRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

spawnExpr.getThreadContextRParenPos(): 1:15-1:16

class StaticInit

public class StaticInit <: Decl {
    public init(body: Block, comments!: Array<Comment> = [])
}

功能:表示一个静态初始化器。

父类型:

prop body

public prop body: Block

功能:获取当前静态初始化器的主体部分。

类型:Block

init(Block, Array<Comment>)

public init(body: Block, comments!: Array<Comment> = [])

功能:构造一个 StaticInit 对象,表示静态初始化器节点。

参数:

  • body: Block - 静态初始化代码块。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    let assignOpKind = AssignOpKind.Assign
    let lhs = SymbolRef("variable_", [])
    let rhs = LitConstExpr(LitConstKind.FloatLiteral, "3.14")

    // 创建 AssignExpr 实例
    let assignExpr = AssignExpr(
        assignOpKind, 
        lhs, 
        rhs
    )

    // 创建 Block 实例
    let block = Block([assignExpr])

    // 创建 StaticInit 实例
    let staticInit = StaticInit(block)

    println("staticInit: ${staticInit}")
}

运行结果:

staticInit: static init() {
    variable_ = 3.14
}

func getInitKeyWordPos()

public func getInitKeyWordPos(): CodePositionRange

功能:获取 StaticInit 节点中 init 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let assignOpKind = AssignOpKind.Assign
    let lhs = SymbolRef("variable_", [])
    let rhs = LitConstExpr(LitConstKind.FloatLiteral, "3.14")

    // 创建 AssignExpr 实例
    let assignExpr = AssignExpr(
        assignOpKind, 
        lhs, 
        rhs
    )

    // 创建 Block 实例
    let block = Block([assignExpr])

    // 创建 StaticInit 实例
    let staticInit = StaticInit(block)
    
    let pos = staticInit.getInitKeyWordPos()
    // 输出 init 关键字位置
    println("staticInit.getInitKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

staticInit.getInitKeyWordPos(): 1:8-1:12

func getParamsLParenPos()

public func getParamsLParenPos(): CodePositionRange

功能:获取 StaticInit 节点中参数左括号的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let assignOpKind = AssignOpKind.Assign
    let lhs = SymbolRef("variable_", [])
    let rhs = LitConstExpr(LitConstKind.FloatLiteral, "3.14")

    // 创建 AssignExpr 实例
    let assignExpr = AssignExpr(
        assignOpKind, 
        lhs, 
        rhs
    )

    // 创建 Block 实例
    let block = Block([assignExpr])

    // 创建 StaticInit 实例
    let staticInit = StaticInit(block)
    
    let pos = staticInit.getParamsLParenPos()
    // 输出 ( 位置
    println("staticInit.getParamsLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

staticInit.getParamsLParenPos(): 1:12-1:13

func getParamsRParenPos()

public func getParamsRParenPos(): CodePositionRange

功能:获取 StaticInit 节点中参数右括号的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let assignOpKind = AssignOpKind.Assign
    let lhs = SymbolRef("variable_", [])
    let rhs = LitConstExpr(LitConstKind.FloatLiteral, "3.14")

    // 创建 AssignExpr 实例
    let assignExpr = AssignExpr(
        assignOpKind, 
        lhs, 
        rhs
    )

    // 创建 Block 实例
    let block = Block([assignExpr])

    // 创建 StaticInit 实例
    let staticInit = StaticInit(block)
    
    let pos = staticInit.getParamsRParenPos()
    // 输出 ) 位置
    println("staticInit.getParamsRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

staticInit.getParamsRParenPos(): 1:13-1:14

func getStaticKeyWordPos()

public func getStaticKeyWordPos(): CodePositionRange

功能:获取 StaticInit 节点中 static 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let assignOpKind = AssignOpKind.Assign
    let lhs = SymbolRef("variable_", [])
    let rhs = LitConstExpr(LitConstKind.FloatLiteral, "3.14")

    // 创建 AssignExpr 实例
    let assignExpr = AssignExpr(
        assignOpKind, 
        lhs, 
        rhs
    )

    // 创建 Block 实例
    let block = Block([assignExpr])

    // 创建 StaticInit 实例
    let staticInit = StaticInit(block)
    
    let pos = staticInit.getStaticKeyWordPos()
    // 输出 static 关键字位置
    println("staticInit.getStaticKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

staticInit.getStaticKeyWordPos(): 1:1-1:7

class StrInterpolationContent

public class StrInterpolationContent <: SyntaxTreeNode {
    public init(interpolationBlock: Block, comments!: Array<Comment> = [])
}

功能:表示字符串插值内容的节点。

一个 StrInterpolationContent 节点:prop str = "hello ${str}" 中的 ${str}

父类型:

prop interpolationBlock

public prop interpolationBlock: Block

功能:获取当前字符串插值内容的插值块。

类型:Block

init(Block, Array<Comment>)

public init(interpolationBlock: Block, comments!: Array<Comment> = [])

功能:构造一个 StrInterpolationContent 对象,表示字符串插值内容。

参数:

  • interpolationBlock: Block - 插值代码块。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建 interpolationBlock
    let interpolationBlock = Block(SymbolRef("str", []))

    // 创建 StrInterpolationContent 实例
    let strInterpolationContent = StrInterpolationContent(interpolationBlock)

    println("strInterpolationContent: ${strInterpolationContent}")
}

运行结果:

strInterpolationContent: ${str}

func getDollarPos()

public func getDollarPos(): CodePositionRange

功能:获取 StrInterpolationContent 节点中 $ 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 interpolationBlock
    let interpolationBlock = Block(SymbolRef("str", []))

    // 创建 StrInterpolationContent 实例
    let strInterpolationContent = StrInterpolationContent(interpolationBlock)
    let pos = strInterpolationContent.getDollarPos()

    // 输出 $ 关键字位置
    println("strInterpolationContent.getDollarPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

strInterpolationContent.getDollarPos(): 1:1-1:2

class StructDecl

public class StructDecl <: Decl {
    public init(body: Body, genericConstraints: Option<GenericConstraints>, genericParams: Array<GenericParam>,
        name: String, superTyAnnotations: Array<TypeAnnotation>, annotations!: Array<Annotation> = [],
        modifiers!: Array<Modifier> = [], comments!: Array<Comment> = [])
}

功能:表示一个 Struct 声明节点。

Struct 的声明使用 struct 关键字,声明依次为:可缺省的修饰符、struct 关键字、struct 名、可选的类型参数、是否指定父接口、可选的泛型约束、struct 体的声明。

父类型:

prop body

public prop body: Body

功能:获取当前结构体声明的主体部分。

类型:Body

prop genericConstraints

public prop genericConstraints: Option<GenericConstraints>

功能:获取当前结构体声明的泛型约束(若不存在返回 None)。

类型:Option<GenericConstraints>

prop genericParams

public prop genericParams: Array<GenericParam>

功能:获取当前结构体声明的泛型参数列表。

类型:Array<GenericParam>

prop name

public prop name: String

功能:获取当前结构体声明的名称。

类型:String

prop superTyAnnotations

public prop superTyAnnotations: Array<TypeAnnotation>

功能:获取当前结构体声明的父类类型标注列表。

类型:Array<TypeAnnotation>

init(Body, Option<GenericConstraints>, Array<GenericParam>, String, Array<TypeAnnotation>, Array<Annotation>, Array<Modifier>, Array<Comment>)

public init(body: Body, genericConstraints: Option<GenericConstraints>, genericParams: Array<GenericParam>,
    name: String, superTyAnnotations: Array<TypeAnnotation>, annotations!: Array<Annotation> = [],
    modifiers!: Array<Modifier> = [], comments!: Array<Comment> = [])

功能:构造一个 StructDecl 对象,表示结构体声明节点。

参数:

  • body: Body - 结构体,包含各类声明。
  • genericConstraints: Option<GenericConstraints> - 可选的泛型约束。
  • genericParams: Array<GenericParam> - 泛型参数列表。
  • name: String - 结构体名。
  • superTyAnnotations: Array<TypeAnnotation> - 父类类型标注列表。
  • annotations!: Array<Annotation> - 附加的注解列表,默认为空数组。
  • modifiers!: Array<Modifier> - 修饰符列表,默认为空数组。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 body 中有除静态初始化器、函数声明、变量声明、宏展开声明和属性声明外的声明,或泛型约束与泛型参数不对应,或输入的 name 不符合仓颉标识符规范时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 body
    let body = Body([])
    
    // 创建 genericConstraints
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])
    
    // 创建 genericParams
    let genericParams = [GenericParam("T")]
    
    // 创建 name
    let name = "A"
    
    // 创建 superTyAnnotations
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    
    // 创建 annotations
    let annotations = [Annotation([Argument(None, false, LitConstExpr(LitConstKind.IntergerLiteral, "123"))], "MyAnno", AtOpKind.At)]
    
    // 创建 modifiers
    let modifiers = [Modifier(ModifierKind.Public)]
    
    // 创建 StructDecl 实例
    let structDecl = StructDecl(
        body, 
        genericConstraints, 
        genericParams, 
        name, 
        superTyAnnotations, 
        annotations: annotations, 
        modifiers: modifiers
    )

    println("structDecl: ${structDecl}")
}

运行结果:

structDecl: @MyAnno[123]
public struct A<T> <: I1 where T<:I1 {
}

func getGenericParamsCommasPos()

public func getGenericParamsCommasPos(): Array<CodePositionRange>

功能:获取 StructDecl 节点中泛型参数中 , 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 body
    let body = Body([])
    
    // 创建 genericConstraints
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])
    
    // 创建 genericParams
    let genericParams = [GenericParam("T"), GenericParam("U")]
    
    // 创建 name
    let name = "A"
    
    // 创建 superTyAnnotations
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    
    // 创建 annotations
    let annotations = [Annotation([Argument(None, false, LitConstExpr(LitConstKind.IntergerLiteral, "123"))], "MyAnno", AtOpKind.At)]
    
    // 创建 modifiers
    let modifiers = [Modifier(ModifierKind.Public)]
    
    // 创建 StructDecl 实例
    let structDecl = StructDecl(
        body, 
        genericConstraints, 
        genericParams, 
        name, 
        superTyAnnotations, 
        annotations: annotations, 
        modifiers: modifiers
    )

    let pos = structDecl.getGenericParamsCommasPos()
    // 遍历输出泛型参数中逗号位置
    for (i in 0..pos.size) {
        println("structDecl.getGenericParamsCommasPos()[${i}]: ${pos[i].beginLine}:${pos[i].beginColumn}-${pos[i].endLine}:${pos[i].endColumn}")
    }
}

运行结果:

structDecl.getGenericParamsCommasPos()[0]: 2:18-2:19

func getGenericParamsLAnglePos()

public func getGenericParamsLAnglePos(): Option<CodePositionRange>

功能:获取 StructDecl 节点中泛型参数的 < 的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回泛型参数的 < 的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main() {
    // 创建 body
    let body = Body([])
    
    // 创建 genericConstraints
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])
    
    // 创建 genericParams
    let genericParams = [GenericParam("T")]
    
    // 创建 name
    let name = "A"
    
    // 创建 superTyAnnotations
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    
    // 创建 annotations
    let annotations = [Annotation([Argument(None, false, LitConstExpr(LitConstKind.IntergerLiteral, "123"))], "MyAnno", AtOpKind.At)]
    
    // 创建 modifiers
    let modifiers = [Modifier(ModifierKind.Public)]
    
    // 创建 StructDecl 实例
    let structDecl = StructDecl(
        body, 
        genericConstraints, 
        genericParams, 
        name, 
        superTyAnnotations, 
        annotations: annotations, 
        modifiers: modifiers
    )

    if (let Some(pos) <- structDecl.getGenericParamsLAnglePos()) {
        // 输出泛型参数 < 位置
        println("structDecl.getGenericParamsLAnglePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

structDecl.getGenericParamsLAnglePos(): 2:16-2:17

func getGenericParamsRAnglePos()

public func getGenericParamsRAnglePos(): Option<CodePositionRange>

功能:获取 StructDecl 节点中泛型参数的 > 的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回泛型参数的 > 的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main() {
    // 创建 body
    let body = Body([])
    
    // 创建 genericConstraints
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])
    
    // 创建 genericParams
    let genericParams = [GenericParam("T")]
    
    // 创建 name
    let name = "A"
    
    // 创建 superTyAnnotations
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    
    // 创建 annotations
    let annotations = [Annotation([Argument(None, false, LitConstExpr(LitConstKind.IntergerLiteral, "123"))], "MyAnno", AtOpKind.At)]
    
    // 创建 modifiers
    let modifiers = [Modifier(ModifierKind.Public)]
    
    // 创建 StructDecl 实例
    let structDecl = StructDecl(
        body, 
        genericConstraints, 
        genericParams, 
        name, 
        superTyAnnotations, 
        annotations: annotations, 
        modifiers: modifiers
    )

    if (let Some(pos) <- structDecl.getGenericParamsRAnglePos()) {
        // 输出泛型参数 > 位置
        println("structDecl.getGenericParamsRAnglePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

structDecl.getGenericParamsRAnglePos(): 2:18-2:19

func getIdentifierPos()

public func getIdentifierPos(): CodePositionRange

功能:获取 StructDecl 节点中标识符的位置。

返回值:

  • CodePositionRange - 返回泛型参数的 < 的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main() {
    // 创建 body
    let body = Body([])
    
    // 创建 genericConstraints
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])
    
    // 创建 genericParams
    let genericParams = [GenericParam("T")]
    
    // 创建 name
    let name = "A"
    
    // 创建 superTyAnnotations
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    
    // 创建 annotations
    let annotations = [Annotation([Argument(None, false, LitConstExpr(LitConstKind.IntergerLiteral, "123"))], "MyAnno", AtOpKind.At)]
    
    // 创建 modifiers
    let modifiers = [Modifier(ModifierKind.Public)]
    
    // 创建 StructDecl 实例
    let structDecl = StructDecl(
        body, 
        genericConstraints, 
        genericParams, 
        name, 
        superTyAnnotations, 
        annotations: annotations, 
        modifiers: modifiers
    )

    let pos = structDecl.getIdentifierPos()
    // 获取标识符位置
    println("structDecl.getIdentifierPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

structDecl.getIdentifierPos(): 2:15-2:16

func getStructKeyWordPos()

public func getStructKeyWordPos(): CodePositionRange

功能:获取 StructDecl 节点中 struct 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 body
    let body = Body([])
    
    // 创建 genericConstraints
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])
    
    // 创建 genericParams
    let genericParams = [GenericParam("T")]
    
    // 创建 name
    let name = "A"
    
    // 创建 superTyAnnotations
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    
    // 创建 annotations
    let annotations = [Annotation([Argument(None, false, LitConstExpr(LitConstKind.IntergerLiteral, "123"))], "MyAnno", AtOpKind.At)]
    
    // 创建 modifiers
    let modifiers = [Modifier(ModifierKind.Public)]
    
    // 创建 StructDecl 实例
    let structDecl = StructDecl(
        body, 
        genericConstraints, 
        genericParams, 
        name, 
        superTyAnnotations, 
        annotations: annotations, 
        modifiers: modifiers
    )

    let pos = structDecl.getStructKeyWordPos()
    // 获取 struct 关键字位置
    println("structDecl.getStructKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

structDecl.getStructKeyWordPos(): 2:8-2:14

func getSuperTyAnnotationsBitAndsPos()

public func getSuperTyAnnotationsBitAndsPos(): Array<CodePositionRange>

功能:获取 StructDecl 节点中父类型中 & 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 body
    let body = Body([])
    
    // 创建 genericConstraints
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])
    
    // 创建 genericParams
    let genericParams = [GenericParam("T")]
    
    // 创建 name
    let name = "A"
    
    // 创建 superTyAnnotations
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], []), CompositeType("I2", [], [])]
    
    // 创建 annotations
    let annotations = [Annotation([Argument(None, false, LitConstExpr(LitConstKind.IntergerLiteral, "123"))], "MyAnno", AtOpKind.At)]
    
    // 创建 modifiers
    let modifiers = [Modifier(ModifierKind.Public)]
    
    // 创建 StructDecl 实例
    let structDecl = StructDecl(
        body, 
        genericConstraints, 
        genericParams, 
        name, 
        superTyAnnotations, 
        annotations: annotations, 
        modifiers: modifiers
    )

    let bitAndsPos = structDecl.getSuperTyAnnotationsBitAndsPos()
    // 遍历输出父类型 & 位置
    for (i in 0..bitAndsPos.size) {
        println("structDecl.getSuperTyAnnotationsBitAndsPos()[${i}]: ${bitAndsPos[i].beginLine}:${bitAndsPos[i].beginColumn}-${bitAndsPos[i].endLine}:${bitAndsPos[i].endColumn}")
    }
}

运行结果:

structDecl.getSuperTyAnnotationsBitAndsPos()[0]: 2:26-2:27

func getUpperBoundPos()

public func getUpperBoundPos(): Option<CodePositionRange>

功能:获取 StructDecl 节点中 <: 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 body
    let body = Body([])
    
    // 创建 genericConstraints
    let genericConstraints = GenericConstraints([GenericConstraint(CompositeType("T", [], []), [CompositeType("I1", [], [])])])
    
    // 创建 genericParams
    let genericParams = [GenericParam("T")]
    
    // 创建 name
    let name = "A"
    
    // 创建 superTyAnnotations
    let superTyAnnotations: Array<TypeAnnotation> = [CompositeType("I1", [], [])]
    
    // 创建 annotations
    let annotations = [Annotation([Argument(None, false, LitConstExpr(LitConstKind.IntergerLiteral, "123"))], "MyAnno", AtOpKind.At)]
    
    // 创建 modifiers
    let modifiers = [Modifier(ModifierKind.Public)]
    
    // 创建 StructDecl 实例
    let structDecl = StructDecl(
        body, 
        genericConstraints, 
        genericParams, 
        name, 
        superTyAnnotations, 
        annotations: annotations, 
        modifiers: modifiers
    )

    if (let Some(pos) <- structDecl.getUpperBoundPos()) {
        // 输出 <: 位置
        println("structDecl.getUpperBoundPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

structDecl.getUpperBoundPos(): 2:20-2:22

class SubscriptExpr

public class SubscriptExpr <: Expr {
    public init(base: Expr, indexs: Array<Expr>, comments!: Array<Comment> = [])
}

功能:表示索引访问表达式。

SubscriptExpr 节点:用于那些支持索引访问的类型(包括 Array 类型和 Tuple 类型)通过下标来访问其具体位置的元素,如 arr[0]

父类型:

prop base

public prop base: Expr

功能:获取当前下标表达式的基表达式,即被访问的数据结构。

类型:Expr

prop indexs

public prop indexs: Array<Expr>

功能:获取当前下标表达式的索引表达式数组。

类型:Array<Expr>

init(Expr, Array<Expr>, Array<Comment>)

public init(base: Expr, indexs: Array<Expr>, comments!: Array<Comment> = [])

功能:构造一个 SubscriptExpr 对象,表示下标访问表达式,如 arr[i]

参数:

  • base: Expr - 被索引的基础表达式。
  • indexs: Array<Expr> - 索引表达式列表。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当 indexs 为空时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 base
    let base = SymbolRef("arr", [])

    // 创建 indexs
    let indexs: Array<Expr> = [
        LitConstExpr(LitConstKind.IntergerLiteral, "1"),
        LitConstExpr(LitConstKind.IntergerLiteral, "2")
    ]

    // 创建 SubscriptExpr 实例
    let subscriptExpr = SubscriptExpr(
        base, 
        indexs
    )

    println("subscriptExpr: ${subscriptExpr}")
}

运行结果:

subscriptExpr: arr[1, 2]

func getCommasPos()

public func getCommasPos(): Array<CodePositionRange>

功能:获取当前 SubscriptExpr 的下标中所有 , 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 base
    let base = SymbolRef("arr", [])

    // 创建 indexs
    let indexs: Array<Expr> = [
        LitConstExpr(LitConstKind.IntergerLiteral, "1"),
        LitConstExpr(LitConstKind.IntergerLiteral, "2"),
        LitConstExpr(LitConstKind.IntergerLiteral, "3")
    ]

    // 创建 SubscriptExpr 实例
    let subscriptExpr = SubscriptExpr(base, indexs)
    let posArr = subscriptExpr.getCommasPos()

    // 遍历输出逗号位置
    for (i in 0..posArr.size) {
        println("subscriptExpr.getCommasPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

subscriptExpr.getCommasPos()[0]: 1:6-1:7
subscriptExpr.getCommasPos()[1]: 1:9-1:10

func getLSquarePos()

public func getLSquarePos(): CodePositionRange

功能:获取当前 SubscriptExpr[ 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 base
    let base = SymbolRef("arr", [])

    // 创建 indexs
    let indexs: Array<Expr> = [LitConstExpr(LitConstKind.IntergerLiteral, "1")]

    // 创建 SubscriptExpr 实例
    let subscriptExpr = SubscriptExpr(base, indexs)
    let pos = subscriptExpr.getLSquarePos()

    // 输出左方括号位置
    println("subscriptExpr.getLSquarePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

subscriptExpr.getLSquarePos(): 1:4-1:5

func getRSquarePos()

public func getRSquarePos(): CodePositionRange

功能:获取当前 ArrayLiteral] 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 base
    let base = SymbolRef("arr", [])

    // 创建 indexs
    let indexs: Array<Expr> = [LitConstExpr(LitConstKind.IntergerLiteral, "1")]

    // 创建 SubscriptExpr 实例
    let subscriptExpr = SubscriptExpr(base, indexs)
    let pos = subscriptExpr.getRSquarePos()

    // 输出右方括号位置
    println("subscriptExpr.getRSquarePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

subscriptExpr.getRSquarePos(): 1:6-1:7

class SymbolRef

public class SymbolRef <: Expr {
    public init(name: String, typeArguments: Array<TypeAnnotation>, comments!: Array<Comment> = [])
}

功能:表示代码中通过标识符对某个声明、包的引用的表达式节点。

父类型:

prop name

public prop name: String

功能:获取 SymbolRef 节点的标识符。

类型:String

prop typeArguments

public prop typeArguments: Array<TypeAnnotation>

功能:获取 SymbolRef 节点中的实例化类型。

类型:Array<TypeAnnotation>

init(String, Array<TypeAnnotation>, Array<Comment>)

public init(name: String, typeArguments: Array<TypeAnnotation>, comments!: Array<Comment> = [])

功能:构造一个 SymbolRef 对象,表示符号引用表达式。

参数:

  • name: String - 符号名称。
  • typeArguments: Array<TypeAnnotation> - 实例化类型。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 name 不符合仓颉标识符规范时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 name
    let name = "x"

    // 创建 typeArguments
    let typeArguments : Array<TypeAnnotation> = [CompositeType("I1", [], [])]

    // 创建 SymbolRef 实例
    let symbolRef = SymbolRef(
        name, 
        typeArguments
    )

    println("symbolRef: ${symbolRef}")
}

运行结果:

symbolRef: x<I1>

func getCommasPos()

public func getCommasPos(): Array<CodePositionRange>

功能:获取当前 SymbolRef 的类型参数中所有 , 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 typeArguments
    let typeArguments: Array<TypeAnnotation> = [
        CompositeType("I1", [], []),
        CompositeType("I2", [], []),
        CompositeType("I3", [], [])
    ]

    // 创建 SymbolRef 实例
    let symbolRef = SymbolRef("x", typeArguments)
    let posArr = symbolRef.getCommasPos()

    // 遍历输出逗号位置
    for (i in 0..posArr.size) {
        println("symbolRef.getCommasPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

symbolRef.getCommasPos()[0]: 1:5-1:6
symbolRef.getCommasPos()[1]: 1:9-1:10

func getIdentifierPos()

public func getIdentifierPos(): CodePositionRange

功能:获取当前 SymbolRef 中变量名的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 SymbolRef 实例
    let symbolRef = SymbolRef("x", [CompositeType("I1", [], [])])
    let pos = symbolRef.getIdentifierPos()

    // 输出标识符位置
    println("symbolRef.getIdentifierPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

symbolRef.getIdentifierPos(): 1:1-1:2

func getLAnglePos()

public func getLAnglePos(): Option<CodePositionRange>

功能:获取当前 SymbolRef 的类型参数中 < 的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回类型参数中 < 的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 SymbolRef 实例
    let symbolRef = SymbolRef("x", [CompositeType("I1", [], [])])

    if (let Some(pos) <- symbolRef.getLAnglePos()) {
        // 输出小于号位置
        println("symbolRef.getLAnglePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

symbolRef.getLAnglePos(): 1:2-1:3

func getRAnglePos()

public func getRAnglePos(): Option<CodePositionRange>

功能:获取当前 SymbolRef 的类型参数中 > 的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回类型参数中 > 的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 SymbolRef 实例
    let symbolRef = SymbolRef("x", [CompositeType("I1", [], [])])

    if (let Some(pos) <- symbolRef.getRAnglePos()) {
        // 输出大于号位置
        println("symbolRef.getRAnglePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

symbolRef.getRAnglePos(): 1:5-1:6

class SynchronizedExpr

public class SynchronizedExpr <: Expr {
    public init(block: Block, structuredMutex: Expr, comments!: Array<Comment> = [])
}

功能:表示 synchronized 表达式。

一个 SynchronizedExpr 节点由 synchronized 关键字和 StructuredMutex 对以及后面的代码块组成,例如 synchronized(m) { foo() }

prop block

public prop block: Block

功能:获取当前 synchronized 语句的代码块,即需要同步执行的代码。

类型:Block

prop structuredMutex

public prop structuredMutex: Expr

功能:获取当前 synchronized 语句的锁对象表达式。

类型:Expr

init(Block, Expr, Array<Comment>)

public init(block: Block, structuredMutex: Expr, comments!: Array<Comment> = [])

功能:构造一个 SynchronizedExpr 对象,表示符号引用表达式。

参数:

  • block: Block - 需要同步执行的代码块。
  • structuredMutex: Expr - 锁对象表达式。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    let callee = SymbolRef("foo", [])

    // 创建 CallExpr 实例
    let callExpr = CallExpr(
        callee,
        []
    )

    // 创建 Block 实例
    let block = Block(
        [callExpr]
    )

    let mutex = SymbolRef("mtx", [])

    // 创建 SynchronizedExpr 实例
    let synchronizedExpr = SynchronizedExpr(
        block,
        mutex
    )
    
    println("synchronizedExpr: ${synchronizedExpr}")
}

运行结果:

synchronizedExpr: synchronized (mtx) {
    foo()
}

func getLParenPos()

public func getLParenPos(): CodePositionRange

功能:获取 SynchronizedExpr 节点中 ( 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let callee = SymbolRef("foo", [])

    // 创建 CallExpr 实例
    let callExpr = CallExpr(
        callee,
        []
    )

    // 创建 Block 实例
    let block = Block(
        [callExpr]
    )

    let mutex = SymbolRef("mtx", [])

    // 创建 SynchronizedExpr 实例
    let synchronizedExpr = SynchronizedExpr(
        block,
        mutex
    )
    
    let pos = synchronizedExpr.getLParenPos()
    // 输出 ( 位置
    println("synchronizedExpr.getLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

synchronizedExpr.getLParenPos(): 1:14-1:15

func getRParenPos()

public func getRParenPos(): CodePositionRange

功能:获取 SynchronizedExpr 节点中 ) 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let callee = SymbolRef("foo", [])

    // 创建 CallExpr 实例
    let callExpr = CallExpr(
        callee,
        []
    )

    // 创建 Block 实例
    let block = Block(
        [callExpr]
    )

    let mutex = SymbolRef("mtx", [])

    // 创建 SynchronizedExpr 实例
    let synchronizedExpr = SynchronizedExpr(
        block,
        mutex
    )
    
    let pos = synchronizedExpr.getRParenPos()
    // 输出 ) 位置
    println("synchronizedExpr.getRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

synchronizedExpr.getRParenPos(): 1:18-1:19

func getSynchronizedKeyWordPos()

public func getSynchronizedKeyWordPos(): CodePositionRange

功能:获取 SynchronizedExpr 节点中 synchronized 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let callee = SymbolRef("foo", [])

    // 创建 CallExpr 实例
    let callExpr = CallExpr(
        callee,
        []
    )

    // 创建 Block 实例
    let block = Block(
        [callExpr]
    )

    let mutex = SymbolRef("mtx", [])

    // 创建 SynchronizedExpr 实例
    let synchronizedExpr = SynchronizedExpr(
        block,
        mutex
    )
    
    let pos = synchronizedExpr.getSynchronizedKeyWordPos()
    // 输出 synchronized 关键字位置
    println("synchronizedExpr.getSynchronizedKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

synchronizedExpr.getSynchronizedKeyWordPos(): 1:1-1:13

class SyntaxTreeNode

sealed abstract class SyntaxTreeNode <: ToString & ToTokens & Hashable & Equatable<SyntaxTreeNode> {
    public let nodePos: CodePositionRange
    public let parentNode: Option<SyntaxTreeNode>
}

功能:所有仓颉语法树节点的父类。

该类提供了所有数据类型通用的操作接口。

父类型:

let nodePos

public let nodePos: CodePositionRange

功能:获取当前语法树节点的位置信息,包含起点和终点位置。

注意:

Package 节点的起始和结束行列号均为 0,文件信息为空。

类型:CodePositionRange

let parentNode

public let parentNode: Option<SyntaxTreeNode>

功能:获取当前语法树节点的父节点信息(若不存在返回 None)。

类型:Option<SyntaxTreeNode>

prop comments

public prop comments: Array<Comment>

功能:获取当前语法树节点的注释节点信息。

类型:Array<Comment>

func hashCode()

public func hashCode(): Int64

功能:获取 SyntaxTreeNode 对象的哈希值。

返回值:

示例:

import stdx.syntax.*

main() {
    let quoteToken = QuoteToken(quote(hello world))

    // 创建 SyntaxTreeNode 子类实例
    let node = QuoteExpr(
        QuoteExprContent.TokenPart(quoteToken)
    )
    // 输出哈希值
    println("node.hashCode(): ${node.hashCode()}")
}

运行结果:

node.hashCode(): -4469856843433877754

func toString()

public open func toString(): String

功能:将语法树节点作为字符串打印出来,保留原本的相对位置信息。

注意:

当前语法树节点的打印不支持行尾空格、分号以及各类注释的打印。

返回值:

  • String - 返回语法树节点打印为字符串的结果。

示例:

import stdx.syntax.*

main() {
    let quoteToken = QuoteToken(quote(hello world))

    // 创建 SyntaxTreeNode 子类实例
    let node = QuoteExpr(
        QuoteExprContent.TokenPart(quoteToken)
    )

    println("node.toString(): ${node.toString()}")
}

运行结果:

node.toString(): quote(hello world)

func toTokens()

public open func toTokens(): Tokens

功能:将语法树节点转换为一组词法单元,保留原本的相对位置信息。

注意:

空格,分号等无法转换为 Token 的内容将被忽略。

返回值:

  • Tokens - 返回语法树节点转换为一组词法单元的结果。

示例:

import stdx.syntax.*

main() {
    let quoteToken = QuoteToken(quote(hello world))

    // 创建 SyntaxTreeNode 子类实例
    let node = QuoteExpr(
        QuoteExprContent.TokenPart(quoteToken)
    )

    // 转化为 Tokens 并输出
    println("node.toTokens(): ${node.toTokens()}")
}

运行结果:

node.toTokens(): quote(hello world)

operator func ==(SyntaxTreeNode)

public operator func ==(that: SyntaxTreeNode): Bool

功能:判断当前 SyntaxTreeNode 与传入的 SyntaxTreeNode 是否相等。

参数:

返回值:

  • Bool - 两个 SyntaxTreeNode 相等则为 true ,不等则为 false

示例:

import stdx.syntax.*

main() {
    let quoteToken = QuoteToken(quote(hello world))

    // 创建 SyntaxTreeNode 子类实例
    let node0 = QuoteExpr(
        QuoteExprContent.TokenPart(quoteToken)
    )
    let node1 = QuoteExpr(
        QuoteExprContent.TokenPart(quoteToken)
    )

    // 输出判等结果
    println("node0 == node0: ${node0 == node0}")
    println("node0 == node1: ${node0 == node1}")
}

运行结果:

node0 == node0: true
node0 == node1: false

class ThrowExpr

public class ThrowExpr <: Expr {
    public init(throwVal: Expr, comments!: Array<Comment> = [])
}

功能:表示一个 throw 表达式。

ThrowExpr 类用于在程序中抛出异常,throwVal 表示被抛出的异常对象。

父类型:

prop throwVal

public prop throwVal: Expr

功能:获取当前 throw 语句的异常值表达式。

类型:Expr

init(Expr, Array<Comment>)

public init(throwVal: Expr, comments!: Array<Comment> = [])

功能:构造一个 ThrowExpr 对象,表示 throw 异常抛出表达式。

参数:

  • throwVal: Expr - 被抛出的异常表达式。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    let callee = SymbolRef("Exception", [])

    // 创建 CallExpr 实例
    let callExpr = CallExpr(
        callee,
        []
    )

    // 创建 ThrowExpr 实例
    let throwExpr = ThrowExpr(
        callExpr
    )
    
    println("throwExpr: ${throwExpr}")
}

运行结果:

throwExpr: throw Exception()

func getThrowKeyWordPos()

public func getThrowKeyWordPos(): CodePositionRange

功能:获取当前 ThrowExprthrow 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let callee = SymbolRef("Exception", [])

    // 创建 CallExpr 实例
    let callExpr = CallExpr(
        callee,
        []
    )

    // 创建 ThrowExpr 实例
    let throwExpr = ThrowExpr(
        callExpr
    )
    
    let pos = throwExpr.getThrowKeyWordPos()
    // 输出 throw 关键字位置
    println("throwExpr.getThrowKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

throwExpr.getThrowKeyWordPos(): 1:1-1:6

class TrailingClosureExpr

public class TrailingClosureExpr <: Expr {
    public init(callee: Expr, arguments: Array<Argument>, trailingLambdaExpr: Lambda, comments!: Array<Comment> = [])
}

功能:表示尾随闭包表达式。尾随闭包是一种语法糖,允许将闭包作为函数的最后一个参数时,可以放在函数调用括号之后。

父类型:

prop arguments

public prop arguments: Array<Argument>

功能:获取 TrailingClosureExpr 节点中的函数参数。

类型:Array<Argument>

prop callee

public prop callee: Expr

功能:获取调用表达式,即包含尾随闭包的函数调用。

类型:Expr

prop trailingLambdaExpr

public prop trailingLambdaExpr: Lambda

功能:获取尾随闭包对应的 Lambda 表达式。

类型:Lambda

init(Expr, Array<Argument>, Lambda, Array<Comment>)

public init(callee: Expr, arguments: Array<Argument>, trailingLambdaExpr: Lambda, comments!: Array<Comment> = [])

功能:构造一个 TrailingClosureExpr 对象,表示尾随闭包调用表达式,如 f(x) { y => y + 1 }

参数:

  • callee: Expr - 被调用的函数表达式。
  • arguments: Array<Argument> - 普通实参列表。
  • trailingLambdaExpr: Lambda - 尾随 lambda 表达式。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当 callee 不是成员访问或引用表达式时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 callee
    let callee = SymbolRef("foo", [])

    // 创建 arguments
    let arguments = [Argument(
        "a1", 
        false, 
        LitConstExpr(LitConstKind.IntergerLiteral, "123")
    )]

    // 创建 trailingLambdaExpr
    let trailingLambdaExpr = Lambda(
        [BinaryExpr(SymbolRef("x", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))], 
        ParameterList(LambdaParam("x", None), hasParen:false)
    )

    // 创建 TrailingClosureExpr 实例
    let trailingClosureExpr = TrailingClosureExpr(
        callee, 
        arguments, 
        trailingLambdaExpr
    )

    println("trailingClosureExpr: ${trailingClosureExpr}")
}

运行结果:

trailingClosureExpr: foo(a1: 123) { x => x + 1 }

func getCommasPos()

public func getCommasPos(): Array<CodePositionRange>

功能:获取当前 TrailingClosureExpr 节点中所有 , 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 callee
    let callee = SymbolRef("foo", [])

    // 创建 arguments
    let arguments = [
        Argument("a1", false, LitConstExpr(LitConstKind.IntergerLiteral, "1")),
        Argument("a2", false, LitConstExpr(LitConstKind.IntergerLiteral, "2")),
        Argument("a3", false, LitConstExpr(LitConstKind.IntergerLiteral, "3"))
    ]

    // 创建 trailingLambdaExpr
    let trailingLambdaExpr = Lambda(
        [BinaryExpr(SymbolRef("x", []), BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))],
        ParameterList(LambdaParam("x", None), hasParen:false)
    )

    // 创建 TrailingClosureExpr 实例
    let trailingClosureExpr = TrailingClosureExpr(callee, arguments, trailingLambdaExpr)
    let posArr = trailingClosureExpr.getCommasPos()

    // 遍历输出逗号位置
    for (i in 0..posArr.size) {
        println("trailingClosureExpr.getCommasPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

trailingClosureExpr.getCommasPos()[0]: 1:10-1:11
trailingClosureExpr.getCommasPos()[1]: 1:17-1:18

func getLParenPos()

public func getLParenPos(): Option<CodePositionRange>

功能:获取 TrailingClosureExpr 节点中 ( 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 callee
    let callee = SymbolRef("foo", [])

    // 创建 arguments
    let arguments = [Argument("a1", false, LitConstExpr(LitConstKind.IntergerLiteral, "123"))]

    // 创建 trailingLambdaExpr
    let trailingLambdaExpr = Lambda(
        [BinaryExpr(SymbolRef("x", []), BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))],
        ParameterList(LambdaParam("x", None), hasParen:false)
    )

    // 创建 TrailingClosureExpr 实例
    let trailingClosureExpr = TrailingClosureExpr(callee, arguments, trailingLambdaExpr)

    if (let Some(pos) <- trailingClosureExpr.getLParenPos()) {
        // 输出左括号位置
        println("trailingClosureExpr.getLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

trailingClosureExpr.getLParenPos(): 1:4-1:5

func getRParenPos()

public func getRParenPos(): Option<CodePositionRange>

功能:获取 TrailingClosureExpr 节点中 ) 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 callee
    let callee = SymbolRef("foo", [])

    // 创建 arguments
    let arguments = [Argument("a1", false, LitConstExpr(LitConstKind.IntergerLiteral, "123"))]

    // 创建 trailingLambdaExpr
    let trailingLambdaExpr = Lambda(
        [BinaryExpr(SymbolRef("x", []), BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))],
        ParameterList(LambdaParam("x", None), hasParen:false)
    )

    // 创建 TrailingClosureExpr 实例
    let trailingClosureExpr = TrailingClosureExpr(callee, arguments, trailingLambdaExpr)

    if (let Some(pos) <- trailingClosureExpr.getRParenPos()) {
        // 输出右括号位置
        println("trailingClosureExpr.getRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

trailingClosureExpr.getRParenPos(): 1:12-1:13

class TryCatch

public class TryCatch <: Expr {
    public init(catchBlocks: Array<Block>, catchPatterns: Array<CatchPattern>, finallyBlock: Option<Block>, resourceSpec: Array<VarDecl>, 
        tryBlock: Block, comments!: Array<Comment> = [])
}

功能:表示 try-catch 表达式节点。

try-catch 表达式包括三个部分:try 块,catch 块和 finally 块。

父类型:

prop catchBlocks

public prop catchBlocks: Array<Block>

功能:获取异常处理代码块的数组,每个代码块对应一种异常处理方式。

类型:Array<Block>

prop catchPatterns

public prop catchPatterns: Array<CatchPattern>

功能:获取异常匹配模式的数组,每个模式对应一个异常类型。

类型:Array<CatchPattern>

prop finallyBlock

public prop finallyBlock: Option<Block>

功能:获取最终执行的代码块,无论异常是否被捕获和处理,该代码块总是会被执行(若不存在返回 None)。

类型:Option<Block>

prop resourceSpec

public prop resourceSpec: Array<VarDecl>

功能:获取需要在完成后释放的资源声明。

类型:Array<VarDecl>

prop tryBlock

public prop tryBlock: Block

功能:获取需要监控的异常的代码块。

类型:Block

init(Array<Block>, Array<CatchPattern>, Option<Block>, Array<VarDecl>, Block, Array<Comment>)

public init(catchBlocks: Array<Block>, catchPatterns: Array<CatchPattern>, finallyBlock: Option<Block>, resourceSpec: Array<VarDecl>, tryBlock: Block, comments!: Array<Comment> = [])

功能:构造一个 TryCatch 对象,表示 try-catch-finally 异常处理表达式。

参数:

  • catchBlocks: Array<Block> - catch 代码块列表。
  • catchPatterns: Array<CatchPattern> - 对应的异常捕获模式列表。
  • finallyBlock: Option<Block> - 可选的 finally 代码块。
  • resourceSpec: Array<VarDecl> - 资源声明列表(try-with-resources)。
  • tryBlock: Block - try 代码块。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 catchPatternsresourceSpecfinallyBlock 同时为空时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 catchBlocks
    let catchBlocks = [Block(BinaryExpr(SymbolRef("y", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1")))]

    // 创建 catchPatterns
    let catchPatterns = [CatchPattern(VarPattern("e1"), [CompositeType("AException", [], []), CompositeType("BException", [], [])])]

    // 创建 finallyBlock
    let finallyBlock = Block(BinaryExpr(SymbolRef("z", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1")))

    // 创建 resourceSpec
    let resourceSpec: Array<VarDecl> = []

    // 创建 tryBlock
    let tryBlock = Block([BinaryExpr(SymbolRef("x", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))])

    // 创建 TryCatch 实例
    let tryCatch = TryCatch(
        catchBlocks, 
        catchPatterns, 
        finallyBlock, 
        resourceSpec, 
        tryBlock
    )

    println("tryCatch: ${tryCatch}")
}

运行结果:

tryCatch: try {
    x + 1
} catch (e1: AException | BException) {
    y + 1
} finally {
    z + 1
}

func getCatchKeyWordsPos()

public func getCatchKeyWordsPos(): Array<CodePositionRange>

功能:获取当前 TryCatch 中所有 catch 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 catchBlocks
    let catchBlocks = [Block(BinaryExpr(SymbolRef("y", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1")))]

    // 创建 catchPatterns
    let catchPatterns = [CatchPattern(VarPattern("e1"), [CompositeType("AException", [], []), CompositeType("BException", [], [])])]

    // 创建 finallyBlock
    let finallyBlock = Block(BinaryExpr(SymbolRef("z", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1")))

    // 创建 resourceSpec
    let resourceSpec: Array<VarDecl> = []

    // 创建 tryBlock
    let tryBlock = Block([BinaryExpr(SymbolRef("x", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))])

    // 创建 TryCatch 实例
    let tryCatch = TryCatch(
        catchBlocks, 
        catchPatterns, 
        finallyBlock, 
        resourceSpec, 
        tryBlock
    )

    // 获取 catch 关键字位置
    let posArr = tryCatch.getCatchKeyWordsPos()
    for (i in 0..posArr.size) {
        println("tryCatch.getCatchKeyWordsPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

tryCatch.getCatchKeyWordsPos()[0]: 3:3-3:8

func getCatchLParensPos()

public func getCatchLParensPos(): Array<CodePositionRange>

功能:获取当前 TryCatch 的所有 catch 语句中 ( 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 catchBlocks
    let catchBlocks = [Block(BinaryExpr(SymbolRef("y", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1")))]

    // 创建 catchPatterns
    let catchPatterns = [CatchPattern(VarPattern("e1"), [CompositeType("AException", [], []), CompositeType("BException", [], [])])]

    // 创建 finallyBlock
    let finallyBlock = Block(BinaryExpr(SymbolRef("z", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1")))

    // 创建 resourceSpec
    let resourceSpec: Array<VarDecl> = []

    // 创建 tryBlock
    let tryBlock = Block([BinaryExpr(SymbolRef("x", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))])

    // 创建 TryCatch 实例
    let tryCatch = TryCatch(
        catchBlocks, 
        catchPatterns, 
        finallyBlock, 
        resourceSpec, 
        tryBlock
    )

    // 获取 catch 语句中 ( 的位置
    let catchLParensPos = tryCatch.getCatchLParensPos()
    for (i in 0..catchLParensPos.size) {
        println("tryCatch.getCatchLParensPos()[${i}]: ${catchLParensPos[i].beginLine}:${catchLParensPos[i].beginColumn}-${catchLParensPos[i].endLine}:${catchLParensPos[i].endColumn}")
    }
}

运行结果:

tryCatch.getCatchLParensPos()[0]: 3:9-3:10

func getCatchRParensPos()

public func getCatchRParensPos(): Array<CodePositionRange>

功能:获取当前 TryCatch 的所有 catch 语句中 ) 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 catchBlocks
    let catchBlocks = [Block(BinaryExpr(SymbolRef("y", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1")))]

    // 创建 catchPatterns
    let catchPatterns = [CatchPattern(VarPattern("e1"), [CompositeType("AException", [], []), CompositeType("BException", [], [])])]

    // 创建 finallyBlock
    let finallyBlock = Block(BinaryExpr(SymbolRef("z", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1")))

    // 创建 resourceSpec
    let resourceSpec: Array<VarDecl> = []

    // 创建 tryBlock
    let tryBlock = Block([BinaryExpr(SymbolRef("x", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))])

    // 创建 TryCatch 实例
    let tryCatch = TryCatch(
        catchBlocks, 
        catchPatterns, 
        finallyBlock, 
        resourceSpec, 
        tryBlock
    )

    // 获取 catch 语句中 ) 的位置
    let catchRParensPos = tryCatch.getCatchRParensPos()
    for (i in 0..catchRParensPos.size) {
        println("tryCatch.getCatchRParensPos()[${i}]: ${catchRParensPos[i].beginLine}:${catchRParensPos[i].beginColumn}-${catchRParensPos[i].endLine}:${catchRParensPos[i].endColumn}")
    }
}

运行结果:

tryCatch.getCatchRParensPos()[0]: 3:37-3:38

func getFinallyKeyWordPos()

public func getFinallyKeyWordPos(): Option<CodePositionRange>

功能:获取当前 TryCatchfinally 关键字的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回 finally 关键字的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 catchBlocks
    let catchBlocks = [Block(BinaryExpr(SymbolRef("y", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1")))]

    // 创建 catchPatterns
    let catchPatterns = [CatchPattern(VarPattern("e1"), [CompositeType("AException", [], []), CompositeType("BException", [], [])])]

    // 创建 finallyBlock
    let finallyBlock = Block(BinaryExpr(SymbolRef("z", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1")))

    // 创建 resourceSpec
    let resourceSpec: Array<VarDecl> = []

    // 创建 tryBlock
    let tryBlock = Block([BinaryExpr(SymbolRef("x", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))])

    // 创建 TryCatch 实例
    let tryCatch = TryCatch(
        catchBlocks, 
        catchPatterns, 
        finallyBlock, 
        resourceSpec, 
        tryBlock
    )

    // 获取 finally 关键字位置
    let finallyKeyWordPos = tryCatch.getFinallyKeyWordPos()
    match (finallyKeyWordPos) {
        case Some(pos) => println("tryCatch.getFinallyKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
        case None => println("tryCatch.getFinallyKeyWordPos(): None")
    }
}

运行结果:

tryCatch.getFinallyKeyWordPos(): 5:3-5:10

func getResourceSpecCommasPos()

public func getResourceSpecCommasPos(): Array<CodePositionRange>

功能:获取当前 TryCatchresource 语句中所有 , 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 catchBlocks
    let catchBlocks = [Block(BinaryExpr(SymbolRef("y", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1")))]

    // 创建 catchPatterns
    let catchPatterns = [CatchPattern(VarPattern("e1"), [CompositeType("AException", [], []), CompositeType("BException", [], [])])]

    // 创建 finallyBlock
    let finallyBlock = Block(BinaryExpr(SymbolRef("z", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1")))

    // 创建 resourceSpec (包含多个资源,用于测试逗号位置)
    let resourceSpec = [
        VarDecl(LitConstExpr(LitConstKind.IntergerLiteral, "1"), VarKind.Var, "x", VarPattern("x"), AtomicType(AtomicTypeKind.Int64Type)),
        VarDecl(LitConstExpr(LitConstKind.IntergerLiteral, "2"), VarKind.Var, "y", VarPattern("y"), AtomicType(AtomicTypeKind.Int64Type))
    ]

    // 创建 tryBlock
    let tryBlock = Block([BinaryExpr(SymbolRef("x", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))])

    // 创建 TryCatch 实例
    let tryCatch = TryCatch(
        catchBlocks, 
        catchPatterns, 
        finallyBlock, 
        resourceSpec, 
        tryBlock
    )

    // 获取 resource 语句中逗号的位置
    let resourceSpecCommasPos = tryCatch.getResourceSpecCommasPos()
    for (i in 0..resourceSpecCommasPos.size) {
        println("tryCatch.getResourceSpecCommasPos()[${i}]: ${resourceSpecCommasPos[i].beginLine}:${resourceSpecCommasPos[i].beginColumn}-${resourceSpecCommasPos[i].endLine}:${resourceSpecCommasPos[i].endColumn}")
    }
}

运行结果:

tryCatch.getResourceSpecCommasPos()[0]: 1:22-1:23

func getResourceSpecLParenPos()

public func getResourceSpecLParenPos(): Option<CodePositionRange>

功能:获取当前 TryCatchresource 语句中 ( 的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回 resource 语句中 ( 的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 catchBlocks
    let catchBlocks = [Block(BinaryExpr(SymbolRef("y", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1")))]

    // 创建 catchPatterns
    let catchPatterns = [CatchPattern(VarPattern("e1"), [CompositeType("AException", [], []), CompositeType("BException", [], [])])]

    // 创建 finallyBlock
    let finallyBlock = Block(BinaryExpr(SymbolRef("z", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1")))

    // 创建 resourceSpec
    let resourceSpec = [VarDecl(LitConstExpr(LitConstKind.IntergerLiteral, "1"), VarKind.Var, "x", VarPattern("x"), AtomicType(AtomicTypeKind.Int64Type))]

    // 创建 tryBlock
    let tryBlock = Block([BinaryExpr(SymbolRef("x", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))])

    // 创建 TryCatch 实例
    let tryCatch = TryCatch(
        catchBlocks, 
        catchPatterns, 
        finallyBlock, 
        resourceSpec, 
        tryBlock
    )

    // 获取 resource 语句中 ( 的位置
    let resourceSpecLParenPos = tryCatch.getResourceSpecLParenPos()
    match (resourceSpecLParenPos) {
        case Some(pos) => println("tryCatch.getResourceSpecLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
        case None => println("tryCatch.getResourceSpecLParenPos(): None")
    }
}

运行结果:

tryCatch.getResourceSpecLParenPos(): 1:5-1:6

func getResourceSpecRParenPos()

public func getResourceSpecRParenPos(): Option<CodePositionRange>

功能:获取当前 TryCatchresource 语句中 ) 的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回 resource 语句中 ) 的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 catchBlocks
    let catchBlocks = [Block(BinaryExpr(SymbolRef("y", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1")))]

    // 创建 catchPatterns
    let catchPatterns = [CatchPattern(VarPattern("e1"), [CompositeType("AException", [], []), CompositeType("BException", [], [])])]

    // 创建 finallyBlock
    let finallyBlock = Block(BinaryExpr(SymbolRef("z", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1")))

    // 创建 resourceSpec
    let resourceSpec = [VarDecl(LitConstExpr(LitConstKind.IntergerLiteral, "1"), VarKind.Var, "x", VarPattern("x"), AtomicType(AtomicTypeKind.Int64Type))]

    // 创建 tryBlock
    let tryBlock = Block([BinaryExpr(SymbolRef("x", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))])

    // 创建 TryCatch 实例
    let tryCatch = TryCatch(
        catchBlocks, 
        catchPatterns, 
        finallyBlock, 
        resourceSpec, 
        tryBlock
    )

    // 获取 resource 语句中 ) 的位置
    let resourceSpecRParenPos = tryCatch.getResourceSpecRParenPos()
    match (resourceSpecRParenPos) {
        case Some(pos) => println("tryCatch.getResourceSpecRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
        case None => println("tryCatch.getResourceSpecRParenPos(): None")
    }
}

运行结果:

tryCatch.getResourceSpecRParenPos(): 1:22-1:23

func getTryKeyWordPos()

public func getTryKeyWordPos(): CodePositionRange

功能:获取当前 TryCatchtry 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 catchBlocks
    let catchBlocks = [Block(BinaryExpr(SymbolRef("y", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1")))]

    // 创建 catchPatterns
    let catchPatterns = [CatchPattern(VarPattern("e1"), [CompositeType("AException", [], []), CompositeType("BException", [], [])])]

    // 创建 finallyBlock
    let finallyBlock = Block(BinaryExpr(SymbolRef("z", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1")))

    // 创建 resourceSpec
    let resourceSpec: Array<VarDecl> = []

    // 创建 tryBlock
    let tryBlock = Block([BinaryExpr(SymbolRef("x", []),BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))])

    // 创建 TryCatch 实例
    let tryCatch = TryCatch(
        catchBlocks, 
        catchPatterns, 
        finallyBlock, 
        resourceSpec, 
        tryBlock
    )

    // 获取 try 关键字位置
    let tryKeyWordPos = tryCatch.getTryKeyWordPos()
    println("tryCatch.getTryKeyWordPos(): ${tryKeyWordPos.beginLine}:${tryKeyWordPos.beginColumn}-${tryKeyWordPos.endLine}:${tryKeyWordPos.endColumn}")
}

运行结果:

tryCatch.getTryKeyWordPos(): 1:1-1:4

class TupleLiteral

public class TupleLiteral <: Expr {
    public init(elements: Array<SyntaxTreeNode>, comments!: Array<Comment> = [])
}

功能:表示 Tuple 字面量节点。

TupleLiteral 节点:使用格式 (element1, element2, ... , elementN) 表示, 每个 element 是一个语法树节点。

父类型:

prop elements

public prop elements: Array<SyntaxTreeNode>

功能:获取 TupleLiteral 中的节点列表。

类型:Array<SyntaxTreeNode>

init(Array<SyntaxTreeNode>, Array<Comment>)

public init(elements: Array<SyntaxTreeNode>, comments!: Array<Comment> = [])

功能:构造一个 TupleLiteral 对象,表示元组字面量表达式,如 (1, "hello")

参数:

  • elements: Array<SyntaxTreeNode> - 元组元素节点列表。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建 LitConstExpr 实例
    let litConstExpr0 = LitConstExpr(
        LitConstKind.FloatLiteral,
        "3.14"
    )
    let litConstExpr1 = LitConstExpr(
        LitConstKind.BoolLiteral,
        "false"
    )
    let litConstExpr2 = LitConstExpr(
        LitConstKind.FloatLiteral,
        "1.1"
    )

    // 创建 TupleLiteral 实例
    let tupleLiteral = TupleLiteral(
        [litConstExpr0, litConstExpr1, litConstExpr2]
    )
    
    println("tupleLiteral: ${tupleLiteral}")
}

运行结果:

tupleLiteral: (3.14, false, 1.1)

func getCommasPos()

public func getCommasPos(): Array<CodePositionRange>

功能:获取当前 TupleLiteral 中所有 , 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 LitConstExpr 实例
    let litConstExpr0 = LitConstExpr(
        LitConstKind.FloatLiteral,
        "3.14"
    )
    let litConstExpr1 = LitConstExpr(
        LitConstKind.BoolLiteral,
        "false"
    )
    let litConstExpr2 = LitConstExpr(
        LitConstKind.FloatLiteral,
        "1.1"
    )

    // 创建 TupleLiteral 实例
    let tupleLiteral = TupleLiteral(
        [litConstExpr0, litConstExpr1, litConstExpr2]
    )
    
    let commasPos = tupleLiteral.getCommasPos()
    // 遍历输出逗号位置
    for (i in 0..commasPos.size) {
        println("tupleLiteral.getCommasPos()[${i}]: ${commasPos[i].beginLine}:${commasPos[i].beginColumn}-${commasPos[i].endLine}:${commasPos[i].endColumn}")
    }
}

运行结果:

tupleLiteral.getCommasPos()[0]: 1:6-1:7
tupleLiteral.getCommasPos()[1]: 1:13-1:14

func getLParenPos()

public func getLParenPos(): CodePositionRange

功能:获取当前 TupleLiteral( 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 LitConstExpr 实例
    let litConstExpr0 = LitConstExpr(
        LitConstKind.FloatLiteral,
        "3.14"
    )
    let litConstExpr1 = LitConstExpr(
        LitConstKind.BoolLiteral,
        "false"
    )
    let litConstExpr2 = LitConstExpr(
        LitConstKind.FloatLiteral,
        "1.1"
    )

    // 创建 TupleLiteral 实例
    let tupleLiteral = TupleLiteral(
        [litConstExpr0, litConstExpr1, litConstExpr2]
    )
    
    let pos = tupleLiteral.getLParenPos()
    // 输出 ( 位置
    println("tupleLiteral.getLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

tupleLiteral.getLParenPos(): 1:1-1:2

func getRParenPos()

public func getRParenPos(): CodePositionRange

功能:获取当前 TupleLiteral) 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 LitConstExpr 实例
    let litConstExpr0 = LitConstExpr(
        LitConstKind.FloatLiteral,
        "3.14"
    )
    let litConstExpr1 = LitConstExpr(
        LitConstKind.BoolLiteral,
        "false"
    )
    let litConstExpr2 = LitConstExpr(
        LitConstKind.FloatLiteral,
        "1.1"
    )

    // 创建 TupleLiteral 实例
    let tupleLiteral = TupleLiteral(
        [litConstExpr0, litConstExpr1, litConstExpr2]
    )
    
    let pos = tupleLiteral.getRParenPos()
    // 输出 ) 位置
    println("tupleLiteral.getRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

tupleLiteral.getRParenPos(): 1:18-1:19

class TuplePattern

public class TuplePattern <: Pattern {
    public init(subPatterns: Array<Pattern>, comments!: Array<Comment> = [])
}

功能:表示 Tuple 模式节点。

用于 tuple 值的匹配,如 case ("Bob", age) => 1 中的 ("Bob", age)

父类型:

prop subPatterns

public prop subPatterns: Array<Pattern>

功能:表示该模式节点中元组内的一组模式节点。

类型:Array<Pattern>

init(Array<Pattern>, Array<Comment>)

public init(subPatterns: Array<Pattern>, comments!: Array<Comment> = [])

功能:构造一个 TuplePattern 对象,表示元组模式。

参数:

  • subPatterns: Array<Pattern> - 子模式列表。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 subPatterns 包含的元素个数少于 2 时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 subPatterns
    let subPatterns: Array<Pattern> = [VarPattern("x"), VarPattern("y")]

    // 创建 TuplePattern 实例
    let tuplePattern = TuplePattern(
        subPatterns
    )

    println("tuplePattern: ${tuplePattern}")
}

运行结果:

tuplePattern: (x, y)

func getCommasPos()

public func getCommasPos(): Array<CodePositionRange>

功能:获取 TuplePattern 节点中 , 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 subPatterns
    let subPatterns: Array<Pattern> = [
        VarPattern("x"),
        VarPattern("y"),
        VarPattern("z")
    ]

    // 创建 TuplePattern 实例
    let tuplePattern = TuplePattern(subPatterns)
    let posArr = tuplePattern.getCommasPos()

    // 遍历输出逗号位置
    for (i in 0..posArr.size) {
        println("tuplePattern.getCommasPos()[${i}]: ${posArr[i].beginLine}:${posArr[i].beginColumn}-${posArr[i].endLine}:${posArr[i].endColumn}")
    }
}

运行结果:

tuplePattern.getCommasPos()[0]: 1:3-1:4
tuplePattern.getCommasPos()[1]: 1:6-1:7

func getLParenPos()

public func getLParenPos(): CodePositionRange

功能:获取 TuplePattern 节点中 ( 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 subPatterns
    let subPatterns: Array<Pattern> = [VarPattern("x"), VarPattern("y")]

    // 创建 TuplePattern 实例
    let tuplePattern = TuplePattern(subPatterns)
    let pos = tuplePattern.getLParenPos()

    // 输出左括号位置
    println("tuplePattern.getLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

tuplePattern.getLParenPos(): 1:1-1:2

func getRParenPos()

public func getRParenPos(): CodePositionRange

功能:获取 TuplePattern 节点中 ) 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 subPatterns
    let subPatterns: Array<Pattern> = [VarPattern("x"), VarPattern("y")]

    // 创建 TuplePattern 实例
    let tuplePattern = TuplePattern(subPatterns)
    let pos = tuplePattern.getRParenPos()

    // 输出右括号位置
    println("tuplePattern.getRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

tuplePattern.getRParenPos(): 1:6-1:7

class TupleType

public class TupleType <: TypeAnnotation {
    public init(labels: Array<String>, elements: Array<TypeAnnotation>, comments!: Array<Comment> = [])
}

功能:表示元组类型节点。

例如 var a : (Int64, Int32) 中的 (Int64, Int32)

父类型:

prop elements

public prop elements: Array<TypeAnnotation>

功能:获取 TupleType 节点中的类型节点列表。

类型:Array<TypeAnnotation>

prop labels

public prop labels: Array<String>

功能:获取 TupleType 节点中的类型参数名,例如 (name: String, age: Int64) 中的 nameage

类型:Array<String>

init(Array<String>, Array<TypeAnnotation>, Array<Comment>)

public init(labels: Array<String>, elements: Array<TypeAnnotation>, comments!: Array<Comment> = [])

功能:构造一个 TupleType 对象,表示元组类型,如 (Int64, String)

参数:

  • labels: Array<String> - 元素标签列表。
  • elements: Array<TypeAnnotation> - 元素类型列表。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当元素类型列表和元素名列表长度不一样时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 AtomicType 实例
    let atomicType0 = AtomicType(AtomicTypeKind.UInt32Type)
    let atomicType1 = AtomicType(AtomicTypeKind.BoolType)
    let atomicType2 = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 TupleType 实例
    let tupleType = TupleType(
        ["a", "b", "c"],
        [atomicType0, atomicType1, atomicType2]
    )
    
    println("tupleType: ${tupleType}")
}

运行结果:

tupleType: (a: UInt32, b: Bool, c: Int64)

func getColonsPos()

public func getColonsPos(): Array<CodePositionRange>

功能:获取 : 的位置序列。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 AtomicType 实例
    let atomicType0 = AtomicType(AtomicTypeKind.UInt32Type)
    let atomicType1 = AtomicType(AtomicTypeKind.BoolType)
    let atomicType2 = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 TupleType 实例
    let tupleType = TupleType(
        ["a", "b", "c"],
        [atomicType0, atomicType1, atomicType2]
    )
    
    let colonsPos = tupleType.getColonsPos()
    // 遍历输出冒号位置
    for (i in 0..colonsPos.size) {
        println("tupleType.getColonsPos()[${i}]: ${colonsPos[i].beginLine}:${colonsPos[i].beginColumn}-${colonsPos[i].endLine}:${colonsPos[i].endColumn}")
    }
}

运行结果:

tupleType.getColonsPos()[0]: 1:3-1:4
tupleType.getColonsPos()[1]: 1:14-1:15
tupleType.getColonsPos()[2]: 1:23-1:24

func getCommasPos()

public func getCommasPos(): Array<CodePositionRange>

功能:获取 , 的位置序列。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 AtomicType 实例
    let atomicType0 = AtomicType(AtomicTypeKind.UInt32Type)
    let atomicType1 = AtomicType(AtomicTypeKind.BoolType)
    let atomicType2 = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 TupleType 实例
    let tupleType = TupleType(
        ["a", "b", "c"],
        [atomicType0, atomicType1, atomicType2]
    )
    
    let commasPos = tupleType.getCommasPos()
    // 遍历输出逗号位置
    for (i in 0..commasPos.size) {
        println("tupleType.getCommasPos()[${i}]: ${commasPos[i].beginLine}:${commasPos[i].beginColumn}-${commasPos[i].endLine}:${commasPos[i].endColumn}")
    }
}

运行结果:

tupleType.getCommasPos()[0]: 1:11-1:12
tupleType.getCommasPos()[1]: 1:20-1:21

func getLabelsPos()

public func getLabelsPos(): Array<CodePositionRange>

功能:获取标签的位置序列。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 AtomicType 实例
    let atomicType0 = AtomicType(AtomicTypeKind.UInt32Type)
    let atomicType1 = AtomicType(AtomicTypeKind.BoolType)
    let atomicType2 = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 TupleType 实例
    let tupleType = TupleType(
        ["a", "b", "c"],
        [atomicType0, atomicType1, atomicType2]
    )
    
    let labelsPos = tupleType.getLabelsPos()
    // 遍历输出标签位置
    for (i in 0..labelsPos.size) {
        println("tupleType.getLabelsPos()[${i}]: ${labelsPos[i].beginLine}:${labelsPos[i].beginColumn}-${labelsPos[i].endLine}:${labelsPos[i].endColumn}")
    }
}

运行结果:

tupleType.getLabelsPos()[0]: 1:2-1:3
tupleType.getLabelsPos()[1]: 1:13-1:14
tupleType.getLabelsPos()[2]: 1:22-1:23

func getLParenPos()

public func getLParenPos(): CodePositionRange

功能:获取 ( 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 AtomicType 实例
    let atomicType0 = AtomicType(AtomicTypeKind.UInt32Type)
    let atomicType1 = AtomicType(AtomicTypeKind.BoolType)
    let atomicType2 = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 TupleType 实例
    let tupleType = TupleType(
        ["a", "b", "c"],
        [atomicType0, atomicType1, atomicType2]
    )
    
    let pos = tupleType.getLParenPos()
    // 输出 ( 位置
    println("tupleType.getLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

tupleType.getLParenPos(): 1:1-1:2

func getRParenPos()

public func getRParenPos(): CodePositionRange

功能:获取 ) 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 AtomicType 实例
    let atomicType0 = AtomicType(AtomicTypeKind.UInt32Type)
    let atomicType1 = AtomicType(AtomicTypeKind.BoolType)
    let atomicType2 = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 TupleType 实例
    let tupleType = TupleType(
        ["a", "b", "c"],
        [atomicType0, atomicType1, atomicType2]
    )
    
    let pos = tupleType.getRParenPos()
    // 输出 ) 位置
    println("tupleType.getRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

tupleType.getRParenPos(): 1:30-1:31

class TypeAlias

public class TypeAlias <: Decl {
    public init(aliasName: String, originalTyAnnotation: TypeAnnotation, typeParameters: Array<GenericParam>,
        modifiers!: Array<Modifier> = [], comments!: Array<Comment> = [])
}

功能:表示类型别名节点。

一个 TypeAlias 节点: type Point2D = Float64

父类型:

prop aliasName

public prop aliasName: String

功能:获取当前类型别名的名称。

类型:String

prop originalTyAnnotation

public prop originalTyAnnotation: TypeAnnotation

功能:获取当前类型别名的原始类型的注解。

类型:Option<TypeAnnotation>

prop typeParameters

public prop typeParameters: Array<GenericParam>

功能:获取当前类型别名的类型参数。

类型:Array<GenericParam>

init(String, TypeAnnotation, Array<GenericParam>, Array<Modifier>, Array<Comment>)

public init(aliasName: String, originalTyAnnotation: TypeAnnotation, typeParameters: Array<GenericParam>,
    modifiers!: Array<Modifier> = [], comments!: Array<Comment> = [])

功能:构造一个 TypeAlias 对象,表示类型别名声明节点。

参数:

  • aliasName: String - 别名名称。
  • originalTyAnnotation: TypeAnnotation - 原始类型注解。
  • typeParameters: Array<GenericParam> - 类型参数列表。
  • modifiers!: Array<Modifier> - 修饰符列表,默认为空数组。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 aliasName 不符合仓颉标识符规范时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 CompositeType 实例
    let compositeType = CompositeType(
        "A", 
        ["p0"], 
        [CompositeType("T", [], [])]
    )
    
    // 创建 TypeAlias 实例
    let typeAlias = TypeAlias(
        "MyType",
        compositeType,
        GenericParam("T")
    )

    println("typeAlias: ${typeAlias}")
}

运行结果:

typeAlias: type MyType<T> = p0.A<T>

func getAssignPos()

public func getAssignPos(): CodePositionRange

功能:获取当前 TypeAlias= 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 CompositeType 实例
    let compositeType = CompositeType(
        "A", 
        ["p0"], 
        [CompositeType("T", [], [])]
    )
    
    // 创建 TypeAlias 实例
    let typeAlias = TypeAlias(
        "MyType",
        compositeType,
        [GenericParam("T")]
    )
    
    let pos = typeAlias.getAssignPos()
    // 输出 = 位置
    println("typeAlias.getAssignPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

typeAlias.getAssignPos(): 1:16-1:17

func getIdentifierPos()

public func getIdentifierPos(): CodePositionRange

功能:获取当前 TypeAlias 中类型别名的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 CompositeType 实例
    let compositeType = CompositeType(
        "A", 
        ["p0"], 
        [CompositeType("T", [], [])]
    )
    
    // 创建 TypeAlias 实例
    let typeAlias = TypeAlias(
        "MyType",
        compositeType,
        [GenericParam("T")]
    )
    
    let pos = typeAlias.getIdentifierPos()
    // 输出标识符位置
    println("typeAlias.getIdentifierPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

typeAlias.getIdentifierPos(): 1:6-1:12

func getTypeAliasKeyWordPos()

public func getTypeAliasKeyWordPos(): CodePositionRange

功能:获取当前 TypeAliastype 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 CompositeType 实例
    let compositeType = CompositeType(
        "A", 
        ["p0"], 
        [CompositeType("T", [], [])]
    )
    
    // 创建 TypeAlias 实例
    let typeAlias = TypeAlias(
        "MyType",
        compositeType,
        [GenericParam("T")]
    )
    
    let pos = typeAlias.getTypeAliasKeyWordPos()
    // 输出 type 关键字位置
    println("typeAlias.getTypeAliasKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

typeAlias.getTypeAliasKeyWordPos(): 1:1-1:5

class TypeAnnotation

sealed abstract class TypeAnnotation <: SyntaxTreeNode {}

功能:表示一个类型标注节点。

父类型:

class TypeConvExpr

public class TypeConvExpr <: Expr {
    public init(srcVal: Expr, targetTypeAnnotation: AtomicType, comments!: Array<Comment> = [])
}

功能:表示一个类型转换表达式。

用于实现若干数值类型间的转换。一个 TypeConvExpr 节点:Int8(32)

父类型:

prop srcVal

public prop srcVal: Expr

功能:获取 TypeConvExpr 中的源表达式节点。

类型:Expr

prop targetTypeAnnotation

public prop targetTypeAnnotation: AtomicType

功能:获取 TypeConvExpr 中将要转换到的目标类型。

类型:AtomicType

init(Expr, AtomicType, Array<Comment>)

public init(srcVal: Expr, targetTypeAnnotation: AtomicType, comments!: Array<Comment> = [])

功能:构造一个 TypeConvExpr 对象,表示显式类型转换表达式,如 Int64(x)

参数:

  • srcVal: Expr - 被转换的源表达式。
  • targetTypeAnnotation: AtomicType - 目标原子类型。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建 LitConstExpr 实例
    let srcVal = LitConstExpr(
        LitConstKind.FloatLiteral,
        "3.14"
    )

    // 创建 AtomicType 实例
    let targetType = AtomicType(AtomicTypeKind.Float64Type)

    // 创建 TypeConvExpr 实例
    let typeConvExpr = TypeConvExpr(
        srcVal,
        targetType
    )

    println("typeConvExpr: ${typeConvExpr}")
}

运行结果:

typeConvExpr: Float64(3.14)

func getLParenPos()

public func getLParenPos(): CodePositionRange

功能:获取 ( 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 LitConstExpr 实例
    let srcVal = LitConstExpr(
        LitConstKind.FloatLiteral,
        "3.14"
    )

    // 创建 AtomicType 实例
    let targetType = AtomicType(AtomicTypeKind.Float64Type)

    // 创建 TypeConvExpr 实例
    let typeConvExpr = TypeConvExpr(
        srcVal,
        targetType
    )
    
    let pos = typeConvExpr.getLParenPos()
    // 输出 ( 位置
    println("typeConvExpr.getLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

typeConvExpr.getLParenPos(): 1:8-1:9

func getRParenPos()

public func getRParenPos(): CodePositionRange

功能:获取 ) 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    // 创建 LitConstExpr 实例
    let srcVal = LitConstExpr(
        LitConstKind.FloatLiteral,
        "3.14"
    )

    // 创建 AtomicType 实例
    let targetType = AtomicType(AtomicTypeKind.Float64Type)

    // 创建 TypeConvExpr 实例
    let typeConvExpr = TypeConvExpr(
        srcVal,
        targetType
    )
    
    let pos = typeConvExpr.getRParenPos()
    // 输出 ) 位置
    println("typeConvExpr.getRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

typeConvExpr.getRParenPos(): 1:13-1:14

class TypePattern

public class TypePattern <: Pattern {
    public init(subPattern: Pattern, patternType: TypeAnnotation, comments!: Array<Comment> = [])
}

功能:表示类型模式节点。

用于判断一个值的运行时类型是否是某个类型的子类型,如 case b: Base => 0 中的 b: Base

父类型:

prop patternType

public prop patternType: TypeAnnotation

功能:表示该模式节点中的待匹配的类型节点。

类型:TypeAnnotation

prop subPattern

public prop subPattern: Pattern

功能:表示该模式节点中的被判断值的模式节点。

类型:Pattern

init(Pattern, TypeAnnotation, Array<Comment>)

public init(subPattern: Pattern, patternType: TypeAnnotation, comments!: Array<Comment> = [])

功能:构造一个 TypePattern 对象,表示带类型的模式,如 x: Int64

参数:

  • subPattern: Pattern - 被判断值的模式节点。
  • patternType: TypeAnnotation - 类型。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 subPattern 不为 WildcardPatternVarPattern 时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 subPattern
    let subPattern = VarPattern("x")

    // 创建 patternType
    let patternType = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 TypePattern 实例
    let typePattern = TypePattern(
        subPattern, 
        patternType
    )

    println("typePattern: ${typePattern}")
}

运行结果:

typePattern: x: Int64

func getColonPos()

public func getColonPos(): CodePositionRange

功能:获取 TypePattern 节点中 : 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 subPattern
    let subPattern = VarPattern("x")

    // 创建 patternType
    let patternType = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 TypePattern 实例
    let typePattern = TypePattern(subPattern, patternType)
    let pos = typePattern.getColonPos()

    // 输出冒号位置
    println("typePattern.getColonPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

typePattern.getColonPos(): 1:2-1:3

class UnaryExpr

public class UnaryExpr <: Expr {
    public init(opKind: UnaryOpKind, operand: Expr, comments!: Array<Comment> = [])
}

功能:表示一个一元操作表达式节点。

一个 UnaryExpr 节点:-1

父类型:

prop operand

public prop operand: Expr

功能:获取 UnaryExpr 节点中的操作数。

类型:Expr

prop opKind

public prop opKind: UnaryOpKind

功能:获取 UnaryExpr 节点中的一元操作符。

类型:UnaryOpKind

init(UnaryOpKind, Expr, Array<Comment>)

public init(opKind: UnaryOpKind, operand: Expr, comments!: Array<Comment> = [])

功能:构造一个 UnaryExpr 对象,表示一元运算表达式,如 !flag-x

参数:

  • opKind: UnaryOpKind - 一元操作符类型。
  • operand: Expr - 被操作的表达式。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建操作数(使用一个字面量表达式作为操作数)
    let operand = LitConstExpr(LitConstKind.IntergerLiteral, "123")
    
    // 创建操作符类型(使用负号操作符)
    let opKind = UnaryOpKind.Sub
    
    // 创建 UnaryExpr 实例
    let unaryExpr = UnaryExpr(
        opKind,
        operand
    )
    
    println("unaryExpr: ${unaryExpr}")
}

运行结果:

unaryExpr: -123

func getOperatorPos()

public func getOperatorPos(): CodePositionRange

功能:获取一元操作符的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建操作数(使用一个字面量表达式作为操作数)
    let operand = LitConstExpr(LitConstKind.IntergerLiteral, "123")
    
    // 创建操作符类型(使用负号操作符)
    let opKind = UnaryOpKind.Sub
    
    // 创建 UnaryExpr 实例
    let unaryExpr = UnaryExpr(
        opKind,
        operand
    )
    
    // 获取操作符位置
    let pos = unaryExpr.getOperatorPos()
    
    // 输出操作符位置
    println("unaryExpr.getOperatorPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

unaryExpr.getOperatorPos(): 1:1-1:2

class UnsafeExpr

public class UnsafeExpr <: Expr {
    public init(block: Block, comments!: Array<Comment> = [])
}

功能:表示一个不安全代码块。

用于标记包含不安全操作(如指针操作、内存管理等)的代码区域,编译器会对该区域放松安全检查。

父类型:

prop block

public prop block: Block

功能:获取不安全代码块的内容。

类型:Block

init(Block, Array<Comment>)

public init(block: Block, comments!: Array<Comment> = [])

功能:构造一个 UnsafeExpr 对象,表示 unsafe 块表达式,用于执行不安全代码。

参数:

  • block: Block - 不安全代码块。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    let callee = SymbolRef("foo", [])

    // 创建 CallExpr 实例
    let callExpr = CallExpr(
        callee,
        []
    )

    let block = Block([callExpr])

    // 创建 UnsafeExpr 实例
    let unsafeExpr = UnsafeExpr(block)

    println("unsafeExpr: ${unsafeExpr}")
}

运行结果:

unsafeExpr: unsafe {
    foo()
}

func getUnsafePos()

public func getUnsafePos(): CodePositionRange

功能:获取当前 UnsafeExprunsafe 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let callee = SymbolRef("foo", [])

    // 创建 CallExpr 实例
    let callExpr = CallExpr(
        callee,
        []
    )

    let block = Block([callExpr])

    // 创建 UnsafeExpr 实例
    let unsafeExpr = UnsafeExpr(block)
    
    let pos = unsafeExpr.getUnsafePos()
    // 输出 unsafe 关键字位置
    println("unsafeExpr.getUnsafePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

unsafeExpr.getUnsafePos(): 1:1-1:7

class VarDecl

public class VarDecl <: Decl {
    public init(initializer: Option<Expr>, kind: VarKind, name: String, pattern: Pattern,
        tyAnnotation: Option<TypeAnnotation>, annotations!: Array<Annotation> = [], modifiers!: Array<Modifier> = [],
        comments!: Array<Comment> = [])
}

功能:表示变量声明节点。

一个 VarDecl 节点:var a: Stringvar b: Int64 = 1 等。

父类型:

prop initializer

public prop initializer: Option<Expr>

功能:获取当前变量声明的初始化表达式(若不存在返回 None)。

类型:Option<Expr>

prop kind

public prop kind: VarKind

功能:获取当前变量声明的种类。

类型:VarKind

prop name

public prop name: String

功能:当前变量声明的模式为 VarPattern 时,获取其名称,其他模式返回空字符串。

类型:String

prop pattern

public prop pattern: Pattern

功能:获取当前变量声明的模式。

类型:Pattern

prop tyAnnotation

public prop tyAnnotation: Option<TypeAnnotation>

功能:获取当前变量声明的类型标注(若不存在返回 None)。

类型:Option<TypeAnnotation>

init(Option<Expr>, VarKind, String, Pattern, Option<TypeAnnotation>, Array<Annotation>, Array<Modifier>, Array<Comment>)

public init(initializer: Option<Expr>, kind: VarKind, name: String, pattern: Pattern,
    tyAnnotation: Option<TypeAnnotation>, annotations!: Array<Annotation> = [], modifiers!: Array<Modifier> = [],
    comments!: Array<Comment> = [])

功能:构造一个 VarDecl 对象,表示变量声明节点。

参数:

  • initializer: Option<Expr> - 可选的初始化表达式。
  • kind: VarKind - 变量种类。
  • name: String - 变量名(仅当模式为 VarPattern 时有效)。
  • pattern: Pattern - 变量绑定模式。
  • tyAnnotation: Option<TypeAnnotation> - 可选的类型注解。
  • annotations!: Array<Annotation> - 附加的注解列表,默认为空数组。
  • modifiers!: Array<Modifier> - 修饰符列表,默认为空数组。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当 pattern 不是通配符模式、变量绑定模式、元组模式或枚举模式,或 modifiers 包含 const,或 kind 不代表 varletconst,或输入的 name 不符合仓颉标识符规范时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 initializer
    let initializer = LitConstExpr(LitConstKind.IntergerLiteral, "1")

    // 创建 kind
    let kind = VarKind.Let

    // 创建 name
    let name = "x"

    // 创建 pattern
    let pattern = VarPattern("x")

    // 创建 tyAnnotation
    let tyAnnotation = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 VarDecl 实例
    let varDecl = VarDecl(
        initializer, 
        kind, 
        name, 
        pattern, 
        tyAnnotation
    )

    println("varDecl: ${varDecl}")
}

运行结果:

varDecl: let x: Int64 = 1

func getAssignPos()

public func getAssignPos(): Option<CodePositionRange>

功能:获取当前 VarDecl= 的位置(若不存在返回 None)。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 initializer
    let initializer = LitConstExpr(LitConstKind.IntergerLiteral, "1")

    // 创建 VarDecl 实例
    let varDecl = VarDecl(initializer, VarKind.Let, "x", VarPattern("x"), AtomicType(AtomicTypeKind.Int64Type))

    if (let Some(pos) <- varDecl.getAssignPos()) {
        // 输出赋值符位置
        println("varDecl.getAssignPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

varDecl.getAssignPos(): 1:14-1:15

func getIdentifierPos()

public func getIdentifierPos(): Option<CodePositionRange>

功能:获取当前 VarDecl 中变量标识符的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回变量标识符的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 initializer
    let initializer = LitConstExpr(LitConstKind.IntergerLiteral, "1")

    // 创建 VarDecl 实例
    let varDecl = VarDecl(initializer, VarKind.Let, "x", VarPattern("x"), AtomicType(AtomicTypeKind.Int64Type))

    if (let Some(pos) <- varDecl.getIdentifierPos()) {
        // 输出变量标识符位置
        println("varDecl.getIdentifierPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

varDecl.getIdentifierPos(): 1:5-1:6

func getTyAnnotationColonPos()

public func getTyAnnotationColonPos(): Option<CodePositionRange>

功能:获取当前 VarDecl 中类型名之前的 : 的位置(若不存在返回 None)。

返回值:

  • Option<CodePositionRange> - 返回类型名之前的 : 的位置(若不存在返回 None)。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 initializer
    let initializer = LitConstExpr(LitConstKind.IntergerLiteral, "1")

    // 创建 VarDecl 实例
    let varDecl = VarDecl(initializer, VarKind.Let, "x", VarPattern("x"), AtomicType(AtomicTypeKind.Int64Type))

    if (let Some(pos) <- varDecl.getTyAnnotationColonPos()) {
        // 输出类型注解冒号位置
        println("varDecl.getTyAnnotationColonPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
    }
}

运行结果:

varDecl.getTyAnnotationColonPos(): 1:6-1:7

func getVarKindKeyWordPos()

public func getVarKindKeyWordPos(): CodePositionRange

功能:获取当前 VarDecl 中变量声明类型关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 initializer
    let initializer = LitConstExpr(LitConstKind.IntergerLiteral, "1")

    // 创建 VarDecl 实例
    let varDecl = VarDecl(initializer, VarKind.Let, "x", VarPattern("x"), AtomicType(AtomicTypeKind.Int64Type))
    let pos = varDecl.getVarKindKeyWordPos()

    // 输出关键字位置
    println("varDecl.getVarKindKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

varDecl.getVarKindKeyWordPos(): 1:1-1:4

class VarOrEnumPattern

public class VarOrEnumPattern <: Pattern {
    public init(identifier: String, comments!: Array<Comment> = [])
}

功能:表示当模式的标识符为 Enum 构造器时的节点。

例如 case RED 中的 REDEnum 构造器。

父类型:

prop identifier

public prop identifier: String

功能:表示该模式节点中的标识符。

类型:String

init(String, Array<Comment>)

public init(identifier: String, comments!: Array<Comment> = [])

功能:构造一个 VarOrEnumPattern 对象,表示变量或枚举模式。

参数:

  • identifier: String - 标识符名称。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 identifier 不符合仓颉标识符规范时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 identifier
    let identifier = "A"

    // 创建 VarOrEnumPattern 实例
    let varOrEnumPattern = VarOrEnumPattern(
        identifier
    )

    println("varOrEnumPattern: ${varOrEnumPattern}")
}

运行结果:

varOrEnumPattern: A

class VarPattern

public class VarPattern <: Pattern {
    public init(name: String, comments!: Array<Comment> = [])
}

功能:表示绑定模式节点。

使用一个合法的标识符表示,如 for (i in 1..10) 中的 i

父类型:

prop name

public prop name: String

功能:表示该模式节点中的标识符。

类型:String

init(String, Array<Comment>)

public init(name: String, comments!: Array<Comment> = [])

功能:构造一个 VarPattern 对象,表示变量模式,如。

参数:

  • name: String - 变量名。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当输入的 name 不符合仓颉标识符规范时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    // 创建 VarPattern 实例
    let varPattern = VarPattern("i")

    println("varPattern: ${varPattern}")
}

运行结果:

varPattern: i

class VArrayExpr

public class VArrayExpr <: Expr {
    public init(argument: Argument, vArrayType: VArrayType, comments!: Array<Comment> = [])
}

功能:表示 VArray 表达式的实例节点。

一个 VArrayExpr 节点:prop arr: VArray<Int64, $5> = VArray<Int64, $5>({ i => i }) 中的 VArray<Int64, $5>({ i => i })

父类型:

prop argument

public prop argument: Argument

功能:获取 VArrayExpr 中的初始化参数。

类型:Argument

prop vArrayType

public prop vArrayType: VArrayType

功能:获取 VArrayExpr 中的 VArray 类型节点。

类型:VArrayType

init(Argument, VArrayType, Array<Comment>)

public init(argument: Argument, vArrayType: VArrayType, comments!: Array<Comment> = [])

功能:构造一个 VArrayExpr 对象,表示 VArray 表达式。

参数:

  • argument: Argument - 构造参数。
  • vArrayType: VArrayType - 定长数组类型。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当 size 小于 0 时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    let symbolRef = SymbolRef("i", [])
    let params = ParameterList(LambdaParam("i", None), hasParen:false)

    // 创建 Lambda 实例
    let lambda = Lambda(
        [symbolRef], 
        params
    )

    // 创建 Argument 实例
    let argument = Argument(
        None, 
        false, 
        lambda
    )

    let elementType = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 VArrayType 实例
    let vArrayType = VArrayType(elementType, 10)

    let vArrayExpr = VArrayExpr(
        argument,
        vArrayType
    )

    println("vArrayExpr: ${vArrayExpr}")
}

运行结果:

vArrayExpr: VArray<Int64, $10>({ i => i })

func getLParenPos()

public func getLParenPos(): CodePositionRange

功能:获取当前 VArrayExpr( 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let symbolRef = SymbolRef("i", [])
    let params = ParameterList([LambdaParam("i", None)], hasParen:false)

    // 创建 Lambda 实例
    let lambda = Lambda(
        [symbolRef], 
        params
    )

    // 创建 Argument 实例
    let argument = Argument(
        None, 
        false, 
        lambda
    )

    let elementType = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 VArrayType 实例
    let vArrayType = VArrayType(elementType, 10)

    let vArrayExpr = VArrayExpr(
        argument,
        vArrayType
    )
    
    let pos = vArrayExpr.getLParenPos()
    // 输出 ( 位置
    println("vArrayExpr.getLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

vArrayExpr.getLParenPos(): 1:19-1:20

func getRParenPos()

public func getRParenPos(): CodePositionRange

功能:获取当前 VArrayExpr) 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let symbolRef = SymbolRef("i", [])
    let params = ParameterList([LambdaParam("i", None)], hasParen:false)

    // 创建 Lambda 实例
    let lambda = Lambda(
        [symbolRef], 
        params
    )

    // 创建 Argument 实例
    let argument = Argument(
        None, 
        false, 
        lambda
    )

    let elementType = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 VArrayType 实例
    let vArrayType = VArrayType(elementType, 10)

    let vArrayExpr = VArrayExpr(
        argument,
        vArrayType
    )
    
    let pos = vArrayExpr.getRParenPos()
    // 输出 ) 位置
    println("vArrayExpr.getRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

vArrayExpr.getRParenPos(): 1:30-1:31

class VArrayType

public class VArrayType <: TypeAnnotation {
    public init(elementType: TypeAnnotation, size: Int64, comments!: Array<Comment> = [])
}

功能:表示 VArray 类型节点。

使用泛型 VArray<T, $N> 表示 VArray 类型,其中 T 表示该值类型数组的元素类型,$N 是一个固定的语法,通过 $ 加上一个 Int64 类型的数值字面量表示这个值类型数组的长度。

父类型:

prop elementType

public prop elementType: TypeAnnotation

功能:获取 VArrayType 节点中的类型变元节点,如 VArray<Int16, $0> 中的 Int16

类型:TypeAnnotation

prop size

public prop size: Int64

功能:获取 VArrayType 节点的大小。

类型:Int64

init(TypeAnnotation, Int64, Array<Comment>)

public init(elementType: TypeAnnotation, size: Int64, comments!: Array<Comment> = [])

功能:构造一个 VArrayType 对象,表示定长数组类型,如 VArray<Int64, $5>

参数:

  • elementType: TypeAnnotation - 元素类型。
  • size: Int64 - 数组长度。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

异常:

  • Exception - 当 size 小于等于 0 时,抛出异常,异常中包含报错提示信息。

示例:

import stdx.syntax.*

main() {
    let elementType = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 VArrayType 实例
    let vArrayType = VArrayType(elementType, 10)

    println("vArrayType: ${vArrayType}")
}

运行结果:

vArrayType: VArray<Int64, $10>

func getCommaPos()

public func getCommaPos(): CodePositionRange

功能:获取 , 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let elementType = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 VArrayType 实例
    let vArrayType = VArrayType(elementType, 10)
    
    let pos = vArrayType.getCommaPos()
    // 输出逗号位置
    println("vArrayType.getCommaPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

vArrayType.getCommaPos(): 1:13-1:14

func getDollarPos()

public func getDollarPos(): CodePositionRange

功能:获取 $ 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let elementType = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 VArrayType 实例
    let vArrayType = VArrayType(elementType, 10)
    
    let pos = vArrayType.getDollarPos()
    // 输出 $ 位置
    println("vArrayType.getDollarPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

vArrayType.getDollarPos(): 1:15-1:16

func getLAnglePos()

public func getLAnglePos(): CodePositionRange

功能:获取 < 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let elementType = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 VArrayType 实例
    let vArrayType = VArrayType(elementType, 10)
    
    let pos = vArrayType.getLAnglePos()
    // 输出 < 位置
    println("vArrayType.getLAnglePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

vArrayType.getLAnglePos(): 1:7-1:8

func getRAnglePos()

public func getRAnglePos(): CodePositionRange

功能:获取 > 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let elementType = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 VArrayType 实例
    let vArrayType = VArrayType(elementType, 10)
    
    let pos = vArrayType.getRAnglePos()
    // 输出 > 位置
    println("vArrayType.getRAnglePos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

vArrayType.getRAnglePos(): 1:18-1:19

func getVArrayPos()

public func getVArrayPos(): CodePositionRange

功能:获取 VArray 的位置。

返回值:

示例:

import stdx.syntax.*

main() {
    let elementType = AtomicType(AtomicTypeKind.Int64Type)

    // 创建 VArrayType 实例
    let vArrayType = VArrayType(elementType, 10)
    
    let pos = vArrayType.getVArrayPos()
    // 输出 VArray 关键字位置
    println("vArrayType.getVArrayPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

vArrayType.getVArrayPos(): 1:1-1:7

class WhileExpr

public class WhileExpr <: Expr {
    public init(body: Block, condition: DisjunctionCondition, comments!: Array<Comment> = [])
}

功能:表示 while 表达式。

while 是关键字,while 之后是一个小括号,小括号内可以是一个表达式或者一个 let 声明的解构匹配,接着是一个 Block 节点。

父类型:

prop body

public prop body: Block

功能:表示 while 循环的循环体。

类型:Block

prop condition

public prop condition: DisjunctionCondition

功能:表示 while 循环的条件。

类型:DisjunctionCondition

init(Block, DisjunctionCondition, Array<Comment>)

public init(body: Block, condition: DisjunctionCondition, comments!: Array<Comment> = [])

功能:构造一个 WhileExpr 对象,表示 while 循环表达式。

参数:

  • body: Block - 循环体代码块。
  • condition: DisjunctionCondition - 循环继续条件。
  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 body
    let body = Block([BinaryExpr(SymbolRef("x", []), BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))])

    // 创建 condition
    let condition = DisjunctionCondition([ConjunctionCondition(AtomicCondition.Expression(SymbolRef("x", [])))])

    // 创建 WhileExpr 实例
    let whileExpr = WhileExpr(body, condition)

    println("whileExpr: ${whileExpr}")
}

运行结果:

whileExpr: while (x) {
    x + 1
}

func getCondLParenPos()

public func getCondLParenPos(): CodePositionRange

功能:获取 WhileExpr 节点中条件的 ( 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 WhileExpr 实例
    let body = Block([BinaryExpr(SymbolRef("x", []), BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))])
    let condition = DisjunctionCondition([ConjunctionCondition(AtomicCondition.Expression(SymbolRef("x", [])))])
    let whileExpr = WhileExpr(body, condition)
    let pos = whileExpr.getCondLParenPos()

    // 输出条件左括号位置
    println("whileExpr.getCondLParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

whileExpr.getCondLParenPos(): 1:7-1:8

func getCondRParenPos()

public func getCondRParenPos(): CodePositionRange

功能:获取 WhileExpr 节点中条件的 ) 的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 WhileExpr 实例
    let body = Block([BinaryExpr(SymbolRef("x", []), BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))])
    let condition = DisjunctionCondition([ConjunctionCondition(AtomicCondition.Expression(SymbolRef("x", [])))])
    let whileExpr = WhileExpr(body, condition)
    let pos = whileExpr.getCondRParenPos()

    // 输出条件右括号位置
    println("whileExpr.getCondRParenPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

whileExpr.getCondRParenPos(): 1:9-1:10

func getWhileKeyWordPos()

public func getWhileKeyWordPos(): CodePositionRange

功能:获取 WhileExpr 节点中 while 关键字的位置。

返回值:

示例:

import stdx.syntax.*

main(): Unit {
    // 创建 WhileExpr 实例
    let body = Block([BinaryExpr(SymbolRef("x", []), BinaryOpKind.Add, LitConstExpr(LitConstKind.IntergerLiteral, "1"))])
    let condition = DisjunctionCondition([ConjunctionCondition(AtomicCondition.Expression(SymbolRef("x", [])))])
    let whileExpr = WhileExpr(body, condition)
    let pos = whileExpr.getWhileKeyWordPos()

    // 输出 while 关键字位置
    println("whileExpr.getWhileKeyWordPos(): ${pos.beginLine}:${pos.beginColumn}-${pos.endLine}:${pos.endColumn}")
}

运行结果:

whileExpr.getWhileKeyWordPos(): 1:1-1:6

class WildcardPattern

public class WildcardPattern <: Pattern {
    public init(comments!: Array<Comment> = [])
}

功能:表示通配符模式节点。

父类型:

init(Array<Comment>)

public init(comments!: Array<Comment> = [])

功能:构造一个 WildcardPattern 对象,表示通配符模式 _

参数:

  • comments!: Array<Comment> - 附加的注释列表,默认为空数组。

示例:

import stdx.syntax.*

main() {
    // 创建 WildcardPattern 实例
    let wildcardPattern = WildcardPattern()

    println("wildcardPattern: ${wildcardPattern}")
}

运行结果:

wildcardPattern: _

枚举

enum AssignOpKind

public enum AssignOpKind {
    | AddAssign
    | AndAssign
    | Assign
    | BitAndAssign
    | BitOrAssign
    | BitXorAssign
    | DivAssign
    | ExpAssign
    | LShiftAssign
    | ModAssign
    | MulAssign
    | OrAssign
    | RShiftAssign
    | SubAssign
    | ...
}

功能:表示赋值操作符的类型。

AddAssign

AddAssign

功能:表示 += 类型的赋值操作符。

AndAssign

AndAssign

功能:表示 &&= 类型的赋值操作符。

Assign

Assign

功能:表示 = 类型的赋值操作符。

BitAndAssign

BitAndAssign

功能:表示 &= 类型的赋值操作符。

BitOrAssign

BitOrAssign

功能:表示 |= 类型的赋值操作符。

BitXorAssign

BitXorAssign

功能:表示 ^= 类型的赋值操作符。

DivAssign

DivAssign

功能:表示 /= 类型的赋值操作符。

ExpAssign

ExpAssign

功能:表示 **= 类型的赋值操作符。

LShiftAssign

LShiftAssign

功能:表示 <<= 类型的赋值操作符。

ModAssign

ModAssign

功能:表示 %= 类型的赋值操作符。

MulAssign

MulAssign

功能:表示 *= 类型的赋值操作符。

OrAssign

OrAssign

功能:表示 ||= 类型的赋值操作符。

RShiftAssign

RShiftAssign

功能:表示 >>= 类型的赋值操作符。

SubAssign

SubAssign

功能:表示 -= 类型的赋值操作符。

enum AtomicCondition

public enum AtomicCondition {
    | LetPatternCondition(LetPattern)
    | Expression(Expr)
    | ParenConditionConstructor(ParenCondition)
    | ...
}

功能:表示原子类型的条件或 let 声明的解构匹配。

Expression(Expr)

Expression(Expr)

功能:表示式类型的条件。

LetPatternCondition(LetPattern)

LetPatternCondition(LetPattern)

功能:表示 let 声明。

ParenConditionConstructor(ParenCondition)

ParenConditionConstructor(ParenCondition)

功能:表示有括号修饰的条件。

enum AtomicTypeKind

public enum AtomicTypeKind {
    | BoolType
    | Float16Type
    | Float32Type
    | Float64Type
    | Int16Type
    | Int32Type
    | Int64Type
    | Int8Type
    | IntNativeType
    | NothingType
    | RuneType
    | ThisType
    | UInt16Type
    | UInt32Type
    | UInt64Type
    | UInt8Type
    | UIntNativeType
    | UnitType
    | ...
}

功能:表示原子类型的种类。

BoolType

BoolType

功能:表示 Bool 基本类型。

Float16Type

Float16Type

功能:表示 16 位浮点数基本类型。

Float32Type

Float32Type

功能:表示 32 位浮点数基本类型。

Float64Type

Float64Type

功能:表示 64 位浮点数基本类型。

Int16Type

Int16Type

功能:表示 16 位有符号整数基本类型。

Int32Type

Int32Type

功能:表示 32 位有符号整数基本类型。

Int64Type

Int64Type

功能:表示 64 位有符号整数基本类型。

Int8Type

Int8Type

功能:表示 8 位有符号整数基本类型。

IntNativeType

IntNativeType

功能:表示平台原生大小的有符号整数基本类型。

NothingType

NothingType

功能:表示空类型(无值类型)。

RuneType

RuneType

功能:表示 Unicode 字符基本类型。

ThisType

ThisType

功能:表示 this 类型。

UInt16Type

UInt16Type

功能:表示 16 位无符号整数基本类型。

UInt32Type

UInt32Type

功能:表示 32 位无符号整数基本类型。

UInt64Type

UInt64Type

功能:表示 64 位无符号整数基本类型。

UInt8Type

UInt8Type

功能:表示 8 位无符号整数基本类型。

UIntNativeType

UIntNativeType

功能:表示平台原生大小的无符号整数基本类型。

UnitType

UnitType

功能:表示 Unit 类型。

enum AtOpKind

public enum AtOpKind {
    | At
    | AtExcl
    | ...
}

功能:表示注解的操作符类型。

At

At

功能:表示 @ 类型的注解操作符。

AtExcl

AtExcl

功能:表示 @! 类型的注解操作符。

enum BinaryOpKind

public enum BinaryOpKind {
    | Add
    | And
    | BitAnd
    | BitOr
    | BitXor
    | Coalescing
    | Composition
    | Div
    | Equal
    | Exp
    | Ge
    | Gt
    | Le
    | LShift
    | Lt
    | Mod
    | Mul
    | NotEq
    | Or
    | Pipeline
    | RShift
    | Sub
    | ...
}

功能:表示二元表达式的操作符类型。

Add

Add

功能:表示 + 类型的二元操作符。

And

And

功能:表示逻辑与 && 类型的二元操作符。

BitAnd

BitAnd

功能:表示按位与 & 类型的二元操作符。

BitOr

BitOr

功能:表示按位或 | 类型的二元操作符。

BitXor

BitXor

功能:表示按位异或 ^ 类型的二元操作符。

Coalescing

Coalescing

功能:表示空值合并 ?? 类型的二元操作符。

Composition

Composition

功能:表示函数组合 ~> 类型的二元操作符。

Div

Div

功能:表示除法 / 类型的二元操作符。

Equal

Equal

功能:表示相等比较 == 类型的二元操作符。

Exp

Exp

功能:表示指数运算 ** 类型的二元操作符。

Ge

Ge

功能:表示大于等于 >= 类型的二元操作符。

Gt

Gt

功能:表示大于 > 类型的二元操作符。

Le

Le

功能:表示小于等于 <= 类型的二元操作符。

LShift

LShift

功能:表示左移位 << 类型的二元操作符。

Lt

Lt

功能:表示小于 < 类型的二元操作符。

Mod

Mod

功能:表示取模 % 类型的二元操作符。

Mul

Mul

功能:表示乘法 * 类型的二元操作符。

NotEq

NotEq

功能:表示不等于 != 类型的二元操作符。

Or

Or

功能:表示逻辑或 || 类型的二元操作符。

Pipeline

Pipeline

功能:表示管道操作 |> 类型的二元操作符。

RShift

RShift

功能:表示右移位 >> 类型的二元操作符。

Sub

Sub

功能:表示减法 - 类型的二元操作符。

enum CommentKind

public enum CommentKind {
    | Block
    | Document
    | Line
    | ...
}

功能:表示语法树节点注释信息的类型。

Block

Block

功能:表示注释信息 /* */ 的块注释类型。

Document

Document

功能:表示注释信息 /** */ 的文档注释类型。

Line

Line

功能:表示注释信息 // 的行注释类型。

enum DiagnosticInfo

public enum DiagnosticInfo {
    | Error(String, String)
    | Warning(String, String)
    | ...
}

功能:表示语法树诊断信息的类型。

Error(String, String)

Error(String, String)

功能:构造一个 (String, String) 类型的 DiagnosticInfo 实例,表示语法分析发现的错误。

Warning(String, String)

Warning(String, String)

功能:构造一个 (String, String) 类型的 DiagnosticInfo 实例,表示语法分析发现的告警。

enum FuncKind

public enum FuncKind {
    | Constructor
    | Finalizer
    | Foreign
    | Normal
    | Operator
    | PrimaryConstructor
    | ...
}

功能:表示声明函数的类型。

Constructor

Constructor

功能:表示一个构造函数,通常用于初始化对象。如 init(srcVal: Expr, targetTypeAnnotation: TypeAnnotation)

Finalizer

Finalizer

功能:表示一个终结器函数,负责在对象被垃圾回收之前执行清理操作。如 ~init()

Foreign

Foreign

功能:表示一个外部函数,通常用于调用外部库中的函数。如 foreign func CjStdSyncStateInit(capacity: Int64): CPointer<UInt8>

Normal

Normal

功能:表示一个普通函数,通常用于执行一系列语句。如 public func hasInterpolation(): Bool

Operator

Operator

功能:表示一个操作符函数,通常用于重载操作符。如 public operator func !=(right: TokenKind): Bool

PrimaryConstructor

PrimaryConstructor

功能:表示一个主构造函数,通常用于初始化对象。如 User(val name: String, var age: Int)

enum ImportKind

public enum ImportKind {
    | Alias 
    | All 
    | Multi 
    | Single 
    | ...
}

功能:表示导入语句的类型。

Alias

Alias

功能:表示别名导入,如 import a.b as c

All

All

功能:表示全导入,如 import a.b.*

Multi

Multi

功能:表示多导入,如 import a.{b, c, d}

Single

Single

功能:表示单导入,如 import a.b

enum IncOrDecOpKind

public enum IncOrDecOpKind {
    | Decr
    | Incr
    | ...
}

功能:表示自增自减表达式的操作符类型。

Decr

Decr

功能:表示 -- 类型的操作符。

Incr

Incr

功能:表示 ++ 类型的操作符。

enum LitConstKind

public enum LitConstKind {
    | BoolLiteral
    | FloatLiteral
    | IntergerLiteral
    | RuneLiteral
    | StringLiteral
    | UnitLiteral
    | ...
}

功能:表示字面量表达式的类型。

BoolLiteral

BoolLiteral

功能:表示布尔类型字面量,如 true

FloatLiteral

FloatLiteral

功能:表示浮点数类型字面量,如 1.0

IntergerLiteral

IntergerLiteral

功能:表示整形字面量,如 1

RuneLiteral

RuneLiteral

功能:表示字符字面量,如 r'a'

StringLiteral

StringLiteral

功能:表示字符串字面量,如 "hello"

UnitLiteral

UnitLiteral

功能:表示 Unit 类型的字面量,如 ()

enum LitConstStrKind

public enum LitConstStrKind {
    | JStringLiteral
    | MultiLineString
    | MultiLineRawString
    | StringLiteral
    | ...
}

功能:表示字符串字面量表达式的类型。

JStringLiteral

JStringLiteral

功能:表示 JavaString 类型的字符串字面量,如 J"xx"

MultiLineRawString

MultiLineRawString

功能:表示多行原始字符串字面量,如 #"aaa"#

MultiLineString

MultiLineString

功能:表示多行字符串字面量,如 """aaa"""

StringLiteral

StringLiteral

功能:表示单行字符串字面量,如 'xx'

enum MacroExpandInput

public enum MacroExpandInput {
    | WithoutParens(Decl)
    | WithParens(Tokens)
    | ...
}

功能:表示宏展开的输入形式,区分不同的宏调用语法形式。

WithoutParens(Decl)

WithoutParens(Decl)

功能:表示无括号形式的宏输入,直接以声明作为宏参数。

WithParens(Tokens)

WithParens(Tokens)

功能:表示带括号形式的宏输入,括号内包含标记序列作为宏参数。

enum ModifierKind

public enum ModifierKind {
    | Abstract
    | Internal
    | Mut
    | Open
    | Operator
    | Override
    | Private
    | Protected
    | Public
    | Redef
    | Sealed
    | Static
    | Unsafe
    | Const
    | ...
}

功能:表示修饰符的类型。

Abstract

Abstract

功能:表示 abstract 类型的修饰符。

Const

Const

功能:表示 const 类型的修饰符。

Internal

Internal

功能:表示 internal 类型的修饰符。

Mut

Mut

功能:表示 mut 类型的修饰符。

Open

Open

功能:表示 open 类型的修饰符。

Operator

Operator

功能:表示 operator 类型的修饰符。

Override

Override

功能:表示 override 类型的修饰符。

Private

Private

功能:表示 private 类型的修饰符。

Protected

Protected

功能:表示 protected 类型的修饰符。

Public

Public

功能:表示 public 类型的修饰符。

Redef

Redef

功能:表示 redef 类型的修饰符。

Sealed

Sealed

功能:表示 sealed 类型的修饰符。

Static

Static

功能:表示 static 类型的修饰符。

Unsafe

Unsafe

功能:表示 unsafe 类型的修饰符。

operator func !=(ModifierKind)

public operator func !=(rhs: ModifierKind): Bool

功能:判断当前修饰符类型是否与传入的修饰符类型不相等。

参数:

返回值:

  • Bool - 如果两个修饰符类型不相等,则返回 true;否则返回 false

示例:

import stdx.syntax.*

main() {
    // 创建 ModifierKind
    let publicKind = ModifierKind.Public
    let internalKind = ModifierKind.Internal

    println("publicKind == publicKind: ${publicKind == publicKind}")
    println("publicKind == internalKind: ${publicKind == internalKind}")
}

运行结果:

publicKind == publicKind: true
publicKind == internalKind: false

operator func ==(ModifierKind)

public operator func ==(rhs: ModifierKind): Bool

功能:判断当前修饰符类型是否与传入的修饰符类型相等。

参数:

返回值:

  • Bool - 如果两个修饰符类型相等,则返回 true;否则返回 false

示例:

import stdx.syntax.*

main() {
    // 创建 ModifierKind
    let publicKind = ModifierKind.Public
    let internalKind = ModifierKind.Internal

    println("publicKind != publicKind: ${publicKind != publicKind}")
    println("publicKind != internalKind: ${publicKind != internalKind}")
}

运行结果:

publicKind != publicKind: false
publicKind != internalKind: true

enum PostActionMode

public enum PostActionMode {
    | Continue
    | Stop
    | ...
}

功能:控制 ASTVisitor 在访问节点完成后的行为策略。

Continue

Continue

功能:func postAction 的默认策略,继续遍历。

Stop

Stop

功能:立即停止整个遍历过程。

enum PreActionMode

public enum PreActionMode {
    | Continue
    | Skip
    | Stop
    | ...
}

功能:控制 ASTVisitor 在访问节点前的行为策略。

Continue

Continue

功能:func preAction 的默认策略,继续访问当前节点及其所有子节点。

Skip

Skip

功能:跳过当前节点的子节点。

Stop

Stop

功能:立即停止整个遍历过程。

enum PrefixTypeOpKind

public enum PrefixTypeOpKind {
    | Quest
    | ...
}

功能:表示前缀类型中的前缀操作符类型。

Quest

Quest

功能:表示 ? 类型的前缀操作符。

enum QuoteExprContent

public enum QuoteExprContent{
    | TokenPart(QuoteToken)
    | QuoteInterpolation(QuoteInterpolationExpr)
    | ...
}

功能:表示 quote 表达式中由 () 括起的内容类型。

QuoteInterpolation(QuoteInterpolationExpr)

QuoteInterpolation(QuoteInterpolationExpr)

功能:表示 QuoteInterpolationExpr 类型的 quote 表达式部分。

TokenPart(QuoteToken)

TokenPart(QuoteToken)

功能:表示 QuoteToken 类型的 quote 表达式部分。

enum RangeKind

public enum RangeKind {
    | ClosedRangeOp
    | RangeOp
    | ...
}

功能:表示区间表达式的操作符类型。

ClosedRangeOp

ClosedRangeOp

功能:表示 := 类型的区间操作符。

RangeOp

RangeOp

功能:表示 : 类型的区间操作符。

enum StrLiteralPart

public enum StrLiteralPart {
    | LitConstPart(LitConstExpr)
    | StrInterpolation(StrInterpolationContent)
    | ...
}

功能:表示字符串常量的不同部分,分为字面量常量部分和字符串插值部分。

LitConstPart(LitConstExpr)

LitConstPart(LitConstExpr)

功能:构造一个 LitConstExpr 类型的 StrLiteralPart 实例,表示字面量常量部分。

StrInterpolation(StrInterpolationContent)

StrInterpolation(StrInterpolationContent)

功能:构造一个 StrInterpolationContent 类型的 StrLiteralPart 实例,表示字符串插值部分。

enum UnaryOpKind

public enum UnaryOpKind {
    | Not
    | Sub
    | ...
}

功能:表示一元表达式的操作符类型。

Not

Not

功能:表示 ! 类型的一元操作符。

Sub

Sub

功能:表示 - 类型的一元操作符。

enum VarKind

public enum VarKind {
    | Const
    | Let
    | Var
    | ...
}

功能:表示变量声明表达式的类型。

Const

Const

功能:表示声明一个字面量,如 const PI = 3.14159

Let

Let

功能:表示声明一个不可变变量,如 let a = 1a 的值为 1 且不可变。

Var

Var

功能:表示声明一个不可变变量,如 var a = 1a 的值为 1,可被重新赋值。

结构体

struct CodePositionRange

public struct CodePositionRange {
    public let beginLine: Int32
    public let beginColumn: Int32
    public let endLine: Int32
    public let endColumn: Int32
}

功能:表示节点位置信息。

let beginColumn

public let beginColumn: Int32

功能:获取起始列号。

类型:Int32

let beginLine

public let beginLine: Int32

功能:获取起始行号。

类型:Int32

let endColumn

public let endColumn: Int32

功能:获取结束列号。

类型:Int32

let endLine

public let endLine: Int32

功能:获取结束行号。

类型:Int32

prop fileName

public prop fileName: String

功能:获取文件名。

类型:String

prop filePath

public prop filePath: String

功能:获取文件绝对路径。

类型:String

使用语法解析函数示例

使用 parseFile 函数的示例

仓颉文件 a.cj 中有如下代码:

package a

main(){
  var expr = 1 + 2
  println(expr)
}

利用 parseFile 函数将上述文件解析为一个 ParsingResult<SourceFile> 对象,代码如下所示:

import stdx.syntax.*

main() {
    let file = parseFile("a.cj").node.getOrThrow() // 获取一个 SourceFile 类型的语法树
    println(file.toString()) // 打印该语法树, 应与原文件中内容完全一致
}

运行结果:

package a

main(){
  var expr = 1 + 2
  println(expr)
}

使用 parsePackage 函数的示例

文件目录 user 下有仓颉文件 file1.cj 和 file2.cj,file1.cj 和 file2.cj 中均包含如下仓颉代码:

package a

func foo() {
}

利用 parsePackage 函数将上述代码解析为一个 ParsingResult<Package> 对象,代码如下所示:

import stdx.syntax.*

main() {
    let pkg = parsePackage("/user/").node.getOrThrow() // 获取一个 Package 类型的语法树
    println(pkg.toString()) // 打印该语法树,包内的文件按文件名字母序排序,对每个文件依次打印文件名和文件内容
}

运行结果:

// file1.cj
package a

func foo() {
}
// file2.cj
package a

func foo() {
}

使用 parseText 函数的示例

利用 parseText 函数将输入的文本解析为一个 ParsingResult<SyntaxTreeNode> 对象,代码如下所示:

import stdx.syntax.*

main() {
    let result = parseText("    1  + 1").node.getOrThrow() // 解析获得一个语法树节点,示例中为二元表达式
    println(result.toString()) // 打印该语法树节点,应与输入字符串完全一致
    println(result.toTokens().toString()) // Tokens 的 toString 接口不保留位置信息
}

运行结果:

    1  + 1
1 + 1

使用 parseTokens 函数的示例

利用 parseTokens 函数将输入的一组词法单元解析为一个 ParsingResult<SyntaxTreeNode> 对象,代码如下所示:

import stdx.syntax.*

main() {
    let tokens = quote(
      let a    =    1
    )
    let result = parseTokens(tokens).node.getOrThrow() // 解析获得一个语法树节点,默认刷新位置信息,示例中为变量声明
    println(result.toString()) // 打印该语法树节点

    let result_1 = parseTokens(tokens, refreshPos: false).node.getOrThrow() // 不刷新位置信息解析,toString 结果保留原始位置
    println(result_1.toString())
}

运行结果:

let a = 1
let a    =    1

遍历节点示例

ASTVisitor 使用示例

ASTVisitor 是 SyntaxTreeNode 访问器的基类。

使用方式:

  1. 继承 ASTVisitor 并重写 preAction / postAction 或特定 visit* 方法;
  2. 调用 walk(root) 从任意节点开始遍历;
  3. 通过返回 PreActionModePostActionMode 控制遍历流程。

假设我们有一段需要分析的代码:

package a

main(){
  var expr = 1 + 2
  println(expr)
  var nextExpr = expr + 1
  println(nextExpr)
}

下面演示如何继承 ASTVisitor,在遍历过程中统计所有 BinaryExpr 节点,并在遇到第一个 CallExpr 后立即停止遍历:

import stdx.syntax.*

// 1. 继承 ASTVisitor
public class BinaryCounter <: ASTVisitor {
    public var count = 0

    // 2. 重写 preAction,只在进入节点前做判断
    public override func preAction(node: SyntaxTreeNode): PreActionMode {
        match (node) {
            // 遇到 BinaryExpr 时计数 +1 并继续
            case _: BinaryExpr =>
                count += 1
                return PreActionMode.Continue

            // 遇到 CallExpr 立即停止整个遍历
            case _: CallExpr =>
                println("Found CallExpr, stop traversal")
                return PreActionMode.Stop

            // 其它节点保持默认行为
            case _ => PreActionMode.Continue
        }
    }
}

// 3. 使用示例
main() {
    let root = parseFile("example.cj")

    let counter = BinaryCounter()
    counter.walk(root.node.getOrThrow())          // 开始遍历

    println("Total BinaryExpr count: ${counter.count}")
}

运行流程:

  1. walk(root) 从根节点开始深度优先遍历;
  2. 每进入一个节点会调用 preAction
    • 如果是 BinaryExpr,计数器自增并返回 CONTINUE 继续;
    • 如果是 CallExpr,返回 STOP,遍历立即终止;
  3. 最终打印统计结果。

运行结果:

Found CallExpr, stop traversal
Total BinaryExpr count: 1

遍历时修改节点示例

ASTRewriter 使用示例

ASTRewriter 是 SyntaxTreeNode 重写器的基类。

使用方式:

  1. 继承 ASTRewriter 并重写 rewrite 方法,可实现自定义节点转换;
  2. 调用 walk 从任意节点开始遍历, 对每一个节点,遍历完其所有的子节点后,会调用自定义的 rewrite 方法,对该节点进行重写;
  3. 调用 walk 时,可以选择是否断开与父节点的关联,若 detachtrue,遍历后产生一颗独立的新树,新树的父节点为空;若 detachfalse,会向上刷新父节点中的内容;
  4. 返回修改后的新节点。

假设我们有一段需要修改的代码,现在需要为所有函数自动生成空的注释模板,方便后续补全文档:

package a

struct Rectangle {
    public var width: Int64
    public var height: Int64

    public init(width: Int64, height: Int64) {
        this.width = width
        this.height = height
    }

    public func area() {
        width * height
    }
}

下面演示如何继承 ASTRewriter,在遍历过程生成 API 文档注释模板:

import stdx.syntax.*
import std.collection.ArrayList

// 1. 继承 ASTRewriter
class DocStubGenerator <: ASTRewriter {
    public override func rewrite(node: SyntaxTreeNode): SyntaxTreeNode {
        match (node) {
            case fn: FuncDecl =>
                let comment = Comment(
                    "// @brief describe ${fn.name}"
                )
                let newComments = ArrayList<Comment>(fn.comments)
                newComments.add(comment)
                // 2. 修改 FuncDecl 中的 comments 属性
                let f = FuncDecl(
                    fn.body,
                    fn.genericConstraints,
                    fn.genericParams,
                    fn.kind,
                    fn.name,
                    fn.params,
                    fn.retTyAnnotation,
                    annotations: fn.annotations,
                    modifiers: fn.modifiers,
                    comments: newComments.toArray()
                )
                return f
            case _ => return node
        }
    }
}

// 3. 使用示例
main() {
    let root = parseFile("rewrite.cj")

    let generator = DocStubGenerator()
    let newNode = generator.walk(root.node.getOrThrow(), detach: true)

    println(newNode)
}

运行结果:

package a

struct Rectangle {
    public var width: Int64
    public var height: Int64

    // @brief describe init
public init(width: Int64, height: Int64) {
        this.width = width
        this.height = height
    }

    // @brief describe area
public func area() {
        width * height
    }
}

stdx.unittest.data

功能介绍

unittest.data 库用于在编写仓颉项目单元测试代码时提供输入序列化格式的测试数据的能力,当前支持 json/csv/tsv 等格式。

标准测试能力可参考标准库 API 文档。

API 列表

函数

函数名功能
csv<T>(String, Rune, Rune, Rune, Option<Rune>, Option<Array<String>>, Array<UInt64>, Array<UInt64>, Bool)该函数可从 csv 文件中读取类型 T 的数据值,其中 T 必须可被序列化。该函数的返回值是参数化测试的一种参数源。
json<T>(String)该函数可从 JSON 文件中读取类型 T 的数据值,其中 T 必须可被序列化。该函数的返回值是参数化测试的一种参数源。
tsv<T>(String, Rune, Rune, Option<Rune>, Option<Array<String>>, Array<UInt64>, Array<UInt64>, Bool)该函数可从 tsv 文件中读取类型 T 的数据值,其中 T 必须可被序列化。该函数的返回值是参数化测试的一种参数源。

类名功能
CsvStrategyDataStrategy 对 CSV 数据格式的序列化实现。
JsonStrategyDataStrategy 对 JSON 数据格式的序列化实现。
SerializableProvider获取序列化数据 DataProvider 接口的实现。

函数

func csv<T>(String, Rune, Rune, Rune, Option<Rune>, Option<Array<String>>, Array<UInt64>, Array<UInt64>, Bool) where T <: Serializable<T>

public func csv<T>(
 fileName: String,
 delimiter!: Rune = ',',
 quoteChar!: Rune = '"',
 escapeChar!: Rune = '"',
 commentChar!: Option<Rune> = None,
 header!: Option<Array<String>> = None,
 skipRows!: Array<UInt64> = [],
 skipColumns!: Array<UInt64> = [],
 skipEmptyLines!: Bool = false
): CsvStrategy<T> where T <: Serializable<T>

功能:该函数可从 csv 文件中读取类型 T 的数据值,其中 T 必须可被序列化。该函数的返回值是参数化测试的一种参数源。

参数:

  • fileName: String - CSV 格式的文件地址,可为相对地址,不限制后缀名。
  • delimiter!: Rune - 一行中作为元素分隔符的符号。默认值为 , (逗号)。
  • quoteChar!: Rune - 括住元素的符号。默认值为 " (双引号)。
  • escapeChar!: Rune - 转义括住元素的符号。默认值为 " (双引号)。
  • commentChar!: Option<Rune> - 注释符号,跳过一行。必须在一行的最左侧。默认值是 None (不存在注释符号)。
  • header!: Option<Array<String>> - 提供一种方式覆盖第一行。
    • 当 header 被指定时,文件的第一行将被作为数据行,指定的 header 将被使用。
    • 当 header 被指定,同时第一行通过指定 skipRows 被跳过时,第一行将被忽略,指定的 header 将被使用。
    • 当 header 未被指定时,即值为 None 时,文件的第一行将被作为表头。此为默认值。
  • skipRows!: Array<UInt64> - 指定需被跳过的数据行号,行号从 0 开始。默认值为空数组 []
  • skipColumns!: Array<UInt64> - 指定需被跳过的数据列号,列号从 0 开始。当有数据列被跳过,并且用户指定了自定义的 header 时,该 header 将按照跳过后的实际数据列对应。默认值为空数据 []
  • skipEmptyLines!: Bool - 指定是否需要跳过空行。默认值为 false

返回值:

  • CsvStrategy<T> - 对象,T 可被序列化,数据值从 CSV 文件中读取。

异常:

  • IllegalStateException - 如果 CSV 数据的结构不正确,则抛出该异常。

func json<T>(String) where T <: Serializable<T>

public func json<T>(fileName: String): JsonStrategy<T> where T <: Serializable<T>

功能:该函数可从 JSON 文件中读取类型 T 的数据值,其中 T 必须可被序列化。该函数的返回值是参数化测试的一种参数源。

参数:

  • fileName: String - JSON 格式的文件地址,可为相对地址。

返回值:

  • JsonStrategy<T> - T 可被序列化,数据值从 JSON 文件中读取。

示例:

@Test[user in json("users.json")]
func test_user_age(user: User): Unit {
    @Expect(user.age, 100)
}

json 文件示例:

[
    {
        "age": 100
    },
    {
        "age": 100
    }
]

创建一种被用作测试函数参数的类,该类实现接口 Serializable

import stdx.serialization.serialization.*
import std.convert.*

class User <: Serializable<User> {
    User(let age: Int64) {}

    public func serialize(): DataModel {
        DataModelStruct().add(Field("age", DataModelInt(age)))
    }

    public static func deserialize(dm: DataModel): User {
        if (let Some(dms) <- (dm as DataModelStruct)) {
            if (let Some(age) <- (dms.get("age") as DataModelInt)) {
                return User(age.getValue())
            }
        }

        throw Exception("Can't deserialize user.")
    }
}

任何实现 Serializable 的类型都可以用作参数类型,包括默认值:

@Test[user in json("numbers.json")]
func test(value: Int64)
@Test[user in json("names.json")]
func test(name: String)

func tsv<T>(String, Rune, Rune, Option<Rune>, Option<Array<String>>, Array<UInt64>, Array<UInt64>, Bool) where T <: Serializable<T>

public func tsv<T>(
    fileName: String,
    quoteChar!: Rune = '"',
    escapeChar!: Rune = '"',
    commentChar!: Option<Rune> = None,
    header!: Option<Array<String>> = None,
    skipRows!: Array<UInt64> = [],
    skipColumns!: Array<UInt64> = [],
    skipEmptyLines!: Bool = false
): CsvStrategy<T> where T <: Serializable<T>

功能:该函数可从 tsv 文件中读取类型 T 的数据值,其中 T 必须可被序列化。该函数的返回值是参数化测试的一种参数源。

参数:

  • fileName: String - TSV 格式的文件地址,可为相对地址,不限制后缀名。
  • quoteChar!: Rune - 括住元素的符号。默认值为 " (双引号)。
  • escapeChar!: Rune - 转义括住元素的符号。默认值为 " (双引号)。
  • commentChar!: Option<Rune> - 注释符号,跳过一行。必须在一行的最左侧。默认值是 None (不存在注释符号)。
  • header!: Option<Array<String>> - 提供一种方式覆盖第一行。
    • 当 header 被指定时,文件的第一行将被作为数据行,指定的 header 将被使用。
    • 当 header 被指定,同时第一行通过指定 skipRows 被跳过时,第一行将被忽略,指定的 header 将被使用。
    • 当 header 未被指定时,即值为 None 时,文件的第一行(跳过后的实际数据)将被作为表头。此为默认值。
  • skipRows!: Array<UInt64> - 指定需被跳过的数据行号,行号从 0 开始。默认值为空数组 []
  • skipColumns!: Array<UInt64> - 指定需被跳过的数据列号,列号从 0 开始。当有数据列被跳过,并且用户指定了自定义的 header 时,该 header 将按照跳过后的实际数据列对应。默认值为空数据 []
  • skipEmptyLines!: Bool - 指定是否需要跳过空行。默认值为 false

返回值:

  • CsvStrategy<T> - T 可被序列化,数据值从 TSV 文件中读取。

异常:

  • IllegalStateException - 如果 TSV 数据的结构不正确,则抛出该异常。

示例:

在单元测试中,可以通过传入 csv/tsv 文件地址进行参数化测试。

CSV 文件每一行的数据应当被表示成一个 Serializable<T> 对象,它的成员名是文件每一列头的值,成员值是 DataModelString 类型的对应列号上的值。

举例来说,有一个 testdata.csv 文件,具有如下内容:

username,age
Alex Great,21
Donald Sweet,28

有几种方式可以序列化上述数据:

  1. 将数据表示为 HashMap<String, String> 类型。

    具体示例为:

    import std.collection.HashMap
    import std.unittest.*
    import std.unittest.testmacro.*
    
    @Test[user in csv("testdata.csv")]
    func testUser(user: HashMap<String, String>) {
        @Assert(user["username"] == "Alex Great" || user["username"] == "Donald Sweet")
        @Assert(user["age"] == "21" || user["age"] == "28")
    }
    
  2. 将数据表示为 Serializable<T> 类型数据,其 String 类型的数据可被反序列化为 DataModelStruct 格式对象。

具体示例为:

import serialization.serialization.*
import std.convert.*
import std.unittest.*
import std.unittest.testmacro.*

public class User <: Serializable<User> {
    public User(let name: String, let age: UInt32) {}

    public func serialize(): DataModel {
        let dms = DataModelStruct()
        dms.add(Field("username", DataModelString(name)))
        dms.add(Field("age", DataModelString(age.toString())))
        return dms
    }

    public static func deserialize(dm: DataModel): User {
        var data: DataModelStruct = match (dm) {
            case dms: DataModelStruct => dms
            case _ => throw DataModelException("this data is not DataModelStruct")
        }

        let name = String.deserialize(data.get("username"))
        let age = String.deserialize(data.get("age"))
        return User(name, UInt32.parse(age))
    }
}

@Test[user in csv("testdata.csv")]
func testUser(user: User) {
   @Assert(user.name == "Alex Great" || user.name == "Donald Sweet")
   @Assert(user.age == 21 || user.age == 28)
}

class CsvStrategy

public class CsvStrategy<T> <: DataStrategy<T> where T <: Serializable<T> {}

功能:DataStrategy 对 CSV 数据格式的序列化实现。

父类型:

  • DataStrategy<T>

func provider(Configuration)

public override func provider(configuration: Configuration): SerializableProvider<T>

功能:生成序列化数据迭代器。

参数:

  • configuration: Configuration - 数据配置信息。

返回值:

class JsonStrategy

public class JsonStrategy<T> <: DataStrategy<T> where T <: Serializable<T> {}

功能:DataStrategy 对 JSON 数据格式的序列化实现。

父类型:

  • DataStrategy<T>

func provider(Configuration)

public override func provider(configuration: Configuration): SerializableProvider<T>

功能:生成序列化数据迭代器。

参数:

  • configuration: Configuration - 数据配置信息。

返回值:

  • SerializableProvider<T> - 序列化迭代器对象。

class SerializableProvider

public class SerializableProvider<T> <: DataProvider<T> where T <: Serializable<T> {}

功能:获取序列化数据 DataProvider 接口的实现。

父类型:

  • DataProvider<T>

func provide()

public override func provide(): Iterable<T> 

功能:获取数据迭代器。

返回值:

  • Iterable<T> - 数据迭代器。