Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Rustdoc JSONからFFIバインディングを自動生成してみた
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Itto Hiramoto
May 11, 2026
Programming
25
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
17
Other Decks in Programming
See All in Programming
Atomic Design, Enforced: Scaling Mobile Design Systems (next.app devCon / droidCon Berlin 2026)
steliosf
PRO
0
170
Agentic Software Factoryに、すごく賢いIF文を。 / super smart IF statement into the Agentic Software Factory.
rkaga
8
2.2k
C#の現在地 進化の歴史と、AI時代の.NET Everywhere
neuecc
5
5.2k
外から家のPCの電源入れたい!をPHPで解決する
kawashimo0
1
140
APNsからLive Activityを開始する話
yumnumm
0
170
Long Living Tokens, Die, Die, Die! (or: The One Ring is Banned in Modern)
sylph01
0
320
Domain-Driven Transformation
hschwentner
2
2.3k
PumaからFalconに移行したRailsアプリケーションでの実践
falcon8823
0
180
AI時代のコードレビューは人に向けるな、仕組みに向けろ
texmeijin
5
3.7k
R8 の設定見直しでアプリサイズ削減
andpad
0
220
半永久的に提供し続けられるプライベートクラウドを目指して ― 利用者の認知負荷を抑えるAPI抽象化とハードウェア世代交代の基盤設計
tomokon
0
500
Jetpack Compose Mechanisms
skydoves
3
820
Featured
See All Featured
Navigating Team Friction
lara
192
16k
Neural Spatial Audio Processing for Sound Field Analysis and Control
skoyamalab
0
570
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
410
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
1
3.4k
GitHub's CSS Performance
jonrohan
1033
470k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2.2k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.7k
Faster Mobile Websites
deanohume
310
32k
Optimizing for Happiness
mojombo
378
71k
First, design no harm
axbom
PRO
2
1.3k
Crafting Experiences
bethany
1
380
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