python-plugin: RAII (PyOwned/PyBorrowed) + autodecode enum; crate: ny-llvmc --emit exe with NyRT link; tools: build_llvm.sh crate-exe path + crate_exe_smoke; CURRENT_TASK update

This commit is contained in:
Selfhosting Dev
2025-09-18 03:57:25 +09:00
parent 1b12b1eb7d
commit 5d51086530
27 changed files with 2802 additions and 2484 deletions

View File

@ -3,18 +3,88 @@ mod tests {
use crate::box_trait::{IntegerBox, NyashBox, StringBox};
use crate::boxes::array::ArrayBox;
use crate::boxes::math_box::FloatBox;
use crate::runtime::plugin_loader_unified::PluginHost;
use std::env;
use std::fs;
use std::path::PathBuf;
// RAII: environment variable guard (restores on drop)
struct EnvGuard {
key: &'static str,
prev: Option<String>,
}
impl EnvGuard {
fn set(key: &'static str, val: &str) -> Self {
let prev = env::var(key).ok();
env::set_var(key, val);
EnvGuard { key, prev }
}
fn remove(key: &'static str) -> Self {
let prev = env::var(key).ok();
env::remove_var(key);
EnvGuard { key, prev }
}
}
impl Drop for EnvGuard {
fn drop(&mut self) {
match &self.prev {
Some(v) => env::set_var(self.key, v),
None => env::remove_var(self.key),
}
}
}
// Helper: read-lock the global plugin host and pass immutable ref to closure
fn with_host<R>(f: impl FnOnce(&PluginHost) -> R) -> R {
let host = crate::runtime::get_global_plugin_host();
let guard = host.read().expect("plugin host RwLock poisoned");
f(&*guard)
}
// ---- Test helpers (invoke wrappers) ----
fn inv_ok(
h: &PluginHost,
box_ty: &str,
method: &str,
id: u32,
args: &[Box<dyn NyashBox>],
) -> Option<Box<dyn NyashBox>> {
h.invoke_instance_method(box_ty, method, id, args)
.expect(&format!("invoke {}::{}", box_ty, method))
}
fn inv_some(
h: &PluginHost,
box_ty: &str,
method: &str,
id: u32,
args: &[Box<dyn NyashBox>],
) -> Box<dyn NyashBox> {
inv_ok(h, box_ty, method, id, args)
.unwrap_or_else(|| panic!("{}::{} returned None", box_ty, method))
}
fn inv_void(
h: &PluginHost,
box_ty: &str,
method: &str,
id: u32,
args: &[Box<dyn NyashBox>],
) {
let _ = h
.invoke_instance_method(box_ty, method, id, args)
.expect(&format!("invoke {}::{}", box_ty, method));
}
fn ensure_host() {
let _ = crate::runtime::init_global_plugin_host("nyash.toml");
}
fn create_plugin_instance(box_type: &str) -> (String, u32, Box<dyn NyashBox>) {
let host = crate::runtime::get_global_plugin_host();
let host = host.read().unwrap();
let bx = host.create_box(box_type, &[]).expect("create_box");
let bx = with_host(|h| h.create_box(box_type, &[]).expect("create_box"));
// Downcast to PluginBoxV2 to get instance_id
if let Some(p) = bx
.as_any()
@ -30,58 +100,25 @@ mod tests {
#[ignore = "MIR13 parity: MapBox TLV vs TypeBox under unified BoxCall/TypeOp pending"]
fn mapbox_get_set_size_tlv_vs_typebox() {
ensure_host();
let host = crate::runtime::get_global_plugin_host();
// TLV path: disable typebox
env::set_var("NYASH_DISABLE_TYPEBOX", "1");
// TLV path: disable typebox (restored automatically)
let _g = EnvGuard::set("NYASH_DISABLE_TYPEBOX", "1");
let (bt1, id1, _hold1) = create_plugin_instance("MapBox");
let out_tlv = {
let h = host.read().unwrap();
// set("k", 42)
let _ = h
.invoke_instance_method(
&bt1,
"set",
id1,
&[Box::new(StringBox::new("k")), Box::new(IntegerBox::new(42))],
)
.expect("set tlv");
// size()
let sz = h
.invoke_instance_method(&bt1, "size", id1, &[])
.expect("size tlv")
.unwrap();
// get("k")
let gv = h
.invoke_instance_method(&bt1, "get", id1, &[Box::new(StringBox::new("k"))])
.expect("get tlv")
.unwrap();
let out_tlv = with_host(|h| {
inv_void(h, &bt1, "set", id1, &[Box::new(StringBox::new("k")), Box::new(IntegerBox::new(42))]);
let sz = inv_some(h, &bt1, "size", id1, &[]);
let gv = inv_some(h, &bt1, "get", id1, &[Box::new(StringBox::new("k"))]);
(sz.to_string_box().value, gv.to_string_box().value)
};
});
// TypeBox path: enable typebox
env::remove_var("NYASH_DISABLE_TYPEBOX");
let _g2 = EnvGuard::remove("NYASH_DISABLE_TYPEBOX");
let (bt2, id2, _hold2) = create_plugin_instance("MapBox");
let out_tb = {
let h = host.read().unwrap();
let _ = h
.invoke_instance_method(
&bt2,
"set",
id2,
&[Box::new(StringBox::new("k")), Box::new(IntegerBox::new(42))],
)
.expect("set tb");
let sz = h
.invoke_instance_method(&bt2, "size", id2, &[])
.expect("size tb")
.unwrap();
let gv = h
.invoke_instance_method(&bt2, "get", id2, &[Box::new(StringBox::new("k"))])
.expect("get tb")
.unwrap();
let out_tb = with_host(|h| {
inv_void(h, &bt2, "set", id2, &[Box::new(StringBox::new("k")), Box::new(IntegerBox::new(42))]);
let sz = inv_some(h, &bt2, "size", id2, &[]);
let gv = inv_some(h, &bt2, "get", id2, &[Box::new(StringBox::new("k"))]);
(sz.to_string_box().value, gv.to_string_box().value)
};
});
assert_eq!(out_tlv, out_tb, "TLV vs TypeBox results should match");
}
@ -90,53 +127,24 @@ mod tests {
#[ignore = "MIR13 parity: ArrayBox len/get under unified ops pending"]
fn arraybox_set_get_len_tlv_vs_typebox() {
ensure_host();
let host = crate::runtime::get_global_plugin_host();
// TLV path
env::set_var("NYASH_DISABLE_TYPEBOX", "1");
// TLV path (guarded)
let _g = EnvGuard::set("NYASH_DISABLE_TYPEBOX", "1");
let (bt1, id1, _hold1) = create_plugin_instance("ArrayBox");
let out_tlv = {
let h = host.read().unwrap();
let _ = h
.invoke_instance_method(
&bt1,
"set",
id1,
&[Box::new(IntegerBox::new(0)), Box::new(IntegerBox::new(7))],
)
.expect("set tlv");
let ln = h
.invoke_instance_method(&bt1, "len", id1, &[])
.expect("len tlv")
.unwrap();
let gv = h
.invoke_instance_method(&bt1, "get", id1, &[Box::new(IntegerBox::new(0))])
.expect("get tlv")
.unwrap();
let out_tlv = with_host(|h| {
inv_void(h, &bt1, "set", id1, &[Box::new(IntegerBox::new(0)), Box::new(IntegerBox::new(7))]);
let ln = inv_some(h, &bt1, "len", id1, &[]);
let gv = inv_some(h, &bt1, "get", id1, &[Box::new(IntegerBox::new(0))]);
(ln.to_string_box().value, gv.to_string_box().value)
};
// TypeBox path
env::remove_var("NYASH_DISABLE_TYPEBOX");
});
// TypeBox path (guarded)
let _g2 = EnvGuard::remove("NYASH_DISABLE_TYPEBOX");
let (bt2, id2, _hold2) = create_plugin_instance("ArrayBox");
let out_tb = {
let h = host.read().unwrap();
let _ = h
.invoke_instance_method(
&bt2,
"set",
id2,
&[Box::new(IntegerBox::new(0)), Box::new(IntegerBox::new(7))],
)
.expect("set tb");
let ln = h
.invoke_instance_method(&bt2, "length", id2, &[])
.expect("len tb")
.unwrap();
let gv = h
.invoke_instance_method(&bt2, "get", id2, &[Box::new(IntegerBox::new(0))])
.expect("get tb")
.unwrap();
let out_tb = with_host(|h| {
inv_void(h, &bt2, "set", id2, &[Box::new(IntegerBox::new(0)), Box::new(IntegerBox::new(7))]);
let ln = inv_some(h, &bt2, "length", id2, &[]);
let gv = inv_some(h, &bt2, "get", id2, &[Box::new(IntegerBox::new(0))]);
(ln.to_string_box().value, gv.to_string_box().value)
};
});
assert_eq!(
out_tlv, out_tb,
"TLV vs TypeBox results should match (ArrayBox)"
@ -149,36 +157,22 @@ mod tests {
ensure_host();
let host = crate::runtime::get_global_plugin_host();
// TLV path
env::set_var("NYASH_DISABLE_TYPEBOX", "1");
let _g = EnvGuard::set("NYASH_DISABLE_TYPEBOX", "1");
let (bt1, id1, _hold1) = create_plugin_instance("StringBox");
let out_tlv = {
let h = host.read().unwrap();
let out_tlv = with_host(|h| {
// birth with init string: use fromUtf8 via set of arg in create? Current loader birth() no-arg, so concat
let _ = h
.invoke_instance_method(&bt1, "concat", id1, &[Box::new(StringBox::new("ab"))])
.expect("concat tlv")
.unwrap();
let ln = h
.invoke_instance_method(&bt1, "length", id1, &[])
.expect("len tlv")
.unwrap();
inv_void(h, &bt1, "concat", id1, &[Box::new(StringBox::new("ab"))]);
let ln = inv_some(h, &bt1, "length", id1, &[]);
(ln.to_string_box().value)
};
});
// TypeBox path
env::remove_var("NYASH_DISABLE_TYPEBOX");
let _g2 = EnvGuard::remove("NYASH_DISABLE_TYPEBOX");
let (bt2, id2, _hold2) = create_plugin_instance("StringBox");
let out_tb = {
let h = host.read().unwrap();
let _ = h
.invoke_instance_method(&bt2, "concat", id2, &[Box::new(StringBox::new("ab"))])
.expect("concat tb")
.unwrap();
let ln = h
.invoke_instance_method(&bt2, "length", id2, &[])
.expect("len tb")
.unwrap();
let out_tb = with_host(|h| {
inv_void(h, &bt2, "concat", id2, &[Box::new(StringBox::new("ab"))]);
let ln = inv_some(h, &bt2, "length", id2, &[]);
(ln.to_string_box().value)
};
});
assert_eq!(
out_tlv, out_tb,
"TLV vs TypeBox results should match (StringBox)"
@ -191,35 +185,21 @@ mod tests {
ensure_host();
let host = crate::runtime::get_global_plugin_host();
// TLV path
env::set_var("NYASH_DISABLE_TYPEBOX", "1");
let _g = EnvGuard::set("NYASH_DISABLE_TYPEBOX", "1");
let (bt1, id1, _hold1) = create_plugin_instance("IntegerBox");
let out_tlv = {
let h = host.read().unwrap();
let _ = h
.invoke_instance_method(&bt1, "set", id1, &[Box::new(IntegerBox::new(123))])
.expect("set tlv")
.unwrap();
let gv = h
.invoke_instance_method(&bt1, "get", id1, &[])
.expect("get tlv")
.unwrap();
let out_tlv = with_host(|h| {
inv_void(h, &bt1, "set", id1, &[Box::new(IntegerBox::new(123))]);
let gv = inv_some(h, &bt1, "get", id1, &[]);
gv.to_string_box().value
};
});
// TypeBox path
env::remove_var("NYASH_DISABLE_TYPEBOX");
let _g2 = EnvGuard::remove("NYASH_DISABLE_TYPEBOX");
let (bt2, id2, _hold2) = create_plugin_instance("IntegerBox");
let out_tb = {
let h = host.read().unwrap();
let _ = h
.invoke_instance_method(&bt2, "set", id2, &[Box::new(IntegerBox::new(123))])
.expect("set tb")
.unwrap();
let gv = h
.invoke_instance_method(&bt2, "get", id2, &[])
.expect("get tb")
.unwrap();
let out_tb = with_host(|h| {
inv_void(h, &bt2, "set", id2, &[Box::new(IntegerBox::new(123))]);
let gv = inv_some(h, &bt2, "get", id2, &[]);
gv.to_string_box().value
};
});
assert_eq!(
out_tlv, out_tb,
"TLV vs TypeBox results should match (IntegerBox)"
@ -232,25 +212,23 @@ mod tests {
ensure_host();
let host = crate::runtime::get_global_plugin_host();
// TLV path
env::set_var("NYASH_DISABLE_TYPEBOX", "1");
let _g = EnvGuard::set("NYASH_DISABLE_TYPEBOX", "1");
let (bt1, id1, _hold1) = create_plugin_instance("ConsoleBox");
let out_tlv_is_none = {
let h = host.read().unwrap();
let out_tlv_is_none = with_host(|h| {
let rv = h
.invoke_instance_method(&bt1, "println", id1, &[Box::new(StringBox::new("hello"))])
.expect("println tlv");
rv.is_none()
};
});
// TypeBox path
env::remove_var("NYASH_DISABLE_TYPEBOX");
let _g2 = EnvGuard::remove("NYASH_DISABLE_TYPEBOX");
let (bt2, id2, _hold2) = create_plugin_instance("ConsoleBox");
let out_tb_is_none = {
let h = host.read().unwrap();
let out_tb_is_none = with_host(|h| {
let rv = h
.invoke_instance_method(&bt2, "println", id2, &[Box::new(StringBox::new("hello"))])
.expect("println tb");
rv.is_none()
};
});
assert!(
out_tlv_is_none && out_tb_is_none,
"println should return void/None in both modes"
@ -264,62 +242,36 @@ mod tests {
let host = crate::runtime::get_global_plugin_host();
// TLV path
env::set_var("NYASH_DISABLE_TYPEBOX", "1");
let _g = EnvGuard::set("NYASH_DISABLE_TYPEBOX", "1");
let (bt1, id1, _hold1) = create_plugin_instance("MathBox");
let out_tlv = {
let h = host.read().unwrap();
let s1 = h
.invoke_instance_method(&bt1, "sqrt", id1, &[Box::new(IntegerBox::new(9))])
.expect("sqrt tlv")
.unwrap();
let s2 = h
.invoke_instance_method(&bt1, "sin", id1, &[Box::new(IntegerBox::new(0))])
.expect("sin tlv")
.unwrap();
let s3 = h
.invoke_instance_method(&bt1, "cos", id1, &[Box::new(IntegerBox::new(0))])
.expect("cos tlv")
.unwrap();
let s4 = h
.invoke_instance_method(&bt1, "round", id1, &[Box::new(IntegerBox::new(26))])
.expect("round tlv")
.unwrap();
let out_tlv = with_host(|h| {
let s1 = inv_some(h, &bt1, "sqrt", id1, &[Box::new(IntegerBox::new(9))]);
let s2 = inv_some(h, &bt1, "sin", id1, &[Box::new(IntegerBox::new(0))]);
let s3 = inv_some(h, &bt1, "cos", id1, &[Box::new(IntegerBox::new(0))]);
let s4 = inv_some(h, &bt1, "round", id1, &[Box::new(IntegerBox::new(26))]);
(
s1.to_string_box().value,
s2.to_string_box().value,
s3.to_string_box().value,
s4.to_string_box().value,
)
};
});
// TypeBox path
env::remove_var("NYASH_DISABLE_TYPEBOX");
let _g2 = EnvGuard::remove("NYASH_DISABLE_TYPEBOX");
let (bt2, id2, _hold2) = create_plugin_instance("MathBox");
let out_tb = {
let h = host.read().unwrap();
let s1 = h
.invoke_instance_method(&bt2, "sqrt", id2, &[Box::new(IntegerBox::new(9))])
.expect("sqrt tb")
.unwrap();
let s2 = h
.invoke_instance_method(&bt2, "sin", id2, &[Box::new(IntegerBox::new(0))])
.expect("sin tb")
.unwrap();
let s3 = h
.invoke_instance_method(&bt2, "cos", id2, &[Box::new(IntegerBox::new(0))])
.expect("cos tb")
.unwrap();
let s4 = h
.invoke_instance_method(&bt2, "round", id2, &[Box::new(IntegerBox::new(26))])
.expect("round tb")
.unwrap();
let out_tb = with_host(|h| {
let s1 = inv_some(h, &bt2, "sqrt", id2, &[Box::new(IntegerBox::new(9))]);
let s2 = inv_some(h, &bt2, "sin", id2, &[Box::new(IntegerBox::new(0))]);
let s3 = inv_some(h, &bt2, "cos", id2, &[Box::new(IntegerBox::new(0))]);
let s4 = inv_some(h, &bt2, "round", id2, &[Box::new(IntegerBox::new(26))]);
(
s1.to_string_box().value,
s2.to_string_box().value,
s3.to_string_box().value,
s4.to_string_box().value,
)
};
});
assert_eq!(
out_tlv, out_tb,
"TLV vs TypeBox results should match (MathBox)"
@ -341,46 +293,34 @@ mod tests {
};
// TLV path
env::set_var("NYASH_DISABLE_TYPEBOX", "1");
let _g = EnvGuard::set("NYASH_DISABLE_TYPEBOX", "1");
let (bt1, id1, _hold1) = create_plugin_instance("EncodingBox");
let out_tlv = {
let h = host.read().unwrap();
let b64 = h
.invoke_instance_method(
&bt1,
"base64Encode",
id1,
&[Box::new(StringBox::new("hi"))],
)
.expect("b64 tlv")
.unwrap();
let hex = h
.invoke_instance_method(&bt1, "hexEncode", id1, &[Box::new(StringBox::new("hi"))])
.expect("hex tlv")
.unwrap();
let out_tlv = with_host(|h| {
let b64 = inv_some(
h,
&bt1,
"base64Encode",
id1,
&[Box::new(StringBox::new("hi"))],
);
let hex = inv_some(h, &bt1, "hexEncode", id1, &[Box::new(StringBox::new("hi"))]);
(b64.to_string_box().value, hex.to_string_box().value)
};
});
// TypeBox path
env::remove_var("NYASH_DISABLE_TYPEBOX");
let _g2 = EnvGuard::remove("NYASH_DISABLE_TYPEBOX");
let (bt2, id2, _hold2) = create_plugin_instance("EncodingBox");
let out_tb = {
let h = host.read().unwrap();
let b64 = h
.invoke_instance_method(
&bt2,
"base64Encode",
id2,
&[Box::new(StringBox::new("hi"))],
)
.expect("b64 tb")
.unwrap();
let hex = h
.invoke_instance_method(&bt2, "hexEncode", id2, &[Box::new(StringBox::new("hi"))])
.expect("hex tb")
.unwrap();
let out_tb = with_host(|h| {
let b64 = inv_some(
h,
&bt2,
"base64Encode",
id2,
&[Box::new(StringBox::new("hi"))],
);
let hex = inv_some(h, &bt2, "hexEncode", id2, &[Box::new(StringBox::new("hi"))]);
(b64.to_string_box().value, hex.to_string_box().value)
};
});
assert_eq!(
out_tlv, out_tb,
"TLV vs TypeBox results should match (EncodingBox)"
@ -394,42 +334,24 @@ mod tests {
let host = crate::runtime::get_global_plugin_host();
// TLV path
env::set_var("NYASH_DISABLE_TYPEBOX", "1");
let _g = EnvGuard::set("NYASH_DISABLE_TYPEBOX", "1");
let (bt1, id1, _hold1) = create_plugin_instance("RegexBox");
let out_tlv = {
let h = host.read().unwrap();
let _ = h
.invoke_instance_method(&bt1, "compile", id1, &[Box::new(StringBox::new("h.+o"))])
.expect("compile tlv");
let m = h
.invoke_instance_method(&bt1, "isMatch", id1, &[Box::new(StringBox::new("hello"))])
.expect("isMatch tlv")
.unwrap();
let f = h
.invoke_instance_method(&bt1, "find", id1, &[Box::new(StringBox::new("hello"))])
.expect("find tlv")
.unwrap();
let out_tlv = with_host(|h| {
inv_void(h, &bt1, "compile", id1, &[Box::new(StringBox::new("h.+o"))]);
let m = inv_some(h, &bt1, "isMatch", id1, &[Box::new(StringBox::new("hello"))]);
let f = inv_some(h, &bt1, "find", id1, &[Box::new(StringBox::new("hello"))]);
(m.to_string_box().value, f.to_string_box().value)
};
});
// TypeBox path
env::remove_var("NYASH_DISABLE_TYPEBOX");
let _g2 = EnvGuard::remove("NYASH_DISABLE_TYPEBOX");
let (bt2, id2, _hold2) = create_plugin_instance("RegexBox");
let out_tb = {
let h = host.read().unwrap();
let _ = h
.invoke_instance_method(&bt2, "compile", id2, &[Box::new(StringBox::new("h.+o"))])
.expect("compile tb");
let m = h
.invoke_instance_method(&bt2, "isMatch", id2, &[Box::new(StringBox::new("hello"))])
.expect("isMatch tb")
.unwrap();
let f = h
.invoke_instance_method(&bt2, "find", id2, &[Box::new(StringBox::new("hello"))])
.expect("find tb")
.unwrap();
let out_tb = with_host(|h| {
inv_void(h, &bt2, "compile", id2, &[Box::new(StringBox::new("h.+o"))]);
let m = inv_some(h, &bt2, "isMatch", id2, &[Box::new(StringBox::new("hello"))]);
let f = inv_some(h, &bt2, "find", id2, &[Box::new(StringBox::new("hello"))]);
(m.to_string_box().value, f.to_string_box().value)
};
});
assert_eq!(
out_tlv, out_tb,
"TLV vs TypeBox results should match (RegexBox)"
@ -443,108 +365,66 @@ mod tests {
let host = crate::runtime::get_global_plugin_host();
// TLV path
env::set_var("NYASH_DISABLE_TYPEBOX", "1");
let _g = EnvGuard::set("NYASH_DISABLE_TYPEBOX", "1");
let (bt1, id1, _hold1) = create_plugin_instance("PathBox");
let out_tlv = {
let h = host.read().unwrap();
let j = h
.invoke_instance_method(
&bt1,
"join",
id1,
&[
Box::new(StringBox::new("/a/b")),
Box::new(StringBox::new("c.txt")),
],
)
.expect("join tlv")
.unwrap();
let d = h
.invoke_instance_method(
&bt1,
"dirname",
id1,
&[Box::new(StringBox::new("/a/b/c.txt"))],
)
.expect("dirname tlv")
.unwrap();
let b = h
.invoke_instance_method(
&bt1,
"basename",
id1,
&[Box::new(StringBox::new("/a/b/c.txt"))],
)
.expect("basename tlv")
.unwrap();
let n = h
.invoke_instance_method(
&bt1,
"normalize",
id1,
&[Box::new(StringBox::new("/a/./b/../b/c"))],
)
.expect("normalize tlv")
.unwrap();
let out_tlv = with_host(|h| {
let j = inv_some(
h,
&bt1,
"join",
id1,
&[
Box::new(StringBox::new("/a/b")),
Box::new(StringBox::new("c.txt")),
],
);
let d = inv_some(h, &bt1, "dirname", id1, &[Box::new(StringBox::new("/a/b/c.txt"))]);
let b = inv_some(h, &bt1, "basename", id1, &[Box::new(StringBox::new("/a/b/c.txt"))]);
let n = inv_some(
h,
&bt1,
"normalize",
id1,
&[Box::new(StringBox::new("/a/./b/../b/c"))],
);
(
j.to_string_box().value,
d.to_string_box().value,
b.to_string_box().value,
n.to_string_box().value,
)
};
});
// TypeBox path
env::remove_var("NYASH_DISABLE_TYPEBOX");
let _g2 = EnvGuard::remove("NYASH_DISABLE_TYPEBOX");
let (bt2, id2, _hold2) = create_plugin_instance("PathBox");
let out_tb = {
let h = host.read().unwrap();
let j = h
.invoke_instance_method(
&bt2,
"join",
id2,
&[
Box::new(StringBox::new("/a/b")),
Box::new(StringBox::new("c.txt")),
],
)
.expect("join tb")
.unwrap();
let d = h
.invoke_instance_method(
&bt2,
"dirname",
id2,
&[Box::new(StringBox::new("/a/b/c.txt"))],
)
.expect("dirname tb")
.unwrap();
let b = h
.invoke_instance_method(
&bt2,
"basename",
id2,
&[Box::new(StringBox::new("/a/b/c.txt"))],
)
.expect("basename tb")
.unwrap();
let n = h
.invoke_instance_method(
&bt2,
"normalize",
id2,
&[Box::new(StringBox::new("/a/./b/../b/c"))],
)
.expect("normalize tb")
.unwrap();
let out_tb = with_host(|h| {
let j = inv_some(
h,
&bt2,
"join",
id2,
&[
Box::new(StringBox::new("/a/b")),
Box::new(StringBox::new("c.txt")),
],
);
let d = inv_some(h, &bt2, "dirname", id2, &[Box::new(StringBox::new("/a/b/c.txt"))]);
let b = inv_some(h, &bt2, "basename", id2, &[Box::new(StringBox::new("/a/b/c.txt"))]);
let n = inv_some(
h,
&bt2,
"normalize",
id2,
&[Box::new(StringBox::new("/a/./b/../b/c"))],
);
(
j.to_string_box().value,
d.to_string_box().value,
b.to_string_box().value,
n.to_string_box().value,
)
};
});
assert_eq!(
out_tlv, out_tb,
"TLV vs TypeBox results should match (PathBox)"
@ -559,54 +439,48 @@ mod tests {
let toml_text = "[package]\nname=\"nyash\"\n[deps]\nregex=\"1\"\n";
// TLV path
env::set_var("NYASH_DISABLE_TYPEBOX", "1");
let _g = EnvGuard::set("NYASH_DISABLE_TYPEBOX", "1");
let (bt1, id1, _hold1) = create_plugin_instance("TOMLBox");
let out_tlv = {
let h = host.read().unwrap();
let _ = h
.invoke_instance_method(&bt1, "parse", id1, &[Box::new(StringBox::new(toml_text))])
.expect("parse tlv")
.unwrap();
let name = h
.invoke_instance_method(
&bt1,
"get",
id1,
&[Box::new(StringBox::new("package.name"))],
)
.expect("get tlv")
.unwrap();
let json = h
.invoke_instance_method(&bt1, "toJson", id1, &[])
.expect("toJson tlv")
.unwrap();
let out_tlv = with_host(|h| {
inv_void(
h,
&bt1,
"parse",
id1,
&[Box::new(StringBox::new(toml_text))],
);
let name = inv_some(
h,
&bt1,
"get",
id1,
&[Box::new(StringBox::new("package.name"))],
);
let json = inv_some(h, &bt1, "toJson", id1, &[]);
(name.to_string_box().value, json.to_string_box().value)
};
});
// TypeBox path
env::remove_var("NYASH_DISABLE_TYPEBOX");
let _g2 = EnvGuard::remove("NYASH_DISABLE_TYPEBOX");
let (bt2, id2, _hold2) = create_plugin_instance("TOMLBox");
let out_tb = {
let h = host.read().unwrap();
let _ = h
.invoke_instance_method(&bt2, "parse", id2, &[Box::new(StringBox::new(toml_text))])
.expect("parse tb")
.unwrap();
let name = h
.invoke_instance_method(
&bt2,
"get",
id2,
&[Box::new(StringBox::new("package.name"))],
)
.expect("get tb")
.unwrap();
let json = h
.invoke_instance_method(&bt2, "toJson", id2, &[])
.expect("toJson tb")
.unwrap();
let out_tb = with_host(|h| {
inv_void(
h,
&bt2,
"parse",
id2,
&[Box::new(StringBox::new(toml_text))],
);
let name = inv_some(
h,
&bt2,
"get",
id2,
&[Box::new(StringBox::new("package.name"))],
);
let json = inv_some(h, &bt2, "toJson", id2, &[]);
(name.to_string_box().value, json.to_string_box().value)
};
});
assert_eq!(
out_tlv, out_tb,
"TLV vs TypeBox results should match (TOMLBox)"
@ -620,28 +494,20 @@ mod tests {
let host = crate::runtime::get_global_plugin_host();
// TLV path
env::set_var("NYASH_DISABLE_TYPEBOX", "1");
let _g = EnvGuard::set("NYASH_DISABLE_TYPEBOX", "1");
let (bt1, id1, _hold1) = create_plugin_instance("TimeBox");
let t_tlv = {
let h = host.read().unwrap();
let v = h
.invoke_instance_method(&bt1, "now", id1, &[])
.expect("now tlv")
.unwrap();
let t_tlv = with_host(|h| {
let v = inv_some(h, &bt1, "now", id1, &[]);
v.to_string_box().value.parse::<i64>().unwrap_or(0)
};
});
// TypeBox path
env::remove_var("NYASH_DISABLE_TYPEBOX");
let _g2 = EnvGuard::remove("NYASH_DISABLE_TYPEBOX");
let (bt2, id2, _hold2) = create_plugin_instance("TimeBox");
let t_tb = {
let h = host.read().unwrap();
let v = h
.invoke_instance_method(&bt2, "now", id2, &[])
.expect("now tb")
.unwrap();
let t_tb = with_host(|h| {
let v = inv_some(h, &bt2, "now", id2, &[]);
v.to_string_box().value.parse::<i64>().unwrap_or(0)
};
});
let diff = (t_tb - t_tlv).abs();
assert!(diff < 5_000, "TimeBox.now difference too large: {}ms", diff);
@ -654,49 +520,31 @@ mod tests {
let host = crate::runtime::get_global_plugin_host();
// TLV path: verify get->inc->get increases by 1
env::set_var("NYASH_DISABLE_TYPEBOX", "1");
let _g = EnvGuard::set("NYASH_DISABLE_TYPEBOX", "1");
let (bt1, id1, _hold1) = create_plugin_instance("CounterBox");
let (a1, b1) = {
let h = host.read().unwrap();
let a = h
.invoke_instance_method(&bt1, "get", id1, &[])
.expect("get tlv")
.unwrap();
let _ = h
.invoke_instance_method(&bt1, "inc", id1, &[])
.expect("inc tlv");
let b = h
.invoke_instance_method(&bt1, "get", id1, &[])
.expect("get2 tlv")
.unwrap();
let (a1, b1) = with_host(|h| {
let a = inv_some(h, &bt1, "get", id1, &[]);
inv_void(h, &bt1, "inc", id1, &[]);
let b = inv_some(h, &bt1, "get", id1, &[]);
(
a.to_string_box().value.parse::<i64>().unwrap_or(0),
b.to_string_box().value.parse::<i64>().unwrap_or(0),
)
};
});
assert_eq!(b1 - a1, 1, "CounterBox TLV should increment by 1");
// TypeBox path: verify same delta behavior (not comparing absolute values due to singleton)
env::remove_var("NYASH_DISABLE_TYPEBOX");
let _g2 = EnvGuard::remove("NYASH_DISABLE_TYPEBOX");
let (bt2, id2, _hold2) = create_plugin_instance("CounterBox");
let (a2, b2) = {
let h = host.read().unwrap();
let a = h
.invoke_instance_method(&bt2, "get", id2, &[])
.expect("get tb")
.unwrap();
let _ = h
.invoke_instance_method(&bt2, "inc", id2, &[])
.expect("inc tb");
let b = h
.invoke_instance_method(&bt2, "get", id2, &[])
.expect("get2 tb")
.unwrap();
let (a2, b2) = with_host(|h| {
let a = inv_some(h, &bt2, "get", id2, &[]);
inv_void(h, &bt2, "inc", id2, &[]);
let b = inv_some(h, &bt2, "get", id2, &[]);
(
a.to_string_box().value.parse::<i64>().unwrap_or(0),
b.to_string_box().value.parse::<i64>().unwrap_or(0),
)
};
});
assert_eq!(b2 - a2, 1, "CounterBox TypeBox should increment by 1");
}
@ -718,8 +566,7 @@ mod tests {
// TLV path
env::set_var("NYASH_DISABLE_TYPEBOX", "1");
let (bt1, id1, _hold1) = create_plugin_instance("FileBox");
let out_tlv = {
let h = host.read().unwrap();
let out_tlv = with_host(|h| {
let _ = h
.invoke_instance_method(
&bt1,
@ -749,21 +596,17 @@ mod tests {
],
)
.expect("open2 tlv");
let rd = h
.invoke_instance_method(&bt1, "read", id1, &[])
.expect("read tlv")
.unwrap();
let rd = inv_some(h, &bt1, "read", id1, &[]);
let _ = h
.invoke_instance_method(&bt1, "close", id1, &[])
.expect("close2 tlv");
rd.to_string_box().value
};
});
// TypeBox path
env::remove_var("NYASH_DISABLE_TYPEBOX");
let _g2 = EnvGuard::remove("NYASH_DISABLE_TYPEBOX");
let (bt2, id2, _hold2) = create_plugin_instance("FileBox");
let out_tb = {
let h = host.read().unwrap();
let out_tb = with_host(|h| {
let _ = h
.invoke_instance_method(
&bt2,
@ -792,15 +635,12 @@ mod tests {
],
)
.expect("open2 tb");
let rd = h
.invoke_instance_method(&bt2, "read", id2, &[])
.expect("read tb")
.unwrap();
let rd = inv_some(h, &bt2, "read", id2, &[]);
let _ = h
.invoke_instance_method(&bt2, "close", id2, &[])
.expect("close2 tb");
rd.to_string_box().value
};
});
// Cleanup best-effort
let _ = fs::remove_file(&path_str);
@ -813,7 +653,9 @@ mod tests {
fn rand_id() -> u64 {
use std::time::{SystemTime, UNIX_EPOCH};
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("SystemTime before UNIX_EPOCH");
now.as_micros() as u64
}
}