C ABIは、Nyashの基本プラグインシステムです。C言語の標準的な関数呼び出し規約を使用し、高速かつ軽量な実装を提供します。
#include <string.h>
#include <stdlib.h>
// 1. create関数:Boxを作成
void* string_create(const char* initial_value) {
char* str = malloc(strlen(initial_value) + 1);
strcpy(str, initial_value);
return str;
}
// 2. method関数:メソッドを実行
void* string_method(void* self, const char* method_name, void** args, int arg_count) {
char* str = (char*)self;
if (strcmp(method_name, "length") == 0) {
int* result = malloc(sizeof(int));
*result = strlen(str);
return result;
}
if (strcmp(method_name, "toUpperCase") == 0) {
char* upper = malloc(strlen(str) + 1);
for (int i = 0; str[i]; i++) {
upper[i] = toupper(str[i]);
}
upper[strlen(str)] = '\0';
return upper;
}
return NULL; // メソッドが見つからない
}
// 3. destroy関数:メモリを解放
void string_destroy(void* self) {
free(self);
}
[[plugins]]
name = "StringBox"
path = "./string_plugin.so"
type = "c-abi"
version = 1
# メソッドの戻り値型を指定
[plugins.methods]
length = { returns = "integer" }
toUpperCase = { returns = "string" }
C ABIでは、複雑なデータをTLV形式でやり取りします:
// TLVヘッダー
typedef struct {
uint8_t type; // 1=bool, 2=i64, 3=f64, 5=string, 6=handle
uint32_t length; // データ長
// この後にデータが続く
} TLVHeader;
// 複数の値を返す例
void* math_stats(void* self, const char* method_name, void** args, int arg_count) {
if (strcmp(method_name, "calculate") == 0) {
// 3つの値を返す: [min, max, average]
size_t total_size = sizeof(TLVHeader) * 3 + sizeof(double) * 3;
uint8_t* buffer = malloc(total_size);
uint8_t* ptr = buffer;
// min値
TLVHeader* hdr1 = (TLVHeader*)ptr;
hdr1->type = 3; // f64
hdr1->length = sizeof(double);
ptr += sizeof(TLVHeader);
*(double*)ptr = 1.0;
ptr += sizeof(double);
// 以下同様にmax値、average値を追加...
return buffer;
}
return NULL;
}
C ABIだけでは、プラグイン間でBoxを生成することができません。例えば、MapBoxがArrayBoxを返したい場合、MapBoxはArrayBoxの実装を知らないため直接作成できません。
この問題を解決するのがTypeBoxです。
TypeBoxは「型情報をBoxとして扱う」という概念です。型の生成方法をBoxとして渡すことで、プラグイン間の連携を可能にします。
// TypeBox構造体:型情報をBoxとして扱う
typedef struct {
uint32_t abi_tag; // 'TYBX' (0x54594258)
const char* name; // "ArrayBox"
void* (*create)(void); // Box生成関数
} TypeBox;
// MapBox.keys()の実装 - ArrayBoxのTypeBoxを引数で受け取る
void* map_keys(void* self, void* array_type_box) {
MapBox* map = (MapBox*)self;
TypeBox* array_type = (TypeBox*)array_type_box;
// 検証
if (!array_type || array_type->abi_tag != 0x54594258) {
return NULL;
}
// ArrayBoxを生成(TypeBox経由)
void* array = array_type->create();
if (!array) return NULL;
// MapのキーをArrayに追加
// (ArrayBoxのメソッドは別途C API経由で呼ぶ)
return array;
}
これらの場合は、C ABI + TypeBoxをベースに構築されたNyash ABIを検討してください。
C ABIは「シンプル・高速・安定」の3拍子が揃った、Nyashの基本プラグインシステムです。
迷ったらC ABIから始めるのが正解です!