🔧 refactor: P2PBox複雑実装を削除し段階的実装方針に変更
- 複雑なP2PBox関連実装を削除: * Transport trait + MessageBus + MessageIntentBox + NewP2PBox * 依存関係が複雑で一度に追加すると失敗することを学習 - nyashバイナリのビルドを安定化: * 全てのimportエラーを修正 * cargo build --bin nyash が正常に動作 - CURRENT_TASK.mdに新しい段階的実装方針を記載: * Phase 1: FloatBox (依存なし) * Phase 2: ArrayBox改良 * Phase 3: 演算子システム改良 - 教訓: 一つずつ確実に実装し、テストファーストで進める 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
33
CLAUDE.md
33
CLAUDE.md
@ -195,6 +195,39 @@ app.setSize(800, 600)
|
||||
|
||||
**実装状況**: 基本実装完了、GUI実行コンテキスト対応中
|
||||
|
||||
## 📖 ドキュメントファースト開発(重要!)
|
||||
|
||||
### 🚨 開発手順の鉄則
|
||||
**絶対にソースコードを直接読みに行かない!必ずこの順序で作業:**
|
||||
|
||||
1. **📚 ドキュメント確認** - まず既存ドキュメントをチェック
|
||||
2. **🔄 ドキュメント更新** - 古い/不足している場合は更新
|
||||
3. **💻 ソース確認** - それでも解決しない場合のみソースコード参照
|
||||
|
||||
### 🎯 最重要ドキュメント(2つの核心)
|
||||
|
||||
#### 🔤 言語仕様
|
||||
- **[構文早見表](docs/quick-reference/syntax-cheatsheet.md)** - 基本構文・よくある間違い
|
||||
- **[完全リファレンス](docs/reference/)** - 言語仕様詳細
|
||||
- **[予約語一覧](docs/reference/keywords.md)** - from, override, pack等
|
||||
|
||||
#### 📦 主要BOXのAPI
|
||||
- **[ビルトイン型](docs/reference/built-in-boxes.md)** - 全Box型API仕様
|
||||
- **P2PBox & IntentBox** - docs/reference/built-in-boxes.md内
|
||||
- **StringBox, IntegerBox, ConsoleBox** - 基本Box API
|
||||
- **EguiBox, DebugBox, MathBox** - 特殊Box API
|
||||
|
||||
### ⚡ API確認の実践例
|
||||
```bash
|
||||
# ❌ 悪い例:いきなりソース読む
|
||||
Read src/boxes/p2p_box.rs # 直接ソース参照
|
||||
|
||||
# ✅ 良い例:ドキュメント優先
|
||||
Read docs/reference/built-in-boxes.md # まずドキュメント
|
||||
# → 古い/不足 → ドキュメント更新
|
||||
# → それでも不明 → ソース確認
|
||||
```
|
||||
|
||||
## 🔧 開発サポート
|
||||
|
||||
### 🤖 AI相談
|
||||
|
||||
803
CURRENT_TASK.md
803
CURRENT_TASK.md
@ -1,677 +1,130 @@
|
||||
# 🎯 現在のタスク (2025-08-11 P2PBox設計完成!)
|
||||
|
||||
## 🚀 2025-08-11 P2PBox完璧設計達成
|
||||
|
||||
### 💡 **ChatGPT大会議成果**
|
||||
**禿げるほど考えた末の完璧なアーキテクチャ決定!**
|
||||
|
||||
#### **核心設計思想**
|
||||
- **Bus = ローカルOS**: 常に保持、配送・購読・監視のハブ
|
||||
- **Transport = NIC**: 通信手段選択、InProcess/WebSocket/WebRTC切り替え
|
||||
- **IntentBox**: メッセージ専用Box(Transportと分離)
|
||||
|
||||
#### **完全実装仕様(コンテキスト圧縮復元)**
|
||||
|
||||
**🎯 IntentBox詳細設計(Nyash同期・シンプル版)**
|
||||
```rust
|
||||
// ✅ 最初の実装はシンプル同期版
|
||||
pub struct IntentBox {
|
||||
pub intent: String, // Intent種類("chat.message", "file.transfer"等)
|
||||
pub payload: HashMap<String, Box<dyn NyashBox>>, // Nyashネイティブ・同期
|
||||
}
|
||||
|
||||
impl IntentBox {
|
||||
pub fn new(intent: &str) -> Self;
|
||||
pub fn set(&mut self, key: &str, value: Box<dyn NyashBox>);
|
||||
pub fn get(&self, key: &str) -> Option<&Box<dyn NyashBox>>;
|
||||
}
|
||||
|
||||
// 🔄 将来拡張用(後回し)
|
||||
// pub struct SendOpts { ack_required, timeout_ms } - async時に追加
|
||||
// pub struct IntentEnvelope { from, to, intent } - ネット対応時に追加
|
||||
```
|
||||
|
||||
**🎯 P2PBox詳細設計(Nyash同期・シンプル版)**
|
||||
```rust
|
||||
// ✅ 最初の実装はシンプル同期版
|
||||
pub struct P2PBox {
|
||||
node_id: String,
|
||||
transport: Box<dyn Transport>,
|
||||
bus: Arc<MessageBus>, // ← 常に保持!(ローカル配送・購読・監視用)
|
||||
}
|
||||
|
||||
impl P2PBox {
|
||||
// シンプル同期コンストラクタ
|
||||
pub fn new(node_id: &str, transport_kind: TransportKind) -> Self {
|
||||
let bus = get_global_message_bus(); // シングルトン取得
|
||||
let transport = create_transport(transport_kind, node_id); // 簡単ファクトリ
|
||||
|
||||
// 自ノード登録
|
||||
bus.register_node(node_id).unwrap();
|
||||
|
||||
Self {
|
||||
node_id: node_id.to_string(),
|
||||
transport,
|
||||
bus
|
||||
}
|
||||
}
|
||||
|
||||
// 購読メソッド - Busに登録
|
||||
pub fn on(&self, intent: &str, callback: Box<dyn Fn(&IntentBox) + Send + Sync>) {
|
||||
self.bus.on(&self.node_id, intent, callback).unwrap();
|
||||
}
|
||||
|
||||
// 送信メソッド - 天才アルゴリズム内蔵(同期版)
|
||||
pub fn send(&self, to: &str, intent_box: &IntentBox) -> Result<(), String> {
|
||||
// 1) 宛先が同プロセス(Busが知っている)ならローカル配送
|
||||
if self.bus.has_node(to) {
|
||||
let message = BusMessage {
|
||||
from: self.node_id.clone(),
|
||||
to: to.to_string(),
|
||||
intent: intent_box.intent.clone(),
|
||||
data: /* IntentBoxをNyashBoxに変換 */,
|
||||
timestamp: std::time::SystemTime::now(),
|
||||
};
|
||||
self.bus.route(message)?; // 爆速ローカル
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// 2) ローカルに居ない → Transportで外へ出す
|
||||
self.transport.send(to, &intent_box.intent, /* data */)
|
||||
}
|
||||
|
||||
pub fn get_node_id(&self) -> &str {
|
||||
&self.node_id
|
||||
}
|
||||
}
|
||||
|
||||
// 🔄 将来拡張用(後回し)
|
||||
// async fn send() - async対応時
|
||||
// TransportFactory::create() - 複雑なオプション対応時
|
||||
// on_receive()コールバック - ネット受信対応時
|
||||
```
|
||||
|
||||
**🎯 TransportKind & ファクトリ(Nyash同期・シンプル版)**
|
||||
```rust
|
||||
// ✅ 最初の実装はシンプル版
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum TransportKind {
|
||||
InProcess, // プロセス内通信(最初に実装)
|
||||
WebSocket, // WebSocket通信(将来実装)
|
||||
WebRTC, // P2P直接通信(将来実装)
|
||||
}
|
||||
|
||||
// シンプルファクトリ関数
|
||||
pub fn create_transport(kind: TransportKind, node_id: &str) -> Box<dyn Transport> {
|
||||
match kind {
|
||||
TransportKind::InProcess => Box::new(InProcessTransport::new(node_id.to_string())),
|
||||
TransportKind::WebSocket => todo!("WebSocket transport - 将来実装"),
|
||||
TransportKind::WebRTC => todo!("WebRTC transport - 将来実装"),
|
||||
}
|
||||
}
|
||||
|
||||
// 🔄 将来拡張用(後回し)
|
||||
// pub struct TransportFactory; - 複雑なオプション対応時
|
||||
// pub struct TransportOpts; - オプション追加時
|
||||
```
|
||||
|
||||
**🎯 4つの核心(忘れてはいけないポイント)**
|
||||
```
|
||||
1. P2PBoxは、トランスポートがネットでもBusを持ち続ける(ローカル配送・購読・監視用)
|
||||
2. P2PBoxはIntentBoxを使って送る
|
||||
3. 送信アルゴリズム:ローカルならBus、それ以外はTransport
|
||||
4. 受信アルゴリズム:Transport→P2PBox→Bus でローカルハンドラに届く
|
||||
```
|
||||
|
||||
**🎯 天才アルゴリズム実装(同期・シンプル版)**
|
||||
```rust
|
||||
// 送信:ローカル優先 → リモートフォールバック
|
||||
if self.bus.has_node(to) {
|
||||
self.bus.route(message)?; // ← 爆速ローカル(ゼロコピー級)
|
||||
return Ok(());
|
||||
} else {
|
||||
self.transport.send(to, intent, data)?; // ← Transport経由(同期)
|
||||
}
|
||||
|
||||
// 受信:将来実装時の流れ
|
||||
// Transport.receive() → IntentBox → MessageBus.route() → LocalHandler
|
||||
```
|
||||
|
||||
**🎯 使用例(Nyash同期・シンプル版)**
|
||||
```rust
|
||||
// 基本使用パターン(同期版)
|
||||
let alice = P2PBox::new("alice", TransportKind::InProcess);
|
||||
let bob = P2PBox::new("bob", TransportKind::InProcess);
|
||||
|
||||
// 購読登録
|
||||
bob.on("chat.message", Box::new(|intent_box: &IntentBox| {
|
||||
if let Some(text) = intent_box.get("text") {
|
||||
println!("Received: {}", text.to_string_box().value);
|
||||
}
|
||||
}));
|
||||
|
||||
// メッセージ送信
|
||||
let mut intent = IntentBox::new("chat.message");
|
||||
intent.set("text", Box::new(StringBox::new("Hello Bob!")));
|
||||
alice.send("bob", &intent).unwrap(); // ← 天才アルゴリズム自動判定(同期)
|
||||
```
|
||||
|
||||
**🎯 実装順序(重要)**
|
||||
```
|
||||
1. まず cargo build --lib でコンパイル確認
|
||||
2. IntentBox実装(HashMap + Nyashネイティブ)
|
||||
3. TransportKind enum実装
|
||||
4. P2PBox本体実装(天才アルゴリズム内蔵)
|
||||
5. テスト用Nyashコード作成・動作確認
|
||||
```
|
||||
|
||||
#### **勝利ポイント**
|
||||
1. **統一API**: send()/on() でローカル・ネット同じ
|
||||
2. **最速ローカル**: Bus直接配送でゼロコピー級
|
||||
3. **拡張自在**: TransportKind で通信手段切り替え
|
||||
4. **デバッグ天国**: Bus でメッセージ全監視
|
||||
5. **NyaMesh実証済み**: Transport抽象化パターン
|
||||
|
||||
### 🎯 **次の実装ステップ(詳細設計復元完了)**
|
||||
|
||||
**基盤レイヤー(ほぼ完了)**
|
||||
1. ✅ **Transport trait 定義** - NyaMesh参考実装完了
|
||||
2. ✅ **MessageBus シングルトン** - 基本実装済み、OnceLock使用
|
||||
3. 🔄 **InProcessTransport修正** - 新仕様対応が必要
|
||||
|
||||
**コアレイヤー(最優先実装)**
|
||||
4. 🚨 **IntentBox実装** - HashMap<String, Box<dyn NyashBox>>構造
|
||||
5. 🚨 **TransportKind enum** - create_transport()ファクトリ含む
|
||||
6. 🚨 **P2PBox本体実装** - 天才アルゴリズム send()メソッド内蔵
|
||||
|
||||
**統合レイヤー(最終段階)**
|
||||
7. **インタープリター統合** - new P2PBox(), new IntentBox()対応
|
||||
8. **テストスイート** - 基本動作確認
|
||||
|
||||
**🚨 現在の状況 - P2PBox天才アルゴリズム完全実装済み**
|
||||
- ✅ Transport trait + MessageBus + NewP2PBox 完全実装済み
|
||||
- ✅ 天才アルゴリズム動作:`if bus.has_node(to) { bus.route() } else { transport.send() }`
|
||||
- 🔥 **重要ギャップ発見:MethodBox統合が未実装**
|
||||
|
||||
**🚨 次の最優先タスク**
|
||||
1. **テスト確認** - 現在のRustクロージャ版で基本動作確認
|
||||
2. **MethodBox統合追加** - Nyash側使用に必須!
|
||||
|
||||
**🎯 MethodBox統合の詳細**
|
||||
```rust
|
||||
// 現在(Rust内部用)
|
||||
pub fn on(&self, intent: &str, callback: Box<dyn Fn(&MessageIntentBox) + Send + Sync>)
|
||||
|
||||
// 必要(Nyash統合用)
|
||||
pub fn on(&self, intent: &str, method_box: MethodBox)
|
||||
// ↓ method_box.invoke(args) でNyash関数呼び出し
|
||||
```
|
||||
|
||||
**理由**: Nyash側で `alice.on("chat", |msg| { print(msg.text) })` を書く時、
|
||||
|msg| { } 部分はMethodBoxとして実装される。Rustクロージャでは受け取れない。
|
||||
|
||||
## 🔥 2025-08-11 本日の大成果
|
||||
|
||||
### 🎉 完了した革命的変更
|
||||
|
||||
#### 1. ✅ **`pack`構文革命完成**
|
||||
- AI大会議(Gemini + GPT-5)で`pack`構文一致採用
|
||||
- パーサー・インタープリター完全実装
|
||||
- デリゲーション: `from Parent.pack()`動作確認
|
||||
- Box哲学の完全具現化:「箱に詰める」直感体験
|
||||
|
||||
#### 2. ✅ **デリゲーションメソッドチェック機能完成**
|
||||
- validate_override_methods実装・有効化
|
||||
- 危険パターン検出(nonExistentMethod等)
|
||||
- パース時早期エラー検出で安全性大幅向上
|
||||
- テストスイート完備(正常/異常ケース)
|
||||
|
||||
#### 3. ✅ **CharmFlow教訓を活かした設計決定**
|
||||
- 過去のプラグイン互換性破綻の実体験を踏まえた戦略決定
|
||||
- GPT-5専門家による深い技術分析
|
||||
- BoxBase + BoxCore戦略で互換性問題完全回避を確認
|
||||
|
||||
## 🚀 BoxBase + BoxCore革命実装開始!
|
||||
|
||||
### 📋 **CharmFlow教訓を活かした大改革**
|
||||
CharmFlowでプラグインバージョンが1つ上がっただけで全プラグイン使用不能になった実体験を活かし、Nyashでは統一インターフェースで互換性問題を根本解決します。
|
||||
|
||||
### 🎯 **GPT-5専門家分析結果**
|
||||
- **互換性**: CharmFlow的破綻を完全回避可能
|
||||
- **コード削減**: 40-70%削減 + 美しさ大幅向上
|
||||
- **拡張性**: 将来のビルトインBox継承に最適
|
||||
- **デバッグ**: 段階的移行で安全性確保
|
||||
|
||||
### 📝 次期実装タスク(最優先)
|
||||
|
||||
#### 1. **BoxBase + BoxCore統一基盤実装**(最優先・大変更)
|
||||
```rust
|
||||
// Phase 1: 統一ID生成システム
|
||||
pub fn next_box_id() -> u64 {
|
||||
static COUNTER: AtomicU64 = AtomicU64::new(1);
|
||||
COUNTER.fetch_add(1, Ordering::Relaxed)
|
||||
}
|
||||
|
||||
// Phase 2: 共通基盤構造
|
||||
pub struct BoxBase {
|
||||
id: u64,
|
||||
}
|
||||
|
||||
pub trait BoxCore: Send + Sync {
|
||||
fn box_id(&self) -> u64;
|
||||
fn fmt_box(&self, f: &mut fmt::Formatter) -> fmt::Result;
|
||||
}
|
||||
|
||||
// Phase 3: 統一トレイト
|
||||
pub trait NyashBox: BoxCore + DynClone + Any {
|
||||
fn type_name(&self) -> &'static str {
|
||||
std::any::type_name::<Self>()
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**実装計画**:
|
||||
1. **ID生成統一**: `unsafe` → `AtomicU64`で安全化
|
||||
2. **BoxBase構造体導入**: 全Box共通の基盤
|
||||
3. **BoxCoreトレイト**: 重複メソッドの統一
|
||||
4. **段階的移行**: StringBox → IntegerBox → 全Box
|
||||
5. **テスト**: 各段階で互換性確認
|
||||
|
||||
#### 2. **ビルトインBox継承基盤準備**(高優先)
|
||||
BoxBase基盤完成後、P2PBox継承機能を実装:
|
||||
```nyash
|
||||
// 実現目標
|
||||
box ChatNode from P2PBox {
|
||||
pack(nodeId, world) {
|
||||
from P2PBox.pack(nodeId, world)
|
||||
me.chatHistory = new ArrayBox()
|
||||
}
|
||||
|
||||
override send(intent, data, target) {
|
||||
me.chatHistory.push(createLogEntry(intent, data, target))
|
||||
from P2PBox.send(intent, data, target)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. **pack構文最適化**(中優先)
|
||||
- `pack` > `init` > Box名優先順位の改善
|
||||
- エラーメッセージの向上
|
||||
- パフォーマンス最適化
|
||||
|
||||
## 🎉 2025-08-11 言語設計史上の大革命実装進行中!
|
||||
|
||||
### 🌟 override + from 統一構文による明示的デリゲーション革命【実装中】
|
||||
**Nyash史上最大の言語設計転換点実装中!** 暗黙のオーバーライド問題を発見し、Gemini・ChatGPT両先生から圧倒的支持を得てoverride + from完全統一構文を実装中。世界初の完全明示デリゲーション言語を目指します!
|
||||
|
||||
#### 🎯 2025-08-11 最新実装状況:
|
||||
- ✅ **from Parent.method()** - ユーザー定義Box間で正常動作確認!
|
||||
- ✅ **overrideキーワード** - パーサー実装完了、正常動作!
|
||||
- ✅ **`box Child from Parent`構文** - 完全実装済み!
|
||||
- ✅ **`init`構文決定** - AI大会議で合意形成!
|
||||
- ❌ **Box宣言時のデリゲーションチェック** - 親メソッドとの重複チェック未実装
|
||||
- ❌ **ビルトインBoxデリゲーション** - P2PBox等が "Undefined class"(後回し)
|
||||
|
||||
#### 🔥 2025-08-11 完全実装済み項目:
|
||||
1. **暗黙オーバーライド問題の完全解決** ✅実装完了
|
||||
- HashMap::insertによる意図しない上書きバグを発見・修正
|
||||
- instance.rs add_method()でoverride必須チェック実装
|
||||
- 明示的overrideなしの重複メソッド→コンパイルエラー
|
||||
|
||||
2. **フルスタック実装完成** ✅全層実装
|
||||
- トークナイザー: OVERRIDE, FROMトークン追加完了
|
||||
- AST: is_overrideフィールド、FromCall構造追加完了
|
||||
- パーサー: override構文、from Parent.method()解析完了
|
||||
- インタープリター: FromCall実行処理完成
|
||||
|
||||
3. **コンストラクタオーバーロード禁止** ✅実装完了
|
||||
- register_box_declaration()で複数コンストラクタ検出
|
||||
- "One Box, One Constructor"哲学の完全実現
|
||||
|
||||
2. **3AI大会議による圧倒的支持獲得** 🎊
|
||||
- Gemini先生:「全面的に賛成」「極めて重要な一歩」
|
||||
- ChatGPT先生:「強く整合」「実装工数3-5日」
|
||||
- 両先生から言語設計の専門的視点で絶賛評価
|
||||
|
||||
3. **override + from 完全統一構文の確立** 🚀
|
||||
```nyash
|
||||
// 世界初の完全明示デリゲーション
|
||||
box MeshNode from P2PBox { // from構文に統一!
|
||||
override send(intent, data, target) { // 置換宣言
|
||||
me.routing.log(target)
|
||||
from P2PBox.send(intent, data, target) // 親実装明示呼び出し
|
||||
}
|
||||
}
|
||||
|
||||
init(nodeId, world) { // initに統一決定!
|
||||
from P2PBox.init(nodeId, world) // コンストラクタも統一
|
||||
me.routing = RoutingTable()
|
||||
}
|
||||
```
|
||||
|
||||
4. **設計原則の確立**
|
||||
- ❌ 暗黙オーバーライド完全禁止
|
||||
- ❌ コンストラクタオーバーロード禁止
|
||||
- ✅ override キーワード必須
|
||||
- ✅ from による明示的親呼び出し
|
||||
- ✅ 多重デリゲーションでの曖昧性完全解消
|
||||
|
||||
5. **他言語との明確な差別化達成**
|
||||
- Python MRO地獄の完全回避
|
||||
- Java/C# super問題の根本解決
|
||||
- 世界初の「完全明示デリゲーション言語」として確立
|
||||
|
||||
## 🎉 2025-08-10 の大成果まとめ
|
||||
|
||||
### 🔥 Arc<Mutex> Revolution + AI大相談会 ダブル完全達成!
|
||||
**Nyash史上最大の2つの革命完了!** 全16種類のBox型が統一パターンで実装され、さらに関数オーバーロード設計が3AI合意で決定されました。
|
||||
|
||||
#### 本日完了した作業:
|
||||
1. **ArrayBoxの完全再実装** ⭐️最重要
|
||||
- Arc<Mutex>パターンで全メソッド統一
|
||||
- `&self`で動作(push, pop, get, set, join等)
|
||||
- Box<dyn NyashBox>引数対応でNyashから完全使用可能
|
||||
|
||||
2. **既存Box修正完了**
|
||||
- BufferBox: ArrayBoxとの連携修正、デバッグ出力削除
|
||||
- StringBox: 新ArrayBoxインポート修正
|
||||
- RandomBox: 新ArrayBoxインポート修正
|
||||
- RegexBox/JSONBox: 既に正しく実装済みを確認
|
||||
|
||||
3. **包括的テスト成功** ✅
|
||||
```nyash
|
||||
// 全Box型の動作確認完了!
|
||||
ArrayBox: push/pop/get/set/join ✅
|
||||
BufferBox: write/readAll/length ✅
|
||||
JSONBox: parse/stringify/get/set/keys ✅
|
||||
RegexBox: test/find/findAll/replace/split ✅
|
||||
StreamBox: write/read/position/reset ✅
|
||||
RandomBox: random/randInt/choice/shuffle ✅
|
||||
```
|
||||
|
||||
4. **技術的成果**
|
||||
- 完全なスレッドセーフティ実現
|
||||
- 統一されたAPI(全て`&self`メソッド)
|
||||
- メモリ安全性とRust所有権システムの完全統合
|
||||
|
||||
5. **🤖 AI大相談会による関数オーバーロード設計決定** ⭐️新規
|
||||
- Claude(司会) + Gemini(設計思想) + ChatGPT(技術実装)による史上初の3AI協働分析
|
||||
- **最終決定**: Rust風トレイトシステム採用 (NyashAddトレイト)
|
||||
- 静的・動的ハイブリッドディスパッチによるパフォーマンス最適化
|
||||
- Everything is Box哲学との完全整合を確認
|
||||
- 詳細記録: `sessions/ai_consultation_overload_design_20250810.md`
|
||||
|
||||
6. **🚀 P2PBox/IntentBox基本実装完了** ⭐️新規
|
||||
- IntentBox: 通信世界を定義するコンテナ実装
|
||||
- P2PBox: 通信ノードの完全実装(send/broadcast/on/off)
|
||||
- LocalTransport: プロセス内メッセージキュー実装
|
||||
- インタープリター完全統合
|
||||
- 包括的テストスイート作成・全パス確認
|
||||
|
||||
7. **🎯 ビルトインBox継承システム設計完了** ⭐️最新
|
||||
- 継承廃止→デリゲーション全面移行を決定
|
||||
- Gemini+ChatGPT+Claude 3AI大会議で文法設計
|
||||
- 最終決定: `box MeshNode extends P2PBox`構文採用
|
||||
- super解禁で直感的なAPI実現
|
||||
- 詳細記録: `sessions/ai_consultation_*_20250810.md`
|
||||
|
||||
## 📊 プロジェクト現状
|
||||
|
||||
### ✅ 実装済みBox一覧(全16種類 - Arc<Mutex>統一完了)
|
||||
| Box名 | 用途 | 実装状態 | テスト |
|
||||
|-------|------|----------|--------|
|
||||
| StringBox | 文字列操作 | ✅ 完全実装 | ✅ |
|
||||
| IntegerBox | 整数演算 | ✅ 完全実装 | ✅ |
|
||||
| BoolBox | 論理値 | ✅ 完全実装 | ✅ |
|
||||
| NullBox | null値 | ✅ 完全実装 | ✅ |
|
||||
| ConsoleBox | コンソール入出力 | ✅ 完全実装 | ✅ |
|
||||
| MathBox | 数学関数 | ✅ 完全実装 | ✅ |
|
||||
| TimeBox | 時刻操作 | ✅ 完全実装 | ✅ |
|
||||
| MapBox | 連想配列 | ✅ 完全実装 | ✅ |
|
||||
| DebugBox | デバッグ支援 | ✅ 完全実装 | ✅ |
|
||||
| RandomBox | 乱数生成 | ✅ 完全実装 | ✅ 本日 |
|
||||
| SoundBox | 音声 | ⚠️ スタブ実装 | - |
|
||||
| ArrayBox | 配列操作 | ✅ 完全実装 | ✅ 本日 |
|
||||
| BufferBox | バイナリデータ | ✅ 完全実装 | ✅ 本日 |
|
||||
| RegexBox | 正規表現 | ✅ 完全実装 | ✅ 本日 |
|
||||
| JSONBox | JSON解析 | ✅ 完全実装 | ✅ 本日 |
|
||||
| StreamBox | ストリーム処理 | ✅ 完全実装 | ✅ 本日 |
|
||||
|
||||
### 🏗️ プロジェクト構造計画(ユーザー後日実施)
|
||||
```
|
||||
nyash-project/ # モノレポジトリ構造
|
||||
├── nyash-core/ # 現在のnyashメイン実装
|
||||
│ ├── src/ # コア実装
|
||||
│ ├── tests/ # テストスイート
|
||||
│ └── examples/ # サンプルアプリ
|
||||
├── nyash-wasm/ # WebAssembly版
|
||||
│ ├── src/ # WASM バインディング
|
||||
│ └── playground/ # Webプレイグラウンド
|
||||
├── nyash-lsp/ # Language Server(将来)
|
||||
└── nyash-vscode/ # VS Code拡張(将来)
|
||||
```
|
||||
|
||||
#### 🌟 実装成果まとめ:
|
||||
```nyash
|
||||
// 🔥 世界初の完全明示デリゲーション言語実現!
|
||||
box MeshNode from P2PBox { // from構文採用!
|
||||
override send(intent, data, target) { // 明示的オーバーライド
|
||||
me.routing.log(target)
|
||||
from P2PBox.send(intent, data, target) // 親実装呼び出し
|
||||
}
|
||||
|
||||
init(nodeId, world) { // init構文決定!
|
||||
from P2PBox.init(nodeId, world) // コンストラクタ統一構文
|
||||
me.routing = RoutingTable()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 📚 ドキュメント完成:
|
||||
- ✅ `docs/design-philosophy/explicit-delegation-revolution.md` - 設計思想詳細
|
||||
- ✅ `docs/language-specification/override-delegation-syntax.md` - 完全仕様
|
||||
- ✅ AI相談記録 - Gemini・ChatGPT絶賛評価の全記録
|
||||
|
||||
## 🚀 次のステップ(優先順位順)
|
||||
|
||||
### 1. 🎉 完了した革命項目
|
||||
- [x] **暗黙オーバーライド問題発見・解決**: HashMap::insert悪魔を完全撲滅 ✅完了
|
||||
- [x] **override + from統一構文**: フルスタック実装完成 ✅完了
|
||||
- [x] **コンストラクタオーバーロード禁止**: "One Box, One Constructor"実現 ✅完了
|
||||
- [x] **完全明示デリゲーション言語**: 世界初達成 ✅完了
|
||||
|
||||
### 2. 🔥 関数オーバーロード実装(完了済み)
|
||||
- [x] **NyashAddトレイト定義**: `trait NyashAdd<Rhs = Self> { type Output; fn add(self, rhs: Rhs) -> Self::Output; }` ✅完了
|
||||
- [x] **静的・動的ハイブリッドディスパッチ**: 型判明時→静的解決、不明時→vtable動的解決 ✅完了
|
||||
- [x] **既存Box型への適用**: IntegerBox, StringBox等にNyashAddトレイト実装 ✅完了
|
||||
- [x] **テスト・最適化**: パフォーマンス測定とエッジケース検証 ✅完了
|
||||
|
||||
### 2. 📡 P2PBox/intentbox実装(✅ 基本実装完了!)
|
||||
**Everything is Box哲学による分散通信システム**
|
||||
|
||||
#### 🎉 本日の実装成果
|
||||
- ✅ **IntentBox完全実装**: 通信世界を定義するコンテナ
|
||||
- Transportトレイトによる通信方式抽象化
|
||||
- LocalTransport実装(プロセス内メッセージキュー)
|
||||
- Arc<Mutex>パターンでスレッドセーフ
|
||||
|
||||
- ✅ **P2PBox完全実装**: 通信ノードBox
|
||||
- send/broadcast/on/offメソッド実装
|
||||
- Arc<P2PBoxInner>構造で適切なクローン対応
|
||||
- 複数リスナー登録可能(同一intent対応)
|
||||
|
||||
- ✅ **インタープリター統合**:
|
||||
- new IntentBox() / new P2PBox(nodeId, world)対応
|
||||
- 全メソッドのディスパッチ実装
|
||||
- エラーハンドリング完備
|
||||
|
||||
- ✅ **包括的テストスイート**:
|
||||
- test_p2p_basic.nyash: 基本機能検証
|
||||
- test_p2p_message_types.nyash: 各種データ型対応
|
||||
- test_p2p_edge_cases.nyash: エラー処理とエッジケース
|
||||
- test_p2p_callback_demo.nyash: 実用例デモ
|
||||
|
||||
#### 実装済みの詳細
|
||||
|
||||
##### Phase 1: 基本設計・構造定義(本日)
|
||||
```rust
|
||||
// intentbox - 通信世界の抽象化
|
||||
pub struct IntentBox {
|
||||
id: u64,
|
||||
transport: Arc<Mutex<Box<dyn Transport>>>,
|
||||
nodes: Arc<Mutex<HashMap<String, Weak<P2PBox>>>>,
|
||||
}
|
||||
|
||||
// P2PBox - 通信ノード
|
||||
pub struct P2PBox {
|
||||
node_id: String,
|
||||
intent_box: Arc<IntentBox>,
|
||||
listeners: Arc<Mutex<HashMap<String, Vec<ListenerFn>>>>,
|
||||
}
|
||||
|
||||
// Transport trait - 通信方法の抽象化
|
||||
pub trait Transport: Send + Sync {
|
||||
fn send(&self, from: &str, to: &str, intent: &str, data: Box<dyn NyashBox>);
|
||||
fn broadcast(&self, from: &str, intent: &str, data: Box<dyn NyashBox>);
|
||||
}
|
||||
```
|
||||
|
||||
##### Phase 2: ローカル通信実装(今日〜明日)
|
||||
```rust
|
||||
// プロセス内通信Transport
|
||||
pub struct LocalTransport {
|
||||
message_queue: Arc<Mutex<VecDeque<Message>>>,
|
||||
}
|
||||
|
||||
// 基本的なメソッド実装
|
||||
impl P2PBox {
|
||||
pub fn send(&self, intent: &str, data: Box<dyn NyashBox>, target: &str) {
|
||||
self.intent_box.transport.lock().unwrap()
|
||||
.send(&self.node_id, target, intent, data);
|
||||
}
|
||||
|
||||
pub fn on(&self, intent: &str, callback: Box<dyn NyashBox>) {
|
||||
// CallbackBoxとして保存
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
##### Phase 3: Nyash統合(明日)
|
||||
```nyash
|
||||
// 使用例
|
||||
local_bus = new IntentBox() // デフォルトでローカル通信
|
||||
|
||||
node_a = new P2PBox("alice", local_bus)
|
||||
node_b = new P2PBox("bob", local_bus)
|
||||
|
||||
// リスナー登録
|
||||
node_b.on("greeting", |data, from| {
|
||||
print(from + " says: " + data.get("text"))
|
||||
})
|
||||
|
||||
// メッセージ送信
|
||||
node_a.send("greeting", { "text": "Hello!" }, "bob")
|
||||
```
|
||||
|
||||
##### Phase 4: Intent辞書パターン(明後日)
|
||||
```nyash
|
||||
// Intent定義の標準化
|
||||
ChatIntents = {
|
||||
"Message": "chat.message",
|
||||
"Join": "chat.user.joined",
|
||||
"Leave": "chat.user.left"
|
||||
}
|
||||
|
||||
// 型安全な使用
|
||||
node.send(ChatIntents.Message, data, target)
|
||||
```
|
||||
|
||||
##### 残りの実装タスク(将来拡張)
|
||||
- [ ] **コールバック実行**: MethodBox統合待ち
|
||||
- [ ] **WebSocket Transport**: ネットワーク通信対応
|
||||
- [ ] **ノード登録管理**: IntentBoxでのP2PBox管理
|
||||
- [ ] **メッセージ配信**: LocalTransportでの実配信
|
||||
|
||||
#### 将来の拡張性(設計に組み込み)
|
||||
- WebSocket Transport(ネットワーク通信)
|
||||
- SharedMemory Transport(高速IPC)
|
||||
- Persistence Layer(メッセージ永続化)
|
||||
- Security Layer(暗号化・認証)
|
||||
|
||||
#### 技術的考慮事項
|
||||
- **Arc<Mutex>統一**: 全16Box型と同じパターンで実装
|
||||
- **Weak参照**: 循環参照防止のため、IntentBoxはP2PBoxをWeakで保持
|
||||
- **非同期対応**: nowait/awaitとの統合を考慮
|
||||
- **エラーハンドリング**: ノード切断・タイムアウト処理
|
||||
|
||||
#### NyashFlowプロジェクトとの関連
|
||||
P2PBox実装は将来のNyashFlowビジュアルプログラミングにおいて、
|
||||
ノード間のデータフロー実行基盤として活用される重要な技術。
|
||||
CharmFlowの教訓を活かし、シンプルで拡張性の高い設計を目指す。
|
||||
|
||||
### 3. 🎮 実用アプリケーション開発(来週)
|
||||
- [ ] **P2P チャットアプリ**: P2PBox実装のデモ
|
||||
- [ ] **分散計算デモ**: 複数ノードでタスク分散
|
||||
- [ ] **リアルタイムゲーム**: 低遅延通信のテスト
|
||||
|
||||
### 4. 📚 ドキュメント整備(今週〜来週)
|
||||
- [ ] Arc<Mutex>設計思想をPHILOSOPHY.mdに追記
|
||||
- [ ] 関数オーバーロード設計思想をPHILOSOPHY.mdに追記
|
||||
- [ ] P2PBox/intentbox設計思想をPHILOSOPHY.mdに追記
|
||||
- [ ] 各Box APIリファレンス完全版作成(P2PBox含む)
|
||||
- [ ] 分散・並行処理プログラミングガイド
|
||||
|
||||
### 5. 🌐 WebAssembly強化(来週)
|
||||
- [ ] nyash-wasmを最新core対応に更新
|
||||
- [ ] Web Workersでの並行処理サポート
|
||||
- [ ] P2PBox WebSocket Transport対応
|
||||
- [ ] npm パッケージとして公開準備
|
||||
|
||||
### 6. 🛠️ 開発ツール(今月中)
|
||||
- [ ] **nyash-lsp**: Language Serverプロジェクト開始
|
||||
- [ ] **VS Code拡張**: シンタックスハイライト実装
|
||||
- [ ] **デバッガー**: ステップ実行・P2P通信トレース
|
||||
|
||||
### 7. ⚡ パフォーマンス最適化(継続的)
|
||||
- [ ] 不要なlock呼び出しの特定と削減
|
||||
- [ ] P2PBox メッセージ配信最適化
|
||||
- [ ] ベンチマークスイート構築
|
||||
- [ ] メモリ使用量プロファイリング
|
||||
|
||||
## 💭 技術的な振り返り
|
||||
|
||||
### Arc<Mutex>パターンの成功要因
|
||||
1. **設計の一貫性**: 全Box型で同じパターン採用
|
||||
2. **Rustの型システム**: コンパイル時の安全性保証
|
||||
3. **段階的移行**: 一つずつ確実に実装・テスト
|
||||
|
||||
### 学んだ教訓
|
||||
1. **ArrayBoxの見落とし**: 既存実装の確認が重要
|
||||
2. **型の互換性**: Box<dyn NyashBox>引数の重要性
|
||||
3. **テストファースト**: 実装前にテストケース作成
|
||||
|
||||
### 今後の課題と機会
|
||||
1. **エコシステム拡大**: サードパーティBox開発支援
|
||||
2. **パフォーマンス**: より効率的なlocking戦略
|
||||
3. **開発体験**: より直感的なAPI設計
|
||||
4. **AI協働開発**: 複数AI相談システムのさらなる活用
|
||||
|
||||
## 📝 重要メモ
|
||||
- **Git状態**: mainブランチは11コミット先行(要プッシュ)
|
||||
- **Copilot PR #2**: 正常にマージ完了、協働開発成功
|
||||
- **AI大相談会記録**: `sessions/ai_consultation_overload_design_20250810.md`
|
||||
- **プロジェクト再編**: 権限問題のため後日実施予定
|
||||
- **関数オーバーロード**: ✅完全実装完了(NyashAddトレイト)
|
||||
- **P2PBox/IntentBox**: ✅基本実装完了!テスト成功!
|
||||
- **次回作業**: コールバック実行機能の実装(MethodBox統合)
|
||||
# 🎯 現在のタスク (2025-08-11 シンプルBoxから段階的実装!)
|
||||
|
||||
## 🚀 2025-08-11 複雑なP2PBox実装をリセット → シンプルBox段階実装開始!
|
||||
|
||||
### 💡 **学習成果**
|
||||
**複雑すぎる実装を一度に追加すると失敗することを学習!**
|
||||
|
||||
#### **新方針**
|
||||
- **依存の少ないBox**: まずシンプルなBoxから追加
|
||||
- **段階的実装**: 一つずつ確実に動作確認
|
||||
- **テストファースト**: 必ず動作確認してから次へ
|
||||
|
||||
### 📋 **段階的実装計画(優先度順)**
|
||||
|
||||
#### **Phase 1: 基本型Box実装** (最優先)
|
||||
|
||||
##### 1. **FloatBox** - 浮動小数点数Box 📊
|
||||
- **依存**: なし (f64の基本実装)
|
||||
- **実装内容**:
|
||||
- 基本値の保持・表示
|
||||
- 四則演算メソッド
|
||||
- 文字列変換
|
||||
- 比較演算子
|
||||
- **テスト**:
|
||||
```nyash
|
||||
f = new FloatBox(3.14)
|
||||
print(f.add(2.86)) // 6.0
|
||||
print(f.toString()) // "3.14"
|
||||
```
|
||||
|
||||
##### 2. **ArrayBoxの改良** - 配列機能の強化 📚
|
||||
- **依存**: 既存ArrayBox実装
|
||||
- **追加機能**:
|
||||
- sort()メソッド - 配列ソート
|
||||
- reverse()メソッド - 配列反転
|
||||
- indexOf()メソッド - 要素検索
|
||||
- slice()メソッド - 部分配列
|
||||
- **テスト**:
|
||||
```nyash
|
||||
arr = new ArrayBox()
|
||||
arr.push(3); arr.push(1); arr.push(2)
|
||||
arr.sort() // [1, 2, 3]
|
||||
```
|
||||
|
||||
#### **Phase 2: 演算子システム** (高優先)
|
||||
|
||||
##### 3. **基本演算子の改良** ➕➖✖️➗
|
||||
- **依存**: 既存の演算子実装
|
||||
- **改良内容**:
|
||||
- 型間演算の対応 (IntegerBox + FloatBox)
|
||||
- 文字列 + 数値の連結
|
||||
- より良いエラーメッセージ
|
||||
- **テスト**:
|
||||
```nyash
|
||||
print(42 + 3.14) // 45.14 (型変換)
|
||||
print("Value: " + 42) // "Value: 42"
|
||||
```
|
||||
|
||||
##### 4. **比較演算子の完全実装** 🔍
|
||||
- **実装内容**:
|
||||
- ==, !=, <, >, <=, >= の完全対応
|
||||
- 型間比較のサポート
|
||||
- null比較の正しい動作
|
||||
- **テスト**: 全ての型の組み合わせテスト
|
||||
|
||||
#### **Phase 3: ユーティリティBox** (中優先)
|
||||
|
||||
##### 5. **DateTimeBox** - 日時操作 📅
|
||||
- **依存**: chrono crate (既存)
|
||||
- **機能**:
|
||||
- 現在時刻の取得
|
||||
- 日時の計算・比較
|
||||
- フォーマット変換
|
||||
- **テスト**: 日時計算、文字列変換
|
||||
|
||||
##### 6. **FileBox** - ファイル操作 📁
|
||||
- **依存**: std::fs
|
||||
- **機能**:
|
||||
- ファイル読み書き
|
||||
- 存在確認
|
||||
- ディレクトリ操作
|
||||
- **テスト**: 基本的なファイル操作
|
||||
|
||||
### 🎯 **今週の実装目標**
|
||||
|
||||
#### **今日 (2025-08-11)**: FloatBox実装
|
||||
1. FloatBox構造体作成
|
||||
2. 基本メソッド実装 (add, sub, mul, div)
|
||||
3. Nyashからの使用テスト
|
||||
4. インタープリター統合
|
||||
|
||||
#### **明日**: ArrayBox改良
|
||||
1. sort()メソッド実装
|
||||
2. reverse()メソッド実装
|
||||
3. テストスクリプト作成・動作確認
|
||||
|
||||
#### **明後日**: 演算子改良
|
||||
1. 型間演算の実装
|
||||
2. エラーハンドリング改善
|
||||
3. 包括的テスト
|
||||
|
||||
### 📊 **実装ステータス**
|
||||
|
||||
#### ✅ 実装済み (Arc<Mutex>統一完了)
|
||||
- StringBox, IntegerBox, BoolBox, NullBox
|
||||
- ConsoleBox, MathBox, TimeBox, MapBox
|
||||
- DebugBox, RandomBox, ArrayBox (基本)
|
||||
- BufferBox, RegexBox, JSONBox, StreamBox
|
||||
|
||||
#### 🚧 今回追加予定
|
||||
- FloatBox (今日)
|
||||
- ArrayBox改良 (明日)
|
||||
- 演算子改良 (明後日)
|
||||
|
||||
#### 📋 将来実装予定
|
||||
- DateTimeBox, FileBox
|
||||
- より複雑なBox (P2PBox等)
|
||||
|
||||
### 💭 **重要な原則**
|
||||
|
||||
1. **一つずつ確実に**: 1つのBoxを完全に実装してから次へ
|
||||
2. **テストファースト**: 必ずNyashスクリプトで動作確認
|
||||
3. **段階的複雑化**: シンプルから複雑へ
|
||||
4. **ビルド確認**: 毎回`cargo build`で確認
|
||||
5. **依存関係注意**: 複雑な依存は後回し
|
||||
|
||||
この方針で、確実で安定した実装を進めていきます!
|
||||
|
||||
---
|
||||
最終更新: 2025-08-11 - デリゲーション革命完了!`from`統一構文+`init`構文決定!🎉
|
||||
|
||||
> 「Everything is Box」の理念が、完全明示デリゲーションという革命的な設計により、
|
||||
> より安全で、より明確で、より美しい言語へと進化しました。
|
||||
> `box Child from Parent`、`init`、`override`、`from Parent.init()` -
|
||||
> すべてが統一され、Nyashは真の「完全明示デリゲーション言語」として確立されました。
|
||||
最終更新: 2025-08-11 - シンプルBox段階実装方針決定!
|
||||
@ -54,9 +54,6 @@ path = "development/egui_research/experiments/visual_node_prototype.rs"
|
||||
name = "test_icon_extraction"
|
||||
path = "examples/test_icon_extraction.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "test_new_p2p_box"
|
||||
path = "test_new_p2p_box.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "test_method_box_integration"
|
||||
|
||||
@ -1,134 +0,0 @@
|
||||
/**
|
||||
* MessageIntentBox - メッセージコンテナBox(P2P通信用)
|
||||
*
|
||||
* 設計原則:
|
||||
* - HashMap<String, Box<dyn NyashBox>>でNyashネイティブデータ保持
|
||||
* - 同期・シンプル実装(async対応は将来拡張)
|
||||
* - Everything is Box哲学に準拠
|
||||
*
|
||||
* 注意: 既存のIntentBox(通信世界)とは別物
|
||||
* - IntentBox = 通信世界・環境の定義
|
||||
* - MessageIntentBox = 実際のメッセージデータ(これ)
|
||||
*/
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use crate::box_trait::{NyashBox, BoxCore, BoxBase, next_box_id};
|
||||
|
||||
/// MessageIntentBox - Intent型通信メッセージのコンテナ
|
||||
pub struct MessageIntentBox {
|
||||
base: BoxBase,
|
||||
/// Intent種類("chat.message", "file.transfer"等)
|
||||
pub intent: String,
|
||||
/// Nyashネイティブデータ保持
|
||||
pub payload: HashMap<String, Box<dyn NyashBox>>,
|
||||
}
|
||||
|
||||
impl MessageIntentBox {
|
||||
/// 新しいMessageIntentBoxを作成
|
||||
pub fn new(intent: &str) -> Self {
|
||||
Self {
|
||||
base: BoxBase {
|
||||
id: next_box_id(),
|
||||
parent_type_id: None, // ビルトインBox継承なし
|
||||
},
|
||||
intent: intent.to_string(),
|
||||
payload: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// キー-値ペアを設定
|
||||
pub fn set(&mut self, key: &str, value: Box<dyn NyashBox>) {
|
||||
self.payload.insert(key.to_string(), value);
|
||||
}
|
||||
|
||||
/// キーに対応する値を取得
|
||||
pub fn get(&self, key: &str) -> Option<&Box<dyn NyashBox>> {
|
||||
self.payload.get(key)
|
||||
}
|
||||
|
||||
/// キーに対応する値を削除
|
||||
pub fn remove(&mut self, key: &str) -> Option<Box<dyn NyashBox>> {
|
||||
self.payload.remove(key)
|
||||
}
|
||||
|
||||
/// すべてのキーを取得
|
||||
pub fn keys(&self) -> Vec<String> {
|
||||
self.payload.keys().cloned().collect()
|
||||
}
|
||||
|
||||
/// ペイロードが空かチェック
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.payload.is_empty()
|
||||
}
|
||||
|
||||
/// ペイロード要素数を取得
|
||||
pub fn len(&self) -> usize {
|
||||
self.payload.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl BoxCore for MessageIntentBox {
|
||||
fn box_id(&self) -> u64 {
|
||||
self.base.id
|
||||
}
|
||||
|
||||
fn parent_type_id(&self) -> Option<std::any::TypeId> {
|
||||
self.base.parent_type_id
|
||||
}
|
||||
|
||||
fn fmt_box(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "MessageIntentBox(intent: {}, payload: {} items)",
|
||||
self.intent, self.payload.len())
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl NyashBox for MessageIntentBox {
|
||||
fn type_name(&self) -> &'static str {
|
||||
"MessageIntentBox"
|
||||
}
|
||||
|
||||
fn to_string_box(&self) -> crate::StringBox {
|
||||
crate::StringBox::new(&format!("MessageIntentBox({})", self.intent))
|
||||
}
|
||||
|
||||
fn clone_box(&self) -> Box<dyn NyashBox> {
|
||||
let mut new_intent = MessageIntentBox::new(&self.intent);
|
||||
|
||||
// PayloadをDeepClone
|
||||
for (key, value) in &self.payload {
|
||||
new_intent.payload.insert(key.clone(), value.clone_box());
|
||||
}
|
||||
|
||||
Box::new(new_intent)
|
||||
}
|
||||
|
||||
fn equals(&self, other: &dyn NyashBox) -> crate::BoolBox {
|
||||
if let Some(other_intent) = other.as_any().downcast_ref::<MessageIntentBox>() {
|
||||
crate::BoolBox::new(self.box_id() == other_intent.box_id())
|
||||
} else {
|
||||
crate::BoolBox::new(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for MessageIntentBox {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.fmt_box(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for MessageIntentBox {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "MessageIntentBox {{ intent: {:?}, payload: {:?} }}",
|
||||
self.intent, self.payload.len())
|
||||
}
|
||||
}
|
||||
@ -108,8 +108,6 @@ pub mod regex;
|
||||
// P2P通信Box群
|
||||
pub mod intent_box;
|
||||
pub mod p2p_box;
|
||||
pub mod message_intent_box;
|
||||
pub mod new_p2p_box;
|
||||
|
||||
// null関数も再エクスポート
|
||||
pub use null_box::{NullBox, null};
|
||||
@ -127,6 +125,4 @@ pub use regex::RegexBox;
|
||||
|
||||
// P2P通信Boxの再エクスポート
|
||||
pub use intent_box::IntentBox;
|
||||
pub use p2p_box::P2PBox;
|
||||
pub use message_intent_box::MessageIntentBox;
|
||||
pub use new_p2p_box::NewP2PBox;
|
||||
pub use p2p_box::P2PBox;
|
||||
@ -1,171 +0,0 @@
|
||||
/**
|
||||
* NewP2PBox - 天才アルゴリズム内蔵P2PBox(同期・シンプル版)
|
||||
*
|
||||
* 設計原則(4つの核心):
|
||||
* 1. P2PBoxは、トランスポートがネットでもBusを持ち続ける(ローカル配送・購読・監視用)
|
||||
* 2. P2PBoxはMessageIntentBoxを使って送る
|
||||
* 3. 送信アルゴリズム:ローカルならBus、それ以外はTransport
|
||||
* 4. 受信アルゴリズム:Transport→P2PBox→Bus でローカルハンドラに届く
|
||||
*
|
||||
* Everything is Box哲学準拠・同期実装
|
||||
*/
|
||||
|
||||
use std::sync::Arc;
|
||||
use crate::box_trait::{NyashBox, BoxCore, BoxBase, next_box_id};
|
||||
use crate::boxes::MessageIntentBox;
|
||||
use crate::transport_trait::{Transport, TransportKind, create_transport};
|
||||
use crate::message_bus::{get_global_message_bus, BusMessage, MessageBus};
|
||||
use crate::method_box::MethodBox;
|
||||
|
||||
/// NewP2PBox - 天才アルゴリズム内蔵P2P通信ノード
|
||||
pub struct NewP2PBox {
|
||||
base: BoxBase,
|
||||
node_id: String,
|
||||
transport: Box<dyn Transport>,
|
||||
bus: Arc<MessageBus>, // ← 常に保持!(ローカル配送・購読・監視用)
|
||||
}
|
||||
|
||||
impl NewP2PBox {
|
||||
/// シンプル同期コンストラクタ
|
||||
pub fn new(node_id: &str, transport_kind: TransportKind) -> Self {
|
||||
let bus = get_global_message_bus(); // シングルトン取得
|
||||
let transport = create_transport(transport_kind, node_id); // 簡単ファクトリ
|
||||
|
||||
// 自ノード登録
|
||||
bus.register_node(node_id).unwrap();
|
||||
|
||||
Self {
|
||||
base: BoxBase {
|
||||
id: next_box_id(),
|
||||
parent_type_id: None,
|
||||
},
|
||||
node_id: node_id.to_string(),
|
||||
transport,
|
||||
bus
|
||||
}
|
||||
}
|
||||
|
||||
/// 購読メソッド - Busに登録(Rustクロージャ版)
|
||||
pub fn on(&self, intent: &str, callback: Box<dyn Fn(&MessageIntentBox) + Send + Sync>) {
|
||||
// BusMessageからMessageIntentBoxを抽出するラッパー
|
||||
let wrapper = Box::new(move |bus_message: &BusMessage| {
|
||||
// BusMessageのdataをMessageIntentBoxにダウンキャスト
|
||||
if let Some(intent_box) = bus_message.data.as_any().downcast_ref::<MessageIntentBox>() {
|
||||
callback(intent_box);
|
||||
}
|
||||
});
|
||||
self.bus.on(&self.node_id, intent, wrapper).unwrap();
|
||||
}
|
||||
|
||||
/// 購読メソッド - MethodBox版(Nyash統合用)
|
||||
pub fn on_method(&self, intent: &str, method_box: MethodBox) -> Result<(), String> {
|
||||
// MethodBoxをクロージャでラップ
|
||||
let wrapper = Box::new(move |bus_message: &BusMessage| {
|
||||
// BusMessageのdataをMessageIntentBoxにダウンキャスト
|
||||
if let Some(intent_box) = bus_message.data.as_any().downcast_ref::<MessageIntentBox>() {
|
||||
// TODO: インタープリターコンテキストが必要
|
||||
// 現在は単純化実装
|
||||
println!("🎯 MethodBox callback triggered for intent '{}' from {}",
|
||||
intent_box.intent, bus_message.from);
|
||||
|
||||
// MethodBox.invoke()を呼び出し(引数としてMessageIntentBoxを渡す)
|
||||
let args = vec![intent_box.clone_box()];
|
||||
match method_box.invoke(args) {
|
||||
Ok(result) => {
|
||||
println!("📥 MethodBox execution result: {}", result.to_string_box().value);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("❌ MethodBox execution error: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
self.bus.on(&self.node_id, intent, wrapper)
|
||||
}
|
||||
|
||||
/// 送信メソッド - 天才アルゴリズム内蔵(同期版)
|
||||
pub fn send(&self, to: &str, intent_box: &MessageIntentBox) -> Result<(), String> {
|
||||
// 1) 宛先が同プロセス(Busが知っている)ならローカル配送
|
||||
if self.bus.has_node(to) {
|
||||
// MessageIntentBoxからBusMessageに変換
|
||||
let message = BusMessage {
|
||||
from: self.node_id.clone(),
|
||||
to: to.to_string(),
|
||||
intent: intent_box.intent.clone(),
|
||||
data: intent_box.clone_box(), // MessageIntentBox全体をデータとして送信
|
||||
timestamp: std::time::SystemTime::now(),
|
||||
};
|
||||
self.bus.route(message)?; // 爆速ローカル
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// 2) ローカルに居ない → Transportで外へ出す
|
||||
self.transport.send(to, &intent_box.intent, intent_box.clone_box())
|
||||
}
|
||||
|
||||
/// ノードID取得
|
||||
pub fn get_node_id(&self) -> &str {
|
||||
&self.node_id
|
||||
}
|
||||
}
|
||||
|
||||
impl BoxCore for NewP2PBox {
|
||||
fn box_id(&self) -> u64 {
|
||||
self.base.id
|
||||
}
|
||||
|
||||
fn parent_type_id(&self) -> Option<std::any::TypeId> {
|
||||
self.base.parent_type_id
|
||||
}
|
||||
|
||||
fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "NewP2PBox(node_id: {}, transport: {})",
|
||||
self.node_id, self.transport.transport_type())
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl NyashBox for NewP2PBox {
|
||||
fn type_name(&self) -> &'static str {
|
||||
"NewP2PBox"
|
||||
}
|
||||
|
||||
fn to_string_box(&self) -> crate::StringBox {
|
||||
crate::StringBox::new(&format!("NewP2PBox({})", self.node_id))
|
||||
}
|
||||
|
||||
fn clone_box(&self) -> Box<dyn NyashBox> {
|
||||
// P2PBoxは基本的にクローンしない(ノードの一意性のため)
|
||||
// 必要に応じて別のコンストラクタで同じ設定の新ノードを作成する
|
||||
todo!("P2PBox clone not recommended - create new node instead")
|
||||
}
|
||||
|
||||
fn equals(&self, other: &dyn NyashBox) -> crate::BoolBox {
|
||||
if let Some(other_p2p) = other.as_any().downcast_ref::<NewP2PBox>() {
|
||||
crate::BoolBox::new(self.node_id == other_p2p.node_id)
|
||||
} else {
|
||||
crate::BoolBox::new(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for NewP2PBox {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
self.fmt_box(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for NewP2PBox {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "NewP2PBox {{ node_id: {:?}, transport: {:?} }}",
|
||||
self.node_id, self.transport.transport_type())
|
||||
}
|
||||
}
|
||||
@ -8,7 +8,7 @@
|
||||
|
||||
use super::*;
|
||||
use crate::ast::UnaryOperator;
|
||||
use crate::boxes::{buffer::BufferBox, JSONBox, HttpClientBox, StreamBox, RegexBox, IntentBox, P2PBox, NewP2PBox, MessageIntentBox};
|
||||
use crate::boxes::{buffer::BufferBox, JSONBox, HttpClientBox, StreamBox, RegexBox, IntentBox, P2PBox};
|
||||
use crate::boxes::{MathBox, ConsoleBox, TimeBox, RandomBox, SoundBox, DebugBox, file::FileBox, MapBox};
|
||||
use crate::operator_traits::OperatorResolver;
|
||||
// TODO: Fix NullBox import issue later
|
||||
@ -747,7 +747,7 @@ impl NyashInterpreter {
|
||||
"TimeBox" | "DateTimeBox" | "TimerBox" | "RandomBox" | "SoundBox" |
|
||||
"DebugBox" | "MethodBox" | "NullBox" | "ConsoleBox" | "FloatBox" |
|
||||
"BufferBox" | "RegexBox" | "JSONBox" | "StreamBox" | "HTTPClientBox" |
|
||||
"IntentBox" | "P2PBox" | "NewP2PBox" | "MessageIntentBox" | "EguiBox"
|
||||
"IntentBox" | "P2PBox" | "EguiBox"
|
||||
);
|
||||
|
||||
if is_builtin {
|
||||
@ -941,26 +941,6 @@ impl NyashInterpreter {
|
||||
message: format!("P2PBox delegation not yet fully implemented: {}.{}", parent, method),
|
||||
});
|
||||
}
|
||||
"NewP2PBox" => {
|
||||
// NewP2PBoxの場合、current_instanceから実際のNewP2PBoxインスタンスを取得
|
||||
if let Some(p2p_box) = current_instance.as_any().downcast_ref::<NewP2PBox>() {
|
||||
self.execute_new_p2p_box_method(p2p_box, method, arguments)
|
||||
} else {
|
||||
Err(RuntimeError::TypeError {
|
||||
message: format!("Expected NewP2PBox instance for method call {}.{}", parent, method),
|
||||
})
|
||||
}
|
||||
}
|
||||
"MessageIntentBox" => {
|
||||
// MessageIntentBoxの場合、current_instanceから実際のMessageIntentBoxインスタンスを取得
|
||||
if let Some(message_box) = current_instance.as_any_mut().downcast_mut::<MessageIntentBox>() {
|
||||
self.execute_message_intent_box_method(message_box, method, arguments)
|
||||
} else {
|
||||
Err(RuntimeError::TypeError {
|
||||
message: format!("Expected MessageIntentBox instance for method call {}.{}", parent, method),
|
||||
})
|
||||
}
|
||||
}
|
||||
"FileBox" => {
|
||||
let file_box = crate::boxes::file::FileBox::new();
|
||||
self.execute_file_method(&file_box, method, arguments)
|
||||
|
||||
@ -6,7 +6,7 @@ use crate::interpreter::core::NyashInterpreter;
|
||||
use crate::interpreter::core::RuntimeError;
|
||||
use crate::ast::ASTNode;
|
||||
use crate::box_trait::{NyashBox, StringBox};
|
||||
use crate::boxes::{IntentBox, P2PBox, NewP2PBox, MessageIntentBox};
|
||||
use crate::boxes::{IntentBox, P2PBox};
|
||||
use crate::method_box::MethodBox;
|
||||
|
||||
impl NyashInterpreter {
|
||||
@ -115,143 +115,4 @@ impl NyashInterpreter {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// NewP2PBoxのメソッド実行(天才アルゴリズム版)
|
||||
pub(in crate::interpreter) fn execute_new_p2p_box_method(
|
||||
&mut self,
|
||||
p2p_box: &NewP2PBox,
|
||||
method: &str,
|
||||
arguments: &[ASTNode],
|
||||
) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
match method {
|
||||
// ノードID取得
|
||||
"getNodeId" | "getId" => {
|
||||
Ok(Box::new(StringBox::new(p2p_box.get_node_id())))
|
||||
}
|
||||
|
||||
// メッセージ送信(天才アルゴリズム)
|
||||
"send" => {
|
||||
if arguments.len() != 2 {
|
||||
return Err(RuntimeError::InvalidOperation {
|
||||
message: "send requires 2 arguments: target, message_intent_box".to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
let target = self.execute_expression(&arguments[0])?;
|
||||
let message_box = self.execute_expression(&arguments[1])?;
|
||||
|
||||
if let Some(target_str) = target.as_any().downcast_ref::<StringBox>() {
|
||||
if let Some(intent_box) = message_box.as_any().downcast_ref::<MessageIntentBox>() {
|
||||
match p2p_box.send(&target_str.value, intent_box) {
|
||||
Ok(()) => Ok(Box::new(StringBox::new("sent"))),
|
||||
Err(e) => Err(RuntimeError::InvalidOperation { message: e }),
|
||||
}
|
||||
} else {
|
||||
Err(RuntimeError::TypeError {
|
||||
message: "send requires MessageIntentBox as second argument".to_string(),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Err(RuntimeError::TypeError {
|
||||
message: "send requires string target as first argument".to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// リスナー登録(MethodBox版)
|
||||
"onMethod" => {
|
||||
if arguments.len() != 2 {
|
||||
return Err(RuntimeError::InvalidOperation {
|
||||
message: "onMethod requires 2 arguments: intent, method_box".to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
let intent = self.execute_expression(&arguments[0])?;
|
||||
let method_box = self.execute_expression(&arguments[1])?;
|
||||
|
||||
if let Some(intent_str) = intent.as_any().downcast_ref::<StringBox>() {
|
||||
if let Some(method_box) = method_box.as_any().downcast_ref::<MethodBox>() {
|
||||
match p2p_box.on_method(&intent_str.value, method_box.clone()) {
|
||||
Ok(()) => Ok(Box::new(StringBox::new("listener registered"))),
|
||||
Err(e) => Err(RuntimeError::InvalidOperation { message: e }),
|
||||
}
|
||||
} else {
|
||||
Err(RuntimeError::TypeError {
|
||||
message: "onMethod requires MethodBox as second argument".to_string(),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Err(RuntimeError::TypeError {
|
||||
message: "onMethod requires string intent as first argument".to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
_ => Err(RuntimeError::UndefinedVariable {
|
||||
name: format!("NewP2PBox method '{}' not found", method),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// MessageIntentBoxのメソッド実行
|
||||
pub(in crate::interpreter) fn execute_message_intent_box_method(
|
||||
&mut self,
|
||||
message_box: &mut MessageIntentBox,
|
||||
method: &str,
|
||||
arguments: &[ASTNode],
|
||||
) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
match method {
|
||||
// intent取得
|
||||
"getIntent" | "intent" => {
|
||||
Ok(Box::new(StringBox::new(&message_box.intent)))
|
||||
}
|
||||
|
||||
// データ設定
|
||||
"set" => {
|
||||
if arguments.len() != 2 {
|
||||
return Err(RuntimeError::InvalidOperation {
|
||||
message: "set requires 2 arguments: key, value".to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
let key = self.execute_expression(&arguments[0])?;
|
||||
let value = self.execute_expression(&arguments[1])?;
|
||||
|
||||
if let Some(key_str) = key.as_any().downcast_ref::<StringBox>() {
|
||||
message_box.set(&key_str.value, value);
|
||||
Ok(Box::new(StringBox::new("set")))
|
||||
} else {
|
||||
Err(RuntimeError::TypeError {
|
||||
message: "set requires string key as first argument".to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// データ取得
|
||||
"get" => {
|
||||
if arguments.len() != 1 {
|
||||
return Err(RuntimeError::InvalidOperation {
|
||||
message: "get requires 1 argument: key".to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
let key = self.execute_expression(&arguments[0])?;
|
||||
if let Some(key_str) = key.as_any().downcast_ref::<StringBox>() {
|
||||
if let Some(value) = message_box.get(&key_str.value) {
|
||||
Ok(value.clone_box())
|
||||
} else {
|
||||
Ok(Box::new(crate::boxes::NullBox::new()))
|
||||
}
|
||||
} else {
|
||||
Err(RuntimeError::TypeError {
|
||||
message: "get requires string key as argument".to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
_ => Err(RuntimeError::UndefinedVariable {
|
||||
name: format!("MessageIntentBox method '{}' not found", method),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,8 +9,6 @@
|
||||
use super::*;
|
||||
use crate::boxes::null_box::NullBox;
|
||||
use crate::boxes::console_box::ConsoleBox;
|
||||
use crate::boxes::{NewP2PBox, MessageIntentBox};
|
||||
use crate::transport_trait::TransportKind;
|
||||
// use crate::boxes::intent_box_wrapper::IntentBoxWrapper;
|
||||
use std::sync::Arc;
|
||||
|
||||
@ -538,64 +536,6 @@ impl NyashInterpreter {
|
||||
});
|
||||
}
|
||||
}
|
||||
"NewP2PBox" => {
|
||||
// NewP2PBoxは引数2個(node_id, transport_kind)で作成
|
||||
if arguments.len() != 2 {
|
||||
return Err(RuntimeError::InvalidOperation {
|
||||
message: format!("NewP2PBox constructor expects 2 arguments (node_id, transport_kind), got {}", arguments.len()),
|
||||
});
|
||||
}
|
||||
|
||||
// node_id
|
||||
let node_id_value = self.execute_expression(&arguments[0])?;
|
||||
let node_id = if let Some(id_str) = node_id_value.as_any().downcast_ref::<StringBox>() {
|
||||
id_str.value.clone()
|
||||
} else {
|
||||
return Err(RuntimeError::TypeError {
|
||||
message: "NewP2PBox constructor requires string node_id as first argument".to_string(),
|
||||
});
|
||||
};
|
||||
|
||||
// transport_kind(文字列 → TransportKind enum)
|
||||
let transport_value = self.execute_expression(&arguments[1])?;
|
||||
let transport_kind = if let Some(transport_str) = transport_value.as_any().downcast_ref::<StringBox>() {
|
||||
match transport_str.value.as_str() {
|
||||
"InProcess" => TransportKind::InProcess,
|
||||
"WebSocket" => TransportKind::WebSocket,
|
||||
"WebRTC" => TransportKind::WebRTC,
|
||||
_ => {
|
||||
return Err(RuntimeError::TypeError {
|
||||
message: format!("Invalid transport kind '{}'. Valid options: InProcess, WebSocket, WebRTC", transport_str.value),
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(RuntimeError::TypeError {
|
||||
message: "NewP2PBox constructor requires string transport_kind as second argument".to_string(),
|
||||
});
|
||||
};
|
||||
|
||||
let p2p_box = Box::new(NewP2PBox::new(&node_id, transport_kind)) as Box<dyn NyashBox>;
|
||||
return Ok(p2p_box);
|
||||
}
|
||||
"MessageIntentBox" => {
|
||||
// MessageIntentBoxは引数1個(intent)で作成
|
||||
if arguments.len() != 1 {
|
||||
return Err(RuntimeError::InvalidOperation {
|
||||
message: format!("MessageIntentBox constructor expects 1 argument (intent), got {}", arguments.len()),
|
||||
});
|
||||
}
|
||||
|
||||
let intent_value = self.execute_expression(&arguments[0])?;
|
||||
if let Some(intent_str) = intent_value.as_any().downcast_ref::<StringBox>() {
|
||||
let message_box = Box::new(MessageIntentBox::new(&intent_str.value)) as Box<dyn NyashBox>;
|
||||
return Ok(message_box);
|
||||
} else {
|
||||
return Err(RuntimeError::TypeError {
|
||||
message: "MessageIntentBox constructor requires string intent as argument".to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
||||
@ -22,9 +22,6 @@ pub mod finalization;
|
||||
pub mod exception_box;
|
||||
pub mod method_box;
|
||||
pub mod type_box; // 🌟 TypeBox revolutionary system
|
||||
pub mod transport_trait;
|
||||
pub mod message_bus;
|
||||
pub mod transports;
|
||||
pub mod operator_traits; // 🚀 Rust-style trait-based operator overloading
|
||||
pub mod box_operators; // 🚀 Operator implementations for basic Box types
|
||||
|
||||
|
||||
@ -1,173 +0,0 @@
|
||||
/**
|
||||
* MessageBus - Central communication hub (Bus = Local OS metaphor)
|
||||
*
|
||||
* Design principles from ChatGPT discussion:
|
||||
* - Always present in P2PBox (even for network transport)
|
||||
* - Handles local routing, subscription, monitoring
|
||||
* - Singleton pattern for process-wide message coordination
|
||||
* - Synchronous-first implementation
|
||||
*
|
||||
* NyaMesh inspiration:
|
||||
* - InProcessMessageBus singleton pattern
|
||||
* - Node registration/unregistration
|
||||
* - Statistics tracking
|
||||
*/
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
use crate::NyashBox;
|
||||
|
||||
/// Message structure for internal routing
|
||||
#[derive(Debug)]
|
||||
pub struct BusMessage {
|
||||
pub from: String,
|
||||
pub to: String,
|
||||
pub intent: String,
|
||||
pub data: Box<dyn NyashBox>,
|
||||
pub timestamp: std::time::SystemTime,
|
||||
}
|
||||
|
||||
impl Clone for BusMessage {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
from: self.from.clone(),
|
||||
to: self.to.clone(),
|
||||
intent: self.intent.clone(),
|
||||
data: self.data.clone_box(), // NyashBoxのclone_box()メソッドを使用
|
||||
timestamp: self.timestamp,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Node registration information
|
||||
struct NodeInfo {
|
||||
node_id: String,
|
||||
callbacks: HashMap<String, Vec<Box<dyn Fn(&BusMessage) + Send + Sync>>>,
|
||||
}
|
||||
|
||||
/// Central MessageBus - handles all local message routing
|
||||
pub struct MessageBus {
|
||||
/// Registered nodes in this process
|
||||
nodes: RwLock<HashMap<String, Arc<Mutex<NodeInfo>>>>,
|
||||
|
||||
/// Bus-level statistics
|
||||
stats: Mutex<BusStats>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct BusStats {
|
||||
pub messages_routed: u64,
|
||||
pub routing_errors: u64,
|
||||
pub nodes_registered: u64,
|
||||
pub total_callbacks: u64,
|
||||
}
|
||||
|
||||
impl MessageBus {
|
||||
/// Create new MessageBus instance
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
nodes: RwLock::new(HashMap::new()),
|
||||
stats: Mutex::new(BusStats::default()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Register a node in the message bus
|
||||
pub fn register_node(&self, node_id: &str) -> Result<(), String> {
|
||||
let mut nodes = self.nodes.write().unwrap();
|
||||
|
||||
if nodes.contains_key(node_id) {
|
||||
return Err(format!("Node '{}' already registered", node_id));
|
||||
}
|
||||
|
||||
let node_info = NodeInfo {
|
||||
node_id: node_id.to_string(),
|
||||
callbacks: HashMap::new(),
|
||||
};
|
||||
|
||||
nodes.insert(node_id.to_string(), Arc::new(Mutex::new(node_info)));
|
||||
|
||||
// Update stats
|
||||
let mut stats = self.stats.lock().unwrap();
|
||||
stats.nodes_registered += 1;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Unregister a node from the message bus
|
||||
pub fn unregister_node(&self, node_id: &str) {
|
||||
let mut nodes = self.nodes.write().unwrap();
|
||||
nodes.remove(node_id);
|
||||
}
|
||||
|
||||
/// Check if a node is registered locally
|
||||
pub fn has_node(&self, node_id: &str) -> bool {
|
||||
let nodes = self.nodes.read().unwrap();
|
||||
nodes.contains_key(node_id)
|
||||
}
|
||||
|
||||
/// Route message to local node
|
||||
pub fn route(&self, message: BusMessage) -> Result<(), String> {
|
||||
let nodes = self.nodes.read().unwrap();
|
||||
|
||||
if let Some(node) = nodes.get(&message.to) {
|
||||
let node = node.lock().unwrap();
|
||||
|
||||
// Find callbacks for this intent
|
||||
if let Some(callbacks) = node.callbacks.get(&message.intent) {
|
||||
for callback in callbacks {
|
||||
callback(&message);
|
||||
}
|
||||
}
|
||||
|
||||
// Update stats
|
||||
let mut stats = self.stats.lock().unwrap();
|
||||
stats.messages_routed += 1;
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
let mut stats = self.stats.lock().unwrap();
|
||||
stats.routing_errors += 1;
|
||||
Err(format!("Node '{}' not found for routing", message.to))
|
||||
}
|
||||
}
|
||||
|
||||
/// Register callback for specific intent on a node
|
||||
pub fn on(&self, node_id: &str, intent: &str, callback: Box<dyn Fn(&BusMessage) + Send + Sync>) -> Result<(), String> {
|
||||
let nodes = self.nodes.read().unwrap();
|
||||
|
||||
if let Some(node) = nodes.get(node_id) {
|
||||
let mut node = node.lock().unwrap();
|
||||
node.callbacks.entry(intent.to_string()).or_insert_with(Vec::new).push(callback);
|
||||
|
||||
// Update stats
|
||||
let mut stats = self.stats.lock().unwrap();
|
||||
stats.total_callbacks += 1;
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!("Node '{}' not found for callback registration", node_id))
|
||||
}
|
||||
}
|
||||
|
||||
/// Get list of registered nodes
|
||||
pub fn get_registered_nodes(&self) -> Vec<String> {
|
||||
let nodes = self.nodes.read().unwrap();
|
||||
nodes.keys().cloned().collect()
|
||||
}
|
||||
|
||||
/// Get bus statistics
|
||||
pub fn get_stats(&self) -> BusStats {
|
||||
let stats = self.stats.lock().unwrap();
|
||||
stats.clone()
|
||||
}
|
||||
}
|
||||
|
||||
use std::sync::OnceLock;
|
||||
|
||||
/// Global MessageBus singleton
|
||||
static GLOBAL_MESSAGE_BUS: OnceLock<Arc<MessageBus>> = OnceLock::new();
|
||||
|
||||
/// Get global message bus instance
|
||||
pub fn get_global_message_bus() -> Arc<MessageBus> {
|
||||
GLOBAL_MESSAGE_BUS.get_or_init(|| Arc::new(MessageBus::new())).clone()
|
||||
}
|
||||
@ -1,80 +0,0 @@
|
||||
/**
|
||||
* Transport trait abstraction - NyaMesh style implementation
|
||||
*
|
||||
* Design principles from NyaMesh:
|
||||
* - Transport = NIC (Network Interface Card) - handles communication method only
|
||||
* - Bus = Local OS - handles routing, subscription, monitoring
|
||||
* - Clean separation between transport mechanism and message routing
|
||||
*
|
||||
* Based on ChatGPT discussion P2PBox architecture:
|
||||
* - P2PBox always has MessageBus (even for network transport)
|
||||
* - Transport abstraction allows switching InProcess/WebSocket/WebRTC
|
||||
* - Synchronous-first implementation strategy
|
||||
*/
|
||||
|
||||
use crate::NyashBox;
|
||||
use crate::transports::InProcessTransport;
|
||||
|
||||
/// Transport trait - represents different communication mechanisms
|
||||
/// Like NyaMesh's TransportInterface, this abstracts the "how to send" part
|
||||
pub trait Transport: Send + Sync {
|
||||
/// Initialize the transport (async-compatible but synchronous first)
|
||||
fn initialize(&mut self) -> Result<(), String>;
|
||||
|
||||
/// Send message through this transport mechanism
|
||||
/// to: target node ID
|
||||
/// intent: message intent type
|
||||
/// data: message payload
|
||||
fn send(&self, to: &str, intent: &str, data: Box<dyn NyashBox>) -> Result<(), String>;
|
||||
|
||||
/// Get transport type identifier (e.g., "inprocess", "websocket", "webrtc")
|
||||
fn transport_type(&self) -> &'static str;
|
||||
|
||||
/// Check if transport is ready
|
||||
fn is_ready(&self) -> bool;
|
||||
|
||||
/// Shutdown transport cleanly
|
||||
fn shutdown(&mut self) -> Result<(), String>;
|
||||
|
||||
/// Get transport statistics
|
||||
fn get_stats(&self) -> TransportStats;
|
||||
}
|
||||
|
||||
/// Transport statistics - standardized across all transport types
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TransportStats {
|
||||
pub transport_type: String,
|
||||
pub messages_sent: u64,
|
||||
pub messages_received: u64,
|
||||
pub errors: u64,
|
||||
pub is_ready: bool,
|
||||
}
|
||||
|
||||
impl TransportStats {
|
||||
pub fn new(transport_type: &str) -> Self {
|
||||
Self {
|
||||
transport_type: transport_type.to_string(),
|
||||
messages_sent: 0,
|
||||
messages_received: 0,
|
||||
errors: 0,
|
||||
is_ready: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// TransportKind - 通信方式の選択(Nyash同期・シンプル版)
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum TransportKind {
|
||||
InProcess, // プロセス内通信(最初に実装)
|
||||
WebSocket, // WebSocket通信(将来実装)
|
||||
WebRTC, // P2P直接通信(将来実装)
|
||||
}
|
||||
|
||||
/// シンプルファクトリ関数
|
||||
pub fn create_transport(kind: TransportKind, node_id: &str) -> Box<dyn Transport> {
|
||||
match kind {
|
||||
TransportKind::InProcess => Box::new(InProcessTransport::new(node_id.to_string())),
|
||||
TransportKind::WebSocket => todo!("WebSocket transport - 将来実装"),
|
||||
TransportKind::WebRTC => todo!("WebRTC transport - 将来実装"),
|
||||
}
|
||||
}
|
||||
@ -1,134 +0,0 @@
|
||||
/**
|
||||
* InProcessTransport - Local process communication transport
|
||||
*
|
||||
* Based on NyaMesh InProcessTransport design:
|
||||
* - Synchronous-first implementation (parallelSafe flag support)
|
||||
* - Direct function pointer callbacks (no async complexity)
|
||||
* - Simple message routing through global MessageBus
|
||||
*
|
||||
* Key features from NyaMesh:
|
||||
* - parallelSafe = false by default (GUI thread safe)
|
||||
* - Direct callback execution
|
||||
* - Statistics tracking
|
||||
*/
|
||||
|
||||
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
|
||||
use crate::transport_trait::{Transport, TransportStats};
|
||||
use crate::message_bus::{get_global_message_bus, BusMessage};
|
||||
use crate::NyashBox;
|
||||
|
||||
/// InProcessTransport - for local communication within same process
|
||||
pub struct InProcessTransport {
|
||||
/// Node ID for this transport
|
||||
node_id: String,
|
||||
|
||||
/// Whether transport is initialized
|
||||
initialized: AtomicBool,
|
||||
|
||||
/// Statistics
|
||||
messages_sent: AtomicU64,
|
||||
messages_received: AtomicU64,
|
||||
errors: AtomicU64,
|
||||
}
|
||||
|
||||
impl InProcessTransport {
|
||||
/// Create new InProcessTransport with given node ID
|
||||
pub fn new(node_id: String) -> Self {
|
||||
Self {
|
||||
node_id,
|
||||
initialized: AtomicBool::new(false),
|
||||
messages_sent: AtomicU64::new(0),
|
||||
messages_received: AtomicU64::new(0),
|
||||
errors: AtomicU64::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get node ID
|
||||
pub fn node_id(&self) -> &str {
|
||||
&self.node_id
|
||||
}
|
||||
}
|
||||
|
||||
impl Transport for InProcessTransport {
|
||||
fn initialize(&mut self) -> Result<(), String> {
|
||||
if self.initialized.load(Ordering::Relaxed) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Register with global message bus
|
||||
let bus = get_global_message_bus();
|
||||
bus.register_node(&self.node_id)?;
|
||||
|
||||
self.initialized.store(true, Ordering::Relaxed);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn send(&self, to: &str, intent: &str, data: Box<dyn NyashBox>) -> Result<(), String> {
|
||||
if !self.initialized.load(Ordering::Relaxed) {
|
||||
self.errors.fetch_add(1, Ordering::Relaxed);
|
||||
return Err("Transport not initialized".to_string());
|
||||
}
|
||||
|
||||
// Create bus message
|
||||
let message = BusMessage {
|
||||
from: self.node_id.clone(),
|
||||
to: to.to_string(),
|
||||
intent: intent.to_string(),
|
||||
data,
|
||||
timestamp: std::time::SystemTime::now(),
|
||||
};
|
||||
|
||||
// Route through global message bus
|
||||
let bus = get_global_message_bus();
|
||||
|
||||
// Check if target is local
|
||||
if bus.has_node(to) {
|
||||
// Local routing - direct through bus
|
||||
match bus.route(message) {
|
||||
Ok(_) => {
|
||||
self.messages_sent.fetch_add(1, Ordering::Relaxed);
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
self.errors.fetch_add(1, Ordering::Relaxed);
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Target not found locally
|
||||
self.errors.fetch_add(1, Ordering::Relaxed);
|
||||
Err(format!("Target node '{}' not found in process", to))
|
||||
}
|
||||
}
|
||||
|
||||
fn transport_type(&self) -> &'static str {
|
||||
"inprocess"
|
||||
}
|
||||
|
||||
fn is_ready(&self) -> bool {
|
||||
self.initialized.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
fn shutdown(&mut self) -> Result<(), String> {
|
||||
if !self.initialized.load(Ordering::Relaxed) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Unregister from global message bus
|
||||
let bus = get_global_message_bus();
|
||||
bus.unregister_node(&self.node_id);
|
||||
|
||||
self.initialized.store(false, Ordering::Relaxed);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_stats(&self) -> TransportStats {
|
||||
TransportStats {
|
||||
transport_type: self.transport_type().to_string(),
|
||||
messages_sent: self.messages_sent.load(Ordering::Relaxed),
|
||||
messages_received: self.messages_received.load(Ordering::Relaxed),
|
||||
errors: self.errors.load(Ordering::Relaxed),
|
||||
is_ready: self.is_ready(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
/**
|
||||
* Transport implementations module
|
||||
*
|
||||
* Contains various transport implementations:
|
||||
* - InProcessTransport: For local communication within same process
|
||||
* - Future: WebSocketTransport, WebRTCTransport, etc.
|
||||
*/
|
||||
|
||||
pub mod in_process_transport;
|
||||
|
||||
pub use in_process_transport::InProcessTransport;
|
||||
@ -1,119 +0,0 @@
|
||||
/**
|
||||
* NewP2PBox天才アルゴリズムテスト
|
||||
*
|
||||
* 1. ローカル配送テスト(Bus経由)
|
||||
* 2. リモート配送テスト(Transport経由)
|
||||
* 3. イベント購読テスト
|
||||
*
|
||||
* MethodBox統合前の基本動作確認
|
||||
*/
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
// Nyashモジュールをインポート
|
||||
use nyash_rust::boxes::{NewP2PBox, MessageIntentBox, StringBox};
|
||||
use nyash_rust::transport_trait::TransportKind;
|
||||
use nyash_rust::message_bus::get_global_message_bus;
|
||||
|
||||
fn main() {
|
||||
println!("🚀 NewP2PBox天才アルゴリズムテスト開始");
|
||||
|
||||
// テスト1: 基本的なP2PBox作成
|
||||
test_basic_creation();
|
||||
|
||||
// テスト2: ローカル配送(Bus経由)
|
||||
test_local_delivery();
|
||||
|
||||
// テスト3: イベント購読とコールバック
|
||||
test_event_subscription();
|
||||
|
||||
println!("✅ 全テスト完了!");
|
||||
}
|
||||
|
||||
fn test_basic_creation() {
|
||||
println!("\n=== テスト1: 基本的なP2PBox作成 ===");
|
||||
|
||||
let alice = NewP2PBox::new("alice", TransportKind::InProcess);
|
||||
let bob = NewP2PBox::new("bob", TransportKind::InProcess);
|
||||
|
||||
println!("✅ Alice作成: {}", alice.get_node_id());
|
||||
println!("✅ Bob作成: {}", bob.get_node_id());
|
||||
|
||||
assert_eq!(alice.get_node_id(), "alice");
|
||||
assert_eq!(bob.get_node_id(), "bob");
|
||||
}
|
||||
|
||||
fn test_local_delivery() {
|
||||
println!("\n=== テスト2: ローカル配送テスト ===");
|
||||
|
||||
let alice = NewP2PBox::new("alice_local", TransportKind::InProcess);
|
||||
let bob = NewP2PBox::new("bob_local", TransportKind::InProcess);
|
||||
|
||||
// メッセージ作成
|
||||
let mut message = MessageIntentBox::new("greeting");
|
||||
message.set("text", Box::new(StringBox::new("Hello Bob!")));
|
||||
message.set("from_user", Box::new(StringBox::new("Alice")));
|
||||
|
||||
println!("📨 Aliceからメッセージ送信中...");
|
||||
|
||||
// Busが両ノードを認識しているかチェック
|
||||
let bus = get_global_message_bus();
|
||||
println!("🚌 Alice認識: {}", bus.has_node("alice_local"));
|
||||
println!("🚌 Bob認識: {}", bus.has_node("bob_local"));
|
||||
|
||||
// ローカル配送テスト
|
||||
match alice.send("bob_local", &message) {
|
||||
Ok(()) => println!("✅ ローカル配送成功!"),
|
||||
Err(e) => println!("❌ ローカル配送エラー: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
fn test_event_subscription() {
|
||||
println!("\n=== テスト3: イベント購読テスト ===");
|
||||
|
||||
let alice = NewP2PBox::new("alice_events", TransportKind::InProcess);
|
||||
let bob = NewP2PBox::new("bob_events", TransportKind::InProcess);
|
||||
|
||||
// 受信メッセージカウンター
|
||||
let message_count = Arc::new(Mutex::new(0));
|
||||
let count_clone = Arc::clone(&message_count);
|
||||
|
||||
// Bobにイベントリスナー登録
|
||||
bob.on("test_message", Box::new(move |intent_box: &MessageIntentBox| {
|
||||
let mut count = count_clone.lock().unwrap();
|
||||
*count += 1;
|
||||
println!("🎧 Bob received message #{}: intent={}", *count, intent_box.intent);
|
||||
|
||||
// メッセージ内容確認
|
||||
if let Some(text_box) = intent_box.get("text") {
|
||||
if let Some(text) = text_box.as_any().downcast_ref::<StringBox>() {
|
||||
println!(" 📝 Content: {}", text.value);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
println!("✅ Bobにイベントリスナー登録完了");
|
||||
|
||||
// Aliceからメッセージ送信
|
||||
let mut test_message = MessageIntentBox::new("test_message");
|
||||
test_message.set("text", Box::new(StringBox::new("Test message from Alice!")));
|
||||
|
||||
println!("📤 Aliceからテストメッセージ送信...");
|
||||
match alice.send("bob_events", &test_message) {
|
||||
Ok(()) => println!("✅ メッセージ送信成功"),
|
||||
Err(e) => println!("❌ メッセージ送信エラー: {}", e),
|
||||
}
|
||||
|
||||
// 少し待ってからカウンターチェック
|
||||
thread::sleep(Duration::from_millis(100));
|
||||
let final_count = *message_count.lock().unwrap();
|
||||
println!("📊 最終受信メッセージ数: {}", final_count);
|
||||
|
||||
if final_count > 0 {
|
||||
println!("✅ イベント購読システム動作確認完了!");
|
||||
} else {
|
||||
println!("⚠️ メッセージが受信されませんでした(非同期処理の可能性)");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user