feat(phase-9.75g-0): Implement BID-FFI Day 6 - Dynamic method discovery system

- Enhanced plugin metadata API with find_method() and get_methods()
- Implemented generic plugin method calling system (execute_plugin_method_generic)
- Fixed TLV encoding: use Bytes tag for string data in write()
- Fixed read() method: provide default size argument when called without args
- Replaced hardcoded execute_plugin_file_method with dynamic system
- Full end-to-end test successful: FileBox plugin write/read working

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Moe Charm
2025-08-18 12:23:58 +09:00
parent 16291630e2
commit 7fc3adef66
4 changed files with 236 additions and 62 deletions

View File

@ -8,6 +8,7 @@ pub struct LoadedPlugin {
pub library: Library,
pub handle: PluginHandle,
pub type_id: u32,
pub plugin_info: NyashPluginInfo, // プラグイン情報を保存
}
impl LoadedPlugin {
@ -48,9 +49,46 @@ impl LoadedPlugin {
handle.initialize(&host, &mut info)?;
let type_id = info.type_id;
Ok(Self { library, handle, type_id })
Ok(Self { library, handle, type_id, plugin_info: info })
}
}
/// Get the plugin's Box type name
pub fn get_type_name(&self) -> BidResult<&str> {
unsafe { self.plugin_info.name() }
}
/// Get all available methods for this plugin
pub fn get_methods(&self) -> BidResult<Vec<(u32, String, u32)>> {
let mut methods = Vec::new();
unsafe {
let methods_slice = self.plugin_info.methods_slice()?;
for method_info in methods_slice {
let method_name = method_info.name()?.to_string();
methods.push((
method_info.method_id,
method_name,
method_info.signature_hash,
));
}
}
Ok(methods)
}
/// Find a method by name and return its info
pub fn find_method(&self, method_name: &str) -> BidResult<Option<(u32, u32)>> {
unsafe {
let methods_slice = self.plugin_info.methods_slice()?;
for method_info in methods_slice {
if method_info.name()? == method_name {
return Ok(Some((method_info.method_id, method_info.signature_hash)));
}
}
}
Ok(None)
}
}
/// Build a minimal host vtable for plugins

View File

@ -35,6 +35,11 @@ pub struct NyashMethodInfo {
pub signature_hash: u32,
}
// SAFETY: The C pointers in NyashMethodInfo are read-only after initialization
// and point to valid memory managed by the plugin system
unsafe impl Send for NyashMethodInfo {}
unsafe impl Sync for NyashMethodInfo {}
impl NyashMethodInfo {
/// Create method info with safe string handling
pub fn new(method_id: u32, method_name: &str, signature_hash: u32) -> BidResult<(Self, CString)> {
@ -78,6 +83,11 @@ pub struct NyashPluginInfo {
pub methods: *const NyashMethodInfo,
}
// SAFETY: The C pointers in NyashPluginInfo are read-only after initialization
// and point to valid memory managed by the plugin system
unsafe impl Send for NyashPluginInfo {}
unsafe impl Sync for NyashPluginInfo {}
impl NyashPluginInfo {
/// Create an empty plugin info
pub fn empty() -> Self {

View File

@ -111,6 +111,48 @@ impl PluginFileBox {
pub fn read_bytes(&self, size: usize) -> BidResult<Vec<u8>> { self.inner.read(size) }
pub fn write_bytes(&self, data: &[u8]) -> BidResult<i32> { self.inner.write(data) }
pub fn close(&self) -> BidResult<()> { self.inner.close() }
/// 汎用メソッド呼び出し(動的ディスパッチ)
pub fn call_method(&self, method_name: &str, args: &[u8]) -> BidResult<Vec<u8>> {
eprintln!("🔍 call_method: method_name='{}', args_len={}", method_name, args.len());
// プラグインからメソッドIDを動的取得
match self.inner.plugin.find_method(method_name) {
Ok(Some((method_id, signature))) => {
eprintln!("🔍 Found method '{}': ID={}, signature=0x{:08X}", method_name, method_id, signature);
let mut out = Vec::new();
match self.inner.plugin.handle.invoke(
self.inner.plugin.type_id,
method_id,
self.inner.instance_id,
args,
&mut out
) {
Ok(()) => {
eprintln!("🔍 Plugin invoke succeeded, output_len={}", out.len());
Ok(out)
}
Err(e) => {
eprintln!("🔍 Plugin invoke failed: {:?}", e);
Err(e)
}
}
}
Ok(None) => {
eprintln!("🔍 Method '{}' not found in plugin", method_name);
Err(BidError::InvalidArgs) // メソッドが見つからない
}
Err(e) => {
eprintln!("🔍 Error looking up method '{}': {:?}", method_name, e);
Err(e)
}
}
}
/// プラグインのメソッド一覧を取得
pub fn get_available_methods(&self) -> BidResult<Vec<(u32, String, u32)>> {
self.inner.plugin.get_methods()
}
}
impl BoxCore for PluginFileBox {