P0: user_defined factory safe init stub; P1: HTTPResponseBox interior mutability via Mutex (thread-safe), implement set_status/header/body/append_body + to_http_string, manual Clone; build green

This commit is contained in:
Selfhosting Dev
2025-09-19 11:23:56 +09:00
parent f64718d22a
commit 21d326333d
2 changed files with 76 additions and 75 deletions

View File

@ -38,14 +38,17 @@ impl BoxFactory for UserDefinedBoxFactory {
})?; })?;
// Create InstanceBox with fields and methods // Create InstanceBox with fields and methods
let instance = InstanceBox::from_declaration( let mut instance = InstanceBox::from_declaration(
name.to_string(), name.to_string(),
box_decl.fields.clone(), box_decl.fields.clone(),
box_decl.methods.clone(), box_decl.methods.clone(),
); );
// TODO: Execute birth/init constructor with args // Safe stub: run minimal init hook (no-op for now).
// For now, just return the instance // - Does not execute user birth/init AST yet (interpreter-owned).
// - Avoids panics; ignores errors to keep factory safe.
let _ = instance.init(_args);
Ok(Box::new(instance)) Ok(Box::new(instance))
} }

View File

@ -256,53 +256,42 @@ impl std::fmt::Display for HTTPRequestBox {
} }
/// HTTP レスポンスを生成・操作するBox /// HTTP レスポンスを生成・操作するBox
#[derive(Debug, Clone)] #[derive(Debug)]
pub struct HTTPResponseBox { pub struct HTTPResponseBox {
base: BoxBase, base: BoxBase,
status_code: i32, status_code: std::sync::Mutex<i32>,
status_message: String, status_message: std::sync::Mutex<String>,
headers: HashMap<String, String>, headers: std::sync::Mutex<HashMap<String, String>>,
body: String, body: std::sync::Mutex<String>,
http_version: String, http_version: std::sync::Mutex<String>,
} }
impl HTTPResponseBox { impl HTTPResponseBox {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
base: BoxBase::new(), base: BoxBase::new(),
status_code: 200, status_code: std::sync::Mutex::new(200),
status_message: "OK".to_string(), status_message: std::sync::Mutex::new("OK".to_string()),
headers: HashMap::new(), headers: std::sync::Mutex::new(HashMap::new()),
body: "".to_string(), body: std::sync::Mutex::new(String::new()),
http_version: "HTTP/1.1".to_string(), http_version: std::sync::Mutex::new("HTTP/1.1".to_string()),
} }
} }
/// ステータスコード・メッセージ設定 /// ステータスコード・メッセージ設定
pub fn set_status( pub fn set_status(&self, code: Box<dyn NyashBox>, message: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
&self, let code_val = code.to_string_box().value.parse::<i32>().unwrap_or(200);
code: Box<dyn NyashBox>, let message_val = message.to_string_box().value;
message: Box<dyn NyashBox>, *self.status_code.lock().unwrap() = code_val;
) -> Box<dyn NyashBox> { *self.status_message.lock().unwrap() = message_val;
// Note: This would need interior mutability for actual mutation
// For now, this is a placeholder for the API structure
let _code_val = code.to_string_box().value.parse::<i32>().unwrap_or(200);
let _message_val = message.to_string_box().value;
// TODO: Use RefCell or similar for interior mutability
Box::new(BoolBox::new(true)) Box::new(BoolBox::new(true))
} }
/// ヘッダー設定 /// ヘッダー設定
pub fn set_header( pub fn set_header(&self, name: Box<dyn NyashBox>, value: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
&self, let name_str = name.to_string_box().value;
name: Box<dyn NyashBox>, let value_str = value.to_string_box().value;
value: Box<dyn NyashBox>, self.headers.lock().unwrap().insert(name_str, value_str);
) -> Box<dyn NyashBox> {
let _name_str = name.to_string_box().value;
let _value_str = value.to_string_box().value;
// TODO: Use RefCell for interior mutability
Box::new(BoolBox::new(true)) Box::new(BoolBox::new(true))
} }
@ -317,17 +306,15 @@ impl HTTPResponseBox {
/// レスポンスボディ設定 /// レスポンスボディ設定
pub fn set_body(&self, content: Box<dyn NyashBox>) -> Box<dyn NyashBox> { pub fn set_body(&self, content: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
let _content_str = content.to_string_box().value; let content_str = content.to_string_box().value;
*self.body.lock().unwrap() = content_str;
// TODO: Use RefCell for interior mutability
Box::new(BoolBox::new(true)) Box::new(BoolBox::new(true))
} }
/// ボディ追加 /// ボディ追加
pub fn append_body(&self, content: Box<dyn NyashBox>) -> Box<dyn NyashBox> { pub fn append_body(&self, content: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
let _content_str = content.to_string_box().value; let content_str = content.to_string_box().value;
self.body.lock().unwrap().push_str(&content_str);
// TODO: Use RefCell for interior mutability
Box::new(BoolBox::new(true)) Box::new(BoolBox::new(true))
} }
@ -336,26 +323,28 @@ impl HTTPResponseBox {
let mut response = String::new(); let mut response = String::new();
// Status line // Status line
response.push_str(&format!( let version = self.http_version.lock().unwrap().clone();
"{} {} {}\r\n", let status_code = *self.status_code.lock().unwrap();
self.http_version, self.status_code, self.status_message let status_message = self.status_message.lock().unwrap().clone();
)); response.push_str(&format!("{} {} {}\r\n", version, status_code, status_message));
// Headers // Headers
for (name, value) in &self.headers { for (name, value) in self.headers.lock().unwrap().iter() {
response.push_str(&format!("{}: {}\r\n", name, value)); response.push_str(&format!("{}: {}\r\n", name, value));
} }
// Content-Length if not already set // Content-Length if not already set
if !self.headers.contains_key("content-length") && !self.body.is_empty() { let body_len = { self.body.lock().unwrap().len() };
response.push_str(&format!("Content-Length: {}\r\n", self.body.len())); let need_len = { !self.headers.lock().unwrap().contains_key("content-length") && body_len > 0 };
if need_len {
response.push_str(&format!("Content-Length: {}\r\n", body_len));
} }
// Empty line before body // Empty line before body
response.push_str("\r\n"); response.push_str("\r\n");
// Body // Body
response.push_str(&self.body); response.push_str(&self.body.lock().unwrap());
Box::new(StringBox::new(response)) Box::new(StringBox::new(response))
} }
@ -363,42 +352,56 @@ impl HTTPResponseBox {
/// Quick HTML response creation /// Quick HTML response creation
pub fn create_html_response(content: Box<dyn NyashBox>) -> Self { pub fn create_html_response(content: Box<dyn NyashBox>) -> Self {
let mut response = HTTPResponseBox::new(); let mut response = HTTPResponseBox::new();
response.status_code = 200; *response.status_code.lock().unwrap() = 200;
response.status_message = "OK".to_string(); *response.status_message.lock().unwrap() = "OK".to_string();
response.headers.insert( response.headers.lock().unwrap().insert(
"Content-Type".to_string(), "Content-Type".to_string(),
"text/html; charset=utf-8".to_string(), "text/html; charset=utf-8".to_string(),
); );
response.body = content.to_string_box().value; *response.body.lock().unwrap() = content.to_string_box().value;
response response
} }
/// Quick JSON response creation /// Quick JSON response creation
pub fn create_json_response(content: Box<dyn NyashBox>) -> Self { pub fn create_json_response(content: Box<dyn NyashBox>) -> Self {
let mut response = HTTPResponseBox::new(); let mut response = HTTPResponseBox::new();
response.status_code = 200; *response.status_code.lock().unwrap() = 200;
response.status_message = "OK".to_string(); *response.status_message.lock().unwrap() = "OK".to_string();
response response.headers.lock().unwrap().insert(
.headers "Content-Type".to_string(),
.insert("Content-Type".to_string(), "application/json".to_string()); "application/json".to_string(),
response.body = content.to_string_box().value; );
*response.body.lock().unwrap() = content.to_string_box().value;
response response
} }
/// Quick 404 response creation /// Quick 404 response creation
pub fn create_404_response() -> Self { pub fn create_404_response() -> Self {
let mut response = HTTPResponseBox::new(); let mut response = HTTPResponseBox::new();
response.status_code = 404; *response.status_code.lock().unwrap() = 404;
response.status_message = "Not Found".to_string(); *response.status_message.lock().unwrap() = "Not Found".to_string();
response.headers.insert( response.headers.lock().unwrap().insert(
"Content-Type".to_string(), "Content-Type".to_string(),
"text/html; charset=utf-8".to_string(), "text/html; charset=utf-8".to_string(),
); );
response.body = "<html><body><h1>404 - Not Found</h1></body></html>".to_string(); *response.body.lock().unwrap() = "<html><body><h1>404 - Not Found</h1></body></html>".to_string();
response response
} }
} }
impl Clone for HTTPResponseBox {
fn clone(&self) -> Self {
Self {
base: self.base.clone(),
status_code: std::sync::Mutex::new(*self.status_code.lock().unwrap()),
status_message: std::sync::Mutex::new(self.status_message.lock().unwrap().clone()),
headers: std::sync::Mutex::new(self.headers.lock().unwrap().clone()),
body: std::sync::Mutex::new(self.body.lock().unwrap().clone()),
http_version: std::sync::Mutex::new(self.http_version.lock().unwrap().clone()),
}
}
}
impl NyashBox for HTTPResponseBox { impl NyashBox for HTTPResponseBox {
fn clone_box(&self) -> Box<dyn NyashBox> { fn clone_box(&self) -> Box<dyn NyashBox> {
Box::new(self.clone()) Box::new(self.clone())
@ -410,12 +413,10 @@ impl NyashBox for HTTPResponseBox {
} }
fn to_string_box(&self) -> StringBox { fn to_string_box(&self) -> StringBox {
StringBox::new(format!( let code = *self.status_code.lock().unwrap();
"HTTPResponse({} {} - {} bytes)", let msg = self.status_message.lock().unwrap().clone();
self.status_code, let len = self.body.lock().unwrap().len();
self.status_message, StringBox::new(format!("HTTPResponse({} {} - {} bytes)", code, msg, len))
self.body.len()
))
} }
fn type_name(&self) -> &'static str { fn type_name(&self) -> &'static str {
@ -441,13 +442,10 @@ impl BoxCore for HTTPResponseBox {
} }
fn fmt_box(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt_box(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!( let code = *self.status_code.lock().unwrap();
f, let msg = self.status_message.lock().unwrap().clone();
"HTTPResponse({} {} - {} bytes)", let len = self.body.lock().unwrap().len();
self.status_code, write!(f, "HTTPResponse({} {} - {} bytes)", code, msg, len)
self.status_message,
self.body.len()
)
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {