chore(fmt): add legacy stubs and strip trailing whitespace to unblock cargo fmt
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
use crate::bid::{BidResult, BidError};
|
||||
use crate::bid::{BidError, BidResult};
|
||||
|
||||
// Minimal helpers to keep loader.rs lean and consistent
|
||||
#[inline]
|
||||
@ -12,5 +12,6 @@ pub fn from_toml<T>(_r: Result<T, toml::de::Error>) -> BidResult<T> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn or_plugin_err<T>(opt: Option<T>) -> BidResult<T> { opt.ok_or(BidError::PluginError) }
|
||||
|
||||
pub fn or_plugin_err<T>(opt: Option<T>) -> BidResult<T> {
|
||||
opt.ok_or(BidError::PluginError)
|
||||
}
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
use super::loader::PluginLoaderV2;
|
||||
use crate::bid::{BidResult};
|
||||
use crate::bid::BidResult;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
static GLOBAL_LOADER_V2: Lazy<Arc<RwLock<PluginLoaderV2>>> =
|
||||
Lazy::new(|| Arc::new(RwLock::new(PluginLoaderV2::new())));
|
||||
|
||||
pub fn get_global_loader_v2() -> Arc<RwLock<PluginLoaderV2>> { GLOBAL_LOADER_V2.clone() }
|
||||
pub fn get_global_loader_v2() -> Arc<RwLock<PluginLoaderV2>> {
|
||||
GLOBAL_LOADER_V2.clone()
|
||||
}
|
||||
|
||||
pub fn init_global_loader_v2(config_path: &str) -> BidResult<()> {
|
||||
let loader = get_global_loader_v2();
|
||||
@ -24,4 +26,3 @@ pub fn shutdown_plugins_v2() -> BidResult<()> {
|
||||
loader.shutdown_singletons();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
// Host bridge helpers for TypeBox invoke (minimal, v2)
|
||||
|
||||
pub type InvokeFn = unsafe extern "C" fn(u32, u32, u32, *const u8, usize, *mut u8, *mut usize) -> i32;
|
||||
pub type InvokeFn =
|
||||
unsafe extern "C" fn(u32, u32, u32, *const u8, usize, *mut u8, *mut usize) -> i32;
|
||||
|
||||
// Call invoke_id with a temporary output buffer; returns (code, bytes_written, buffer)
|
||||
pub fn invoke_alloc(
|
||||
@ -25,4 +26,3 @@ pub fn invoke_alloc(
|
||||
};
|
||||
(code, out_len, out)
|
||||
}
|
||||
|
||||
|
||||
@ -1,14 +1,16 @@
|
||||
use super::types::{PluginBoxMetadata, PluginBoxV2, PluginHandleInner, LoadedPluginV2};
|
||||
use crate::bid::{BidResult, BidError};
|
||||
use super::types::{LoadedPluginV2, PluginBoxMetadata, PluginBoxV2, PluginHandleInner};
|
||||
use crate::bid::{BidError, BidResult};
|
||||
use crate::box_trait::NyashBox;
|
||||
use crate::config::nyash_toml_v2::{NyashConfigV2, LibraryDefinition};
|
||||
use crate::config::nyash_toml_v2::{LibraryDefinition, NyashConfigV2};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use libloading::{Library, Symbol};
|
||||
|
||||
fn dbg_on() -> bool { std::env::var("NYASH_DEBUG_PLUGIN").unwrap_or_default() == "1" }
|
||||
fn dbg_on() -> bool {
|
||||
std::env::var("NYASH_DEBUG_PLUGIN").unwrap_or_default() == "1"
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
struct LoadedBoxSpec {
|
||||
@ -17,14 +19,17 @@ struct LoadedBoxSpec {
|
||||
fini_method_id: Option<u32>,
|
||||
}
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct MethodSpec { method_id: u32, returns_result: bool }
|
||||
struct MethodSpec {
|
||||
method_id: u32,
|
||||
returns_result: bool,
|
||||
}
|
||||
|
||||
pub struct PluginLoaderV2 {
|
||||
pub(super) plugins: RwLock<HashMap<String, Arc<LoadedPluginV2>>>,
|
||||
pub config: Option<NyashConfigV2>,
|
||||
pub(super) config_path: Option<String>,
|
||||
pub(super) singletons: RwLock<HashMap<(String,String), Arc<PluginHandleInner>>>,
|
||||
pub(super) box_specs: RwLock<HashMap<(String,String), LoadedBoxSpec>>,
|
||||
pub(super) singletons: RwLock<HashMap<(String, String), Arc<PluginHandleInner>>>,
|
||||
pub(super) box_specs: RwLock<HashMap<(String, String), LoadedBoxSpec>>,
|
||||
}
|
||||
|
||||
impl PluginLoaderV2 {
|
||||
@ -39,12 +44,19 @@ impl PluginLoaderV2 {
|
||||
}
|
||||
|
||||
pub fn load_config(&mut self, config_path: &str) -> BidResult<()> {
|
||||
let canonical = std::fs::canonicalize(config_path).map(|p| p.to_string_lossy().to_string()).unwrap_or_else(|_| config_path.to_string());
|
||||
let canonical = std::fs::canonicalize(config_path)
|
||||
.map(|p| p.to_string_lossy().to_string())
|
||||
.unwrap_or_else(|_| config_path.to_string());
|
||||
self.config_path = Some(canonical.clone());
|
||||
self.config = Some(NyashConfigV2::from_file(&canonical).map_err(|_| BidError::PluginError)?);
|
||||
self.config =
|
||||
Some(NyashConfigV2::from_file(&canonical).map_err(|_| BidError::PluginError)?);
|
||||
if let Some(cfg) = self.config.as_ref() {
|
||||
let mut labels: Vec<String> = Vec::new();
|
||||
for (_lib, def) in &cfg.libraries { for bt in &def.boxes { labels.push(format!("BoxRef:{}", bt)); } }
|
||||
for (_lib, def) in &cfg.libraries {
|
||||
for bt in &def.boxes {
|
||||
labels.push(format!("BoxRef:{}", bt));
|
||||
}
|
||||
}
|
||||
crate::runtime::cache_versions::bump_many(&labels);
|
||||
}
|
||||
Ok(())
|
||||
@ -52,8 +64,12 @@ impl PluginLoaderV2 {
|
||||
|
||||
pub fn load_all_plugins(&self) -> BidResult<()> {
|
||||
let config = self.config.as_ref().ok_or(BidError::PluginError)?;
|
||||
for (lib_name, lib_def) in &config.libraries { let _ = self.load_plugin(lib_name, lib_def); }
|
||||
for (plugin_name, root) in &config.plugins { let _ = self.load_plugin_from_root(plugin_name, root); }
|
||||
for (lib_name, lib_def) in &config.libraries {
|
||||
let _ = self.load_plugin(lib_name, lib_def);
|
||||
}
|
||||
for (plugin_name, root) in &config.plugins {
|
||||
let _ = self.load_plugin_from_root(plugin_name, root);
|
||||
}
|
||||
self.prebirth_singletons()?;
|
||||
Ok(())
|
||||
}
|
||||
@ -88,24 +104,38 @@ impl PluginLoaderV2 {
|
||||
if let Some(fname) = c.file_name().and_then(|s| s.to_str()) {
|
||||
if let Some(resolved) = cfg.resolve_plugin_path(fname) {
|
||||
let pb = PathBuf::from(resolved);
|
||||
if pb.exists() { lib_path = Some(pb); break; }
|
||||
if pb.exists() {
|
||||
lib_path = Some(pb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let lib_path = lib_path.unwrap_or_else(|| base.to_path_buf());
|
||||
if dbg_on() { eprintln!("[PluginLoaderV2] load_plugin: lib='{}' path='{}'", lib_name, lib_path.display()); }
|
||||
if dbg_on() {
|
||||
eprintln!(
|
||||
"[PluginLoaderV2] load_plugin: lib='{}' path='{}'",
|
||||
lib_name,
|
||||
lib_path.display()
|
||||
);
|
||||
}
|
||||
let lib = unsafe { Library::new(&lib_path) }.map_err(|_| BidError::PluginError)?;
|
||||
let lib_arc = Arc::new(lib);
|
||||
|
||||
// Resolve required invoke symbol (TypeBox v2: nyash_plugin_invoke)
|
||||
unsafe {
|
||||
let invoke_sym: Symbol<unsafe extern "C" fn(u32,u32,u32,*const u8,usize,*mut u8,*mut usize) -> i32> =
|
||||
lib_arc.get(b"nyash_plugin_invoke\0").map_err(|_| BidError::PluginError)?;
|
||||
let invoke_sym: Symbol<
|
||||
unsafe extern "C" fn(u32, u32, u32, *const u8, usize, *mut u8, *mut usize) -> i32,
|
||||
> = lib_arc
|
||||
.get(b"nyash_plugin_invoke\0")
|
||||
.map_err(|_| BidError::PluginError)?;
|
||||
|
||||
// Optional init (best-effort)
|
||||
if let Ok(init_sym) = lib_arc.get::<Symbol<unsafe extern "C" fn() -> i32>>(b"nyash_plugin_init\0") {
|
||||
if let Ok(init_sym) =
|
||||
lib_arc.get::<Symbol<unsafe extern "C" fn() -> i32>>(b"nyash_plugin_init\0")
|
||||
{
|
||||
let _ = init_sym();
|
||||
}
|
||||
|
||||
@ -116,13 +146,18 @@ impl PluginLoaderV2 {
|
||||
init_fn: None,
|
||||
invoke_fn: *invoke_sym,
|
||||
};
|
||||
self.plugins.write().map_err(|_| BidError::PluginError)?.insert(lib_name.to_string(), Arc::new(loaded));
|
||||
self.plugins
|
||||
.write()
|
||||
.map_err(|_| BidError::PluginError)?
|
||||
.insert(lib_name.to_string(), Arc::new(loaded));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn load_plugin_from_root(&self, _plugin_name: &str, _root: &str) -> BidResult<()> { Ok(()) }
|
||||
fn load_plugin_from_root(&self, _plugin_name: &str, _root: &str) -> BidResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn prebirth_singletons(&self) -> BidResult<()> {
|
||||
let config = self.config.as_ref().ok_or(BidError::PluginError)?;
|
||||
@ -131,16 +166,29 @@ impl PluginLoaderV2 {
|
||||
let toml_value: toml::Value = super::errors::from_toml(toml::from_str(&toml_content))?;
|
||||
for (lib_name, lib_def) in &config.libraries {
|
||||
for box_name in &lib_def.boxes {
|
||||
if let Some(bc) = config.get_box_config(lib_name, box_name, &toml_value) { if bc.singleton { let _ = self.ensure_singleton_handle(lib_name, box_name); } }
|
||||
if let Some(bc) = config.get_box_config(lib_name, box_name, &toml_value) {
|
||||
if bc.singleton {
|
||||
let _ = self.ensure_singleton_handle(lib_name, box_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn find_box_by_type_id<'a>(&'a self, config: &'a NyashConfigV2, toml_value: &'a toml::Value, type_id: u32) -> Option<(&'a str, &'a str)> {
|
||||
fn find_box_by_type_id<'a>(
|
||||
&'a self,
|
||||
config: &'a NyashConfigV2,
|
||||
toml_value: &'a toml::Value,
|
||||
type_id: u32,
|
||||
) -> Option<(&'a str, &'a str)> {
|
||||
for (lib_name, lib_def) in &config.libraries {
|
||||
for box_name in &lib_def.boxes {
|
||||
if let Some(box_conf) = config.get_box_config(lib_name, box_name, toml_value) { if box_conf.type_id == type_id { return Some((lib_name.as_str(), box_name.as_str())); } }
|
||||
if let Some(box_conf) = config.get_box_config(lib_name, box_name, toml_value) {
|
||||
if box_conf.type_id == type_id {
|
||||
return Some((lib_name.as_str(), box_name.as_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
@ -160,12 +208,18 @@ impl PluginLoaderV2 {
|
||||
let mut resolved_type = type_id;
|
||||
let mut fini_method = None;
|
||||
if let Some(spec) = self.box_specs.read().ok()?.get(&spec_key).cloned() {
|
||||
if let Some(tid) = spec.type_id { resolved_type = tid; }
|
||||
if let Some(fini) = spec.fini_method_id { fini_method = Some(fini); }
|
||||
if let Some(tid) = spec.type_id {
|
||||
resolved_type = tid;
|
||||
}
|
||||
if let Some(fini) = spec.fini_method_id {
|
||||
fini_method = Some(fini);
|
||||
}
|
||||
}
|
||||
if resolved_type == type_id || fini_method.is_none() {
|
||||
if let Some(cfg) = config.get_box_config(lib_name, box_type, &toml_value) {
|
||||
if resolved_type == type_id { resolved_type = cfg.type_id; }
|
||||
if resolved_type == type_id {
|
||||
resolved_type = cfg.type_id;
|
||||
}
|
||||
if fini_method.is_none() {
|
||||
fini_method = cfg.methods.get("fini").map(|m| m.method_id);
|
||||
}
|
||||
@ -180,7 +234,11 @@ impl PluginLoaderV2 {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn construct_existing_instance(&self, type_id: u32, instance_id: u32) -> Option<Box<dyn NyashBox>> {
|
||||
pub fn construct_existing_instance(
|
||||
&self,
|
||||
type_id: u32,
|
||||
instance_id: u32,
|
||||
) -> Option<Box<dyn NyashBox>> {
|
||||
let config = self.config.as_ref()?;
|
||||
let cfg_path = self.config_path.as_ref()?;
|
||||
let toml_str = std::fs::read_to_string(cfg_path).ok()?;
|
||||
@ -188,42 +246,122 @@ impl PluginLoaderV2 {
|
||||
let (lib_name, box_type) = self.find_box_by_type_id(config, &toml_value, type_id)?;
|
||||
let plugins = self.plugins.read().ok()?;
|
||||
let plugin = plugins.get(lib_name)?.clone();
|
||||
let fini_method_id = if let Some(spec) = self.box_specs.read().ok()?.get(&(lib_name.to_string(), box_type.to_string())) { spec.fini_method_id } else { let box_conf = config.get_box_config(lib_name, box_type, &toml_value)?; box_conf.methods.get("fini").map(|m| m.method_id) };
|
||||
let bx = super::types::construct_plugin_box(box_type.to_string(), type_id, plugin.invoke_fn, instance_id, fini_method_id);
|
||||
let fini_method_id = if let Some(spec) = self
|
||||
.box_specs
|
||||
.read()
|
||||
.ok()?
|
||||
.get(&(lib_name.to_string(), box_type.to_string()))
|
||||
{
|
||||
spec.fini_method_id
|
||||
} else {
|
||||
let box_conf = config.get_box_config(lib_name, box_type, &toml_value)?;
|
||||
box_conf.methods.get("fini").map(|m| m.method_id)
|
||||
};
|
||||
let bx = super::types::construct_plugin_box(
|
||||
box_type.to_string(),
|
||||
type_id,
|
||||
plugin.invoke_fn,
|
||||
instance_id,
|
||||
fini_method_id,
|
||||
);
|
||||
Some(Box::new(bx))
|
||||
}
|
||||
|
||||
fn find_lib_name_for_box(&self, box_type: &str) -> Option<String> {
|
||||
if let Some(cfg) = &self.config { if let Some((name, _)) = cfg.find_library_for_box(box_type) { return Some(name.to_string()); } }
|
||||
for ((lib, b), _) in self.box_specs.read().unwrap().iter() { if b == box_type { return Some(lib.clone()); } }
|
||||
if let Some(cfg) = &self.config {
|
||||
if let Some((name, _)) = cfg.find_library_for_box(box_type) {
|
||||
return Some(name.to_string());
|
||||
}
|
||||
}
|
||||
for ((lib, b), _) in self.box_specs.read().unwrap().iter() {
|
||||
if b == box_type {
|
||||
return Some(lib.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn ensure_singleton_handle(&self, lib_name: &str, box_type: &str) -> BidResult<()> {
|
||||
if self.singletons.read().unwrap().contains_key(&(lib_name.to_string(), box_type.to_string())) { return Ok(()); }
|
||||
if self
|
||||
.singletons
|
||||
.read()
|
||||
.unwrap()
|
||||
.contains_key(&(lib_name.to_string(), box_type.to_string()))
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
let cfg_path = self.config_path.as_deref().unwrap_or("nyash.toml");
|
||||
let toml_value: toml::Value = toml::from_str(&std::fs::read_to_string(cfg_path).map_err(|_| BidError::PluginError)?).map_err(|_| BidError::PluginError)?;
|
||||
let toml_value: toml::Value =
|
||||
toml::from_str(&std::fs::read_to_string(cfg_path).map_err(|_| BidError::PluginError)?)
|
||||
.map_err(|_| BidError::PluginError)?;
|
||||
let config = self.config.as_ref().ok_or(BidError::PluginError)?;
|
||||
let plugins = self.plugins.read().unwrap();
|
||||
let plugin = plugins.get(lib_name).ok_or(BidError::PluginError)?;
|
||||
let type_id = if let Some(spec) = self.box_specs.read().unwrap().get(&(lib_name.to_string(), box_type.to_string())) { spec.type_id.unwrap_or_else(|| config.box_types.get(box_type).copied().unwrap_or(0)) } else { let box_conf = config.get_box_config(lib_name, box_type, &toml_value).ok_or(BidError::InvalidType)?; box_conf.type_id };
|
||||
let type_id = if let Some(spec) = self
|
||||
.box_specs
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(&(lib_name.to_string(), box_type.to_string()))
|
||||
{
|
||||
spec.type_id
|
||||
.unwrap_or_else(|| config.box_types.get(box_type).copied().unwrap_or(0))
|
||||
} else {
|
||||
let box_conf = config
|
||||
.get_box_config(lib_name, box_type, &toml_value)
|
||||
.ok_or(BidError::InvalidType)?;
|
||||
box_conf.type_id
|
||||
};
|
||||
let out = vec![0u8; 1024];
|
||||
let out_len = out.len();
|
||||
let tlv_args = crate::runtime::plugin_ffi_common::encode_empty_args();
|
||||
let (birth_result, _len, out_vec) = super::host_bridge::invoke_alloc(plugin.invoke_fn, type_id, 0, 0, &tlv_args);
|
||||
let (birth_result, _len, out_vec) =
|
||||
super::host_bridge::invoke_alloc(plugin.invoke_fn, type_id, 0, 0, &tlv_args);
|
||||
let out = out_vec;
|
||||
if birth_result != 0 || out_len < 4 { return Err(BidError::PluginError); }
|
||||
if birth_result != 0 || out_len < 4 {
|
||||
return Err(BidError::PluginError);
|
||||
}
|
||||
let instance_id = u32::from_le_bytes([out[0], out[1], out[2], out[3]]);
|
||||
let fini_id = if let Some(spec) = self.box_specs.read().unwrap().get(&(lib_name.to_string(), box_type.to_string())) { spec.fini_method_id } else { let box_conf = config.get_box_config(lib_name, box_type, &toml_value).ok_or(BidError::InvalidType)?; box_conf.methods.get("fini").map(|m| m.method_id) };
|
||||
let handle = Arc::new(PluginHandleInner { type_id, invoke_fn: plugin.invoke_fn, instance_id, fini_method_id: fini_id, finalized: std::sync::atomic::AtomicBool::new(false) });
|
||||
self.singletons.write().unwrap().insert((lib_name.to_string(), box_type.to_string()), handle);
|
||||
let fini_id = if let Some(spec) = self
|
||||
.box_specs
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(&(lib_name.to_string(), box_type.to_string()))
|
||||
{
|
||||
spec.fini_method_id
|
||||
} else {
|
||||
let box_conf = config
|
||||
.get_box_config(lib_name, box_type, &toml_value)
|
||||
.ok_or(BidError::InvalidType)?;
|
||||
box_conf.methods.get("fini").map(|m| m.method_id)
|
||||
};
|
||||
let handle = Arc::new(PluginHandleInner {
|
||||
type_id,
|
||||
invoke_fn: plugin.invoke_fn,
|
||||
instance_id,
|
||||
fini_method_id: fini_id,
|
||||
finalized: std::sync::atomic::AtomicBool::new(false),
|
||||
});
|
||||
self.singletons
|
||||
.write()
|
||||
.unwrap()
|
||||
.insert((lib_name.to_string(), box_type.to_string()), handle);
|
||||
crate::runtime::cache_versions::bump_version(&format!("BoxRef:{}", box_type));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn extern_call(&self, iface_name: &str, method_name: &str, args: &[Box<dyn NyashBox>]) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
pub fn extern_call(
|
||||
&self,
|
||||
iface_name: &str,
|
||||
method_name: &str,
|
||||
args: &[Box<dyn NyashBox>],
|
||||
) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
match (iface_name, method_name) {
|
||||
("env.console", "log") => { for a in args { println!("{}", a.to_string_box().value); } Ok(None) }
|
||||
("env.console", "log") => {
|
||||
for a in args {
|
||||
println!("{}", a.to_string_box().value);
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
("env.modules", "set") => {
|
||||
if args.len() >= 2 {
|
||||
let key = args[0].to_string_box().value;
|
||||
@ -235,27 +373,110 @@ impl PluginLoaderV2 {
|
||||
("env.modules", "get") => {
|
||||
if let Some(k) = args.get(0) {
|
||||
let key = k.to_string_box().value;
|
||||
if let Some(v) = crate::runtime::modules_registry::get(&key) { return Ok(Some(v)); }
|
||||
if let Some(v) = crate::runtime::modules_registry::get(&key) {
|
||||
return Ok(Some(v));
|
||||
}
|
||||
}
|
||||
Ok(Some(Box::new(crate::box_trait::VoidBox::new())))
|
||||
}
|
||||
("env.task", "cancelCurrent") => { let tok = crate::runtime::global_hooks::current_group_token(); tok.cancel(); Ok(None) }
|
||||
("env.task", "currentToken") => { let tok = crate::runtime::global_hooks::current_group_token(); let tb = crate::boxes::token_box::TokenBox::from_token(tok); Ok(Some(Box::new(tb))) }
|
||||
("env.debug", "trace") => { if std::env::var("NYASH_DEBUG_TRACE").ok().as_deref() == Some("1") { for a in args { eprintln!("[debug.trace] {}", a.to_string_box().value); } } Ok(None) }
|
||||
("env.runtime", "checkpoint") => { if crate::config::env::runtime_checkpoint_trace() { eprintln!("[runtime.checkpoint] reached"); } crate::runtime::global_hooks::safepoint_and_poll(); Ok(None) }
|
||||
("env.future", "new") | ("env.future", "birth") => { let fut = crate::boxes::future::FutureBox::new(); if let Some(v) = args.get(0) { fut.set_result(v.clone_box()); } Ok(Some(Box::new(fut))) }
|
||||
("env.future", "set") => { if args.len() >= 2 { if let Some(fut) = args[0].as_any().downcast_ref::<crate::boxes::future::FutureBox>() { fut.set_result(args[1].clone_box()); } } Ok(None) }
|
||||
("env.future", "await") => { use crate::boxes::result::NyashResultBox; if let Some(arg) = args.get(0) { if let Some(fut) = arg.as_any().downcast_ref::<crate::boxes::future::FutureBox>() { let max_ms: u64 = crate::config::env::await_max_ms(); let start = std::time::Instant::now(); let mut spins = 0usize; while !fut.ready() { crate::runtime::global_hooks::safepoint_and_poll(); std::thread::yield_now(); spins += 1; if spins % 1024 == 0 { std::thread::sleep(std::time::Duration::from_millis(1)); } if start.elapsed() >= std::time::Duration::from_millis(max_ms) { let err = crate::box_trait::StringBox::new("Timeout"); return Ok(Some(Box::new(NyashResultBox::new_err(Box::new(err))))); } } return match fut.wait_and_get() { Ok(v) => Ok(Some(Box::new(NyashResultBox::new_ok(v)))), Err(e) => { let err = crate::box_trait::StringBox::new(format!("Error: {}", e)); Ok(Some(Box::new(NyashResultBox::new_err(Box::new(err))))) } }; } else { return Ok(Some(Box::new(NyashResultBox::new_ok(arg.clone_box())))); } } Ok(Some(Box::new(crate::boxes::result::NyashResultBox::new_err(Box::new(crate::box_trait::StringBox::new("InvalidArgs")))))) }
|
||||
_ => Err(BidError::PluginError)
|
||||
("env.task", "cancelCurrent") => {
|
||||
let tok = crate::runtime::global_hooks::current_group_token();
|
||||
tok.cancel();
|
||||
Ok(None)
|
||||
}
|
||||
("env.task", "currentToken") => {
|
||||
let tok = crate::runtime::global_hooks::current_group_token();
|
||||
let tb = crate::boxes::token_box::TokenBox::from_token(tok);
|
||||
Ok(Some(Box::new(tb)))
|
||||
}
|
||||
("env.debug", "trace") => {
|
||||
if std::env::var("NYASH_DEBUG_TRACE").ok().as_deref() == Some("1") {
|
||||
for a in args {
|
||||
eprintln!("[debug.trace] {}", a.to_string_box().value);
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
("env.runtime", "checkpoint") => {
|
||||
if crate::config::env::runtime_checkpoint_trace() {
|
||||
eprintln!("[runtime.checkpoint] reached");
|
||||
}
|
||||
crate::runtime::global_hooks::safepoint_and_poll();
|
||||
Ok(None)
|
||||
}
|
||||
("env.future", "new") | ("env.future", "birth") => {
|
||||
let fut = crate::boxes::future::FutureBox::new();
|
||||
if let Some(v) = args.get(0) {
|
||||
fut.set_result(v.clone_box());
|
||||
}
|
||||
Ok(Some(Box::new(fut)))
|
||||
}
|
||||
("env.future", "set") => {
|
||||
if args.len() >= 2 {
|
||||
if let Some(fut) = args[0]
|
||||
.as_any()
|
||||
.downcast_ref::<crate::boxes::future::FutureBox>()
|
||||
{
|
||||
fut.set_result(args[1].clone_box());
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
("env.future", "await") => {
|
||||
use crate::boxes::result::NyashResultBox;
|
||||
if let Some(arg) = args.get(0) {
|
||||
if let Some(fut) = arg
|
||||
.as_any()
|
||||
.downcast_ref::<crate::boxes::future::FutureBox>()
|
||||
{
|
||||
let max_ms: u64 = crate::config::env::await_max_ms();
|
||||
let start = std::time::Instant::now();
|
||||
let mut spins = 0usize;
|
||||
while !fut.ready() {
|
||||
crate::runtime::global_hooks::safepoint_and_poll();
|
||||
std::thread::yield_now();
|
||||
spins += 1;
|
||||
if spins % 1024 == 0 {
|
||||
std::thread::sleep(std::time::Duration::from_millis(1));
|
||||
}
|
||||
if start.elapsed() >= std::time::Duration::from_millis(max_ms) {
|
||||
let err = crate::box_trait::StringBox::new("Timeout");
|
||||
return Ok(Some(Box::new(NyashResultBox::new_err(Box::new(err)))));
|
||||
}
|
||||
}
|
||||
return match fut.wait_and_get() {
|
||||
Ok(v) => Ok(Some(Box::new(NyashResultBox::new_ok(v)))),
|
||||
Err(e) => {
|
||||
let err = crate::box_trait::StringBox::new(format!("Error: {}", e));
|
||||
Ok(Some(Box::new(NyashResultBox::new_err(Box::new(err)))))
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return Ok(Some(Box::new(NyashResultBox::new_ok(arg.clone_box()))));
|
||||
}
|
||||
}
|
||||
Ok(Some(Box::new(
|
||||
crate::boxes::result::NyashResultBox::new_err(Box::new(
|
||||
crate::box_trait::StringBox::new("InvalidArgs"),
|
||||
)),
|
||||
)))
|
||||
}
|
||||
_ => Err(BidError::PluginError),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_method_id_from_file(&self, box_type: &str, method_name: &str) -> BidResult<u32> {
|
||||
let cfg = self.config.as_ref().ok_or(BidError::PluginError)?;
|
||||
let cfg_path = self.config_path.as_deref().unwrap_or("nyash.toml");
|
||||
let toml_value: toml::Value = super::errors::from_toml(toml::from_str(&std::fs::read_to_string(cfg_path).map_err(|_| BidError::PluginError)?))?;
|
||||
let toml_value: toml::Value = super::errors::from_toml(toml::from_str(
|
||||
&std::fs::read_to_string(cfg_path).map_err(|_| BidError::PluginError)?,
|
||||
))?;
|
||||
if let Some((lib_name, _)) = cfg.find_library_for_box(box_type) {
|
||||
if let Some(bc) = cfg.get_box_config(&lib_name, box_type, &toml_value) { if let Some(m) = bc.methods.get(method_name) { return Ok(m.method_id); } }
|
||||
if let Some(bc) = cfg.get_box_config(&lib_name, box_type, &toml_value) {
|
||||
if let Some(m) = bc.methods.get(method_name) {
|
||||
return Ok(m.method_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(BidError::InvalidMethod)
|
||||
}
|
||||
@ -264,8 +485,16 @@ impl PluginLoaderV2 {
|
||||
if let Some(cfg) = &self.config {
|
||||
if let Some((lib_name, _)) = cfg.find_library_for_box(box_type) {
|
||||
if let Some(cfg_path) = self.config_path.as_deref() {
|
||||
if let Ok(toml_value) = toml::from_str::<toml::Value>(&std::fs::read_to_string(cfg_path).unwrap_or_default()) {
|
||||
if let Some(bc) = cfg.get_box_config(&lib_name, box_type, &toml_value) { return bc.methods.get(method_name).map(|m| m.returns_result).unwrap_or(false); }
|
||||
if let Ok(toml_value) = toml::from_str::<toml::Value>(
|
||||
&std::fs::read_to_string(cfg_path).unwrap_or_default(),
|
||||
) {
|
||||
if let Some(bc) = cfg.get_box_config(&lib_name, box_type, &toml_value) {
|
||||
return bc
|
||||
.methods
|
||||
.get(method_name)
|
||||
.map(|m| m.returns_result)
|
||||
.unwrap_or(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -274,41 +503,83 @@ impl PluginLoaderV2 {
|
||||
}
|
||||
|
||||
/// Resolve (type_id, method_id, returns_result) for a box_type.method
|
||||
pub fn resolve_method_handle(&self, box_type: &str, method_name: &str) -> BidResult<(u32, u32, bool)> {
|
||||
pub fn resolve_method_handle(
|
||||
&self,
|
||||
box_type: &str,
|
||||
method_name: &str,
|
||||
) -> BidResult<(u32, u32, bool)> {
|
||||
let cfg = self.config.as_ref().ok_or(BidError::PluginError)?;
|
||||
let cfg_path = self.config_path.as_deref().unwrap_or("nyash.toml");
|
||||
let toml_value: toml::Value = toml::from_str(&std::fs::read_to_string(cfg_path).map_err(|_| BidError::PluginError)?).map_err(|_| BidError::PluginError)?;
|
||||
let (lib_name, _) = cfg.find_library_for_box(box_type).ok_or(BidError::InvalidType)?;
|
||||
let bc = cfg.get_box_config(lib_name, box_type, &toml_value).ok_or(BidError::InvalidType)?;
|
||||
let toml_value: toml::Value =
|
||||
toml::from_str(&std::fs::read_to_string(cfg_path).map_err(|_| BidError::PluginError)?)
|
||||
.map_err(|_| BidError::PluginError)?;
|
||||
let (lib_name, _) = cfg
|
||||
.find_library_for_box(box_type)
|
||||
.ok_or(BidError::InvalidType)?;
|
||||
let bc = cfg
|
||||
.get_box_config(lib_name, box_type, &toml_value)
|
||||
.ok_or(BidError::InvalidType)?;
|
||||
let m = bc.methods.get(method_name).ok_or(BidError::InvalidMethod)?;
|
||||
Ok((bc.type_id, m.method_id, m.returns_result))
|
||||
}
|
||||
|
||||
pub fn invoke_instance_method(&self, box_type: &str, method_name: &str, instance_id: u32, args: &[Box<dyn NyashBox>]) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
pub fn invoke_instance_method(
|
||||
&self,
|
||||
box_type: &str,
|
||||
method_name: &str,
|
||||
instance_id: u32,
|
||||
args: &[Box<dyn NyashBox>],
|
||||
) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
// Non-recursive direct bridge for minimal methods used by semantics and basic VM paths
|
||||
// Resolve library/type/method ids from cached config
|
||||
let cfg = self.config.as_ref().ok_or(BidError::PluginError)?;
|
||||
let cfg_path = self.config_path.as_deref().unwrap_or("nyash.toml");
|
||||
let toml_value: toml::Value = toml::from_str(&std::fs::read_to_string(cfg_path).map_err(|_| BidError::PluginError)?).map_err(|_| BidError::PluginError)?;
|
||||
let (lib_name, _lib_def) = cfg.find_library_for_box(box_type).ok_or(BidError::InvalidType)?;
|
||||
let box_conf = cfg.get_box_config(lib_name, box_type, &toml_value).ok_or(BidError::InvalidType)?;
|
||||
let toml_value: toml::Value =
|
||||
toml::from_str(&std::fs::read_to_string(cfg_path).map_err(|_| BidError::PluginError)?)
|
||||
.map_err(|_| BidError::PluginError)?;
|
||||
let (lib_name, _lib_def) = cfg
|
||||
.find_library_for_box(box_type)
|
||||
.ok_or(BidError::InvalidType)?;
|
||||
let box_conf = cfg
|
||||
.get_box_config(lib_name, box_type, &toml_value)
|
||||
.ok_or(BidError::InvalidType)?;
|
||||
let type_id = box_conf.type_id;
|
||||
let method = box_conf.methods.get(method_name).ok_or(BidError::InvalidMethod)?;
|
||||
let method = box_conf
|
||||
.methods
|
||||
.get(method_name)
|
||||
.ok_or(BidError::InvalidMethod)?;
|
||||
// Get plugin handle
|
||||
let plugins = self.plugins.read().map_err(|_| BidError::PluginError)?;
|
||||
let plugin = plugins.get(lib_name).ok_or(BidError::PluginError)?;
|
||||
// Encode TLV args via shared helper (numeric→string→toString)
|
||||
let tlv = crate::runtime::plugin_ffi_common::encode_args(args);
|
||||
let (_code, out_len, out) = super::host_bridge::invoke_alloc(plugin.invoke_fn, type_id, method.method_id, instance_id, &tlv);
|
||||
let (_code, out_len, out) = super::host_bridge::invoke_alloc(
|
||||
plugin.invoke_fn,
|
||||
type_id,
|
||||
method.method_id,
|
||||
instance_id,
|
||||
&tlv,
|
||||
);
|
||||
// Decode TLV (first entry) generically
|
||||
if let Some((tag, _sz, payload)) = crate::runtime::plugin_ffi_common::decode::tlv_first(&out[..out_len]) {
|
||||
if let Some((tag, _sz, payload)) =
|
||||
crate::runtime::plugin_ffi_common::decode::tlv_first(&out[..out_len])
|
||||
{
|
||||
let bx: Box<dyn NyashBox> = match tag {
|
||||
1 => Box::new(crate::box_trait::BoolBox::new(crate::runtime::plugin_ffi_common::decode::bool(payload).unwrap_or(false))),
|
||||
2 => Box::new(crate::box_trait::IntegerBox::new(crate::runtime::plugin_ffi_common::decode::i32(payload).unwrap_or(0) as i64)),
|
||||
1 => Box::new(crate::box_trait::BoolBox::new(
|
||||
crate::runtime::plugin_ffi_common::decode::bool(payload).unwrap_or(false),
|
||||
)),
|
||||
2 => Box::new(crate::box_trait::IntegerBox::new(
|
||||
crate::runtime::plugin_ffi_common::decode::i32(payload).unwrap_or(0) as i64,
|
||||
)),
|
||||
3 => {
|
||||
// i64 payload
|
||||
if payload.len() == 8 { let mut b=[0u8;8]; b.copy_from_slice(payload); Box::new(crate::box_trait::IntegerBox::new(i64::from_le_bytes(b))) }
|
||||
else { Box::new(crate::box_trait::IntegerBox::new(0)) }
|
||||
if payload.len() == 8 {
|
||||
let mut b = [0u8; 8];
|
||||
b.copy_from_slice(payload);
|
||||
Box::new(crate::box_trait::IntegerBox::new(i64::from_le_bytes(b)))
|
||||
} else {
|
||||
Box::new(crate::box_trait::IntegerBox::new(0))
|
||||
}
|
||||
}
|
||||
5 => {
|
||||
let x = crate::runtime::plugin_ffi_common::decode::f64(payload).unwrap_or(0.0);
|
||||
@ -320,7 +591,9 @@ impl PluginLoaderV2 {
|
||||
}
|
||||
8 => {
|
||||
// Plugin handle (type_id, instance_id) → wrap into PluginBoxV2
|
||||
if let Some((ret_type, inst)) = crate::runtime::plugin_ffi_common::decode::plugin_handle(payload) {
|
||||
if let Some((ret_type, inst)) =
|
||||
crate::runtime::plugin_ffi_common::decode::plugin_handle(payload)
|
||||
{
|
||||
let handle = Arc::new(super::types::PluginHandleInner {
|
||||
type_id: ret_type,
|
||||
invoke_fn: plugin.invoke_fn,
|
||||
@ -328,13 +601,20 @@ impl PluginLoaderV2 {
|
||||
fini_method_id: None,
|
||||
finalized: std::sync::atomic::AtomicBool::new(false),
|
||||
});
|
||||
Box::new(super::types::PluginBoxV2 { box_type: box_type.to_string(), inner: handle })
|
||||
} else { Box::new(crate::box_trait::VoidBox::new()) }
|
||||
Box::new(super::types::PluginBoxV2 {
|
||||
box_type: box_type.to_string(),
|
||||
inner: handle,
|
||||
})
|
||||
} else {
|
||||
Box::new(crate::box_trait::VoidBox::new())
|
||||
}
|
||||
}
|
||||
9 => {
|
||||
// Host handle (u64) → try to map back to BoxRef, else void
|
||||
if let Some(u) = crate::runtime::plugin_ffi_common::decode::u64(payload) {
|
||||
if let Some(arc) = crate::runtime::host_handles::get(u) { return Ok(Some(arc.share_box())); }
|
||||
if let Some(arc) = crate::runtime::host_handles::get(u) {
|
||||
return Ok(Some(arc.share_box()));
|
||||
}
|
||||
}
|
||||
Box::new(crate::box_trait::VoidBox::new())
|
||||
}
|
||||
@ -345,17 +625,31 @@ impl PluginLoaderV2 {
|
||||
Ok(Some(Box::new(crate::box_trait::VoidBox::new())))
|
||||
}
|
||||
|
||||
pub fn create_box(&self, box_type: &str, _args: &[Box<dyn NyashBox>]) -> BidResult<Box<dyn NyashBox>> {
|
||||
pub fn create_box(
|
||||
&self,
|
||||
box_type: &str,
|
||||
_args: &[Box<dyn NyashBox>],
|
||||
) -> BidResult<Box<dyn NyashBox>> {
|
||||
// Non-recursive: directly call plugin 'birth' and construct PluginBoxV2
|
||||
let cfg = self.config.as_ref().ok_or(BidError::PluginError)?;
|
||||
let cfg_path = self.config_path.as_deref().unwrap_or("nyash.toml");
|
||||
let toml_value: toml::Value = toml::from_str(&std::fs::read_to_string(cfg_path).map_err(|_| BidError::PluginError)?).map_err(|_| BidError::PluginError)?;
|
||||
let (lib_name, _) = cfg.find_library_for_box(box_type).ok_or(BidError::InvalidType)?;
|
||||
let toml_value: toml::Value =
|
||||
toml::from_str(&std::fs::read_to_string(cfg_path).map_err(|_| BidError::PluginError)?)
|
||||
.map_err(|_| BidError::PluginError)?;
|
||||
let (lib_name, _) = cfg
|
||||
.find_library_for_box(box_type)
|
||||
.ok_or(BidError::InvalidType)?;
|
||||
|
||||
// Resolve type_id and method ids
|
||||
let box_conf = cfg.get_box_config(lib_name, box_type, &toml_value).ok_or(BidError::InvalidType)?;
|
||||
let box_conf = cfg
|
||||
.get_box_config(lib_name, box_type, &toml_value)
|
||||
.ok_or(BidError::InvalidType)?;
|
||||
let type_id = box_conf.type_id;
|
||||
let birth_id = box_conf.methods.get("birth").map(|m| m.method_id).ok_or(BidError::InvalidMethod)?;
|
||||
let birth_id = box_conf
|
||||
.methods
|
||||
.get("birth")
|
||||
.map(|m| m.method_id)
|
||||
.ok_or(BidError::InvalidMethod)?;
|
||||
let fini_id = box_conf.methods.get("fini").map(|m| m.method_id);
|
||||
|
||||
// Get loaded plugin invoke
|
||||
@ -364,15 +658,26 @@ impl PluginLoaderV2 {
|
||||
|
||||
// Call birth (no args TLV) and read returned instance id (little-endian u32 in bytes 0..4)
|
||||
if dbg_on() {
|
||||
eprintln!("[PluginLoaderV2] invoking birth: box_type={} type_id={} birth_id={}", box_type, type_id, birth_id);
|
||||
eprintln!(
|
||||
"[PluginLoaderV2] invoking birth: box_type={} type_id={} birth_id={}",
|
||||
box_type, type_id, birth_id
|
||||
);
|
||||
}
|
||||
let tlv = crate::runtime::plugin_ffi_common::encode_empty_args();
|
||||
let (code, out_len, out_buf) = super::host_bridge::invoke_alloc(plugin.invoke_fn, type_id, birth_id, 0, &tlv);
|
||||
let (code, out_len, out_buf) =
|
||||
super::host_bridge::invoke_alloc(plugin.invoke_fn, type_id, birth_id, 0, &tlv);
|
||||
if dbg_on() {
|
||||
eprintln!("[PluginLoaderV2] create_box: box_type={} type_id={} birth_id={} code={} out_len={}", box_type, type_id, birth_id, code, out_len);
|
||||
if out_len > 0 { eprintln!("[PluginLoaderV2] create_box: out[0..min(8)]={:02x?}", &out_buf[..out_len.min(8)]); }
|
||||
if out_len > 0 {
|
||||
eprintln!(
|
||||
"[PluginLoaderV2] create_box: out[0..min(8)]={:02x?}",
|
||||
&out_buf[..out_len.min(8)]
|
||||
);
|
||||
}
|
||||
}
|
||||
if code != 0 || out_len < 4 {
|
||||
return Err(BidError::PluginError);
|
||||
}
|
||||
if code != 0 || out_len < 4 { return Err(BidError::PluginError); }
|
||||
let instance_id = u32::from_le_bytes([out_buf[0], out_buf[1], out_buf[2], out_buf[3]]);
|
||||
|
||||
let bx = PluginBoxV2 {
|
||||
@ -391,6 +696,8 @@ impl PluginLoaderV2 {
|
||||
/// Shutdown singletons: finalize and clear all singleton handles
|
||||
pub fn shutdown_singletons(&self) {
|
||||
let mut map = self.singletons.write().unwrap();
|
||||
for (_, handle) in map.drain() { handle.finalize_now(); }
|
||||
for (_, handle) in map.drain() {
|
||||
handle.finalize_now();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,15 @@
|
||||
mod types;
|
||||
mod loader;
|
||||
mod globals;
|
||||
mod errors;
|
||||
mod globals;
|
||||
mod host_bridge;
|
||||
mod loader;
|
||||
mod types;
|
||||
|
||||
pub use types::{PluginBoxMetadata, PluginBoxV2, PluginHandleInner, NyashTypeBoxFfi, make_plugin_box_v2, construct_plugin_box};
|
||||
pub use loader::PluginLoaderV2;
|
||||
pub use globals::{get_global_loader_v2, init_global_loader_v2, shutdown_plugins_v2};
|
||||
pub use loader::PluginLoaderV2;
|
||||
pub use types::{
|
||||
construct_plugin_box, make_plugin_box_v2, NyashTypeBoxFfi, PluginBoxMetadata, PluginBoxV2,
|
||||
PluginHandleInner,
|
||||
};
|
||||
|
||||
pub fn metadata_for_type_id(type_id: u32) -> Option<PluginBoxMetadata> {
|
||||
let loader = get_global_loader_v2();
|
||||
@ -14,4 +17,6 @@ pub fn metadata_for_type_id(type_id: u32) -> Option<PluginBoxMetadata> {
|
||||
guard.metadata_for_type_id(type_id)
|
||||
}
|
||||
|
||||
pub fn backend_kind() -> &'static str { "enabled" }
|
||||
pub fn backend_kind() -> &'static str {
|
||||
"enabled"
|
||||
}
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
use crate::box_trait::{BoxCore, NyashBox, StringBox};
|
||||
use super::host_bridge::InvokeFn;
|
||||
use crate::box_trait::{BoxCore, NyashBox, StringBox};
|
||||
use std::any::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
fn dbg_on() -> bool { std::env::var("NYASH_DEBUG_PLUGIN").unwrap_or_default() == "1" }
|
||||
fn dbg_on() -> bool {
|
||||
std::env::var("NYASH_DEBUG_PLUGIN").unwrap_or_default() == "1"
|
||||
}
|
||||
|
||||
/// Loaded plugin information (library handle + exported addresses)
|
||||
pub struct LoadedPluginV2 {
|
||||
@ -36,9 +38,18 @@ pub struct PluginHandleInner {
|
||||
impl Drop for PluginHandleInner {
|
||||
fn drop(&mut self) {
|
||||
if let Some(fini_id) = self.fini_method_id {
|
||||
if !self.finalized.swap(true, std::sync::atomic::Ordering::SeqCst) {
|
||||
if !self
|
||||
.finalized
|
||||
.swap(true, std::sync::atomic::Ordering::SeqCst)
|
||||
{
|
||||
let tlv_args: [u8; 4] = [1, 0, 0, 0];
|
||||
let _ = super::host_bridge::invoke_alloc(self.invoke_fn, self.type_id, fini_id, self.instance_id, &tlv_args);
|
||||
let _ = super::host_bridge::invoke_alloc(
|
||||
self.invoke_fn,
|
||||
self.type_id,
|
||||
fini_id,
|
||||
self.instance_id,
|
||||
&tlv_args,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -47,10 +58,19 @@ impl Drop for PluginHandleInner {
|
||||
impl PluginHandleInner {
|
||||
pub fn finalize_now(&self) {
|
||||
if let Some(fini_id) = self.fini_method_id {
|
||||
if !self.finalized.swap(true, std::sync::atomic::Ordering::SeqCst) {
|
||||
if !self
|
||||
.finalized
|
||||
.swap(true, std::sync::atomic::Ordering::SeqCst)
|
||||
{
|
||||
crate::runtime::leak_tracker::finalize_plugin("PluginBox", self.instance_id);
|
||||
let tlv_args: [u8; 4] = [1, 0, 0, 0];
|
||||
let _ = super::host_bridge::invoke_alloc(self.invoke_fn, self.type_id, fini_id, self.instance_id, &tlv_args);
|
||||
let _ = super::host_bridge::invoke_alloc(
|
||||
self.invoke_fn,
|
||||
self.type_id,
|
||||
fini_id,
|
||||
self.instance_id,
|
||||
&tlv_args,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -76,46 +96,113 @@ pub struct PluginBoxV2 {
|
||||
}
|
||||
|
||||
impl BoxCore for PluginBoxV2 {
|
||||
fn box_id(&self) -> u64 { self.inner.instance_id as u64 }
|
||||
fn parent_type_id(&self) -> Option<std::any::TypeId> { None }
|
||||
fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}({})", self.box_type, self.inner.instance_id) }
|
||||
fn as_any(&self) -> &dyn Any { self }
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any { self }
|
||||
fn box_id(&self) -> u64 {
|
||||
self.inner.instance_id as u64
|
||||
}
|
||||
fn parent_type_id(&self) -> Option<std::any::TypeId> {
|
||||
None
|
||||
}
|
||||
fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}({})", self.box_type, self.inner.instance_id)
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl NyashBox for PluginBoxV2 {
|
||||
fn is_identity(&self) -> bool { true }
|
||||
fn type_name(&self) -> &'static str {
|
||||
match self.box_type.as_str() { "FileBox" => "FileBox", _ => "PluginBoxV2" }
|
||||
fn is_identity(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn clone_box(&self) -> Box<dyn NyashBox> {
|
||||
if dbg_on() { eprintln!("[PluginBoxV2] clone_box {}({})", self.box_type, self.inner.instance_id); }
|
||||
let tlv_args = [1u8, 0, 0, 0];
|
||||
let (result, out_len, out_buf) = super::host_bridge::invoke_alloc(self.inner.invoke_fn, self.inner.type_id, 0, 0, &tlv_args);
|
||||
if result == 0 && out_len >= 4 {
|
||||
let new_instance_id = u32::from_le_bytes([out_buf[0], out_buf[1], out_buf[2], out_buf[3]]);
|
||||
Box::new(PluginBoxV2 {
|
||||
box_type: self.box_type.clone(),
|
||||
inner: Arc::new(PluginHandleInner { type_id: self.inner.type_id, invoke_fn: self.inner.invoke_fn, instance_id: new_instance_id, fini_method_id: self.inner.fini_method_id, finalized: std::sync::atomic::AtomicBool::new(false) }),
|
||||
})
|
||||
} else {
|
||||
Box::new(StringBox::new(format!("Clone failed for {}", self.box_type)))
|
||||
fn type_name(&self) -> &'static str {
|
||||
match self.box_type.as_str() {
|
||||
"FileBox" => "FileBox",
|
||||
_ => "PluginBoxV2",
|
||||
}
|
||||
}
|
||||
fn to_string_box(&self) -> StringBox { StringBox::new(format!("{}({})", self.box_type, self.inner.instance_id)) }
|
||||
fn equals(&self, _other: &dyn NyashBox) -> crate::box_trait::BoolBox { crate::box_trait::BoolBox::new(false) }
|
||||
fn share_box(&self) -> Box<dyn NyashBox> { Box::new(PluginBoxV2 { box_type: self.box_type.clone(), inner: self.inner.clone() }) }
|
||||
fn clone_box(&self) -> Box<dyn NyashBox> {
|
||||
if dbg_on() {
|
||||
eprintln!(
|
||||
"[PluginBoxV2] clone_box {}({})",
|
||||
self.box_type, self.inner.instance_id
|
||||
);
|
||||
}
|
||||
let tlv_args = [1u8, 0, 0, 0];
|
||||
let (result, out_len, out_buf) = super::host_bridge::invoke_alloc(
|
||||
self.inner.invoke_fn,
|
||||
self.inner.type_id,
|
||||
0,
|
||||
0,
|
||||
&tlv_args,
|
||||
);
|
||||
if result == 0 && out_len >= 4 {
|
||||
let new_instance_id =
|
||||
u32::from_le_bytes([out_buf[0], out_buf[1], out_buf[2], out_buf[3]]);
|
||||
Box::new(PluginBoxV2 {
|
||||
box_type: self.box_type.clone(),
|
||||
inner: Arc::new(PluginHandleInner {
|
||||
type_id: self.inner.type_id,
|
||||
invoke_fn: self.inner.invoke_fn,
|
||||
instance_id: new_instance_id,
|
||||
fini_method_id: self.inner.fini_method_id,
|
||||
finalized: std::sync::atomic::AtomicBool::new(false),
|
||||
}),
|
||||
})
|
||||
} else {
|
||||
Box::new(StringBox::new(format!(
|
||||
"Clone failed for {}",
|
||||
self.box_type
|
||||
)))
|
||||
}
|
||||
}
|
||||
fn to_string_box(&self) -> StringBox {
|
||||
StringBox::new(format!("{}({})", self.box_type, self.inner.instance_id))
|
||||
}
|
||||
fn equals(&self, _other: &dyn NyashBox) -> crate::box_trait::BoolBox {
|
||||
crate::box_trait::BoolBox::new(false)
|
||||
}
|
||||
fn share_box(&self) -> Box<dyn NyashBox> {
|
||||
Box::new(PluginBoxV2 {
|
||||
box_type: self.box_type.clone(),
|
||||
inner: self.inner.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PluginBoxV2 {
|
||||
pub fn instance_id(&self) -> u32 { self.inner.instance_id }
|
||||
pub fn finalize_now(&self) { self.inner.finalize_now() }
|
||||
pub fn is_finalized(&self) -> bool { self.inner.finalized.load(std::sync::atomic::Ordering::SeqCst) }
|
||||
pub fn instance_id(&self) -> u32 {
|
||||
self.inner.instance_id
|
||||
}
|
||||
pub fn finalize_now(&self) {
|
||||
self.inner.finalize_now()
|
||||
}
|
||||
pub fn is_finalized(&self) -> bool {
|
||||
self.inner
|
||||
.finalized
|
||||
.load(std::sync::atomic::Ordering::SeqCst)
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper to construct a PluginBoxV2 from raw ids and invoke pointer safely
|
||||
pub fn make_plugin_box_v2(box_type: String, type_id: u32, instance_id: u32, invoke_fn: InvokeFn) -> PluginBoxV2 {
|
||||
PluginBoxV2 { box_type, inner: Arc::new(PluginHandleInner { type_id, invoke_fn, instance_id, fini_method_id: None, finalized: std::sync::atomic::AtomicBool::new(false) }) }
|
||||
pub fn make_plugin_box_v2(
|
||||
box_type: String,
|
||||
type_id: u32,
|
||||
instance_id: u32,
|
||||
invoke_fn: InvokeFn,
|
||||
) -> PluginBoxV2 {
|
||||
PluginBoxV2 {
|
||||
box_type,
|
||||
inner: Arc::new(PluginHandleInner {
|
||||
type_id,
|
||||
invoke_fn,
|
||||
instance_id,
|
||||
fini_method_id: None,
|
||||
finalized: std::sync::atomic::AtomicBool::new(false),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Public helper to construct a PluginBoxV2 from raw parts (for VM/JIT integration)
|
||||
@ -126,5 +213,14 @@ pub fn construct_plugin_box(
|
||||
instance_id: u32,
|
||||
fini_method_id: Option<u32>,
|
||||
) -> PluginBoxV2 {
|
||||
PluginBoxV2 { box_type, inner: Arc::new(PluginHandleInner { type_id, invoke_fn, instance_id, fini_method_id, finalized: std::sync::atomic::AtomicBool::new(false) }) }
|
||||
PluginBoxV2 {
|
||||
box_type,
|
||||
inner: Arc::new(PluginHandleInner {
|
||||
type_id,
|
||||
invoke_fn,
|
||||
instance_id,
|
||||
fini_method_id,
|
||||
finalized: std::sync::atomic::AtomicBool::new(false),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,4 +9,3 @@ mod stub;
|
||||
pub use enabled::*;
|
||||
#[cfg(any(not(feature = "plugins"), target_arch = "wasm32"))]
|
||||
pub use stub::*;
|
||||
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
use crate::bid::{BidResult, BidError};
|
||||
use crate::bid::{BidError, BidResult};
|
||||
use crate::box_trait::NyashBox;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
pub type InvokeFn = unsafe extern "C" fn(u32, u32, u32, *const u8, usize, *mut u8, *mut usize) -> i32;
|
||||
pub type InvokeFn =
|
||||
unsafe extern "C" fn(u32, u32, u32, *const u8, usize, *mut u8, *mut usize) -> i32;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PluginBoxV2 {
|
||||
@ -28,32 +29,82 @@ pub struct PluginHandleInner {
|
||||
pub fini_method_id: Option<u32>,
|
||||
}
|
||||
|
||||
pub struct PluginLoaderV2 { pub config: Option<()> }
|
||||
impl PluginLoaderV2 { pub fn new() -> Self { Self { config: None } } }
|
||||
pub struct PluginLoaderV2 {
|
||||
pub config: Option<()>,
|
||||
}
|
||||
impl PluginLoaderV2 {
|
||||
pub fn new() -> Self {
|
||||
Self { config: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl PluginLoaderV2 {
|
||||
pub fn load_config(&mut self, _p: &str) -> BidResult<()> { Ok(()) }
|
||||
pub fn load_all_plugins(&self) -> BidResult<()> { Ok(()) }
|
||||
pub fn create_box(&self, _t: &str, _a: &[Box<dyn NyashBox>]) -> BidResult<Box<dyn NyashBox>> { Err(BidError::PluginError) }
|
||||
pub fn extern_call(&self, _iface_name: &str, _method_name: &str, _args: &[Box<dyn NyashBox>]) -> BidResult<Option<Box<dyn NyashBox>>> { Err(BidError::PluginError) }
|
||||
pub fn invoke_instance_method(&self, _box_type: &str, _method_name: &str, _instance_id: u32, _args: &[Box<dyn NyashBox>]) -> BidResult<Option<Box<dyn NyashBox>>> { Err(BidError::PluginError) }
|
||||
pub fn metadata_for_type_id(&self, _type_id: u32) -> Option<PluginBoxMetadata> { None }
|
||||
pub fn load_config(&mut self, _p: &str) -> BidResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
pub fn load_all_plugins(&self) -> BidResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
pub fn create_box(&self, _t: &str, _a: &[Box<dyn NyashBox>]) -> BidResult<Box<dyn NyashBox>> {
|
||||
Err(BidError::PluginError)
|
||||
}
|
||||
pub fn extern_call(
|
||||
&self,
|
||||
_iface_name: &str,
|
||||
_method_name: &str,
|
||||
_args: &[Box<dyn NyashBox>],
|
||||
) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
Err(BidError::PluginError)
|
||||
}
|
||||
pub fn invoke_instance_method(
|
||||
&self,
|
||||
_box_type: &str,
|
||||
_method_name: &str,
|
||||
_instance_id: u32,
|
||||
_args: &[Box<dyn NyashBox>],
|
||||
) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
Err(BidError::PluginError)
|
||||
}
|
||||
pub fn metadata_for_type_id(&self, _type_id: u32) -> Option<PluginBoxMetadata> {
|
||||
None
|
||||
}
|
||||
pub fn shutdown_singletons(&self) {}
|
||||
}
|
||||
|
||||
static GLOBAL_LOADER_V2: Lazy<Arc<RwLock<PluginLoaderV2>>> = Lazy::new(|| Arc::new(RwLock::new(PluginLoaderV2::new())));
|
||||
pub fn get_global_loader_v2() -> Arc<RwLock<PluginLoaderV2>> { GLOBAL_LOADER_V2.clone() }
|
||||
pub fn init_global_loader_v2(_config_path: &str) -> BidResult<()> { Ok(()) }
|
||||
pub fn shutdown_plugins_v2() -> BidResult<()> { Ok(()) }
|
||||
static GLOBAL_LOADER_V2: Lazy<Arc<RwLock<PluginLoaderV2>>> =
|
||||
Lazy::new(|| Arc::new(RwLock::new(PluginLoaderV2::new())));
|
||||
pub fn get_global_loader_v2() -> Arc<RwLock<PluginLoaderV2>> {
|
||||
GLOBAL_LOADER_V2.clone()
|
||||
}
|
||||
pub fn init_global_loader_v2(_config_path: &str) -> BidResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
pub fn shutdown_plugins_v2() -> BidResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn backend_kind() -> &'static str { "stub" }
|
||||
pub fn backend_kind() -> &'static str {
|
||||
"stub"
|
||||
}
|
||||
|
||||
pub fn metadata_for_type_id(_type_id: u32) -> Option<PluginBoxMetadata> { None }
|
||||
pub fn metadata_for_type_id(_type_id: u32) -> Option<PluginBoxMetadata> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn make_plugin_box_v2(box_type: String, type_id: u32, instance_id: u32, invoke_fn: InvokeFn) -> PluginBoxV2 {
|
||||
pub fn make_plugin_box_v2(
|
||||
box_type: String,
|
||||
type_id: u32,
|
||||
instance_id: u32,
|
||||
invoke_fn: InvokeFn,
|
||||
) -> PluginBoxV2 {
|
||||
PluginBoxV2 {
|
||||
box_type,
|
||||
inner: Arc::new(PluginHandleInner { type_id, invoke_fn, instance_id, fini_method_id: None }),
|
||||
inner: Arc::new(PluginHandleInner {
|
||||
type_id,
|
||||
invoke_fn,
|
||||
instance_id,
|
||||
fini_method_id: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,6 +117,11 @@ pub fn construct_plugin_box(
|
||||
) -> PluginBoxV2 {
|
||||
PluginBoxV2 {
|
||||
box_type,
|
||||
inner: Arc::new(PluginHandleInner { type_id, invoke_fn, instance_id, fini_method_id }),
|
||||
inner: Arc::new(PluginHandleInner {
|
||||
type_id,
|
||||
invoke_fn,
|
||||
instance_id,
|
||||
fini_method_id,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user