feat(phase-9.75g-0): Implement BID-FFI Day 3 - Box type integration
- Implement BID Box Bridge interface for Nyash Box <-> BID Handle conversion - Add StringBox BID bridge implementation with handle/TLV support - Add IntegerBox BID bridge implementation with handle/TLV support - Implement BoxRegistry for managing Box instances and handles - Add comprehensive tests for StringBox/IntegerBox BID round-trip - Extract helper functions for string/integer value extraction Everything is Box philosophy shines through unified BID integration! 🎉 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -0,0 +1,179 @@
|
|||||||
|
# ChatGPT先生による箱理論設計 最終レビュー結果 (2025-08-17)
|
||||||
|
|
||||||
|
## 🎯 総合評価
|
||||||
|
|
||||||
|
### ✅ **Executive Summary(ChatGPT判定)**
|
||||||
|
> **方向性は正しい**: primitives-by-value + box-by-handle は適切で、Everything is Box哲学を維持している。
|
||||||
|
> **1週間Phase 1は現実的**(スコープを限定すれば)
|
||||||
|
|
||||||
|
## 🔧 重要な修正提案
|
||||||
|
|
||||||
|
### 1. **Handle設計の改善** 🚨
|
||||||
|
```rust
|
||||||
|
// ❌ 現在の設計
|
||||||
|
Handle(String) // "StringBox:123" - 文字列解析コスト高い
|
||||||
|
|
||||||
|
// ✅ ChatGPT推奨
|
||||||
|
Handle {
|
||||||
|
type_id: u32, // StringBox=1, FileBox=6等
|
||||||
|
instance_id: u32 // インスタンス識別子
|
||||||
|
}
|
||||||
|
// または単一u64として: type_id << 32 | instance_id
|
||||||
|
```
|
||||||
|
|
||||||
|
**理由**: 文字列解析は遅く、エラーの原因。バイナリ形式が効率的。
|
||||||
|
|
||||||
|
### 2. **メタデータAPI追加** 💡
|
||||||
|
```c
|
||||||
|
// プラグインに追加すべき関数
|
||||||
|
u32 nyash_plugin_abi(void); // ABI版本(1)を返す
|
||||||
|
i32 nyash_plugin_init(const NyashHostVtable*, NyashPluginInfo*);
|
||||||
|
void nyash_plugin_shutdown(void);
|
||||||
|
```
|
||||||
|
|
||||||
|
**理由**: バージョン管理、ホスト連携、型・メソッド登録が必要。
|
||||||
|
|
||||||
|
### 3. **TLV統一フォーマット** 📦
|
||||||
|
```c
|
||||||
|
// BID-1 TLV仕様(ChatGPT提案)
|
||||||
|
struct BidTLV {
|
||||||
|
u16 version; // 1
|
||||||
|
u16 argc; // 引数数
|
||||||
|
// TLVs: u8 tag, u8 reserved, u16 size, payload
|
||||||
|
}
|
||||||
|
|
||||||
|
// タグ定義
|
||||||
|
1=Bool(1), 2=I32(4), 3=I64(8), 4=F32(4), 5=F64(8),
|
||||||
|
6=String(utf8), 7=Bytes, 8=Handle(8 bytes)
|
||||||
|
// 予約: 20=Result, 21=Option, 22=Array (Phase 2)
|
||||||
|
```
|
||||||
|
|
||||||
|
**理由**: メソッドごとの個別エンコードを避け、統一フォーマットで効率化。
|
||||||
|
|
||||||
|
### 4. **メモリ管理の明確化** 🛠️
|
||||||
|
```c
|
||||||
|
// ChatGPT推奨: 2回呼び出しパターン
|
||||||
|
// 1回目: result_ptr=null でサイズ取得
|
||||||
|
// 2回目: ホストがallocateして再呼び出し
|
||||||
|
i32 nyash_plugin_invoke(..., result_ptr, result_len);
|
||||||
|
```
|
||||||
|
|
||||||
|
**理由**: 所有権が明確、メモリリーク回避。
|
||||||
|
|
||||||
|
## 📊 各質問への回答
|
||||||
|
|
||||||
|
### 1. 箱理論の技術的妥当性 ✅
|
||||||
|
- **適切性**: 全Boxをハンドル統一は妥当
|
||||||
|
- **統一扱い**: 既存/プラグインを同一レジストリで管理可
|
||||||
|
- **ハンドル表現**: バイナリ形式(type_id, instance_id)に変更推奨
|
||||||
|
|
||||||
|
### 2. 最低設計のメリット・デメリット ✅
|
||||||
|
- **メリット**: 実装最短、既存Box再利用最大化、API安定
|
||||||
|
- **デメリット**: Array/Map未対応で複合データが冗長(TLVで緩和可)
|
||||||
|
- **戦略**: Phase 1基本 → Phase 2拡張は正解
|
||||||
|
|
||||||
|
### 3. 既存資産活用の是非 ✅
|
||||||
|
- **FutureBox再利用**: 正解、二重実装回避
|
||||||
|
- **統合アプローチ**: 適切、メソッドIDはメタデータで合意
|
||||||
|
- **純粋性トレードオフ**: 実用性を優先が現実的
|
||||||
|
|
||||||
|
### 4. 実装現実性 ✅
|
||||||
|
- **1週間**: 現実的(スコープ限定時)
|
||||||
|
- **統合難易度**: 中レベル、FutureBoxのwake統合がポイント
|
||||||
|
- **Linux x86-64限定**: 妥当
|
||||||
|
|
||||||
|
### 5. 将来拡張性 ✅
|
||||||
|
- **gRPC/REST**: invoke+TLVをRPCカプセル化で対応可
|
||||||
|
- **Transport抽象化**: Phase 2でTransportBox導入
|
||||||
|
- **P2P**: 同じinvokeメッセージで転送可能
|
||||||
|
|
||||||
|
## 🔧 具体的な実装修正案
|
||||||
|
|
||||||
|
### BidType修正版
|
||||||
|
```rust
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum BidType {
|
||||||
|
// プリミティブ(値渡し)
|
||||||
|
Bool, I32, I64, F32, F64, String, Bytes,
|
||||||
|
|
||||||
|
// Box参照(ハンドル)
|
||||||
|
Handle { type_id: u32, instance_id: u32 },
|
||||||
|
|
||||||
|
// メタ型
|
||||||
|
Void,
|
||||||
|
|
||||||
|
// Phase 2予約(TLVタグ予約済み)
|
||||||
|
Option(Box<BidType>), // tag=21
|
||||||
|
Result(Box<BidType>, Box<BidType>), // tag=20
|
||||||
|
Array(Box<BidType>), // tag=22
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### C ABI修正版
|
||||||
|
```c
|
||||||
|
// メタデータ構造体
|
||||||
|
typedef struct {
|
||||||
|
u32 type_id;
|
||||||
|
const char* type_name;
|
||||||
|
u32 method_count;
|
||||||
|
// メソッドテーブル...
|
||||||
|
} NyashPluginInfo;
|
||||||
|
|
||||||
|
// ホスト機能
|
||||||
|
typedef struct {
|
||||||
|
void* (*alloc)(size_t size);
|
||||||
|
void (*free)(void* ptr);
|
||||||
|
void (*wake)(u32 future_id); // FutureBox起床
|
||||||
|
void (*log)(const char* msg);
|
||||||
|
} NyashHostVtable;
|
||||||
|
|
||||||
|
// プラグインAPI
|
||||||
|
u32 nyash_plugin_abi(void);
|
||||||
|
i32 nyash_plugin_init(const NyashHostVtable* host, NyashPluginInfo* info);
|
||||||
|
i32 nyash_plugin_invoke(u32 type_id, u32 method_id, u32 instance_id,
|
||||||
|
const u8* args, size_t args_len,
|
||||||
|
u8* result, size_t* result_len);
|
||||||
|
void nyash_plugin_shutdown(void);
|
||||||
|
```
|
||||||
|
|
||||||
|
## ⚠️ リスク対策
|
||||||
|
|
||||||
|
### ChatGPT指摘のリスク
|
||||||
|
1. **ハンドル再利用**: generation追加で回避
|
||||||
|
2. **スレッド前提**: シングルスレッド前提を明記
|
||||||
|
3. **メソッドID衝突**: ビルド時固定で回避
|
||||||
|
4. **エラー伝播**: トランスポート/ドメインエラー分離
|
||||||
|
5. **文字列エンコード**: UTF-8必須、内部NUL禁止
|
||||||
|
|
||||||
|
## 📋 Phase 1実装チェックリスト(ChatGPT提案)
|
||||||
|
|
||||||
|
- [ ] BID-1 TLV仕様とエラーコード定義
|
||||||
|
- [ ] ホストレジストリ + Handle{type_id,instance_id}
|
||||||
|
- [ ] プラグインinit/abi/shutdown追加
|
||||||
|
- [ ] 既存StringBox/IntegerBox/FutureBoxブリッジ
|
||||||
|
- [ ] FileBoxプラグイン(open/read/close)
|
||||||
|
- [ ] FutureBox用wake経路
|
||||||
|
- [ ] 適合性テスト(プリミティブ、ハンドル、エラー)
|
||||||
|
|
||||||
|
## 🚀 結論
|
||||||
|
|
||||||
|
ChatGPT先生の判定:
|
||||||
|
> **箱理論設計は技術的に妥当!** ただし具体的な実装詳細で重要な改善提案あり。
|
||||||
|
|
||||||
|
### 主要な価値
|
||||||
|
1. **Everything is Box哲学の技術的実現**を評価
|
||||||
|
2. **具体的で実装可能な修正案**を提示
|
||||||
|
3. **1週間実装の現実性**を確認
|
||||||
|
4. **将来拡張への明確な道筋**を提示
|
||||||
|
|
||||||
|
### 推奨アクション
|
||||||
|
1. Handle設計をバイナリ形式に変更
|
||||||
|
2. メタデータAPIを追加
|
||||||
|
3. TLV統一フォーマット導入
|
||||||
|
4. Phase 1スコープでの実装開始
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**レビュー日**: 2025-08-17
|
||||||
|
**レビュワー**: ChatGPT-5
|
||||||
|
**結論**: 方向性正しい、実装詳細要修正、1週間実装可能
|
||||||
@ -0,0 +1,248 @@
|
|||||||
|
# Phase 9.75g-0 修正版: Everything is Box哲学準拠のシンプル設計
|
||||||
|
|
||||||
|
## 🎯 基本方針:Nyash哲学ファースト
|
||||||
|
|
||||||
|
**重要な気づき**: ChatGPT設計は一般的だが、**既存のFutureBox等と二重実装**になってしまう。
|
||||||
|
Nyashの「Everything is Box」哲学を貫き、既存資産を活用する。
|
||||||
|
|
||||||
|
## 🌟 Nyash哲学に準拠した設計
|
||||||
|
|
||||||
|
### 1. 型システム:プリミティブ + Handle
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// src/bid/types.rs - Everything is Box哲学準拠
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum BidType {
|
||||||
|
// === プリミティブ型(FFI境界で直接渡せる) ===
|
||||||
|
Bool, // Nyashのbool literal
|
||||||
|
I32, // 32ビット整数
|
||||||
|
I64, // Nyashの標準整数
|
||||||
|
F32, // 32ビット浮動小数点
|
||||||
|
F64, // Nyashの標準浮動小数点
|
||||||
|
String, // UTF-8文字列 (ptr: usize, len: usize)
|
||||||
|
Bytes, // バイナリデータ (ptr: usize, len: usize)
|
||||||
|
|
||||||
|
// === Everything is Box: すべてのBoxは統一Handle ===
|
||||||
|
Handle(String), // "StringBox:123", "FileBox:456", "FutureBox:789"
|
||||||
|
|
||||||
|
// === メタ型(FFI用) ===
|
||||||
|
Void, // 戻り値なし
|
||||||
|
|
||||||
|
// Phase 2以降で追加(定義だけ先に)
|
||||||
|
Option(Box<BidType>), // Option<T>
|
||||||
|
Result(Box<BidType>, Box<BidType>), // Result<T, E>
|
||||||
|
Array(Box<BidType>), // Array<T>
|
||||||
|
|
||||||
|
// === Everything is Box哲学の拡張 ===
|
||||||
|
// Array, Map, Future等はすべてHandle("ArrayBox:id")として扱う
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nyashの既存Boxとの対応表
|
||||||
|
/*
|
||||||
|
Handle("StringBox:123") → StringBox インスタンス
|
||||||
|
Handle("IntegerBox:456") → IntegerBox インスタンス
|
||||||
|
Handle("FutureBox:789") → FutureBox インスタンス(非同期)
|
||||||
|
Handle("FileBox:101") → FileBox インスタンス
|
||||||
|
Handle("ArrayBox:102") → ArrayBox インスタンス
|
||||||
|
Handle("P2PBox:103") → P2PBox インスタンス
|
||||||
|
*/
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. シンプルなBoxヘッダー(Nyash統一仕様)
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// 既存のNyash Boxヘッダーと統一
|
||||||
|
#[repr(C, align(8))]
|
||||||
|
pub struct BoxHeader {
|
||||||
|
magic: u32, // "NYBX" (0x5859424E)
|
||||||
|
version: u16, // 1
|
||||||
|
_pad: u16, // アライメント用
|
||||||
|
type_id: u32, // BoxTypeId(StringBox=1, FileBox=2等)
|
||||||
|
instance_id: u32, // インスタンス識別子
|
||||||
|
ref_count: u32, // 非atomic(Nyashはシングルスレッド中心)
|
||||||
|
flags: u32, // 将来の拡張用
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nyashの既存Box型との統合
|
||||||
|
pub const NYASH_BOX_TYPES: &[(u32, &str)] = &[
|
||||||
|
(1, "StringBox"),
|
||||||
|
(2, "IntegerBox"),
|
||||||
|
(3, "BoolBox"),
|
||||||
|
(4, "ArrayBox"),
|
||||||
|
(5, "MapBox"),
|
||||||
|
(6, "FileBox"), // プラグインで提供
|
||||||
|
(7, "FutureBox"), // 既存の非同期Box
|
||||||
|
(8, "P2PBox"), // 既存のP2P Box
|
||||||
|
// 新しいプラグインBoxも同じ仕組みで追加
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 単一エントリーポイント(Everything is Box対応)
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Nyashの全Boxを統一的に扱える設計
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn nyash_plugin_invoke(
|
||||||
|
box_type_id: u32, // どのBox型?(StringBox=1, FileBox=6等)
|
||||||
|
method_id: u32, // どのメソッド?(open=1, read=2等)
|
||||||
|
instance_id: u32, // どのインスタンス?(Handle解析用)
|
||||||
|
args_ptr: *const u8, // 引数データ
|
||||||
|
args_len: usize, // 引数サイズ
|
||||||
|
result_ptr: *mut u8, // 結果置き場
|
||||||
|
result_len: *mut usize, // 結果サイズ
|
||||||
|
) -> i32 { // 0=成功, 非0=エラー
|
||||||
|
// Everything is Box哲学:すべて同じ仕組みで処理
|
||||||
|
}
|
||||||
|
|
||||||
|
// 既存のNyash Boxとの統合例
|
||||||
|
fn handle_stringbox_call(method_id: u32, instance_id: u32, args: &[u8]) -> Result<Vec<u8>, BidError> {
|
||||||
|
match method_id {
|
||||||
|
1 => { /* length() */ },
|
||||||
|
2 => { /* substring() */ },
|
||||||
|
3 => { /* append() */ },
|
||||||
|
_ => Err(BidError::MethodNotFound),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_filebox_call(method_id: u32, instance_id: u32, args: &[u8]) -> Result<Vec<u8>, BidError> {
|
||||||
|
match method_id {
|
||||||
|
1 => { /* open() */ },
|
||||||
|
2 => { /* read() */ },
|
||||||
|
3 => { /* write() */ },
|
||||||
|
4 => { /* close() */ },
|
||||||
|
_ => Err(BidError::MethodNotFound),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 既存Nyash Boxとの統合戦略
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// src/bid/integration.rs - 既存Boxとの橋渡し
|
||||||
|
|
||||||
|
pub struct NyashBoxRegistry {
|
||||||
|
// 既存のStringBox、ArrayBox等のインスタンス管理
|
||||||
|
instances: HashMap<u32, Arc<RwLock<dyn NyashBox>>>,
|
||||||
|
next_id: AtomicU32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NyashBoxRegistry {
|
||||||
|
pub fn register_box(&self, box_instance: Arc<RwLock<dyn NyashBox>>) -> u32 {
|
||||||
|
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
|
||||||
|
self.instances.insert(id, box_instance);
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call_method(&self, type_id: u32, instance_id: u32, method_id: u32, args: &[u8])
|
||||||
|
-> Result<Vec<u8>, BidError>
|
||||||
|
{
|
||||||
|
match type_id {
|
||||||
|
1 => self.call_stringbox_method(instance_id, method_id, args),
|
||||||
|
6 => self.call_filebox_method(instance_id, method_id, args),
|
||||||
|
7 => self.call_futurebox_method(instance_id, method_id, args), // 既存FutureBox活用!
|
||||||
|
_ => Err(BidError::UnknownBoxType(type_id)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📋 修正された実装計画
|
||||||
|
|
||||||
|
### Day 1: Nyash統合基盤
|
||||||
|
- [ ] `src/bid/types.rs` - Everything is Box準拠型定義
|
||||||
|
- [ ] `src/bid/registry.rs` - 既存Box統合レジストリ
|
||||||
|
- [ ] `src/bid/header.rs` - 統一Boxヘッダー
|
||||||
|
- [ ] テスト: 既存StringBoxとの統合
|
||||||
|
|
||||||
|
### Day 2: プラグインローダー
|
||||||
|
- [ ] `src/bid/loader.rs` - dlopen/dlsym
|
||||||
|
- [ ] 最小プラグイン(MathBox拡張)
|
||||||
|
- [ ] テスト: 既存BoxとプラグインBoxの共存
|
||||||
|
|
||||||
|
### Day 3: Handle型統合
|
||||||
|
- [ ] Handle("FileBox:123")の解決機構
|
||||||
|
- [ ] プリミティブ⇔Handle変換
|
||||||
|
- [ ] テスト: 全Box型の統一的操作
|
||||||
|
|
||||||
|
### Day 4: FileBox実装
|
||||||
|
- [ ] FileBoxプラグインの完全実装
|
||||||
|
- [ ] 既存のNyashコードとの互換性
|
||||||
|
- [ ] テスト: FileBox e2e動作
|
||||||
|
|
||||||
|
### Day 5: エラー処理とOption/Result
|
||||||
|
- [ ] 統一エラーシステム
|
||||||
|
- [ ] Option/Result型の最小実装
|
||||||
|
- [ ] テスト: エラーケース網羅
|
||||||
|
|
||||||
|
### Day 6-7: 統合テスト・ドキュメント
|
||||||
|
- [ ] 既存インタープリターとの統合
|
||||||
|
- [ ] 使用例とドキュメント
|
||||||
|
- [ ] Linux x86-64 CI設定
|
||||||
|
|
||||||
|
## 🌟 この設計の哲学的利点
|
||||||
|
|
||||||
|
### 1. Everything is Box哲学の完全準拠
|
||||||
|
```nyash
|
||||||
|
// Nyashコード側:変わらない!
|
||||||
|
local file = new FileBox("test.txt", "r") // プラグイン提供
|
||||||
|
local future = new FutureBox() // 既存Box
|
||||||
|
local array = new ArrayBox() // 既存Box
|
||||||
|
|
||||||
|
// すべて同じHandle("BoxType:id")として扱われる
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 既存資産の完全活用
|
||||||
|
- ❌ 新しいBidFuture実装 → ✅ 既存FutureBox活用
|
||||||
|
- ❌ 新しい型システム → ✅ 既存Nyash型との統合
|
||||||
|
- ❌ 二重実装 → ✅ 単一の統一システム
|
||||||
|
|
||||||
|
### 3. スレッド最小設計
|
||||||
|
```rust
|
||||||
|
// Nyashの現実に合わせた設計
|
||||||
|
ref_count: u32, // 非atomic(シングルスレッド中心)
|
||||||
|
|
||||||
|
// Phase 2以降でatomic対応を検討
|
||||||
|
#[cfg(feature = "atomic")]
|
||||||
|
ref_count: AtomicU32,
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. エラー対策の強化
|
||||||
|
```rust
|
||||||
|
// 統一エラー処理でプラグインの安定性向上
|
||||||
|
pub enum BidError {
|
||||||
|
UnknownBoxType(u32),
|
||||||
|
InstanceNotFound(u32),
|
||||||
|
MethodNotFound(u32),
|
||||||
|
InvalidArguments(String),
|
||||||
|
PluginError(String), // プラグイン側エラーを安全に伝播
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## ✅ 成功基準(Everything is Box準拠)
|
||||||
|
|
||||||
|
### 必須
|
||||||
|
- [ ] 既存StringBox、ArrayBoxとプラグインFileBoxが同じ仕組みで動作
|
||||||
|
- [ ] Handle("FileBox:123")でのBox操作
|
||||||
|
- [ ] 既存FutureBoxの活用(新実装なし)
|
||||||
|
- [ ] すべてのBoxが統一的にアクセス可能
|
||||||
|
|
||||||
|
### 理想
|
||||||
|
- [ ] 新しいプラグインBoxも既存Boxと見分けがつかない
|
||||||
|
- [ ] Nyashコード側は変更不要
|
||||||
|
- [ ] Everything is Box哲学の技術的実現
|
||||||
|
|
||||||
|
## 📝 まとめ
|
||||||
|
|
||||||
|
**ChatGPT先生の一般論は正しいが、Nyashの独特な哲学には合わない。**
|
||||||
|
|
||||||
|
**Nyash Way**: Everything is Box → すべてHandle + 既存Box活用
|
||||||
|
**一般的Way**: 型システム分離 → 新しい実装追加
|
||||||
|
|
||||||
|
**結論**: Nyashの哲学を貫いて、既存の資産を最大活用する設計で進む!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**修正日**: 2025-08-17
|
||||||
|
**修正理由**: Everything is Box哲学の完全準拠、既存資産活用
|
||||||
|
**キーワード**: Simple, Nyash-native, No-duplication
|
||||||
@ -0,0 +1,231 @@
|
|||||||
|
# Phase 9.75g-0 最終修正版: ChatGPT先生の知恵を反映した型設計
|
||||||
|
|
||||||
|
## 🎯 ChatGPT先生の明確な判断
|
||||||
|
|
||||||
|
> **結論**: Future/StreamはBidType(値型)に含めないでください。非同期性は「実行モデル」であって「値の表現」ではありません。
|
||||||
|
|
||||||
|
## 🛠️ 修正された型システム設計
|
||||||
|
|
||||||
|
### 1. 値型(BidType)- 純粋な値のみ
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// src/bid/types.rs - ChatGPT先生推奨の清潔な設計
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum BidType {
|
||||||
|
// === 基本型(Phase 1で実装) ===
|
||||||
|
Bool,
|
||||||
|
I32,
|
||||||
|
I64,
|
||||||
|
F32,
|
||||||
|
F64,
|
||||||
|
String, // (ptr: usize, len: usize)
|
||||||
|
Bytes, // (ptr: usize, len: usize)
|
||||||
|
|
||||||
|
// === 複合型(Phase 2で実装) ===
|
||||||
|
Array(Box<BidType>), // 配列
|
||||||
|
List(Box<BidType>), // 可変長リスト
|
||||||
|
Map(Box<BidType>, Box<BidType>), // キーバリューマップ
|
||||||
|
Tuple(Vec<BidType>), // タプル
|
||||||
|
Record(Vec<(String, BidType)>), // 名前付きフィールド
|
||||||
|
Variant(Vec<(String, Option<BidType>)>), // 列挙型
|
||||||
|
|
||||||
|
// === 特殊型(Phase 2で実装) ===
|
||||||
|
Option(Box<BidType>), // null許容
|
||||||
|
Result(Box<BidType>, Box<BidType>), // エラー型
|
||||||
|
Handle(String), // 不透明ハンドル(同期リソース用)
|
||||||
|
Void, // 戻り値なし
|
||||||
|
|
||||||
|
// === 拡張用(定義だけ) ===
|
||||||
|
Opaque(String), // 不透明型
|
||||||
|
|
||||||
|
// ❌ 削除: Future/Streamは値型ではない!
|
||||||
|
// Future(Box<BidType>), // 削除
|
||||||
|
// Stream(Box<BidType>), // 削除
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 実行モデル(MethodShape)- 新設計
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// メソッドの実行形状を表現(ChatGPT推奨)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum MethodShape {
|
||||||
|
Sync, // 通常の同期呼び出し
|
||||||
|
Async, // Future<T>を返す(ハンドル経由)
|
||||||
|
Streaming, // Stream<T>を返す(ハンドル経由)
|
||||||
|
}
|
||||||
|
|
||||||
|
// メソッドシグネチャ(形状と値型を分離)
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct MethodSig {
|
||||||
|
pub name: String,
|
||||||
|
pub shape: MethodShape, // 実行モデル
|
||||||
|
pub params: Vec<BidType>, // 引数の値型
|
||||||
|
pub returns: BidType, // 戻り値の値型(Future抜き)
|
||||||
|
pub effects: Vec<Effect>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// BID定義でメソッド記述
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Method {
|
||||||
|
pub sig: MethodSig,
|
||||||
|
pub doc: Option<String>,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 非同期ハンドル(FFI境界用)
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// ChatGPT推奨のハンドル方式
|
||||||
|
use std::ffi::c_void;
|
||||||
|
|
||||||
|
// FFI境界での非同期ハンドル(不透明ポインタ)
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct BidFutureHandle(*mut c_void);
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct BidStreamHandle(*mut c_void);
|
||||||
|
|
||||||
|
// Rust側の安全ラッパー
|
||||||
|
pub struct BidFuture {
|
||||||
|
handle: BidFutureHandle,
|
||||||
|
return_type: BidType,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BidStream {
|
||||||
|
handle: BidStreamHandle,
|
||||||
|
item_type: BidType,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将来のRust async/await統合
|
||||||
|
impl std::future::Future for BidFuture {
|
||||||
|
type Output = Result<BidValue, BidError>;
|
||||||
|
|
||||||
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
// FFI経由でpolling or callback設定
|
||||||
|
unimplemented!("Phase 3で実装")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl futures_core::Stream for BidStream {
|
||||||
|
type Item = Result<BidValue, BidError>;
|
||||||
|
|
||||||
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
|
unimplemented!("Phase 3で実装")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Connection trait(形状別実装)
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// ChatGPT推奨の分離アプローチ
|
||||||
|
pub trait Connection: Send + Sync {
|
||||||
|
// 同期呼び出し(Phase 1で実装)
|
||||||
|
fn invoke(&self, sig: &MethodSig, args: &[BidValue]) -> Result<BidValue, BidError>;
|
||||||
|
|
||||||
|
// 非同期呼び出し(Phase 3で実装)
|
||||||
|
fn invoke_future(&self, sig: &MethodSig, args: &[BidValue]) -> Result<BidFuture, BidError> {
|
||||||
|
Err(BidError::Unsupported("async not supported yet".to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ストリーミング(Phase 3で実装)
|
||||||
|
fn invoke_stream(&self, sig: &MethodSig, args: &[BidValue]) -> Result<BidStream, BidError> {
|
||||||
|
Err(BidError::Unsupported("streaming not supported yet".to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. FFI境界の非同期API(Phase 3で実装)
|
||||||
|
|
||||||
|
```c
|
||||||
|
// ChatGPT推奨のC ABI設計(Phase 3で実装予定)
|
||||||
|
|
||||||
|
// Future操作
|
||||||
|
extern "C" fn bid_future_poll(
|
||||||
|
handle: *mut c_void,
|
||||||
|
out_value: *mut BidValue,
|
||||||
|
out_is_ready: *mut bool
|
||||||
|
) -> BidStatus;
|
||||||
|
|
||||||
|
extern "C" fn bid_future_set_callback(
|
||||||
|
handle: *mut c_void,
|
||||||
|
callback: extern "C" fn(*mut c_void, BidValue, BidStatus),
|
||||||
|
user_data: *mut c_void
|
||||||
|
) -> BidStatus;
|
||||||
|
|
||||||
|
extern "C" fn bid_future_cancel(handle: *mut c_void) -> BidStatus;
|
||||||
|
extern "C" fn bid_future_free(handle: *mut c_void);
|
||||||
|
|
||||||
|
// Stream操作
|
||||||
|
extern "C" fn bid_stream_poll_next(
|
||||||
|
handle: *mut c_void,
|
||||||
|
out_item: *mut BidValue,
|
||||||
|
out_has_item: *mut bool,
|
||||||
|
out_is_closed: *mut bool
|
||||||
|
) -> BidStatus;
|
||||||
|
|
||||||
|
extern "C" fn bid_stream_set_callback(
|
||||||
|
handle: *mut c_void,
|
||||||
|
callback: extern "C" fn(*mut c_void, BidValue, bool, BidStatus),
|
||||||
|
user_data: *mut c_void
|
||||||
|
) -> BidStatus;
|
||||||
|
|
||||||
|
extern "C" fn bid_stream_close(handle: *mut c_void) -> BidStatus;
|
||||||
|
extern "C" fn bid_stream_free(handle: *mut c_void);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📋 修正された実装スケジュール
|
||||||
|
|
||||||
|
### Phase 1(1週間)- 同期のみ
|
||||||
|
```rust
|
||||||
|
// 実装するもの
|
||||||
|
- BidType基本型(Bool, I32, I64, F32, F64, String)
|
||||||
|
- MethodShape::Syncのみ
|
||||||
|
- DynamicLibraryコネクター
|
||||||
|
- Connection::invoke()のみ
|
||||||
|
|
||||||
|
// 実装しないもの
|
||||||
|
- 非同期型(Future/Stream) → 定義から削除済み
|
||||||
|
- MethodShape::Async/Streaming → unsupportedエラー
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 2(2週間後)- 複合型
|
||||||
|
```rust
|
||||||
|
// 追加実装
|
||||||
|
- Array, List, Map, Option, Result型
|
||||||
|
- エラー処理の充実
|
||||||
|
- 複数プラグイン同時ロード
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 3(1ヶ月後)- 非同期
|
||||||
|
```rust
|
||||||
|
// ハンドル方式で非同期追加
|
||||||
|
- BidFuture/BidStream実装
|
||||||
|
- FFI境界非同期API
|
||||||
|
- Rust async/await統合
|
||||||
|
- WasmComponent対応
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🌟 ChatGPT先生の知恵のまとめ
|
||||||
|
|
||||||
|
1. **型と実行モデルの分離** - 値型は純粋に、実行形状は別定義
|
||||||
|
2. **FFI境界の現実性** - ハンドル+API関数群で非同期表現
|
||||||
|
3. **WASM整合性** - Component Modelの流儀に準拠
|
||||||
|
4. **段階的実装** - unsupportedエラーでpanic回避
|
||||||
|
5. **将来拡張性** - Transport差異を抽象化で吸収
|
||||||
|
|
||||||
|
## ✅ この設計の利点
|
||||||
|
|
||||||
|
- **シンプル**: 型システムが明確(値型のみ)
|
||||||
|
- **拡張可能**: 実行モデルを後から追加可能
|
||||||
|
- **FFI現実的**: C ABIで実際に渡せる形
|
||||||
|
- **標準準拠**: WASM Component Modelと整合
|
||||||
|
- **実装しやすい**: 同期から始めて段階的に
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**修正日**: 2025-08-17
|
||||||
|
**修正理由**: ChatGPT先生のアドバイス適用
|
||||||
|
**重要な変更**: Future/Stream削除、MethodShape導入
|
||||||
91
local_tests/bid_async_design_review.txt
Normal file
91
local_tests/bid_async_design_review.txt
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
Nyash BID-FFI実装の型定義ファースト戦略について、特に非同期型の設計に関してレビューをお願いします。
|
||||||
|
|
||||||
|
【現在の設計】
|
||||||
|
phase_9_75g_0_revised_type_first_approach.mdより抜粋:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
pub enum BidType {
|
||||||
|
// 基本型
|
||||||
|
Bool, I32, I64, F32, F64, String, Bytes,
|
||||||
|
|
||||||
|
// 複合型
|
||||||
|
Array(Box<BidType>), Map(Box<BidType>, Box<BidType>),
|
||||||
|
Option(Box<BidType>), Result(Box<BidType>, Box<BidType>),
|
||||||
|
|
||||||
|
// === 問題のある部分 ===
|
||||||
|
Future(Box<BidType>), // 非同期結果
|
||||||
|
Stream(Box<BidType>), // ストリーム
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
【懸念点】
|
||||||
|
1. **Future/StreamはBidTypeに含めるべきか?**
|
||||||
|
- FFI境界でFutureそのものは渡せない
|
||||||
|
- C ABIは基本的に同期的
|
||||||
|
- 非同期は実装の詳細であって値の型ではない?
|
||||||
|
|
||||||
|
2. **現在のConnection trait設計**
|
||||||
|
```rust
|
||||||
|
trait Connection {
|
||||||
|
fn invoke(&self, ...) -> Result<BidValue, BidError>;
|
||||||
|
fn invoke_async(&self, ...) -> Result<FutureHandle, BidError>;
|
||||||
|
fn stream(&self, ...) -> Result<StreamHandle, BidError>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
【代替案の検討】
|
||||||
|
|
||||||
|
案A: メソッドのシェイプで表現
|
||||||
|
```rust
|
||||||
|
pub enum MethodShape {
|
||||||
|
Sync, // 通常の同期呼び出し
|
||||||
|
Async, // Future<T>を返す
|
||||||
|
Stream, // Stream<T>を返す
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Method {
|
||||||
|
pub shape: MethodShape, // ここで同期/非同期を区別
|
||||||
|
pub returns: BidType, // 実際の値の型(Future抜き)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
案B: ハンドル型として扱う
|
||||||
|
```rust
|
||||||
|
pub enum BidType {
|
||||||
|
// Future/Stream削除
|
||||||
|
Handle(String), // "FutureHandle", "StreamHandle"等
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
案C: 型階層を分ける
|
||||||
|
```rust
|
||||||
|
pub enum BidType { /* 値型のみ */ }
|
||||||
|
pub enum BidAsyncType {
|
||||||
|
Future(BidType),
|
||||||
|
Stream(BidType),
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
【質問】
|
||||||
|
|
||||||
|
1. **型システム設計**
|
||||||
|
- Future/StreamをBidTypeに含めるのは適切か?
|
||||||
|
- FFI境界での非同期処理の正しい表現方法は?
|
||||||
|
- 値型と実行モデルを混在させることの是非は?
|
||||||
|
|
||||||
|
2. **実装戦略**
|
||||||
|
- 型定義ファースト戦略(全型を最初に定義)は妥当か?
|
||||||
|
- unimplemented!()での段階的実装は適切か?
|
||||||
|
- ビルドエラー回避とAPI安定性のトレードオフは?
|
||||||
|
|
||||||
|
3. **FFI境界での非同期**
|
||||||
|
- C ABI経由での非同期処理の標準的な方法は?
|
||||||
|
- ポーリング vs コールバック vs ハンドル方式?
|
||||||
|
- WASM Component Modelではどう扱われている?
|
||||||
|
|
||||||
|
4. **将来の拡張性**
|
||||||
|
- gRPC/RESTでの非同期は別の話?
|
||||||
|
- TransportTypeごとに非同期モデルが異なる場合の抽象化は?
|
||||||
|
- Rust async/awaitとの統合方法は?
|
||||||
|
|
||||||
|
実装者(Rust中級者)が混乱しない、シンプルで拡張可能な設計を教えてください。特に「Future/StreamはBidTypeに含めるべきか」の判断をお願いします。
|
||||||
125
local_tests/nyash_box_theory_final_review.txt
Normal file
125
local_tests/nyash_box_theory_final_review.txt
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
Nyash「箱理論」に基づくBID-FFI設計の最終レビューをお願いします。
|
||||||
|
|
||||||
|
【Nyashの箱理論(Everything is Box)】
|
||||||
|
Nyashプログラミング言語は「Everything is Box」哲学を採用しており、すべてのデータと機能がBoxとして統一されています。
|
||||||
|
|
||||||
|
既存のBox型:
|
||||||
|
- StringBox, IntegerBox, BoolBox(基本型)
|
||||||
|
- ArrayBox, MapBox(コレクション)
|
||||||
|
- FutureBox(非同期処理)
|
||||||
|
- P2PBox(ネットワーク)
|
||||||
|
- FileBox(将来プラグインで提供予定)
|
||||||
|
|
||||||
|
【設計の変遷】
|
||||||
|
1. 最初の設計: 野心的すぎて複雑(gRPC/REST/P2P等全部)
|
||||||
|
2. ChatGPT提案: 一般的で正しいが、既存FutureBoxと二重実装になる
|
||||||
|
3. 最終設計: 箱理論準拠の最低設計
|
||||||
|
|
||||||
|
【最終設計案】
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// 1. 型システム:プリミティブ + Handle統一
|
||||||
|
pub enum BidType {
|
||||||
|
// プリミティブ(FFI境界で直接渡せる)
|
||||||
|
Bool, I32, I64, F32, F64, String, Bytes,
|
||||||
|
|
||||||
|
// Everything is Box: すべてのBoxは統一Handle
|
||||||
|
Handle(String), // "StringBox:123", "FileBox:456", "FutureBox:789"
|
||||||
|
|
||||||
|
// メタ型
|
||||||
|
Void,
|
||||||
|
|
||||||
|
// Phase 2以降(定義だけ)
|
||||||
|
Option(Box<BidType>),
|
||||||
|
Result(Box<BidType>, Box<BidType>),
|
||||||
|
Array(Box<BidType>),
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 既存Boxとの対応
|
||||||
|
/*
|
||||||
|
Handle("StringBox:123") → 既存StringBox インスタンス
|
||||||
|
Handle("FileBox:456") → プラグインFileBox
|
||||||
|
Handle("FutureBox:789") → 既存FutureBox(非同期)
|
||||||
|
Handle("P2PBox:101") → 既存P2PBox
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 3. 統一エントリーポイント
|
||||||
|
extern "C" fn nyash_plugin_invoke(
|
||||||
|
box_type_id: u32, // StringBox=1, FileBox=6等
|
||||||
|
method_id: u32, // open=1, read=2等
|
||||||
|
instance_id: u32, // Handle解析用
|
||||||
|
args_ptr: *const u8,
|
||||||
|
args_len: usize,
|
||||||
|
result_ptr: *mut u8,
|
||||||
|
result_len: *mut usize,
|
||||||
|
) -> i32
|
||||||
|
|
||||||
|
// 4. Boxヘッダー統一
|
||||||
|
#[repr(C, align(8))]
|
||||||
|
pub struct BoxHeader {
|
||||||
|
magic: u32, // "NYBX"
|
||||||
|
version: u16,
|
||||||
|
type_id: u32, // BoxTypeId
|
||||||
|
instance_id: u32, // インスタンス識別子
|
||||||
|
ref_count: u32, // 非atomic(シングルスレッド中心)
|
||||||
|
flags: u32, // 拡張用
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 既存Box統合
|
||||||
|
pub struct NyashBoxRegistry {
|
||||||
|
instances: HashMap<u32, Arc<RwLock<dyn NyashBox>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NyashBoxRegistry {
|
||||||
|
fn call_method(&self, type_id: u32, instance_id: u32, method_id: u32, args: &[u8])
|
||||||
|
-> Result<Vec<u8>, BidError> {
|
||||||
|
match type_id {
|
||||||
|
1 => self.call_stringbox_method(...), // 既存StringBox
|
||||||
|
6 => self.call_filebox_method(...), // プラグインFileBox
|
||||||
|
7 => self.call_futurebox_method(...), // 既存FutureBox活用
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
【設計原則】
|
||||||
|
1. **箱理論準拠**: すべてのBoxが同じ仕組みで扱える
|
||||||
|
2. **既存資産活用**: FutureBox等の既存実装を最大活用
|
||||||
|
3. **最低設計**: 動くものを最速で、複雑な機能は後回し
|
||||||
|
4. **二重実装回避**: 新しいBidFutureではなく既存FutureBox使用
|
||||||
|
5. **シングルスレッド中心**: Nyashの現実に合わせた設計
|
||||||
|
|
||||||
|
【具体的な利点】
|
||||||
|
- Nyashコード側は変更不要(local file = new FileBox("test.txt"))
|
||||||
|
- 既存StringBox, ArrayBox, FutureBoxと新しいプラグインFileBoxが同じ仕組み
|
||||||
|
- Handle("BoxType:id")による統一的なBox参照
|
||||||
|
- 非同期はFutureBoxで、新実装不要
|
||||||
|
|
||||||
|
【質問】
|
||||||
|
|
||||||
|
1. **箱理論の技術的妥当性**
|
||||||
|
- すべてをHandle統一する設計は適切か?
|
||||||
|
- 既存BoxとプラグインBoxの統一的な扱いは可能か?
|
||||||
|
- FFI境界でのBox参照としてHandle("Type:id")は適切か?
|
||||||
|
|
||||||
|
2. **最低設計のメリット・デメリット**
|
||||||
|
- プリミティブ + Handle のみの設計は十分か?
|
||||||
|
- 複雑な型(Array, Map等)を後回しにする判断は?
|
||||||
|
- Phase 1で基本動作、Phase 2で拡張の戦略は妥当か?
|
||||||
|
|
||||||
|
3. **既存資産活用の是非**
|
||||||
|
- 新しいBidFutureを作らずFutureBox活用は正解か?
|
||||||
|
- 既存のStringBox等との統合アプローチは適切か?
|
||||||
|
- 二重実装回避 vs 設計の純粋性のトレードオフは?
|
||||||
|
|
||||||
|
4. **実装現実性**
|
||||||
|
- 1週間でのPhase 1実装は現実的か?
|
||||||
|
- 既存インタープリターとの統合難易度は?
|
||||||
|
- Linux x86-64限定での最初の実装は妥当か?
|
||||||
|
|
||||||
|
5. **将来拡張性**
|
||||||
|
- この基盤で将来のgRPC/REST対応は可能か?
|
||||||
|
- Transport抽象化への拡張パスは明確か?
|
||||||
|
- P2P(NyaMesh)統合への道筋は適切か?
|
||||||
|
|
||||||
|
「箱理論」という独特な哲学を持つNyashにとって、一般的なFFI設計とは異なる特殊なアプローチが必要だと考えています。この「最低設計から始めて段階的拡張」の戦略についての専門的見解をお願いします。
|
||||||
202
src/bid/bridge.rs
Normal file
202
src/bid/bridge.rs
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
use crate::box_trait::NyashBox;
|
||||||
|
use super::{BidHandle, BidType, BidError};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
/// BID-FFI Bridge for Nyash Box types
|
||||||
|
/// Provides conversion between Nyash runtime values and BID handles
|
||||||
|
pub trait BidBridge {
|
||||||
|
/// Convert a Nyash Box to a BID handle
|
||||||
|
fn to_bid_handle(&self, registry: &mut BoxRegistry) -> Result<BidHandle, BidError>;
|
||||||
|
|
||||||
|
/// Get the BID type representation
|
||||||
|
fn bid_type(&self) -> BidType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Registry for managing Box instances and their handles
|
||||||
|
pub struct BoxRegistry {
|
||||||
|
/// Maps handle to Arc<dyn NyashBox>
|
||||||
|
handle_to_box: HashMap<BidHandle, Arc<dyn NyashBox>>,
|
||||||
|
|
||||||
|
/// Next instance ID for each type
|
||||||
|
next_instance_id: HashMap<u32, u32>,
|
||||||
|
|
||||||
|
/// Reverse lookup: Arc pointer to handle
|
||||||
|
box_to_handle: HashMap<usize, BidHandle>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BoxRegistry {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
handle_to_box: HashMap::new(),
|
||||||
|
next_instance_id: HashMap::new(),
|
||||||
|
box_to_handle: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register a Box and get its handle
|
||||||
|
pub fn register_box(&mut self, type_id: u32, boxed: Arc<dyn NyashBox>) -> BidHandle {
|
||||||
|
// Check if already registered by comparing Arc pointers
|
||||||
|
// We use the address of the Arc allocation itself as the key
|
||||||
|
let arc_addr = &*boxed as *const dyn NyashBox as *const () as usize;
|
||||||
|
if let Some(&handle) = self.box_to_handle.get(&arc_addr) {
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate new instance ID
|
||||||
|
let instance_id = self.next_instance_id.entry(type_id).or_insert(1);
|
||||||
|
let handle = BidHandle::new(type_id, *instance_id);
|
||||||
|
*instance_id += 1;
|
||||||
|
|
||||||
|
// Register bidirectionally
|
||||||
|
self.handle_to_box.insert(handle, boxed.clone());
|
||||||
|
self.box_to_handle.insert(arc_addr, handle);
|
||||||
|
|
||||||
|
handle
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve a Box by its handle
|
||||||
|
pub fn get_box(&self, handle: BidHandle) -> Option<Arc<dyn NyashBox>> {
|
||||||
|
self.handle_to_box.get(&handle).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove a Box from the registry
|
||||||
|
pub fn unregister(&mut self, handle: BidHandle) -> Option<Arc<dyn NyashBox>> {
|
||||||
|
if let Some(boxed) = self.handle_to_box.remove(&handle) {
|
||||||
|
let arc_addr = &*boxed as *const dyn NyashBox as *const () as usize;
|
||||||
|
self.box_to_handle.remove(&arc_addr);
|
||||||
|
Some(boxed)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert Nyash Box to BID handle
|
||||||
|
pub fn box_to_bid_handle(
|
||||||
|
arc_box: &Arc<dyn NyashBox>,
|
||||||
|
registry: &mut BoxRegistry,
|
||||||
|
) -> Result<(BidType, BidHandle), BidError> {
|
||||||
|
// Downcast to specific box types
|
||||||
|
if let Some(_string_box) = arc_box.as_any().downcast_ref::<crate::boxes::string_box::StringBox>() {
|
||||||
|
let handle = registry.register_box(
|
||||||
|
crate::bid::types::BoxTypeId::StringBox as u32,
|
||||||
|
arc_box.clone()
|
||||||
|
);
|
||||||
|
Ok((BidType::Handle { type_id: 1, instance_id: handle.instance_id }, handle))
|
||||||
|
} else if let Some(_integer_box) = arc_box.as_any().downcast_ref::<crate::boxes::integer_box::IntegerBox>() {
|
||||||
|
let handle = registry.register_box(
|
||||||
|
crate::bid::types::BoxTypeId::IntegerBox as u32,
|
||||||
|
arc_box.clone()
|
||||||
|
);
|
||||||
|
Ok((BidType::Handle { type_id: 2, instance_id: handle.instance_id }, handle))
|
||||||
|
} else {
|
||||||
|
Err(BidError::InvalidType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert BID handle back to Nyash Box
|
||||||
|
pub fn bid_handle_to_box(
|
||||||
|
handle: BidHandle,
|
||||||
|
registry: &BoxRegistry,
|
||||||
|
) -> Result<Arc<dyn NyashBox>, BidError> {
|
||||||
|
registry.get_box(handle)
|
||||||
|
.ok_or(BidError::InvalidHandle)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extract string value from a Box for TLV encoding
|
||||||
|
pub fn extract_string_value(arc_box: &Arc<dyn NyashBox>) -> Result<String, BidError> {
|
||||||
|
if let Some(string_box) = arc_box.as_any().downcast_ref::<crate::boxes::string_box::StringBox>() {
|
||||||
|
Ok(string_box.value.clone())
|
||||||
|
} else {
|
||||||
|
Err(BidError::InvalidType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extract integer value from a Box for TLV encoding
|
||||||
|
pub fn extract_integer_value(arc_box: &Arc<dyn NyashBox>) -> Result<i64, BidError> {
|
||||||
|
if let Some(integer_box) = arc_box.as_any().downcast_ref::<crate::boxes::integer_box::IntegerBox>() {
|
||||||
|
Ok(integer_box.value)
|
||||||
|
} else {
|
||||||
|
Err(BidError::InvalidType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_box_registry() {
|
||||||
|
let mut registry = BoxRegistry::new();
|
||||||
|
|
||||||
|
// Create a mock box
|
||||||
|
let string_box = crate::boxes::string_box::StringBox::new("Hello");
|
||||||
|
let arc_box: Arc<dyn NyashBox> = Arc::new(string_box);
|
||||||
|
|
||||||
|
// Register it
|
||||||
|
let handle = registry.register_box(1, arc_box.clone());
|
||||||
|
assert_eq!(handle.type_id, 1);
|
||||||
|
assert_eq!(handle.instance_id, 1);
|
||||||
|
|
||||||
|
// Retrieve it
|
||||||
|
let retrieved = registry.get_box(handle).unwrap();
|
||||||
|
assert_eq!(Arc::as_ptr(&retrieved), Arc::as_ptr(&arc_box));
|
||||||
|
|
||||||
|
// Register same box again should return same handle
|
||||||
|
let handle2 = registry.register_box(1, arc_box.clone());
|
||||||
|
assert_eq!(handle, handle2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_string_box_bid_conversion() {
|
||||||
|
let mut registry = BoxRegistry::new();
|
||||||
|
|
||||||
|
// Create StringBox
|
||||||
|
let string_box = crate::boxes::string_box::StringBox::new("Test String");
|
||||||
|
let arc_box: Arc<dyn NyashBox> = Arc::new(string_box);
|
||||||
|
|
||||||
|
// Convert to BID handle
|
||||||
|
let (bid_type, handle) = box_to_bid_handle(&arc_box, &mut registry).unwrap();
|
||||||
|
assert_eq!(handle.type_id, 1); // StringBox type ID
|
||||||
|
match bid_type {
|
||||||
|
BidType::Handle { type_id, .. } => assert_eq!(type_id, 1),
|
||||||
|
_ => panic!("Expected Handle type"),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract string value
|
||||||
|
let value = extract_string_value(&arc_box).unwrap();
|
||||||
|
assert_eq!(value, "Test String");
|
||||||
|
|
||||||
|
// Round-trip test
|
||||||
|
let retrieved = bid_handle_to_box(handle, ®istry).unwrap();
|
||||||
|
let retrieved_value = extract_string_value(&retrieved).unwrap();
|
||||||
|
assert_eq!(retrieved_value, "Test String");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_integer_box_bid_conversion() {
|
||||||
|
let mut registry = BoxRegistry::new();
|
||||||
|
|
||||||
|
// Create IntegerBox
|
||||||
|
let integer_box = crate::boxes::integer_box::IntegerBox::new(42);
|
||||||
|
let arc_box: Arc<dyn NyashBox> = Arc::new(integer_box);
|
||||||
|
|
||||||
|
// Convert to BID handle
|
||||||
|
let (bid_type, handle) = box_to_bid_handle(&arc_box, &mut registry).unwrap();
|
||||||
|
assert_eq!(handle.type_id, 2); // IntegerBox type ID
|
||||||
|
match bid_type {
|
||||||
|
BidType::Handle { type_id, .. } => assert_eq!(type_id, 2),
|
||||||
|
_ => panic!("Expected Handle type"),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract integer value
|
||||||
|
let value = extract_integer_value(&arc_box).unwrap();
|
||||||
|
assert_eq!(value, 42);
|
||||||
|
|
||||||
|
// Round-trip test
|
||||||
|
let retrieved = bid_handle_to_box(handle, ®istry).unwrap();
|
||||||
|
let retrieved_value = extract_integer_value(&retrieved).unwrap();
|
||||||
|
assert_eq!(retrieved_value, 42);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,12 +6,14 @@ pub mod tlv;
|
|||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod metadata;
|
pub mod metadata;
|
||||||
pub mod plugin_api;
|
pub mod plugin_api;
|
||||||
|
pub mod bridge;
|
||||||
|
|
||||||
pub use types::*;
|
pub use types::*;
|
||||||
pub use tlv::*;
|
pub use tlv::*;
|
||||||
pub use error::*;
|
pub use error::*;
|
||||||
pub use metadata::*;
|
pub use metadata::*;
|
||||||
pub use plugin_api::*;
|
pub use plugin_api::*;
|
||||||
|
pub use bridge::*;
|
||||||
|
|
||||||
/// BID-1 version constant
|
/// BID-1 version constant
|
||||||
pub const BID_VERSION: u16 = 1;
|
pub const BID_VERSION: u16 = 1;
|
||||||
|
|||||||
@ -38,6 +38,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use crate::box_trait::{NyashBox, BoxCore, BoxBase};
|
use crate::box_trait::{NyashBox, BoxCore, BoxBase};
|
||||||
|
use crate::bid::{BidBridge, BidHandle, BidType, BidError, BoxRegistry};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
@ -117,3 +118,22 @@ impl Display for IntegerBox {
|
|||||||
self.fmt_box(f)
|
self.fmt_box(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl BidBridge for IntegerBox {
|
||||||
|
fn to_bid_handle(&self, registry: &mut BoxRegistry) -> Result<BidHandle, BidError> {
|
||||||
|
use std::sync::Arc;
|
||||||
|
let arc_box: Arc<dyn NyashBox> = Arc::new(self.clone());
|
||||||
|
let handle = registry.register_box(
|
||||||
|
crate::bid::types::BoxTypeId::IntegerBox as u32,
|
||||||
|
arc_box
|
||||||
|
);
|
||||||
|
Ok(handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bid_type(&self) -> BidType {
|
||||||
|
BidType::Handle {
|
||||||
|
type_id: crate::bid::types::BoxTypeId::IntegerBox as u32,
|
||||||
|
instance_id: 0 // Will be filled by registry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -28,6 +28,7 @@
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
use crate::box_trait::{NyashBox, BoxCore, BoxBase};
|
use crate::box_trait::{NyashBox, BoxCore, BoxBase};
|
||||||
|
use crate::bid::{BidBridge, BidHandle, BidType, BidError, BoxRegistry};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
@ -185,3 +186,22 @@ impl Display for StringBox {
|
|||||||
self.fmt_box(f)
|
self.fmt_box(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl BidBridge for StringBox {
|
||||||
|
fn to_bid_handle(&self, registry: &mut BoxRegistry) -> Result<BidHandle, BidError> {
|
||||||
|
use std::sync::Arc;
|
||||||
|
let arc_box: Arc<dyn NyashBox> = Arc::new(self.clone());
|
||||||
|
let handle = registry.register_box(
|
||||||
|
crate::bid::types::BoxTypeId::StringBox as u32,
|
||||||
|
arc_box
|
||||||
|
);
|
||||||
|
Ok(handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bid_type(&self) -> BidType {
|
||||||
|
BidType::Handle {
|
||||||
|
type_id: crate::bid::types::BoxTypeId::StringBox as u32,
|
||||||
|
instance_id: 0 // Will be filled by registry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user