Rust SDK 概述
Darra AI SDK 的 Rust 绑定。工作区两个 crate:只翻译 C ABI 的类型和错误码,零密码学、零容器格式逻辑。契约权威 = Core/include/darra_ai.h。
| crate | 职责 |
|---|---|
darra-ai-sys | 手写 extern "C"(不用 bindgen)+ build.rs 按 DARRA_AI_CORE_LIB_DIR 找库 |
darra-ai | 安全封装:Session / Error / runtime / diagnostics / authoring |
同一 bug 只允许在 Core 修一次。
- crate 名(
Cargo.toml依赖):darra-ai - 库名(代码里
use):darra_ai,例如use darra_ai::{ImageDesc, Session};
工作区 publish = false、version = "1.0.0"、rust-version = "1.70"。
安装
本绑定不发布 crates.io。以路径依赖接入:
[dependencies]
darra-ai = { path = "A:/c/Darra/Darra_AI_Studio/Darra.AI.Studio.SDK/Rust/darra-ai" }
签发三个函数再加 features = ["authoring"](见下方 authoring)。
构建必须设置 DARRA_AI_CORE_LIB_DIR,指向 Core 链接库目录(找不到会 panic 中文 hint):
$env:DARRA_AI_CORE_LIB_DIR = 'A:\c\Darra\Darra_AI_Studio\Darra.AI.Studio.SDK\Core\out\build\windows-x64-debug\lib\Debug'
cd A:\c\Darra\Darra_AI_Studio\Darra.AI.Studio.SDK\Rust
cargo check
Windows 该目录需含 darraai_core.lib 或 DarraAI.Core.lib;Linux 需含 libdarraai_core.so(build.rs 还认 libDarraAI.Core.so / darraai_core.so)。运行时还要把对应的 .dll / .so 放到 PATH 或可执行文件旁。
环境要求
| 项目 | 要求 |
|---|---|
| 操作系统 | Windows 或 Linux(build.rs 按 CARGO_CFG_TARGET_OS 选 .lib / .so) |
| Rust | 1.70+(stable,工作区 rust-version) |
| Core | 已编出的 darraai_core 链接库;ABI major 必须为 1 |
加载后 open / ensure / collect 等入口会核对 darra_version 的 major == DARRA_VERSION_MAJOR(1),不等立即失败。
快速开始
diagnostics::collect导出本机诊断(可选,禁止放进 PLC 扫描周期)runtime::ensure(None, None, …)按硬件自动选 Provider 包(幂等)Session::open打开.darmodel,或Session::open_plain打开明文.onnxinfer_image推理;Session离开作用域时Drop→darra_session_close
use darra_ai::{ImageDesc, Session};
use darra_ai::{diagnostics, runtime};
fn main() -> Result<(), darra_ai::Error> {
let packed = darra_ai::version();
if darra_ai::version_major(packed) != 1 {
return Err(darra_ai::Error::Internal {
message: format!("ABI 不匹配,库版本 = {}", darra_ai::version_string()),
hint: "Darra.AI SDK 与 DarraAI.Core 升到同一发布批次后重试。".to_string(),
});
}
let _ = diagnostics::collect();
runtime::ensure(None, None, Some(&|percent, stage| {
eprint!("\r环境准备 [{stage:<8}] {percent:5.1}% ");
}))?;
let session = Session::open("model.darmodel", Some("model.darmkey"), None, None)?;
eprintln!("[meta] {}", session.meta()?);
let jpeg = std::fs::read("photo.jpg").map_err(|e| darra_ai::Error::IoNotFound {
message: format!("读图片失败:photo.jpg ({e})"),
hint: String::new(),
})?;
let json = session.infer_image(&jpeg, &ImageDesc::auto())?;
println!("{json}");
Ok(())
}
明文 ONNX:Session::open_plain("model.onnx", None)。绑定注释:训练格式(.pt / .pth / Paddle)收到即 UnsupportedPayload。
工业相机裸缓冲 BGR888(禁止 ImageDesc::auto(),嗅探不出通道序;stride = 0 表示紧凑 = width × 3):
let desc = ImageDesc::bgr888(1920, 1080, 0);
let json = session.infer_image(&frame, &desc)?;
完整脚本见 darra-ai/examples/infer.rs:
cargo run -p darra-ai --example infer -- model.darmodel photo.jpg model.darmkey
cargo run -p darra-ai --example infer -- model.onnx photo.jpg
设计理念
- 薄绑定 — 类型 / 错误码翻译,容器解码与验票全在 Core
- RAII —
Session不可Clone;Drop调darra_session_close(NULL 安全由 Core 保证) Result<T, Error>— 失败变体与darra_error_code1..=18 逐码对应;未知新码走Error::Unknown- 安全 API — 用户侧无需
unsafe;FFI 封在darra-ai-sys与本 crate 内部 - ABI 门 — 入口
ensure_abi():major 不等禁止继续
功能特性
| 功能 | API |
|---|---|
| 版本 | version() 打包 (major<<16)|(minor<<8)|patch;version_string() 形如 "1.0.0+runtime" / "1.0.0+authoring"(静态,禁止释放);version_major(packed) |
| 加密容器会话 | Session::open(path, key_path, password, prefer_provider);key_path 与 password 至少给一个,都给则 key 文件优先验票 |
| 可扩展入口 | Session::open_ex(path, &SessionOptions) — 当前翻译到 darra_session_open 四参(SessionOptions 只有 key_path / password / prefer_provider,没有 Core 的 intra/inter 线程字段) |
| 明文 ONNX | Session::open_plain(onnx_path, prefer_provider) |
| 元信息 | meta() UTF-8 JSON;feature json 下 meta_json() → serde_json::Value |
| 只读属性 | task / labels / input_width / input_height / channels / layout / payload_kind / provider_id / encrypted,全部从 meta JSON 派生 |
| 推理 | infer_image(&[u8], &ImageDesc);feature json 下 infer_image_json。v1 单张图像,不承诺硬实时 |
| 图像描述 | ImageDesc::auto() / rgb888(w,h,stride) / bgr888(w,h,stride);ImageFormat::{Auto, Encoded, Rgb888, Bgr888} |
| Provider 包 | runtime::ensure(profile, offline_zip, progress);runtime::cancel() |
| 环境自检 | diagnostics::collect();feature json 下 collect_json() |
签发(feature authoring) | encrypt_onnx / issue_key / fingerprint_perturb |
prefer_provider 为 None 时按载荷 × 硬件 × 已装包自动选;指名但不可用 = fail-closed,绝不静默降级。
快速示例:
use darra_ai::{ImageDesc, ImageFormat, Session, SessionOptions};
let session = Session::open_ex(
"model.darmodel",
&SessionOptions::new()
.key_path("model.darmkey")
.prefer_provider("onnx-cpu"),
)?;
let _ = session.task()?; // Some("detect") 或 None
let _ = session.provider_id()?; // 实际选中的 Provider,不是 prefer 入参
let _ = session.encrypted()?; // 明文 ONNX 为 false
let encoded = ImageDesc {
format: ImageFormat::Encoded,
width: 0,
height: 0,
stride: 0,
};
let _ = session.infer_image(&jpeg, &encoded)?;
进度回调 (percent 0..100, stage),stage ∈ probe / manifest / download / verify / install / done。回调在 SDK 内部工作线程触发,回调里禁止再调任何 darra API(ensure 的 trampoline 已挡住 panic 穿过 FFI)。cancel 可从任意线程调(含 UI);进度回调内部禁止调用。
Cargo feature
| feature | 默认 | 作用 |
|---|---|---|
json | 开 | serde_json:Session::infer_image_json / meta_json / diagnostics::collect_json |
authoring | 关 | 三个签发函数,连带打开 darra-ai-sys/authoring |
authoring:必须链接 authoring 版 Core
encrypt_onnx / issue_key / fingerprint_perturb 只在 Core 的 authoring 构建(DARRA_AUTHORING=ON)里有符号。runtime 构建物理上没有 darra_encrypt_ / darra_issue_ / darra_fingerprint_ 前缀,链接 runtime 再调用 = 链接/加载失败(物理隔离,不是权限开关)。
darra-ai = { path = "...", features = ["authoring"] }
调用顺序:fingerprint_perturb → encrypt_onnx → issue_key。扰动必须发生在加密前。
use darra_ai::authoring::{self, KeyOptions};
authoring::fingerprint_perturb("in.onnx", "perturbed.onnx", customer_seed)?;
authoring::encrypt_onnx("perturbed.onnx", "model.darmodel")?;
authoring::issue_key(
"model.darmodel",
Some("password"),
"model.darmkey",
Some(&KeyOptions::permanent()), // bind_machine=false, trial_runs=0
)?;
KeyOptions { bind_machine, trial_runs }:bind_machine=true 绑定签发时的机器指纹;trial_runs>0 为试用计次。password 为 None = 本授权不启用密码通道。密码无法事后找回,官方不解回明文。本模块零密码学:只转发 C ABI。
线程安全(头文件 §6)
- 不同会话可并发(
Session: Send)。 - 同一会话
infer_image可多线程并发(Session: Sync);吞吐扩展仍推荐每线程一个会话。 close(Drop)禁止与在飞调用并发——安全 Rust 借用 /Arc规则保证。diagnostics::collect耗时可到数百毫秒(WMI / NVML / sysfs),禁止在 PLC 扫描周期调用。runtime::ensure进程内互斥串行,重复/并发安全。
错误处理
失败返回 darra_ai::Error。每个变体对应一个 darra_error_code(1..=18);未知新码走 Error::Unknown { code, message, hint }(#[non_exhaustive],向前容忍)。message / hint 原样透传 Core,不改写。hint 文案权威见 错误码目录。
| 码 | 变体 |
|---|---|
| 1 | IoNotFound |
| 2 | IoDenied |
| 3 | BadContainer |
| 4 | BadLicense |
| 5 | PasswordRequired |
| 6 | PasswordWrong |
| 7 | MachineMismatch |
| 8 | TrialExhausted |
| 9 | UnsupportedPayload |
| 10 | UnsupportedPlatform |
| 11 | ProviderMissing |
| 12 | ProviderAbiMismatch |
| 13 | HardwareMissing |
| 14 | DriverTooOld |
| 15 | NetworkFailed |
| 16 | ChecksumMismatch |
| 17 | Cancelled |
| 18 | Internal |
Display 格式:[码] 描述 或 [码] 描述 | 建议: hint。另有 code() / message() / hint()。实现 std::error::Error。
match Session::open("model.darmodel", Some("model.darmkey"), None, None) {
Ok(s) => { let _ = s; }
Err(e) => eprintln!("{e}"), // 含 [码] 描述 | 建议: hint
}
版本兼容
当前绑定版本 1.0.0,与头文件 DARRA_VERSION_* 对齐。version_string() 后缀区分构建风味:客户机必须看到 +runtime。major 不等 = 装错了库,禁止继续。