Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Rustdoc JSONからFFIバインディングを自動生成してみた
Search
Itto Hiramoto
May 11, 2026
Programming
15
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Rustdoc JSONからFFIバインディングを自動生成してみた
Kyoto.rs #1
Itto Hiramoto
May 11, 2026
More Decks by Itto Hiramoto
See All by Itto Hiramoto
開発効率と性能の両立を目指すRust連携プログラミング言語Kaede
ittohiramoto
0
12
Other Decks in Programming
See All in Programming
生成AI導入の「期待外れ」を乗り越える ー 開発フロー改革が目指す、真の組織変革
starfish719
0
5k
人間の目はかわらない、だからJPEGは30年もつ
yuzneri
12
19k
ドリフトを絶対に許さない(?)CDK運用 / CDK Ops with Zero Tolerance for Drifts (?)
akihisaikeda
1
220
実装をデザインガイドラインに追従させるための取り組み / 260731-dip-mosh-design-system
dachi023
0
6.6k
typoなんかねぇよ
raspython3
0
100
使いながら育てる Claude Code — 開発フローの1コマンド化 × 繰り返し指摘の自動仕組み化
shiki_kakaku
0
1.9k
言葉の格闘技のススメ~紙とペンと言葉から始める、キャリアの描き方~
progresscicada
2
170
AIを紡ぐPMのお話
swdtkuy
0
120
仕様書を書く前にハーネスを作る - Agent Native開発は「探索を速く、判定を固く」
gotalab555
4
1.7k
TSX の <Hoge<Fuga>> という構文に驚いた話 / tsx-type-argument-syntax
kanaru0928
0
240
自動化したのに回らないテスト運用の壁ーAI時代の品質責任と生産性
mfunaki
1
150
変わらないものが、変わるものを決める — 意図駆動開発 × イベントソーシング × イミュータブル | What Doesn't Change Decides What Can — IDD × Event Sourcing × Immutability
tomohisa
0
1.8k
Featured
See All Featured
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
19k
Why You Should Never Use an ORM
jnunemaker
PRO
61
10k
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
730
Stewardship and Sustainability of Urban and Community Forests
pwiseman
0
480
Making the Leap to Tech Lead
cromwellryan
135
10k
Paper Plane (Part 1)
katiecoart
PRO
1
10k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
4.4k
Utilizing Notion as your number one productivity tool
mfonobong
4
550
New Earth Scene 8
popppiees
3
2.5k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
49
10k
How STYLIGHT went responsive
nonsquared
100
6.2k
Transcript
Rustdoc JSON から FFI バインディングを自動生成してみた 平本一桐 Kyoto.rs #1 1
自己紹介 平本 一桐 ヒラモト イットウ 放送大学 教養学部 教養学科 情報コース 3
年 普段はアルバイトとして、以下の開発をしています。 Web フロントエンド と バックエンド Elasticsearch を使った検索基盤の構築 ソースコードからコールグラフを生成する静的解析ツールの開発 プログラミング言語処理系を作るのが好きで、その中で出てきた小ネタを今日は 持ってきました。 2
自作言語 Kaede Web サーバーを簡潔に書くための静的型付け言語 LLVM バックエンド・GC 軽量スレッド + 非同期I/O —
多数の接続を素直に捌ける Rust に近い表現力 性能が要る所は Rust をそのまま呼べる import rust::mylib msg := rust::mylib::greet("Kyoto.rs") import rust::<crate> の一行で Rust の公開関数を直接呼べる — 今日はこの裏側の話 3
FFI 自動生成、二つの問い 入力と出力、それぞれ選択がある 入力:Rust の型情報を どこから取る? ソースを直接読む(syn )… 出力:何を吐いて Kaede
からリンクする? 元クレートに生やす / proc-macro で注入する … この 2 つを順に見ていきます 4
1. 入力 Rust の型情報をどう取るか 5
素朴なやり方 syn でソースを AST にする cbindgen と同じ路線 型はソースのトークンのまま — String
を見ても std::string::String なのか独自定義の型かは判別できない マクロ展開前の AST なので、 #[derive] などが生やした関数は 見えない visibility ・再エクスポート・依存クレート横断を すべて自前で解決 する必要 rustc が済ませた仕事を、自分でもう一度やるハメになる 6
アイデア rustdoc JSON で型情報を取る nightly の --output-format json で全部取れる cargo
+nightly rustdoc --manifest-path Cargo.toml --lib -- \ -Z unstable-options --output-format json target/doc/<crate>.json に 型・シグネチャ・visibility が構造化 で出力さ れる rustc 自身が解析した結果なので マクロ展開後・型解決済み これを読めば「公開関数の一覧と型」が機械的に取れる 代償は nightly 依存・フォーマット unstable ・rustdoc 実行が遅い 7
実装:rustdoc JSON を読む rustdoc-types の型に向けて serde_json::from_str let krate: Crate =
serde_json::from_str(&json_content)?; rustdoc-types 側は serde derive 付きの型定義を提供しているだけ pub struct Crate { pub index: HashMap<Id, Item>, // すべてのアイテム pub paths: HashMap<Id, ItemSummary>, // 他クレートの型解決用 pub format_version: u32, /* ... */ } pub enum Type { Primitive(String), // i32 / bool / char / ... Tuple(Vec<Type>), // () / (T, U) / ... BorrowedRef { /* .. */ }, // &T / &mut T ResolvedPath(Path), // 任意の名前付き型 /* ... */ } 8
2. 出力 何を吐いて Kaede からリンクするか 9
素朴なやり方 ① flutter_rust_bridge 流 生成ファイルを元クレートに取り込んでもらう extern "C" ラッパーを frb_generated.rs のような
Rust ファイルとして 書き出す 元クレートの lib.rs から mod frb_generated; で取り込み crate-type = ["cdylib"] でビルド 結局 元クレートの改変が必須 未改変の crates.io クレートを取り込みたい用途には弱い 10
素朴なやり方 ② napi-rs 流 proc-macro でコンパイル時に extern を注入 #[napi] pub
fn greet(name: String) -> String { /* ... */ } proc-macro が extern "C" ラッパーを コンパイル時に展開 展開後のコードは元クレートにそのままコンパイルされ cdylib に含まれる 結局 元クレートに #[napi] を貼る改変が必要 機構は違っても、結論は ① と同じ 11
アイデア Shim crate を生やす こんな小さな crate を、import ごとに自動生成 [package] name
= "kaede_rust_shim_mylib" [lib] crate-type = ["cdylib"] [dependencies] mylib = { path = "../../../mylib" } # ← 元クレートをそのまま参照 元クレートは 未改変 できあがった cdylib は Kaede がビルドする実行ファイルにリンク 12
実装①:Shim crate を生成する ディレクトリ丸ごと書き出して cargo build build/kaede_rust_shim/mylib/ ├── Cargo.toml #
cdylib + path 依存(前スライド) ├── src/ │ └── lib.rs # extern "C" ラッパー(次スライド) └── build.rs # Kaede ランタイム (libkd) を rustc-link-* で繋ぐ cdylib ・依存解決・リンクは全部 cargo に丸投げ 13
実装②:生成される lib.rs (イメージ) 元の Rust 関数を extern "C" ラッパーで包む //
元クレート mylib にある公開関数 pub fn format_user(id: u64, name: &str) -> String { /* ... */ } // 自動生成される shim/src/lib.rs #[unsafe(no_mangle)] pub extern "C" fn kaede_rust_shim_mylib_format_user( id: u64, name: *const KaedeStr, // KaedeStr &str は次スライド ) -> *mut KaedeString { rust_str_into_kaede_string( mylib::format_user( // ← 元関数を呼ぶ id, unsafe { kaede_str_as_rust_str(name) }, ) ) } 関数名はサニタイズして kaede_rust_shim_<crate>_<fn> に統一。 14
文字列の橋渡し &str / String をどう FFI 越しに運ぶか 引数 &str —
KaedeStr { ptr, len } をスライス化 → &str unsafe fn kaede_str_as_rust_str<'a>(v: *const KaedeStr) -> &'a str { let v = unsafe { &*v }; let bytes = unsafe { std::slice::from_raw_parts(v.ptr, v.len as usize) }; unsafe { std::str::from_utf8_unchecked(bytes) } } 戻り値 String — Kaede の GC ヒープに コピーして *mut KaedeString を返す fn rust_str_into_kaede_string(value: impl AsRef<str>) -> *mut KaedeString { let bytes = value.as_ref().as_bytes(); let ptr = unsafe { kaede_mem_alloc(bytes.len()) }.cast::<u8>(); unsafe { std::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, bytes.len()); } /* KaedeVectorU8 と KaedeString を同じく alloc して書き込む */ } 15
まとめ rustdoc JSON で FFI 自動化が素直になる ユーザーは import rust::<crate> の
1 行 入力は rustdoc JSON に、出力は cargo に任せる 元クレートを改変せず、そのまま使える 16
リポジトリ️ https://github.com/itto-hiramoto/kaede ご清聴ありがとうございました! 17