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:
@ -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))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user