Phase 9.75-B: Convert StreamBox from Arc<Mutex> to RwLock, progress on DebugBox

Co-authored-by: moe-charm <217100418+moe-charm@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2025-08-14 23:59:11 +00:00
parent ffa09b17fb
commit 5bcaa14b52
8 changed files with 92 additions and 45 deletions

View File

@ -751,14 +751,14 @@ impl VM {
if let Some(array_box) = box_value.as_any().downcast_ref::<crate::boxes::array::ArrayBox>() { if let Some(array_box) = box_value.as_any().downcast_ref::<crate::boxes::array::ArrayBox>() {
match method { match method {
"length" | "len" => { "length" | "len" => {
let items = array_box.items.lock().unwrap(); let items = array_box.items.read().unwrap();
return Ok(Box::new(IntegerBox::new(items.len() as i64))); return Ok(Box::new(IntegerBox::new(items.len() as i64)));
}, },
"get" => { "get" => {
// get(index) - get element at index // get(index) - get element at index
if let Some(index_box) = _args.get(0) { if let Some(index_box) = _args.get(0) {
if let Some(index_int) = index_box.as_any().downcast_ref::<IntegerBox>() { if let Some(index_int) = index_box.as_any().downcast_ref::<IntegerBox>() {
let items = array_box.items.lock().unwrap(); let items = array_box.items.read().unwrap();
let index = index_int.value as usize; let index = index_int.value as usize;
if index < items.len() { if index < items.len() {
return Ok(items[index].clone_box()); return Ok(items[index].clone_box());

View File

@ -176,7 +176,7 @@ impl StringBox {
/// Join array elements using this string as delimiter /// Join array elements using this string as delimiter
pub fn join(&self, array_box: Box<dyn NyashBox>) -> Box<dyn NyashBox> { pub fn join(&self, array_box: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
if let Some(array) = array_box.as_any().downcast_ref::<ArrayBox>() { if let Some(array) = array_box.as_any().downcast_ref::<ArrayBox>() {
let strings: Vec<String> = array.items.lock().unwrap() let strings: Vec<String> = array.items.read().unwrap()
.iter() .iter()
.map(|element| element.to_string_box().value) .map(|element| element.to_string_box().value)
.collect(); .collect();

View File

@ -299,8 +299,8 @@ impl NyashBox for ArrayBox {
fn equals(&self, other: &dyn NyashBox) -> BoolBox { fn equals(&self, other: &dyn NyashBox) -> BoolBox {
if let Some(other_array) = other.as_any().downcast_ref::<ArrayBox>() { if let Some(other_array) = other.as_any().downcast_ref::<ArrayBox>() {
let self_items = self.items.lock().unwrap(); let self_items = self.items.read().unwrap();
let other_items = other_array.items.lock().unwrap(); let other_items = other_array.items.read().unwrap();
if self_items.len() != other_items.len() { if self_items.len() != other_items.len() {
return BoolBox::new(false); return BoolBox::new(false);
@ -318,3 +318,14 @@ impl NyashBox for ArrayBox {
} }
} }
} }
// Debug implementation for ArrayBox
impl std::fmt::Debug for ArrayBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let items = self.items.read().unwrap();
f.debug_struct("ArrayBox")
.field("id", &self.base.id)
.field("length", &items.len())
.finish()
}
}

View File

@ -216,3 +216,14 @@ impl NyashBox for BufferBox {
} }
} }
} }
// Debug implementation for BufferBox
impl std::fmt::Debug for BufferBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let data = self.data.read().unwrap();
f.debug_struct("BufferBox")
.field("id", &self.base.id)
.field("length", &data.len())
.finish()
}
}

View File

@ -100,7 +100,7 @@
*/ */
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::{Arc, Mutex}; use std::sync::RwLock;
use chrono::Local; use chrono::Local;
use crate::box_trait::{BoxCore, BoxBase, next_box_id, NyashBox, StringBox, BoolBox, VoidBox}; use crate::box_trait::{BoxCore, BoxBase, next_box_id, NyashBox, StringBox, BoolBox, VoidBox};
use crate::interpreter::RuntimeError; use crate::interpreter::RuntimeError;
@ -110,10 +110,10 @@ use std::any::Any;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct DebugBox { pub struct DebugBox {
base: BoxBase, base: BoxBase,
tracking_enabled: Arc<Mutex<bool>>, tracking_enabled: RwLock<bool>,
tracked_boxes: Arc<Mutex<HashMap<String, TrackedBoxInfo>>>, tracked_boxes: RwLock<HashMap<String, TrackedBoxInfo>>,
breakpoints: Arc<Mutex<Vec<String>>>, breakpoints: RwLock<Vec<String>>,
call_stack: Arc<Mutex<Vec<CallInfo>>>, call_stack: RwLock<Vec<CallInfo>>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -135,34 +135,34 @@ impl DebugBox {
pub fn new() -> Self { pub fn new() -> Self {
DebugBox { DebugBox {
base: BoxBase::new(), base: BoxBase::new(),
tracking_enabled: Arc::new(Mutex::new(false)), tracking_enabled: RwLock::new(false),
tracked_boxes: Arc::new(Mutex::new(HashMap::new())), tracked_boxes: RwLock::new(HashMap::new()),
breakpoints: Arc::new(Mutex::new(Vec::new())), breakpoints: RwLock::new(Vec::new()),
call_stack: Arc::new(Mutex::new(Vec::new())), call_stack: RwLock::new(Vec::new()),
} }
} }
pub fn start_tracking(&self) -> Result<Box<dyn NyashBox>, RuntimeError> { pub fn start_tracking(&self) -> Result<Box<dyn NyashBox>, RuntimeError> {
let mut enabled = self.tracking_enabled.lock().unwrap(); let mut enabled = self.tracking_enabled.write().unwrap();
*enabled = true; *enabled = true;
println!("[DEBUG] Tracking started"); println!("[DEBUG] Tracking started");
Ok(Box::new(VoidBox::new())) Ok(Box::new(VoidBox::new()))
} }
pub fn stop_tracking(&self) -> Result<Box<dyn NyashBox>, RuntimeError> { pub fn stop_tracking(&self) -> Result<Box<dyn NyashBox>, RuntimeError> {
let mut enabled = self.tracking_enabled.lock().unwrap(); let mut enabled = self.tracking_enabled.write().unwrap();
*enabled = false; *enabled = false;
println!("[DEBUG] Tracking stopped"); println!("[DEBUG] Tracking stopped");
Ok(Box::new(VoidBox::new())) Ok(Box::new(VoidBox::new()))
} }
pub fn track_box(&self, box_value: &dyn NyashBox, name: &str) -> Result<Box<dyn NyashBox>, RuntimeError> { pub fn track_box(&self, box_value: &dyn NyashBox, name: &str) -> Result<Box<dyn NyashBox>, RuntimeError> {
let enabled = self.tracking_enabled.lock().unwrap(); let enabled = self.tracking_enabled.read().unwrap();
if !*enabled { if !*enabled {
return Ok(Box::new(VoidBox::new())); return Ok(Box::new(VoidBox::new()));
} }
let mut tracked = self.tracked_boxes.lock().unwrap(); let mut tracked = self.tracked_boxes.write().unwrap();
let info = TrackedBoxInfo { let info = TrackedBoxInfo {
box_type: box_value.type_name().to_string(), box_type: box_value.type_name().to_string(),
@ -298,7 +298,7 @@ impl DebugBox {
} }
pub fn is_tracking(&self) -> Result<Box<dyn NyashBox>, RuntimeError> { pub fn is_tracking(&self) -> Result<Box<dyn NyashBox>, RuntimeError> {
let enabled = self.tracking_enabled.lock().unwrap(); let enabled = self.tracking_enabled.read().unwrap();
Ok(Box::new(BoolBox::new(*enabled))) Ok(Box::new(BoolBox::new(*enabled)))
} }

View File

@ -242,14 +242,14 @@ fn nyash_box_to_json_value(value: Box<dyn NyashBox>) -> Value {
} else if let Some(string_box) = value.as_any().downcast_ref::<StringBox>() { } else if let Some(string_box) = value.as_any().downcast_ref::<StringBox>() {
Value::String(string_box.value.clone()) Value::String(string_box.value.clone())
} else if let Some(array_box) = value.as_any().downcast_ref::<ArrayBox>() { } else if let Some(array_box) = value.as_any().downcast_ref::<ArrayBox>() {
let items = array_box.items.lock().unwrap(); let items = array_box.items.read().unwrap();
let arr: Vec<Value> = items.iter() let arr: Vec<Value> = items.iter()
.map(|item| nyash_box_to_json_value(item.clone_box())) .map(|item| nyash_box_to_json_value(item.clone_box()))
.collect(); .collect();
Value::Array(arr) Value::Array(arr)
} else if let Some(map_box) = value.as_any().downcast_ref::<MapBox>() { } else if let Some(map_box) = value.as_any().downcast_ref::<MapBox>() {
let data = map_box.get_data(); let data = map_box.get_data();
let map = data.lock().unwrap(); let map = data.read().unwrap();
let mut obj = serde_json::Map::new(); let mut obj = serde_json::Map::new();
for (key, val) in map.iter() { for (key, val) in map.iter() {
obj.insert(key.clone(), nyash_box_to_json_value(val.clone_box())); obj.insert(key.clone(), nyash_box_to_json_value(val.clone_box()));

View File

@ -6,36 +6,35 @@ use crate::box_trait::{NyashBox, StringBox, BoolBox, IntegerBox, BoxCore, BoxBas
use crate::boxes::buffer::BufferBox; use crate::boxes::buffer::BufferBox;
use crate::boxes::array::ArrayBox; use crate::boxes::array::ArrayBox;
use std::any::Any; use std::any::Any;
use std::sync::{Arc, Mutex}; use std::sync::RwLock;
use std::io::{Read, Write, Result}; use std::io::{Read, Write, Result};
#[derive(Debug, Clone)]
pub struct NyashStreamBox { pub struct NyashStreamBox {
buffer: Arc<Mutex<Vec<u8>>>, buffer: RwLock<Vec<u8>>,
position: Arc<Mutex<usize>>, position: RwLock<usize>,
base: BoxBase, base: BoxBase,
} }
impl NyashStreamBox { impl NyashStreamBox {
pub fn new() -> Self { pub fn new() -> Self {
NyashStreamBox { NyashStreamBox {
buffer: Arc::new(Mutex::new(Vec::new())), buffer: RwLock::new(Vec::new()),
position: Arc::new(Mutex::new(0)), position: RwLock::new(0),
base: BoxBase::new(), base: BoxBase::new(),
} }
} }
pub fn from_data(data: Vec<u8>) -> Self { pub fn from_data(data: Vec<u8>) -> Self {
NyashStreamBox { NyashStreamBox {
buffer: Arc::new(Mutex::new(data)), buffer: RwLock::new(data),
position: Arc::new(Mutex::new(0)), position: RwLock::new(0),
base: BoxBase::new(), base: BoxBase::new(),
} }
} }
pub fn read(&self, buf: &mut [u8]) -> Result<usize> { pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
let buffer = self.buffer.lock().unwrap(); let buffer = self.buffer.read().unwrap();
let mut position = self.position.lock().unwrap(); let mut position = self.position.write().unwrap();
let available = buffer.len().saturating_sub(*position); let available = buffer.len().saturating_sub(*position);
let to_read = buf.len().min(available); let to_read = buf.len().min(available);
@ -50,21 +49,21 @@ impl NyashStreamBox {
} }
pub fn write(&self, buf: &[u8]) -> Result<()> { pub fn write(&self, buf: &[u8]) -> Result<()> {
let mut buffer = self.buffer.lock().unwrap(); let mut buffer = self.buffer.write().unwrap();
buffer.extend_from_slice(buf); buffer.extend_from_slice(buf);
Ok(()) Ok(())
} }
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.buffer.lock().unwrap().len() self.buffer.read().unwrap().len()
} }
pub fn position(&self) -> usize { pub fn position(&self) -> usize {
*self.position.lock().unwrap() *self.position.read().unwrap()
} }
pub fn reset(&self) { pub fn reset(&self) {
*self.position.lock().unwrap() = 0; *self.position.write().unwrap() = 0;
} }
/// ストリームに書き込み /// ストリームに書き込み
@ -75,7 +74,7 @@ impl NyashStreamBox {
let array_data = buffer_box.readAll(); let array_data = buffer_box.readAll();
// ArrayBoxをバイト配列に変換 // ArrayBoxをバイト配列に変換
if let Some(array_box) = array_data.as_any().downcast_ref::<ArrayBox>() { if let Some(array_box) = array_data.as_any().downcast_ref::<ArrayBox>() {
let items = array_box.items.lock().unwrap(); let items = array_box.items.read().unwrap();
let mut bytes = Vec::new(); let mut bytes = Vec::new();
for item in items.iter() { for item in items.iter() {
if let Some(int_box) = item.as_any().downcast_ref::<IntegerBox>() { if let Some(int_box) = item.as_any().downcast_ref::<IntegerBox>() {
@ -142,8 +141,8 @@ impl NyashBox for NyashStreamBox {
} }
fn to_string_box(&self) -> StringBox { fn to_string_box(&self) -> StringBox {
let buffer = self.buffer.lock().unwrap(); let buffer = self.buffer.read().unwrap();
let position = self.position.lock().unwrap(); let position = self.position.read().unwrap();
StringBox::new(format!("NyashStreamBox({} bytes, pos: {})", buffer.len(), *position)) StringBox::new(format!("NyashStreamBox({} bytes, pos: {})", buffer.len(), *position))
} }
@ -155,10 +154,10 @@ impl NyashBox for NyashStreamBox {
fn equals(&self, other: &dyn NyashBox) -> BoolBox { fn equals(&self, other: &dyn NyashBox) -> BoolBox {
if let Some(other_stream) = other.as_any().downcast_ref::<NyashStreamBox>() { if let Some(other_stream) = other.as_any().downcast_ref::<NyashStreamBox>() {
let self_buffer = self.buffer.lock().unwrap(); let self_buffer = self.buffer.read().unwrap();
let self_position = self.position.lock().unwrap(); let self_position = self.position.read().unwrap();
let other_buffer = other_stream.buffer.lock().unwrap(); let other_buffer = other_stream.buffer.read().unwrap();
let other_position = other_stream.position.lock().unwrap(); let other_position = other_stream.position.read().unwrap();
BoolBox::new(*self_buffer == *other_buffer && *self_position == *other_position) BoolBox::new(*self_buffer == *other_buffer && *self_position == *other_position)
} else { } else {
BoolBox::new(false) BoolBox::new(false)
@ -176,8 +175,8 @@ impl BoxCore for NyashStreamBox {
} }
fn fmt_box(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt_box(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let buffer = self.buffer.lock().unwrap(); let buffer = self.buffer.read().unwrap();
let position = self.position.lock().unwrap(); let position = self.position.read().unwrap();
write!(f, "NyashStreamBox({} bytes, pos: {})", buffer.len(), *position) write!(f, "NyashStreamBox({} bytes, pos: {})", buffer.len(), *position)
} }
@ -190,6 +189,32 @@ impl BoxCore for NyashStreamBox {
} }
} }
// Clone implementation for NyashStreamBox (needed since RwLock doesn't auto-derive Clone)
impl Clone for NyashStreamBox {
fn clone(&self) -> Self {
let buffer = self.buffer.read().unwrap();
let position = self.position.read().unwrap();
NyashStreamBox {
buffer: RwLock::new(buffer.clone()),
position: RwLock::new(*position),
base: BoxBase::new(),
}
}
}
// Debug implementation for NyashStreamBox
impl std::fmt::Debug for NyashStreamBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let buffer = self.buffer.read().unwrap();
let position = self.position.read().unwrap();
f.debug_struct("NyashStreamBox")
.field("id", &self.base.id)
.field("buffer_len", &buffer.len())
.field("position", &position)
.finish()
}
}
impl std::fmt::Display for NyashStreamBox { impl std::fmt::Display for NyashStreamBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_box(f) self.fmt_box(f)

View File

@ -117,7 +117,7 @@ impl StringBox {
pub fn join(&self, array_box: Box<dyn NyashBox>) -> Box<dyn NyashBox> { pub fn join(&self, array_box: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
use crate::boxes::array::ArrayBox; use crate::boxes::array::ArrayBox;
if let Some(array) = array_box.as_any().downcast_ref::<ArrayBox>() { if let Some(array) = array_box.as_any().downcast_ref::<ArrayBox>() {
let strings: Vec<String> = array.items.lock().unwrap() let strings: Vec<String> = array.items.read().unwrap()
.iter() .iter()
.map(|element| element.to_string_box().value) .map(|element| element.to_string_box().value)
.collect(); .collect();