use std::fmt;
use std::sync::Arc;
use serde_json::Value as JsonValue;
use crate::error::Result;
use crate::signature::Signature;
use crate::value::{OUTER_WRAPPER, Value};
type Implementation =
dyn Fn(&[Option<JsonValue>], &HostCall<'_>) -> Result<Option<JsonValue>> + Send + Sync;
#[derive(Clone)]
pub struct HostFunction {
imp: Arc<Implementation>,
signature: Option<Arc<Signature>>,
arity: usize,
}
impl HostFunction {
pub fn new<F>(arity: usize, imp: F) -> Self
where
F: Fn(&[Option<JsonValue>], &HostCall<'_>) -> Result<Option<JsonValue>>
+ Send
+ Sync
+ 'static,
{
HostFunction {
imp: Arc::new(imp),
signature: None,
arity,
}
}
pub fn with_signature<F>(signature: &str, imp: F) -> Result<Self>
where
F: Fn(&[Option<JsonValue>], &HostCall<'_>) -> Result<Option<JsonValue>>
+ Send
+ Sync
+ 'static,
{
let signature = Signature::parse(signature)?;
Ok(HostFunction {
imp: Arc::new(imp),
arity: signature.params.len(),
signature: Some(Arc::new(signature)),
})
}
pub fn signature(&self) -> Option<&Signature> {
self.signature.as_deref()
}
pub fn arity(&self) -> usize {
self.arity
}
pub(crate) fn call(&self, args: &[Value], input: &Value) -> Result<Value> {
let args: Vec<Option<JsonValue>> = args.iter().map(Value::to_json).collect();
let result = (self.imp)(&args, &HostCall { input })?;
Ok(result.as_ref().map_or(Value::Undefined, Value::from_json))
}
}
impl fmt::Debug for HostFunction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("HostFunction")
.field(
"signature",
&self.signature.as_ref().map(|s| s.definition.as_str()),
)
.field("arity", &self.arity)
.finish_non_exhaustive()
}
}
pub struct HostCall<'a> {
input: &'a Value,
}
impl HostCall<'_> {
pub fn input(&self) -> Option<JsonValue> {
match self.input {
Value::Array(a) if a.has(OUTER_WRAPPER) && a.len() == 1 => a.items[0].to_json(),
v => v.to_json(),
}
}
}