uni_plugin_extism/adapter_common.rs
1//! Shared helpers for the three Extism adapter modules.
2//!
3//! `acquire`, `extism_err_to_fn_err`, and the qname → export-symbol
4//! sanitizer were copy-pasted across [`crate::adapter`],
5//! [`crate::adapter_aggregate`], and [`crate::adapter_procedure`]. They
6//! live here once so the lease/error/symbol conventions stay in lock-step
7//! across the scalar, aggregate, and procedure adapters.
8
9// Rust guideline compliant
10
11use std::sync::Arc;
12
13use uni_plugin::QName;
14use uni_plugin::errors::FnError;
15use uni_plugin_wasm_rt::IpcError;
16
17use crate::pool::{ExtismInstancePool, PooledInstance};
18
19/// Sanitize a qname into the `.`-free stem used in plugin export symbols.
20///
21/// Plugin authors expose `invoke_<stem>` / `agg_<stem>_*` /
22/// `proc_<stem>_invoke` where every `.` in the qname is replaced by `_`,
23/// because Rust identifiers cannot contain `.`. The mapping is
24/// deterministic and shared by all three adapters so the host always
25/// derives the same export symbol from a canonical qname.
26///
27/// # Examples
28///
29/// ```
30/// use uni_plugin::QName;
31/// use uni_plugin_extism::adapter_common::sanitize_qname;
32///
33/// let q = QName::parse("geo.haversine").unwrap();
34/// assert_eq!(sanitize_qname(&q), "geo_haversine");
35/// ```
36#[must_use]
37pub fn sanitize_qname(qname: &QName) -> String {
38 qname.to_string().replace('.', "_")
39}
40
41/// Lease one warm instance from `pool`, mapping pool exhaustion to a
42/// [`FnError`] carrying [`FnError::CODE_RESOURCE_LIMIT`].
43///
44/// # Errors
45///
46/// Returns [`FnError`] when the pool cannot hand out an instance (e.g.
47/// `max_instances` reached).
48pub fn acquire(
49 pool: &Arc<ExtismInstancePool<extism::Plugin>>,
50) -> Result<PooledInstance<extism::Plugin>, FnError> {
51 PooledInstance::acquire(Arc::clone(pool)).map_err(|e| {
52 FnError::new(
53 FnError::CODE_RESOURCE_LIMIT,
54 format!("acquire plugin instance: {e}"),
55 )
56 })
57}
58
59/// Map an Arrow-IPC boundary error to a [`FnError`] carrying
60/// [`FnError::CODE_TYPE_COERCION`].
61#[must_use]
62pub fn extism_err_to_fn_err(e: IpcError) -> FnError {
63 FnError::new(FnError::CODE_TYPE_COERCION, format!("extism IPC: {e}"))
64}