重要な設計変更: 複雑なFactory設計から、極限までシンプルなTypeBoxアプローチへ移行しました。
TypeBoxは、C ABIプラグイン間でBox型情報を受け渡すための最小限の仕組みです。「Everything is Box」の哲学に従い、型情報すらBoxとして扱います。
// nyrt_typebox.h - すべてのプラグインが共有する最小限のヘッダ
typedef struct NyrtTypeBox {
uint32_t abi_tag; // 'TYBX' (0x58425954) マジックナンバー
const char* name; // "ArrayBox", "StringBox" など
void* (*create)(void); // Box生成関数(引数なし版)
} NyrtTypeBox;
// オプション:コンテキスト付き版(将来拡張用)
typedef struct NyrtTypeBoxV2 {
uint32_t abi_tag; // 'TYB2' (0x32425954)
uint16_t abi_major; // 1
uint16_t abi_minor; // 0
const char* name; // 型名
void* (*create)(void* context); // コンテキスト付き生成
uint32_t size; // sizeof(NyrtTypeBoxV2)
} NyrtTypeBoxV2;
// src/runtime/type_boxes.rs
use std::os::raw::c_void;
#[repr(C)]
pub struct NyrtTypeBox {
pub abi_tag: u32,
pub name: *const std::os::raw::c_char,
pub create: extern "C" fn() -> *mut c_void,
}
// ArrayBox用の静的TypeBox定義
#[no_mangle]
pub static ARRAY_TYPE_BOX: NyrtTypeBox = NyrtTypeBox {
abi_tag: 0x58425954, // 'TYBX'
name: b"ArrayBox\0".as_ptr() as *const _,
create: create_array_box_impl,
};
#[no_mangle]
extern "C" fn create_array_box_impl() -> *mut c_void {
// ArrayBoxインスタンスを作成
let array = ArrayBox::new();
let boxed = Box::new(array);
Box::into_raw(boxed) as *mut c_void
}
// オプション:型検証ヘルパー
#[no_mangle]
pub extern "C" fn nyrt_validate_typebox(tb: *const NyrtTypeBox) -> bool {
if tb.is_null() { return false; }
unsafe {
(*tb).abi_tag == 0x58425954
}
}
// plugins/map/map_box.c
#include "nyrt_typebox.h"
// MapBox.keys()の実装 - TypeBoxを引数で受け取る
void* map_keys(void* self, void* array_type_box) {
MapBox* map = (MapBox*)self;
NyrtTypeBox* array_type = (NyrtTypeBox*)array_type_box;
// 最小限の検証
if (!array_type || array_type->abi_tag != 0x58425954) {
return NULL;
}
// ArrayBoxを作成(直接関数ポインタを呼ぶ)
void* array = array_type->create();
if (!array) return NULL;
// キーをArrayBoxに追加
// 注:ArrayBoxのpushメソッドは別途C API経由で呼ぶ必要あり
for (size_t i = 0; i < map->size; i++) {
// ArrayBox固有のAPIを使用(プラグイン間の取り決め)
// array_push(array, map->entries[i].key);
}
return array;
}
// 呼び出し側の例
void example_usage(void* map) {
// ランタイムから型情報を取得(または静的に保持)
extern NyrtTypeBox ARRAY_TYPE_BOX; // ランタイムが提供
void* keys = map_keys(map, &ARRAY_TYPE_BOX);
// ...
}
GeminiとCodexによる深い技術分析の結果、以下の結論に至りました:
アプローチ | 複雑さ | MIR影響 | 保守性 |
---|---|---|---|
TypeBox(採用) | ★☆☆☆☆ | 最小 | 優秀 |
Factory Pattern | ★★★★☆ | 中 | 困難 |
COM/JNI風 | ★★★★★ | 大 | 複雑 |
サービスレジストリ | ★★★☆☆ | 中 | 良好 |
// TypeBoxは静的メタデータ(参照カウント不要)
// ランタイムが提供する不変のデータとして扱う
extern const NyrtTypeBox ARRAY_TYPE_BOX; // 'static lifetime
extern const NyrtTypeBox STRING_TYPE_BOX; // 'static lifetime
// 生成されたBoxインスタンスは通常通り参照カウント管理
void* array = array_type->create();
// 使用...
nyrt_release(array); // 既存の参照カウントAPI
// 最小限の検証で安全性を確保
bool is_valid_typebox(const NyrtTypeBox* tb) {
return tb != NULL &&
tb->abi_tag == 0x58425954 && // 'TYBX'
tb->name != NULL &&
tb->create != NULL;
}
// 使用例
if (!is_valid_typebox(array_type)) {
return NULL; // 不正なTypeBoxを拒否
}
直接生成: ~50ns
TypeBox経由: ~60ns(関数ポインタ1回)
→ ほぼ無視できるレベル
TypeBox構造体: 24bytes(最小構成)
グローバル変数: 0(すべて引数渡し)
→ 極めて効率的
// map_box.c
void* map_keys(void* self, void* array_type_box, void* string_type_box) {
MapBox* map = (MapBox*)self;
NyrtTypeBox* array_type = (NyrtTypeBox*)array_type_box;
NyrtTypeBox* string_type = (NyrtTypeBox*)string_type_box;
// TypeBox検証
if (!is_valid_typebox(array_type) || !is_valid_typebox(string_type)) {
return NULL;
}
// ArrayBox作成
void* array = array_type->create();
if (!array) return NULL;
// 各キーをStringBoxとして追加
for (size_t i = 0; i < map->size; i++) {
// 注:実際の実装では、ArrayBoxのpush APIを
// 別途定義された方法で呼び出す必要があります
}
return array;
}
「ご提案のTypeBoxアプローチは、NyashのC ABIにおけるBox生成ファクトリの設計として、これ以上ないほどシンプルかつ強力なものです。」
「Keep the concept, refine it: the TypeBox pointer is the sweet spot — explicit, cheap, zero global cache thrash, and one function pointer.”
「Everything is Box - 型情報すらBoxとして扱う」- TypeBoxアプローチ