//! ArrayBox 📦 - 配列・リスト操作 // Nyashの箱システムによる配列・リスト操作を提供します。 // Arcパターンで内部可変性を実現 use crate::box_trait::{NyashBox, StringBox, BoolBox, IntegerBox, BoxCore, BoxBase}; use std::any::Any; use std::sync::{Arc, Mutex}; use std::fmt::Display; #[derive(Debug, Clone)] pub struct ArrayBox { pub items: Arc>>>, base: BoxBase, } impl ArrayBox { /// 新しいArrayBoxを作成 pub fn new() -> Self { ArrayBox { items: Arc::new(Mutex::new(Vec::new())), base: BoxBase::new(), } } /// 要素を持つArrayBoxを作成 pub fn new_with_elements(elements: Vec>) -> Self { ArrayBox { items: Arc::new(Mutex::new(elements)), base: BoxBase::new(), } } /// 要素を追加 pub fn push(&self, item: Box) -> Box { self.items.lock().unwrap().push(item); Box::new(StringBox::new("ok")) } /// 最後の要素を取り出す pub fn pop(&self) -> Box { match self.items.lock().unwrap().pop() { Some(item) => item, None => Box::new(crate::boxes::null_box::NullBox::new()), } } /// 要素数を取得 pub fn length(&self) -> Box { Box::new(IntegerBox::new(self.items.lock().unwrap().len() as i64)) } /// インデックスで要素を取得 pub fn get(&self, index: Box) -> Box { if let Some(idx_box) = index.as_any().downcast_ref::() { 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(crate::boxes::null_box::NullBox::new()), } } else { Box::new(StringBox::new("Error: get() requires integer index")) } } /// インデックスで要素を設定 pub fn set(&self, index: Box, value: Box) -> Box { if let Some(idx_box) = index.as_any().downcast_ref::() { 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) -> Box { if let Some(idx_box) = index.as_any().downcast_ref::() { let idx = idx_box.value as usize; let mut items = self.items.lock().unwrap(); if idx < items.len() { items.remove(idx) } else { Box::new(crate::boxes::null_box::NullBox::new()) } } else { Box::new(StringBox::new("Error: remove() requires integer index")) } } /// 指定された値のインデックスを検索 pub fn indexOf(&self, value: Box) -> Box { let items = self.items.lock().unwrap(); for (i, item) in items.iter().enumerate() { if item.equals(value.as_ref()).value { return Box::new(IntegerBox::new(i as i64)); } } Box::new(IntegerBox::new(-1)) } /// 指定された値が含まれているか確認 pub fn contains(&self, value: Box) -> Box { let items = self.items.lock().unwrap(); for item in items.iter() { if item.equals(value.as_ref()).value { return Box::new(BoolBox::new(true)); } } Box::new(BoolBox::new(false)) } /// 配列を空にする pub fn clear(&self) -> Box { self.items.lock().unwrap().clear(); Box::new(StringBox::new("ok")) } /// 文字列結合 pub fn join(&self, delimiter: Box) -> Box { if let Some(sep_box) = delimiter.as_any().downcast_ref::() { let items = self.items.lock().unwrap(); let parts: Vec = 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")) } } /// 配列をソート(昇順) pub fn sort(&self) -> Box { let mut items = self.items.lock().unwrap(); // Numeric values first, then string values items.sort_by(|a, b| { use std::cmp::Ordering; // Try to compare as numbers first if let (Some(a_int), Some(b_int)) = ( a.as_any().downcast_ref::(), b.as_any().downcast_ref::() ) { return a_int.value.cmp(&b_int.value); } // Try FloatBox comparison if let (Some(a_float), Some(b_float)) = ( a.as_any().downcast_ref::(), b.as_any().downcast_ref::() ) { return a_float.value.partial_cmp(&b_float.value).unwrap_or(Ordering::Equal); } // Mixed numeric types if let (Some(a_int), Some(b_float)) = ( a.as_any().downcast_ref::(), b.as_any().downcast_ref::() ) { return (a_int.value as f64).partial_cmp(&b_float.value).unwrap_or(Ordering::Equal); } if let (Some(a_float), Some(b_int)) = ( a.as_any().downcast_ref::(), b.as_any().downcast_ref::() ) { return a_float.value.partial_cmp(&(b_int.value as f64)).unwrap_or(Ordering::Equal); } // Fall back to string comparison let a_str = a.to_string_box().value; let b_str = b.to_string_box().value; a_str.cmp(&b_str) }); Box::new(StringBox::new("ok")) } /// 配列を反転 pub fn reverse(&self) -> Box { let mut items = self.items.lock().unwrap(); items.reverse(); Box::new(StringBox::new("ok")) } /// 部分配列を取得 pub fn slice(&self, start: Box, end: Box) -> Box { let items = self.items.lock().unwrap(); // Extract start and end indices let start_idx = if let Some(start_int) = start.as_any().downcast_ref::() { if start_int.value < 0 { 0 } else { start_int.value as usize } } else { return Box::new(StringBox::new("Error: slice() start index must be an integer")); }; let end_idx = if let Some(end_int) = end.as_any().downcast_ref::() { if end_int.value < 0 { items.len() } else { (end_int.value as usize).min(items.len()) } } else { return Box::new(StringBox::new("Error: slice() end index must be an integer")); }; // Validate indices if start_idx > items.len() || start_idx > end_idx { return Box::new(ArrayBox::new()); } // Create slice let slice_items: Vec> = items[start_idx..end_idx] .iter() .map(|item| item.clone_box()) .collect(); Box::new(ArrayBox::new_with_elements(slice_items)) } } impl BoxCore for ArrayBox { fn box_id(&self) -> u64 { self.base.id } fn parent_type_id(&self) -> Option { self.base.parent_type_id } fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let items = self.items.lock().unwrap(); let strings: Vec = items.iter() .map(|item| item.to_string_box().value) .collect(); write!(f, "[{}]", strings.join(", ")) } fn as_any(&self) -> &dyn Any { self } fn as_any_mut(&mut self) -> &mut dyn Any { self } } impl Display for ArrayBox { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.fmt_box(f) } } impl NyashBox for ArrayBox { fn clone_box(&self) -> Box { Box::new(self.clone()) } fn to_string_box(&self) -> StringBox { let items = self.items.lock().unwrap(); let strings: Vec = items.iter() .map(|item| item.to_string_box().value) .collect(); StringBox::new(format!("[{}]", strings.join(", "))) } fn type_name(&self) -> &'static str { "ArrayBox" } fn equals(&self, other: &dyn NyashBox) -> BoolBox { if let Some(other_array) = other.as_any().downcast_ref::() { 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.as_ref()).value { return BoolBox::new(false); } } BoolBox::new(true) } else { BoolBox::new(false) } } }