Files
hakorune/src/box_trait.rs.backup

1455 lines
41 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*!
* Nyash Box Trait System - Everything is Box in Rust
*
* This module implements the core "Everything is Box" philosophy using Rust's
* ownership system and trait system. Every value in Nyash is a Box that
* implements the NyashBox trait.
*/
use std::fmt::{Debug, Display};
use std::any::Any;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicU64, Ordering};
use std::fs;
use std::path::Path;
// 🔥 新しい型エイリアス - 将来的にBox<dyn NyashBox>を全て置き換える
pub type SharedNyashBox = Arc<dyn NyashBox>;
/// 🔥 BoxBase + BoxCore革命 - 統一ID生成システム
/// CharmFlow教訓を活かした互換性保証の基盤
pub fn next_box_id() -> u64 {
static COUNTER: AtomicU64 = AtomicU64::new(1);
COUNTER.fetch_add(1, Ordering::Relaxed)
}
/// 🏗️ BoxBase - 全てのBox型の共通基盤構造体
/// Phase 2: 統一的な基盤データを提供
/// 🔥 Phase 1: ビルトインBox継承システム - 最小限拡張
#[derive(Debug, Clone, PartialEq)]
pub struct BoxBase {
pub id: u64,
pub parent_type_id: Option<std::any::TypeId>, // ビルトインBox継承用
}
impl BoxBase {
/// 新しいBoxBase作成 - 安全なID生成
pub fn new() -> Self {
Self {
id: next_box_id(),
parent_type_id: None, // ビルトインBox: 継承なし
}
}
/// ビルトインBox継承用コンストラクタ
pub fn with_parent_type(parent_type_id: std::any::TypeId) -> Self {
Self {
id: next_box_id(),
parent_type_id: Some(parent_type_id),
}
}
}
/// 🎯 BoxCore - Box型共通メソッドの統一インターフェース
/// Phase 2: 重複コードを削減する中核トレイト
/// 🔥 Phase 2: ビルトインBox継承システム対応
pub trait BoxCore: Send + Sync {
/// ボックスの一意ID取得
fn box_id(&self) -> u64;
/// 継承元の型ID取得ビルトインBox継承用
fn parent_type_id(&self) -> Option<std::any::TypeId>;
/// Display実装のための統一フォーマット
fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result;
/// Any変換ダウンキャスト用
fn as_any(&self) -> &dyn Any;
/// Anyミュータブル変換ダウンキャスト用
fn as_any_mut(&mut self) -> &mut dyn Any;
}
/// The fundamental trait that all Nyash values must implement.
/// This embodies the "Everything is Box" philosophy with Rust's type safety.
pub trait NyashBox: BoxCore + Debug {
/// Convert this box to a string representation (equivalent to Python's toString())
fn to_string_box(&self) -> StringBox;
/// Check equality with another box (equivalent to Python's equals())
fn equals(&self, other: &dyn NyashBox) -> BoolBox;
/// Get the type name of this box for debugging
fn type_name(&self) -> &'static str {
std::any::type_name::<Self>()
}
/// Clone this box (equivalent to Python's copy())
fn clone_box(&self) -> Box<dyn NyashBox>;
/// Arc参照を返す新しいcloneメソッド参照共有
fn clone_arc(&self) -> SharedNyashBox {
Arc::from(self.clone_box())
}
// 🌟 TypeBox革命: Get type information as a Box
// Everything is Box極限実現 - 型情報もBoxとして取得
// TODO: 次のステップで完全実装
// fn get_type_box(&self) -> std::sync::Arc<crate::type_box::TypeBox>;
}
// ===== Basic Box Types =====
/// String values in Nyash - immutable and owned
#[derive(Debug, Clone, PartialEq)]
pub struct StringBox {
pub value: String,
base: BoxBase,
}
impl StringBox {
pub fn new(value: impl Into<String>) -> Self {
Self {
value: value.into(),
base: BoxBase::new(),
}
}
pub fn empty() -> Self {
Self::new("")
}
// ===== String Methods for Nyash =====
/// Split string by delimiter and return ArrayBox
pub fn split(&self, delimiter: &str) -> Box<dyn NyashBox> {
let parts: Vec<String> = self.value.split(delimiter).map(|s| s.to_string()).collect();
let array_elements: Vec<Box<dyn NyashBox>> = parts.into_iter()
.map(|s| Box::new(StringBox::new(s)) as Box<dyn NyashBox>)
.collect();
Box::new(ArrayBox::new_with_elements(array_elements))
}
/// Find substring and return position (or -1 if not found)
pub fn find(&self, search: &str) -> Box<dyn NyashBox> {
match self.value.find(search) {
Some(pos) => Box::new(IntegerBox::new(pos as i64)),
None => Box::new(IntegerBox::new(-1)),
}
}
/// Replace all occurrences of old with new
pub fn replace(&self, old: &str, new: &str) -> Box<dyn NyashBox> {
Box::new(StringBox::new(self.value.replace(old, new)))
}
/// Trim whitespace from both ends
pub fn trim(&self) -> Box<dyn NyashBox> {
Box::new(StringBox::new(self.value.trim()))
}
/// Convert to uppercase
pub fn to_upper(&self) -> Box<dyn NyashBox> {
Box::new(StringBox::new(self.value.to_uppercase()))
}
/// Convert to lowercase
pub fn to_lower(&self) -> Box<dyn NyashBox> {
Box::new(StringBox::new(self.value.to_lowercase()))
}
/// Check if string contains substring
pub fn contains(&self, search: &str) -> Box<dyn NyashBox> {
Box::new(BoolBox::new(self.value.contains(search)))
}
/// Check if string starts with prefix
pub fn starts_with(&self, prefix: &str) -> Box<dyn NyashBox> {
Box::new(BoolBox::new(self.value.starts_with(prefix)))
}
/// Check if string ends with suffix
pub fn ends_with(&self, suffix: &str) -> Box<dyn NyashBox> {
Box::new(BoolBox::new(self.value.ends_with(suffix)))
}
/// Join array elements using this string as delimiter
pub fn join(&self, array_box: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
if let Some(array) = array_box.as_any().downcast_ref::<ArrayBox>() {
let strings: Vec<String> = array.items.lock().unwrap()
.iter()
.map(|element| element.to_string_box().value)
.collect();
Box::new(StringBox::new(strings.join(&self.value)))
} else {
// If not an ArrayBox, treat as single element
Box::new(StringBox::new(array_box.to_string_box().value))
}
}
/// Get string length
pub fn length(&self) -> Box<dyn NyashBox> {
Box::new(IntegerBox::new(self.value.len() as i64))
}
/// Get character at index
pub fn get(&self, index: usize) -> Option<Box<dyn NyashBox>> {
if let Some(ch) = self.value.chars().nth(index) {
Some(Box::new(StringBox::new(ch.to_string())))
} else {
None
}
}
}
impl BoxCore for StringBox {
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, "{}", self.value)
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl NyashBox for StringBox {
fn to_string_box(&self) -> StringBox {
self.clone()
}
fn equals(&self, other: &dyn NyashBox) -> BoolBox {
if let Some(other_string) = other.as_any().downcast_ref::<StringBox>() {
BoolBox::new(self.value == other_string.value)
} else {
BoolBox::new(false)
}
}
fn type_name(&self) -> &'static str {
"StringBox"
}
fn clone_box(&self) -> Box<dyn NyashBox> {
Box::new(self.clone())
}
}
impl Display for StringBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_box(f)
}
}
/// Integer values in Nyash - 64-bit signed integers
#[derive(Debug, Clone, PartialEq)]
pub struct IntegerBox {
pub value: i64,
base: BoxBase,
}
impl IntegerBox {
pub fn new(value: i64) -> Self {
Self {
value,
base: BoxBase::new()
}
}
pub fn zero() -> Self {
Self::new(0)
}
}
impl BoxCore for IntegerBox {
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, "{}", self.value)
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl NyashBox for IntegerBox {
fn to_string_box(&self) -> StringBox {
StringBox::new(self.value.to_string())
}
fn equals(&self, other: &dyn NyashBox) -> BoolBox {
if let Some(other_int) = other.as_any().downcast_ref::<IntegerBox>() {
BoolBox::new(self.value == other_int.value)
} else {
BoolBox::new(false)
}
}
fn type_name(&self) -> &'static str {
"IntegerBox"
}
fn clone_box(&self) -> Box<dyn NyashBox> {
Box::new(self.clone())
}
}
impl Display for IntegerBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_box(f)
}
}
/// Boolean values in Nyash - true/false
#[derive(Debug, Clone, PartialEq)]
pub struct BoolBox {
pub value: bool,
base: BoxBase,
}
impl BoolBox {
pub fn new(value: bool) -> Self {
Self {
value,
base: BoxBase::new()
}
}
pub fn true_box() -> Self {
Self::new(true)
}
pub fn false_box() -> Self {
Self::new(false)
}
}
impl BoxCore for BoolBox {
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, "{}", if self.value { "true" } else { "false" })
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl NyashBox for BoolBox {
fn to_string_box(&self) -> StringBox {
StringBox::new(if self.value { "true" } else { "false" })
}
fn equals(&self, other: &dyn NyashBox) -> BoolBox {
if let Some(other_bool) = other.as_any().downcast_ref::<BoolBox>() {
BoolBox::new(self.value == other_bool.value)
} else {
BoolBox::new(false)
}
}
fn type_name(&self) -> &'static str {
"BoolBox"
}
fn clone_box(&self) -> Box<dyn NyashBox> {
Box::new(self.clone())
}
}
impl Display for BoolBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_box(f)
}
}
/// Void/null values in Nyash - represents empty or null results
#[derive(Debug, Clone, PartialEq)]
pub struct VoidBox {
base: BoxBase,
}
impl VoidBox {
pub fn new() -> Self {
Self {
base: BoxBase::new()
}
}
}
impl Default for VoidBox {
fn default() -> Self {
Self::new()
}
}
impl BoxCore for VoidBox {
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, "void")
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl NyashBox for VoidBox {
fn to_string_box(&self) -> StringBox {
StringBox::new("void")
}
fn equals(&self, other: &dyn NyashBox) -> BoolBox {
BoolBox::new(other.as_any().is::<VoidBox>())
}
fn type_name(&self) -> &'static str {
"VoidBox"
}
fn clone_box(&self) -> Box<dyn NyashBox> {
Box::new(self.clone())
}
}
impl Display for VoidBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_box(f)
}
}
// ArrayBox is now defined in boxes::array module
pub use crate::boxes::array::ArrayBox;
/// File values in Nyash - file system operations
#[derive(Debug, Clone)]
pub struct FileBox {
pub path: String,
base: BoxBase,
}
impl FileBox {
pub fn new(path: impl Into<String>) -> Self {
Self {
path: path.into(),
base: BoxBase::new(),
}
}
// ===== File Methods for Nyash =====
/// Read file contents as string
pub fn read(&self) -> Box<dyn NyashBox> {
match fs::read_to_string(&self.path) {
Ok(content) => Box::new(StringBox::new(content)),
Err(_) => Box::new(VoidBox::new()), // Return void on error for now
}
}
/// Write content to file
pub fn write(&self, content: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
let content_str = content.to_string_box().value;
match fs::write(&self.path, content_str) {
Ok(_) => Box::new(BoolBox::new(true)),
Err(_) => Box::new(BoolBox::new(false)),
}
}
/// Check if file exists
pub fn exists(&self) -> Box<dyn NyashBox> {
Box::new(BoolBox::new(Path::new(&self.path).exists()))
}
/// Delete file
pub fn delete(&self) -> Box<dyn NyashBox> {
match fs::remove_file(&self.path) {
Ok(_) => Box::new(BoolBox::new(true)),
Err(_) => Box::new(BoolBox::new(false)),
}
}
/// Copy file to destination
pub fn copy(&self, dest_path: &str) -> Box<dyn NyashBox> {
match fs::copy(&self.path, dest_path) {
Ok(_) => Box::new(BoolBox::new(true)),
Err(_) => Box::new(BoolBox::new(false)),
}
}
}
impl BoxCore for FileBox {
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, "<FileBox: {}>", self.path)
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl NyashBox for FileBox {
fn to_string_box(&self) -> StringBox {
StringBox::new(format!("<FileBox: {}>", self.path))
}
fn equals(&self, other: &dyn NyashBox) -> BoolBox {
if let Some(other_file) = other.as_any().downcast_ref::<FileBox>() {
BoolBox::new(self.path == other_file.path)
} else {
BoolBox::new(false)
}
}
fn type_name(&self) -> &'static str {
"FileBox"
}
fn clone_box(&self) -> Box<dyn NyashBox> {
Box::new(self.clone())
}
}
impl Display for FileBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_box(f)
}
}
/// Error values in Nyash - represents error information
#[derive(Debug, Clone)]
pub struct ErrorBox {
pub error_type: String,
pub message: String,
base: BoxBase,
}
impl ErrorBox {
pub fn new(error_type: impl Into<String>, message: impl Into<String>) -> Self {
Self {
error_type: error_type.into(),
message: message.into(),
base: BoxBase::new(),
}
}
}
impl BoxCore for ErrorBox {
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, "{}: {}", self.error_type, self.message)
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl NyashBox for ErrorBox {
fn to_string_box(&self) -> StringBox {
StringBox::new(format!("{}: {}", self.error_type, self.message))
}
fn equals(&self, other: &dyn NyashBox) -> BoolBox {
if let Some(other_error) = other.as_any().downcast_ref::<ErrorBox>() {
BoolBox::new(self.error_type == other_error.error_type && self.message == other_error.message)
} else {
BoolBox::new(false)
}
}
fn type_name(&self) -> &'static str {
"ErrorBox"
}
fn clone_box(&self) -> Box<dyn NyashBox> {
Box::new(self.clone())
}
}
impl Display for ErrorBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_box(f)
}
}
/// Result values in Nyash - represents success or error results
#[derive(Debug)]
pub struct ResultBox {
pub is_success: bool,
pub value: Option<Box<dyn NyashBox>>,
pub error: Option<ErrorBox>,
base: BoxBase,
}
impl ResultBox {
pub fn new_success(value: Box<dyn NyashBox>) -> Self {
Self {
is_success: true,
value: Some(value),
error: None,
base: BoxBase::new(),
}
}
pub fn new_error(error: ErrorBox) -> Self {
Self {
is_success: false,
value: None,
error: Some(error),
base: BoxBase::new(),
}
}
// ===== Result Methods for Nyash =====
/// Check if result is successful
pub fn is_ok(&self) -> Box<dyn NyashBox> {
Box::new(BoolBox::new(self.is_success))
}
/// Get success value (returns void if error)
pub fn get_value(&self) -> Box<dyn NyashBox> {
match &self.value {
Some(val) => val.clone_box(),
None => Box::new(VoidBox::new()),
}
}
/// Get error (returns void if success)
pub fn get_error(&self) -> Box<dyn NyashBox> {
match &self.error {
Some(err) => Box::new(err.clone()),
None => Box::new(VoidBox::new()),
}
}
}
impl BoxCore for ResultBox {
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, "{}", self.to_string_box().value)
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl NyashBox for ResultBox {
fn to_string_box(&self) -> StringBox {
if self.is_success {
if let Some(value) = &self.value {
StringBox::new(format!("Result(OK: {})", value.to_string_box().value))
} else {
StringBox::new("Result(OK: void)".to_string())
}
} else {
if let Some(error) = &self.error {
StringBox::new(format!("Result(Error: {})", error.to_string_box().value))
} else {
StringBox::new("Result(Error: unknown)".to_string())
}
}
}
fn equals(&self, other: &dyn NyashBox) -> BoolBox {
if let Some(other_result) = other.as_any().downcast_ref::<ResultBox>() {
if self.is_success != other_result.is_success {
return BoolBox::new(false);
}
if self.is_success {
// Compare success values
match (&self.value, &other_result.value) {
(Some(a), Some(b)) => a.equals(b.as_ref()),
(None, None) => BoolBox::new(true),
_ => BoolBox::new(false),
}
} else {
// Compare errors
match (&self.error, &other_result.error) {
(Some(a), Some(b)) => a.equals(b),
(None, None) => BoolBox::new(true),
_ => BoolBox::new(false),
}
}
} else {
BoolBox::new(false)
}
}
fn type_name(&self) -> &'static str {
"ResultBox"
}
fn clone_box(&self) -> Box<dyn NyashBox> {
if self.is_success {
if let Some(value) = &self.value {
Box::new(ResultBox::new_success(value.clone_box()))
} else {
Box::new(ResultBox::new_success(Box::new(VoidBox::new())))
}
} else {
if let Some(error) = &self.error {
Box::new(ResultBox::new_error(error.clone()))
} else {
Box::new(ResultBox::new_error(ErrorBox::new("Unknown", "Unknown error")))
}
}
}
}
impl Display for ResultBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_box(f)
}
}
/// Future values in Nyash - represents async operations
#[derive(Debug)]
pub struct FutureBox {
pub result: Arc<Mutex<Option<Box<dyn NyashBox>>>>,
pub is_ready: Arc<Mutex<bool>>,
base: BoxBase,
}
impl Clone for FutureBox {
fn clone(&self) -> Self {
Self {
result: Arc::clone(&self.result),
is_ready: Arc::clone(&self.is_ready),
base: BoxBase::new(), // 新しいIDを生成
}
}
}
impl FutureBox {
pub fn new() -> Self {
Self {
result: Arc::new(Mutex::new(None)),
is_ready: Arc::new(Mutex::new(false)),
base: BoxBase::new(),
}
}
/// Set the result of the future
pub fn set_result(&self, value: Box<dyn NyashBox>) {
let mut result = self.result.lock().unwrap();
*result = Some(value);
let mut ready = self.is_ready.lock().unwrap();
*ready = true;
}
/// Get the result (blocks until ready)
pub fn get(&self) -> Box<dyn NyashBox> {
// 簡易実装: ビジーウェイト後でcondvarに改善
loop {
let ready = self.is_ready.lock().unwrap();
if *ready {
break;
}
drop(ready);
std::thread::yield_now();
}
let result = self.result.lock().unwrap();
result.as_ref().unwrap().clone_box()
}
/// Check if the future is ready
pub fn ready(&self) -> Box<dyn NyashBox> {
Box::new(BoolBox::new(*self.is_ready.lock().unwrap()))
}
/// Wait and get the result (for await implementation)
pub fn wait_and_get(&self) -> Result<Box<dyn NyashBox>, String> {
// 結果が準備できるまで待機
while !*self.is_ready.lock().unwrap() {
std::thread::yield_now();
}
let result = self.result.lock().unwrap();
result.as_ref()
.map(|v| v.clone_box())
.ok_or_else(|| "Future has no result".to_string())
}
}
impl NyashBox for FutureBox {
fn to_string_box(&self) -> StringBox {
let ready = *self.is_ready.lock().unwrap();
if ready {
let result = self.result.lock().unwrap();
if let Some(value) = result.as_ref() {
StringBox::new(format!("Future(ready: {})", value.to_string_box().value))
} else {
StringBox::new("Future(ready: void)".to_string())
}
} else {
StringBox::new("Future(pending)".to_string())
}
}
fn equals(&self, other: &dyn NyashBox) -> BoolBox {
if let Some(other_future) = other.as_any().downcast_ref::<FutureBox>() {
BoolBox::new(self.base.id == other_future.base.id)
} else {
BoolBox::new(false)
}
}
fn type_name(&self) -> &'static str {
"FutureBox"
}
fn clone_box(&self) -> Box<dyn NyashBox> {
Box::new(self.clone())
}
}
impl BoxCore for FutureBox {
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, "{}", self.to_string_box().value)
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl Display for FutureBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_box(f)
}
// Re-export operation boxes from the dedicated operations module
pub use crate::box_operations::{AddBox, SubtractBox, MultiplyBox, DivideBox, CompareBox};
#[cfg(test)]
pub left: Box<dyn NyashBox>,
pub right: Box<dyn NyashBox>,
base: BoxBase,
}
impl AddBox {
pub fn new(left: Box<dyn NyashBox>, right: Box<dyn NyashBox>) -> Self {
Self {
left,
right,
base: BoxBase::new(),
}
}
/// Execute the addition operation and return the result
pub fn execute(&self) -> Box<dyn NyashBox> {
use crate::boxes::math_box::FloatBox;
// 1. Integer + Integer
if let (Some(left_int), Some(right_int)) = (
self.left.as_any().downcast_ref::<IntegerBox>(),
self.right.as_any().downcast_ref::<IntegerBox>()
) {
return Box::new(IntegerBox::new(left_int.value + right_int.value));
}
// 2. Float + Float
if let (Some(left_float), Some(right_float)) = (
self.left.as_any().downcast_ref::<FloatBox>(),
self.right.as_any().downcast_ref::<FloatBox>()
) {
return Box::new(FloatBox::new(left_float.value + right_float.value));
}
// 3. Integer + Float -> Float
if let (Some(left_int), Some(right_float)) = (
self.left.as_any().downcast_ref::<IntegerBox>(),
self.right.as_any().downcast_ref::<FloatBox>()
) {
return Box::new(FloatBox::new(left_int.value as f64 + right_float.value));
}
// 4. Float + Integer -> Float
if let (Some(left_float), Some(right_int)) = (
self.left.as_any().downcast_ref::<FloatBox>(),
self.right.as_any().downcast_ref::<IntegerBox>()
) {
return Box::new(FloatBox::new(left_float.value + right_int.value as f64));
}
// 5. Fall back to string concatenation
let left_str = self.left.to_string_box();
let right_str = self.right.to_string_box();
Box::new(StringBox::new(format!("{}{}", left_str.value, right_str.value)))
}
}
impl Debug for AddBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AddBox")
.field("left", &self.left.to_string_box().value)
.field("right", &self.right.to_string_box().value)
.field("id", &self.base.id)
.finish()
}
}
impl NyashBox for AddBox {
fn to_string_box(&self) -> StringBox {
let result = self.execute();
result.to_string_box()
}
fn equals(&self, other: &dyn NyashBox) -> BoolBox {
if let Some(other_add) = other.as_any().downcast_ref::<AddBox>() {
let left_eq = self.left.equals(other_add.left.as_ref());
let right_eq = self.right.equals(other_add.right.as_ref());
BoolBox::new(left_eq.value && right_eq.value)
} else {
BoolBox::new(false)
}
}
fn type_name(&self) -> &'static str {
"AddBox"
}
fn clone_box(&self) -> Box<dyn NyashBox> {
Box::new(AddBox::new(
self.left.clone_box(),
self.right.clone_box()
))
}
}
impl BoxCore for AddBox {
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, "({} + {})", self.left.to_string_box().value, self.right.to_string_box().value)
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl Display for AddBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_box(f)
}
}
// ===== 数値演算Boxの実装 =====
/// 減算を行うBox
pub struct SubtractBox {
left: Box<dyn NyashBox>,
right: Box<dyn NyashBox>,
}
impl SubtractBox {
pub fn new(left: Box<dyn NyashBox>, right: Box<dyn NyashBox>) -> Self {
Self { left, right }
}
pub fn execute(&self) -> Box<dyn NyashBox> {
use crate::boxes::math_box::FloatBox;
// 1. Integer - Integer
if let (Some(left_int), Some(right_int)) = (
self.left.as_any().downcast_ref::<IntegerBox>(),
self.right.as_any().downcast_ref::<IntegerBox>()
) {
return Box::new(IntegerBox::new(left_int.value - right_int.value));
}
// 2. Float - Float
if let (Some(left_float), Some(right_float)) = (
self.left.as_any().downcast_ref::<FloatBox>(),
self.right.as_any().downcast_ref::<FloatBox>()
) {
return Box::new(FloatBox::new(left_float.value - right_float.value));
}
// 3. Integer - Float -> Float
if let (Some(left_int), Some(right_float)) = (
self.left.as_any().downcast_ref::<IntegerBox>(),
self.right.as_any().downcast_ref::<FloatBox>()
) {
return Box::new(FloatBox::new(left_int.value as f64 - right_float.value));
}
// 4. Float - Integer -> Float
if let (Some(left_float), Some(right_int)) = (
self.left.as_any().downcast_ref::<FloatBox>(),
self.right.as_any().downcast_ref::<IntegerBox>()
) {
return Box::new(FloatBox::new(left_float.value - right_int.value as f64));
}
// エラーの場合はvoid返す
Box::new(VoidBox::new())
}
}
/// 乗算を行うBox
pub struct MultiplyBox {
left: Box<dyn NyashBox>,
right: Box<dyn NyashBox>,
}
impl MultiplyBox {
pub fn new(left: Box<dyn NyashBox>, right: Box<dyn NyashBox>) -> Self {
Self { left, right }
}
pub fn execute(&self) -> Box<dyn NyashBox> {
use crate::boxes::math_box::FloatBox;
// 1. Integer * Integer
if let (Some(left_int), Some(right_int)) = (
self.left.as_any().downcast_ref::<IntegerBox>(),
self.right.as_any().downcast_ref::<IntegerBox>()
) {
return Box::new(IntegerBox::new(left_int.value * right_int.value));
}
// 2. Float * Float
if let (Some(left_float), Some(right_float)) = (
self.left.as_any().downcast_ref::<FloatBox>(),
self.right.as_any().downcast_ref::<FloatBox>()
) {
return Box::new(FloatBox::new(left_float.value * right_float.value));
}
// 3. Integer * Float -> Float
if let (Some(left_int), Some(right_float)) = (
self.left.as_any().downcast_ref::<IntegerBox>(),
self.right.as_any().downcast_ref::<FloatBox>()
) {
return Box::new(FloatBox::new(left_int.value as f64 * right_float.value));
}
// 4. Float * Integer -> Float
if let (Some(left_float), Some(right_int)) = (
self.left.as_any().downcast_ref::<FloatBox>(),
self.right.as_any().downcast_ref::<IntegerBox>()
) {
return Box::new(FloatBox::new(left_float.value * right_int.value as f64));
}
// エラーの場合はvoid返す
Box::new(VoidBox::new())
}
}
/// 除算を行うBox
pub struct DivideBox {
left: Box<dyn NyashBox>,
right: Box<dyn NyashBox>,
}
impl DivideBox {
pub fn new(left: Box<dyn NyashBox>, right: Box<dyn NyashBox>) -> Self {
Self { left, right }
}
pub fn execute(&self) -> Box<dyn NyashBox> {
use crate::boxes::math_box::FloatBox;
// 1. Integer / Integer -> Float (常に浮動小数点で返す)
if let (Some(left_int), Some(right_int)) = (
self.left.as_any().downcast_ref::<IntegerBox>(),
self.right.as_any().downcast_ref::<IntegerBox>()
) {
if right_int.value == 0 {
// ゼロ除算エラー
return Box::new(StringBox::new("Error: Division by zero".to_string()));
}
return Box::new(FloatBox::new(left_int.value as f64 / right_int.value as f64));
}
// 2. Float / Float
if let (Some(left_float), Some(right_float)) = (
self.left.as_any().downcast_ref::<FloatBox>(),
self.right.as_any().downcast_ref::<FloatBox>()
) {
if right_float.value == 0.0 {
// ゼロ除算エラー
return Box::new(StringBox::new("Error: Division by zero".to_string()));
}
return Box::new(FloatBox::new(left_float.value / right_float.value));
}
// 3. Integer / Float -> Float
if let (Some(left_int), Some(right_float)) = (
self.left.as_any().downcast_ref::<IntegerBox>(),
self.right.as_any().downcast_ref::<FloatBox>()
) {
if right_float.value == 0.0 {
// ゼロ除算エラー
return Box::new(StringBox::new("Error: Division by zero".to_string()));
}
return Box::new(FloatBox::new(left_int.value as f64 / right_float.value));
}
// 4. Float / Integer -> Float
if let (Some(left_float), Some(right_int)) = (
self.left.as_any().downcast_ref::<FloatBox>(),
self.right.as_any().downcast_ref::<IntegerBox>()
) {
if right_int.value == 0 {
// ゼロ除算エラー
return Box::new(StringBox::new("Error: Division by zero".to_string()));
}
return Box::new(FloatBox::new(left_float.value / right_int.value as f64));
}
// エラーの場合はvoid返す
Box::new(VoidBox::new())
}
}
/// 比較演算用のヘルパー
pub struct CompareBox;
impl CompareBox {
pub fn less(left: &dyn NyashBox, right: &dyn NyashBox) -> BoolBox {
use crate::boxes::FloatBox;
// Integer < Integer
if let (Some(left_int), Some(right_int)) = (
left.as_any().downcast_ref::<IntegerBox>(),
right.as_any().downcast_ref::<IntegerBox>()
) {
return BoolBox::new(left_int.value < right_int.value);
}
// Float < Float
if let (Some(left_float), Some(right_float)) = (
left.as_any().downcast_ref::<FloatBox>(),
right.as_any().downcast_ref::<FloatBox>()
) {
return BoolBox::new(left_float.value < right_float.value);
}
// Integer < Float
if let (Some(left_int), Some(right_float)) = (
left.as_any().downcast_ref::<IntegerBox>(),
right.as_any().downcast_ref::<FloatBox>()
) {
return BoolBox::new((left_int.value as f64) < right_float.value);
}
// Float < Integer
if let (Some(left_float), Some(right_int)) = (
left.as_any().downcast_ref::<FloatBox>(),
right.as_any().downcast_ref::<IntegerBox>()
) {
return BoolBox::new(left_float.value < (right_int.value as f64));
}
BoolBox::new(false)
}
pub fn greater(left: &dyn NyashBox, right: &dyn NyashBox) -> BoolBox {
use crate::boxes::FloatBox;
// Integer > Integer
if let (Some(left_int), Some(right_int)) = (
left.as_any().downcast_ref::<IntegerBox>(),
right.as_any().downcast_ref::<IntegerBox>()
) {
return BoolBox::new(left_int.value > right_int.value);
}
// Float > Float
if let (Some(left_float), Some(right_float)) = (
left.as_any().downcast_ref::<FloatBox>(),
right.as_any().downcast_ref::<FloatBox>()
) {
return BoolBox::new(left_float.value > right_float.value);
}
// Integer > Float
if let (Some(left_int), Some(right_float)) = (
left.as_any().downcast_ref::<IntegerBox>(),
right.as_any().downcast_ref::<FloatBox>()
) {
return BoolBox::new((left_int.value as f64) > right_float.value);
}
// Float > Integer
if let (Some(left_float), Some(right_int)) = (
left.as_any().downcast_ref::<FloatBox>(),
right.as_any().downcast_ref::<IntegerBox>()
) {
return BoolBox::new(left_float.value > (right_int.value as f64));
}
BoolBox::new(false)
}
pub fn less_equal(left: &dyn NyashBox, right: &dyn NyashBox) -> BoolBox {
use crate::boxes::FloatBox;
// Integer <= Integer
if let (Some(left_int), Some(right_int)) = (
left.as_any().downcast_ref::<IntegerBox>(),
right.as_any().downcast_ref::<IntegerBox>()
) {
return BoolBox::new(left_int.value <= right_int.value);
}
// Float <= Float
if let (Some(left_float), Some(right_float)) = (
left.as_any().downcast_ref::<FloatBox>(),
right.as_any().downcast_ref::<FloatBox>()
) {
return BoolBox::new(left_float.value <= right_float.value);
}
// Integer <= Float
if let (Some(left_int), Some(right_float)) = (
left.as_any().downcast_ref::<IntegerBox>(),
right.as_any().downcast_ref::<FloatBox>()
) {
return BoolBox::new((left_int.value as f64) <= right_float.value);
}
// Float <= Integer
if let (Some(left_float), Some(right_int)) = (
left.as_any().downcast_ref::<FloatBox>(),
right.as_any().downcast_ref::<IntegerBox>()
) {
return BoolBox::new(left_float.value <= (right_int.value as f64));
}
BoolBox::new(false)
}
pub fn greater_equal(left: &dyn NyashBox, right: &dyn NyashBox) -> BoolBox {
use crate::boxes::FloatBox;
// Integer >= Integer
if let (Some(left_int), Some(right_int)) = (
left.as_any().downcast_ref::<IntegerBox>(),
right.as_any().downcast_ref::<IntegerBox>()
) {
return BoolBox::new(left_int.value >= right_int.value);
}
// Float >= Float
if let (Some(left_float), Some(right_float)) = (
left.as_any().downcast_ref::<FloatBox>(),
right.as_any().downcast_ref::<FloatBox>()
) {
return BoolBox::new(left_float.value >= right_float.value);
}
// Integer >= Float
if let (Some(left_int), Some(right_float)) = (
left.as_any().downcast_ref::<IntegerBox>(),
right.as_any().downcast_ref::<FloatBox>()
) {
return BoolBox::new((left_int.value as f64) >= right_float.value);
}
// Float >= Integer
if let (Some(left_float), Some(right_int)) = (
left.as_any().downcast_ref::<FloatBox>(),
right.as_any().downcast_ref::<IntegerBox>()
) {
return BoolBox::new(left_float.value >= (right_int.value as f64));
}
BoolBox::new(false)
}
}
// ===== Tests =====
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_string_box_creation() {
let s = StringBox::new("Hello, Rust!");
assert_eq!(s.value, "Hello, Rust!");
assert_eq!(s.type_name(), "StringBox");
assert_eq!(s.to_string_box().value, "Hello, Rust!");
}
#[test]
fn test_integer_box_creation() {
let i = IntegerBox::new(42);
assert_eq!(i.value, 42);
assert_eq!(i.type_name(), "IntegerBox");
assert_eq!(i.to_string_box().value, "42");
}
#[test]
fn test_bool_box_creation() {
let b = BoolBox::new(true);
assert_eq!(b.value, true);
assert_eq!(b.type_name(), "BoolBox");
assert_eq!(b.to_string_box().value, "true");
}
#[test]
fn test_box_equality() {
let s1 = StringBox::new("test");
let s2 = StringBox::new("test");
let s3 = StringBox::new("different");
assert!(s1.equals(&s2).value);
assert!(!s1.equals(&s3).value);
}
#[test]
fn test_add_box_integers() {
let left = Box::new(IntegerBox::new(5)) as Box<dyn NyashBox>;
let right = Box::new(IntegerBox::new(3)) as Box<dyn NyashBox>;
let add = AddBox::new(left, right);
let result = add.execute();
let result_int = result.as_any().downcast_ref::<IntegerBox>().unwrap();
assert_eq!(result_int.value, 8);
}
#[test]
fn test_add_box_strings() {
let left = Box::new(StringBox::new("Hello, ")) as Box<dyn NyashBox>;
let right = Box::new(StringBox::new("Rust!")) as Box<dyn NyashBox>;
let add = AddBox::new(left, right);
let result = add.execute();
let result_str = result.as_any().downcast_ref::<StringBox>().unwrap();
assert_eq!(result_str.value, "Hello, Rust!");
}
#[test]
fn test_box_ids_unique() {
let s1 = StringBox::new("test");
let s2 = StringBox::new("test");
// Same content but different IDs
assert_ne!(s1.box_id(), s2.box_id());
}
#[test]
fn test_void_box() {
let v = VoidBox::new();
assert_eq!(v.type_name(), "VoidBox");
assert_eq!(v.to_string_box().value, "void");
}
}