プログラミング
Rustにおけるコレオグラフィックプログラミング
Choreographic Programming in Rust (github.com)
要約
Hibanaは、Rustで記述されたプログラムが単一のグローバルコレオグラフィから有限多者プロトコルを実行できるようにするライブラリです。コレオグラフィは各役割(ロール)ごとにコンパクトなプログラムに投影され、送受信やルーティングの各ステップは、進行がコミットされる前にそのプログラムと一致する必要があります。Hibanaは、コレオグラフィから派生したランタイム強制カーネルであり、allocatorを必要とせず、ストレージは呼び出し元が提供します。
全文翻訳
Hibana Hibanaは、Rustプログラムが単一のグローバルコレオグラフィから有限多者プロトコルを実行できるようにします。コレオグラフィは各役割のためにコンパクトなプログラムに投影され、送受信またはルーティングの各ステップは、進行がコミットされる前にそのプログラムと一致する必要があります。Hibanaは、コレオグラフィから派生したランタイム強制カーネルです。それは無条件にno_stdであり、allocatorを必要とせず、呼び出し元が提供するストレージを使用します。プロトコル状態は、各状態に対して個別のRust継続型ではなく、コンパクトなディスクリプタに保持されるため、プロトコルの成長がエンドポイント型の成長になることはありません。
最大256の役割に対応する単一のコレオグラフィ。完全な1バイトの役割ドメインを使用します。非同期送信、seq、par、バイナリルーティング、およびガード付きロール。ドロップは可能ですが、進行を2度公開できないアフィンエンドポイント。単一のTransportトレイトを介したトランスポートニュートラルな統合。ホストおよび組み込みターゲットで同じ公開APIを使用します。役割IDは0..=255をカバーします。投影、ルーティング参加、およびアタッチメントの計上は、実際のイベントとローカル参加者からストレージを導き出します。ランタイムは256エントリの役割テーブルを予約しません。複数のセッションにプロトコルを分割しても、保証の境界は変化します。Hibanaは、元のコレオグラフィ全体をグローバルプロトコルとしてではなく、各セッションをチェックします。Hibanaはネットワークスタックや分散アルゴリズムを実装しません。各アタッチされたエンドポイントでプロトコルを強制し、そのローカルな結果を分散保証に引き上げるために必要なキャリア、デプロイメント、コーデック、およびスケジューリング条件を述べます。
このREADMEは責任範囲ごとに構成されています。
読者
ここから始めてください。
評価するHibana
モデル
何が強制され、何が外部に残され、なぜエンドポイント型が小さく保たれるのか。
コレオグラフィを作成する
プロトコル言語
投影、メッセージ、ルーティング、並列フロー、および繰り返し。
役割を実装する
エンドポイント操作
送信、受信、オファー、ブランチ処理、および失敗の動作。
プロトコルを統合する
ランタイム境界
ストレージ、アタッチ、セッション、リゾルバ、および観測。
キャリアを実装する
トランスポート
完全な5オペレーション契約と配信前提条件。
デプロイメントを監査する
保証
ローカル保証、条件付き分散保証、リソース使用、および検証。
クイックスタート
クレートを追加する:cargo add hibana
クレートはRust 2024を使用し、安定版Rust 1.95以降が必要です。通常の依存関係はなく、フィーチャー選択されたホストバリアントもありません。
リポジトリチェックアウトから完全な2役割の例を実行する:cargo run --example ping_pong ping=7, pong=8
例は自己チェックであり、公開パッケージに含まれており、リリースゲートによって実行されます。examples/ping_pong.rsの完全なソースを読んでください。そのプロトコルは、一箇所で見えるほど小さいです。
use hibana::{ g::{self, Msg}, runtime::program::{RoleProgram, project}, }; fn ping_pong() -> (RoleProgram<0>, RoleProgram<1>) { let choreography = g::seq( g::send::<0, 1, Msg<1, u32>>(), g::send::<1, 0, Msg<2, u32>>(), ); (project(&choreography), project(&choreography)) }
実行可能な例は、呼び出し元所有のランタイムストレージとインメモリホストトランスポートを追加し、両方の役割プログラムを1つのSessionIdにアタッチし、send()とrecv()で2つのエンドポイントを駆動します。組み込みデプロイメントは独自のトランスポート、ストレージ予算、およびエグゼキュータを提供します。コレオグラフィとエンドポイント操作は同じままです。
モデル
グローバルコレオグラフィ -> 各役割ごとに一度 project(&choreography) -> コンパクトなRoleProgramディスクリプタ -> 各役割を1つのSessionIdにアタッチ -> Endpoint::send / recv / offer を駆動 -> 許可されたステップを正確に1つコミットするか、セッションを失敗させる。
多者(Multiparty)とは、ピア、方向、および順序が各役割に投影された単一のコレオグラフィから来ることを意味します。非同期(Asynchronous)とは、成功した送信がフレームをキャリアに転送することを意味し、リモート受信を待たないことを意味します。アフィン(Affine)とは、1つのライブエンドポイント所有者が投影されたステップを最大1回進めることができることを意味します。エンドポイントはドロップできますが、クローンしたり、重複した進行を公開するために使用したりすることはできません。
Hibanaには2つの公開サーフェスがあります。
| Audience | Surface | Responsibility |
|---|---|---|
| Role implementation | hibana::g, Endpoint, RouteBranch, EndpointError | メッセージを記述し、アタッチされた単一の役割を駆動する |
| Protocol integration | hibana::runtime | 役割を投影し、ストレージとトランスポートを提供し、セッションをアタッチし、明示的なリゾルバをインストールする |
アプリケーションコードは通常 hibana::g および Endpoint に留まります。プロトコル統合コードは hibana::runtime を使用します。キャリアの状態やディスクリプタの仕組みを役割コードに公開しません。docs.rs は、ここで説明されているのと同じサーフェスのシグネチャリファレンスです。
一時的なコレオグラフィ値はRust内でその構造を運び、project(&choreography) はコンパクトなRoleProgram<ROLE>を構築します。エンドポイントの将来(futures)は、コレオグラフィツリーや将来のペイロードタイプ全体を運びません。したがって、1つの投影されたアーティファクトを多くの分離されたセッションで再利用しても、エンドポイントタイプが倍増することはありません。投影は既存の公開DSLを単一の内部パスに低下させます。そのフラットなイベント行、スコープマーカー、リゾルバマーカー、およびアロケーションスクラッチは、エンドポイント、ディスクリプタヘッダー、またはPicoランタイム状態に入りません。
プロトコル言語
名前付きコレオグラフィは impl Projectable を返すことができ、Rustに式からステップリストを推測させます。これらの値は、投影前に同じg演算子を通じて合成されます。2番目の型レベル宣言は不要です。
use hibana::{g, runtime::program::{Projectable, project}}; fn exchange() -> impl Projectable { g::seq( g::send::<0, 1, g::Msg<1, u32>>(), g::send::<1, 0, g::Msg<2, u32>>(), ) }
let conversation = g::seq(exchange(), exchange());
let client = project::<0>(&conversation);
let server = project::<1>(&conversation);
Projectableは密封されており、Hibanaコレオグラフィコンストラクタのみがそれを確立します。投影されていない値はゼロサイズのままで、合成は具体的なステップリストと投影チェックを維持します。ランタイムエンドポイントおよび所有リソースは、このコレオグラフィインターフェースによってコピー可能になりません。
| Form | Meaning |
|---|---|
| g::send<FROM, TO, g::Msg<LABEL, PAYLOAD>>() | 単一の可視非同期メッセージ |
| g::seq(left, right) | left が right の前に来る |
| g::par(left, right) | 独立したアームは並行して進行できる |
| g::route(left, right) | 2つのプロトコルアームのいずれか |
| route.resolve<ID>() | 明示的なリゾルバが非メッセージ選択ボディを所有する |
| body.roll() | ガード付き構造領域は再入力できる |
投影は、サポートされていないルーティング形状、曖昧な同時エンドポイント操作、競合する並列レーン、空の並列アーム、およびガードなしの再入力を拒否します。論理メッセージラベルはコレオグラフィメッセージを識別します。それらはグローバルに一意である必要はありません。同じ役割の送信はゼロバイトのローカル効果であり、()を使用する必要があります。ペイロードデータをプライベートキューに隠しません。繰り返し領域は、エンドポイント型、ディスクリプタ行、または8バイトのコアフレームヘッダーに反復フィールドを追加しません。新鮮さは、投影された実行ルール、キャリアFIFO、リプレイ除外、および生成分離から来ます。フレームまたはエンドポイントを成長させることからではありません。
コンパクトディスクリプタドメインは、これらの明示的な制限を課します。
| Domain | Limit | Meaning |
|---|---|---|
| Roles | 256 | 完全なu8役割ドメイン、0..=255 |
| Event identities | 65,535 | 密なIDドメイン。u16::MAX は不在のセンチネルのまま |
| Program image | 65,535 B | 単一の不変グローバルイメージのコンパクトなu16バイトオフセットドメイン |
| Atom-only program | 7,281 events | 65,535 / 9; コントロール列がこの形状依存の天井を減らす |
| Role image | 65,535 B per role | 単一の投影された役割イメージのコンパクトなu16バイトオフセットドメイン |
| Structured scopes | Image-derived | 各スコープは少なくとも2つの5バイトマーカーを寄与するため、バイト天井はコンパクトなスコープIDドメインの前に束縛される |
| Route commit chain | Image-derived | u16ディスクリプタ範囲。個別のu8チェーン天井なし |
| Resolver identities | 65,536 | 完全なu16ドメイン。組み込み/動的権限はルーティング行で個別にタグ付けされる |
| Physical lanes | 256 | ストレージは正確な投影レーン範囲に従う。レーンは、エンドポイント-役割セットが競合せず、隠されたバインディングレーンが予約されていない場合に再利用される |
| Offer frontier | Descriptor-derived | アクティブキーのストレージはアクティブレーンに従う。再起動をまたぐ訪問済みIDは、有限ローカルステップドメインに従う |
| Inbound frame colors | 256 | 最大同時競合受信