feat: ArrayBox完全実装 - Nyash初の動的配列コレクション!

## 🎯 実装内容
- ArrayBoxにNyashBoxトレイト完全実装
- Arc<Mutex>による内部可変性実現(MapBoxと同じパターン)
- 全メソッド実装: push/pop/get/set/length/indexOf/contains/join/clear/remove
- 包括的なテストスイート作成

## 🔧 技術的改善
- GitHub Copilot作成の基本構造をNyash対応に拡張
- execute_array_methodを&self参照に修正
- collection_methods.rsとの統合完了

##  テスト結果
- 全機能正常動作確認
- 異なる型の要素混在可能(Everything is Box哲学)
- インデックス範囲外アクセスでNullBox返却

## 📝 残課題
- BufferBox, ResultBox, FileBox等は基本構造のみ(未実装)
- RegexBoxはNyashBoxトレイト実装済みだがregex依存関係未追加

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Moe Charm
2025-08-10 12:24:59 +09:00
parent 85a8c7f2d7
commit cbee14809d
8 changed files with 408 additions and 56 deletions

View File

@ -1,34 +1,270 @@
//! ArrayBox 📦 - 配列・リスト操作(両者一致!)
// Nyashの箱システムによる配列・リスト操作を提供します。
// 参考: 既存Boxの設計思想
/*! 📦 ArrayBox - 配列・リスト操作Box
*
* ## 📝 概要
* 順序付きコレクションを扱うためのBox。
* JavaScript風の配列操作APIで直感的なデータ管理が可能。
*
* ## 🛠️ 利用可能メソッド
* - `push(item)` - 要素を末尾に追加
* - `pop()` - 末尾の要素を削除して返す
* - `get(index)` - 指定インデックスの要素を取得
* - `set(index, value)` - 指定インデックスに要素を設定
* - `length()` - 配列の長さを取得
* - `remove(index)` - 指定インデックスの要素を削除
* - `indexOf(item)` - 要素のインデックスを検索
* - `contains(item)` - 要素が含まれているか確認
* - `clear()` - すべての要素を削除
* - `join(separator)` - 文字列として結合
*
* ## 💡 使用例
* ```nyash
* local arr, item
* arr = new ArrayBox()
*
* // 要素の追加
* arr.push("Apple")
* arr.push("Banana")
* arr.push("Cherry")
*
* // 要素へのアクセス
* print(arr.get(0)) // "Apple"
* print(arr.length()) // 3
*
* // 要素の削除
* item = arr.pop() // "Cherry"
* arr.remove(0) // "Apple"削除
*
* // 文字列結合
* print(arr.join(", ")) // "Banana"
* ```
*
* ## 🎮 実用例 - TodoList
* ```nyash
* static box TodoList {
* init { items, console }
*
* main() {
* me.items = new ArrayBox()
* me.console = new ConsoleBox()
*
* me.addTask("Nyash開発")
* me.addTask("ドキュメント作成")
* me.addTask("テスト実行")
*
* me.showTasks()
* }
*
* addTask(task) {
* me.items.push(task)
* me.console.log("✅ タスク追加: " + task)
* }
*
* showTasks() {
* me.console.log("=== Todo List ===")
* local i
* i = 0
* loop(i < me.items.length()) {
* me.console.log((i + 1) + ". " + me.items.get(i))
* i = i + 1
* }
* }
* }
* ```
*
* ## ⚠️ 注意
* - インデックスは0から開始
* - 範囲外のインデックスアクセスはNullBoxを返す
* - 異なる型の要素を混在可能Everything is Box
*/
use crate::box_trait::{NyashBox, StringBox, IntegerBox, BoolBox};
use crate::boxes::null_box::NullBox;
use std::any::Any;
use std::fmt::{Debug, Display};
use std::sync::{Arc, Mutex};
#[derive(Debug, Clone)]
pub struct ArrayBox {
pub items: Vec<Box<dyn std::any::Any>>,
items: Arc<Mutex<Vec<Box<dyn NyashBox>>>>,
id: u64,
}
impl ArrayBox {
/// 新しいArrayBoxを作成
pub fn new() -> Self {
ArrayBox { items: Vec::new() }
static mut COUNTER: u64 = 0;
let id = unsafe {
COUNTER += 1;
COUNTER
};
ArrayBox {
items: Arc::new(Mutex::new(Vec::new())),
id,
}
}
/// 要素を追加
pub fn push(&mut self, item: Box<dyn std::any::Any>) {
self.items.push(item);
/// 要素を末尾に追加
pub fn push(&self, item: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
self.items.lock().unwrap().push(item);
Box::new(StringBox::new("ok"))
}
/// 末尾の要素を削除して返す
pub fn pop(&self) -> Box<dyn NyashBox> {
match self.items.lock().unwrap().pop() {
Some(item) => item,
None => Box::new(NullBox::new()),
}
}
/// 要素数を取得
pub fn len(&self) -> usize {
self.items.len()
pub fn length(&self) -> Box<dyn NyashBox> {
Box::new(IntegerBox::new(self.items.lock().unwrap().len() as i64))
}
/// 要素を取得
pub fn get(&self, index: usize) -> Option<&Box<dyn std::any::Any>> {
self.items.get(index)
}
/// 要素を削除
pub fn remove(&mut self, index: usize) -> Option<Box<dyn std::any::Any>> {
if index < self.items.len() {
Some(self.items.remove(index))
/// 指定インデックスの要素を取得
pub fn get(&self, index: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
if let Some(idx_box) = index.as_any().downcast_ref::<IntegerBox>() {
let idx = idx_box.value as usize;
let items = self.items.lock().unwrap();
match items.get(idx) {
Some(item) => item.clone_box(),
None => Box::new(NullBox::new()),
}
} else {
None
Box::new(StringBox::new("Error: get() requires integer index"))
}
}
/// 指定インデックスに要素を設定
pub fn set(&self, index: Box<dyn NyashBox>, value: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
if let Some(idx_box) = index.as_any().downcast_ref::<IntegerBox>() {
let idx = idx_box.value as usize;
let mut items = self.items.lock().unwrap();
if idx < items.len() {
items[idx] = value;
Box::new(StringBox::new("ok"))
} else {
Box::new(StringBox::new("Error: index out of bounds"))
}
} else {
Box::new(StringBox::new("Error: set() requires integer index"))
}
}
/// 指定インデックスの要素を削除
pub fn remove(&self, index: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
if let Some(idx_box) = index.as_any().downcast_ref::<IntegerBox>() {
let idx = idx_box.value as usize;
let mut items = self.items.lock().unwrap();
if idx < items.len() {
items.remove(idx)
} else {
Box::new(NullBox::new())
}
} else {
Box::new(StringBox::new("Error: remove() requires integer index"))
}
}
/// 要素のインデックスを検索
pub fn indexOf(&self, item: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
let items = self.items.lock().unwrap();
for (i, element) in items.iter().enumerate() {
if element.equals(item.as_ref()).value {
return Box::new(IntegerBox::new(i as i64));
}
}
Box::new(IntegerBox::new(-1))
}
/// 要素が含まれているか確認
pub fn contains(&self, item: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
let items = self.items.lock().unwrap();
for element in items.iter() {
if element.equals(item.as_ref()).value {
return Box::new(BoolBox::new(true));
}
}
Box::new(BoolBox::new(false))
}
/// すべての要素を削除
pub fn clear(&self) -> Box<dyn NyashBox> {
self.items.lock().unwrap().clear();
Box::new(StringBox::new("ok"))
}
/// 文字列として結合
pub fn join(&self, separator: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
if let Some(sep_box) = separator.as_any().downcast_ref::<StringBox>() {
let items = self.items.lock().unwrap();
let parts: Vec<String> = items
.iter()
.map(|item| item.to_string_box().value)
.collect();
Box::new(StringBox::new(parts.join(&sep_box.value)))
} else {
Box::new(StringBox::new("Error: join() requires string separator"))
}
}
}
impl NyashBox for ArrayBox {
fn type_name(&self) -> &'static str {
"ArrayBox"
}
fn to_string_box(&self) -> StringBox {
let items = self.items.lock().unwrap();
let elements: Vec<String> = items
.iter()
.map(|item| item.to_string_box().value)
.collect();
StringBox::new(format!("[{}]", elements.join(", ")))
}
fn clone_box(&self) -> Box<dyn NyashBox> {
Box::new(self.clone())
}
fn equals(&self, other: &dyn NyashBox) -> BoolBox {
if let Some(other_array) = other.as_any().downcast_ref::<ArrayBox>() {
let self_items = self.items.lock().unwrap();
let other_items = other_array.items.lock().unwrap();
if self_items.len() != other_items.len() {
return BoolBox::new(false);
}
for (a, b) in self_items.iter().zip(other_items.iter()) {
if !a.equals(&**b).value {
return BoolBox::new(false);
}
}
BoolBox::new(true)
} else {
BoolBox::new(false)
}
}
fn as_any(&self) -> &dyn Any {
self
}
fn box_id(&self) -> u64 {
self.id
}
}
impl Display for ArrayBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let items = self.items.lock().unwrap();
let elements: Vec<String> = items
.iter()
.map(|item| item.to_string_box().value)
.collect();
write!(f, "[{}]", elements.join(", "))
}
}

View File

@ -103,7 +103,8 @@
* - 存在しないキーの取得は "Key not found" メッセージ返却
*/
use crate::box_trait::{NyashBox, StringBox, IntegerBox, BoolBox, ArrayBox};
use crate::box_trait::{NyashBox, StringBox, IntegerBox, BoolBox};
use crate::boxes::array::ArrayBox;
use std::fmt::{Debug, Display};
use std::any::Any;
use std::collections::HashMap;

View File

@ -99,9 +99,9 @@ pub mod null_box;
// pub mod intent_box_wrapper;
// pub mod p2p_box;
// 今後追加予定のBox型コメントアウト
// pub mod array_box;
// pub use array_box::ArrayBox;
// 配列・リスト操作Box
pub mod array;
pub use array::ArrayBox;
// null関数も再エクスポート
pub use null_box::{NullBox, null};