//! Extern interface registry (env.*) for diagnostics and optional slotting //! //! 目的: ExternCallの未登録/未対応時に候補提示やSTRICT診断を改善する。 use once_cell::sync::Lazy; #[derive(Clone, Copy, Debug)] pub struct ExternSpec { pub iface: &'static str, pub method: &'static str, pub min_arity: u8, pub max_arity: u8, pub slot: Option, } static EXTERNS: Lazy> = Lazy::new(|| { vec![ // console ExternSpec { iface: "env.console", method: "log", min_arity: 1, max_arity: 255, slot: Some(10), }, ExternSpec { iface: "env.console", method: "warn", min_arity: 1, max_arity: 255, slot: Some(10), }, ExternSpec { iface: "env.console", method: "error", min_arity: 1, max_arity: 255, slot: Some(10), }, ExternSpec { iface: "env.console", method: "info", min_arity: 1, max_arity: 255, slot: Some(10), }, ExternSpec { iface: "env.console", method: "debug", min_arity: 1, max_arity: 255, slot: Some(10), }, // debug ExternSpec { iface: "env.debug", method: "trace", min_arity: 1, max_arity: 255, slot: Some(11), }, // runtime ExternSpec { iface: "env.runtime", method: "checkpoint", min_arity: 0, max_arity: 0, slot: Some(12), }, // task ExternSpec { iface: "env.task", method: "cancelCurrent", min_arity: 0, max_arity: 0, slot: Some(30), }, ExternSpec { iface: "env.task", method: "currentToken", min_arity: 0, max_arity: 0, slot: Some(31), }, ExternSpec { iface: "env.task", method: "yieldNow", min_arity: 0, max_arity: 0, slot: Some(32), }, ExternSpec { iface: "env.task", method: "sleepMs", min_arity: 1, max_arity: 1, slot: Some(33), }, // future (scaffold) ExternSpec { iface: "env.future", method: "new", min_arity: 1, max_arity: 1, slot: Some(20), }, ExternSpec { iface: "env.future", method: "birth", min_arity: 1, max_arity: 1, slot: Some(20), }, ExternSpec { iface: "env.future", method: "set", min_arity: 2, max_arity: 2, slot: Some(21), }, ExternSpec { iface: "env.future", method: "await", min_arity: 1, max_arity: 1, slot: Some(22), }, // core-13 pure support shims ExternSpec { iface: "env.local", method: "get", min_arity: 1, max_arity: 1, slot: Some(40), }, ExternSpec { iface: "env.local", method: "set", min_arity: 2, max_arity: 2, slot: Some(41), }, ExternSpec { iface: "env.box", method: "new", min_arity: 1, max_arity: 255, slot: Some(50), }, ExternSpec { iface: "env.box_introspect", method: "kind", min_arity: 1, max_arity: 1, slot: Some(51), }, // basic env access ExternSpec { iface: "env", method: "get", min_arity: 1, max_arity: 1, slot: Some(60), }, // host providers (delegate path) ExternSpec { iface: "env.mirbuilder", method: "emit", min_arity: 1, max_arity: 1, slot: Some(70), }, ExternSpec { iface: "env.codegen", method: "emit_object", min_arity: 1, max_arity: 2, slot: Some(71), }, // hostbridge trampoline (dev/testing) ExternSpec { iface: "hostbridge", method: "extern_invoke", min_arity: 2, max_arity: 3, slot: Some(80), }, ] }); pub fn resolve(iface: &str, method: &str) -> Option { EXTERNS .iter() .copied() .find(|e| e.iface == iface && e.method == method) } pub fn known_for_iface(iface: &str) -> Vec<&'static str> { let mut v: Vec<&'static str> = EXTERNS .iter() .filter(|e| e.iface == iface) .map(|e| e.method) .collect(); v.sort(); v.dedup(); v } pub fn all_ifaces() -> Vec<&'static str> { let mut v: Vec<&'static str> = EXTERNS.iter().map(|e| e.iface).collect(); v.sort(); v.dedup(); v } /// Resolve slot id for an extern call (if assigned) pub fn resolve_slot(iface: &str, method: &str) -> Option { resolve(iface, method).and_then(|s| s.slot) } /// Check arity against registry; returns Ok or an explanatory error string pub fn check_arity(iface: &str, method: &str, argc: usize) -> Result<(), String> { if let Some(s) = resolve(iface, method) { if argc as u8 >= s.min_arity && argc as u8 <= s.max_arity { Ok(()) } else { Err(format!( "arity {} out of range {}..{}", argc, s.min_arity, s.max_arity )) } } else { Err("unknown extern".to_string()) } }