use super::ForeignFunctionCallbackResult;
use crate::value_conversions::{value_to_u64, value_to_usize};
use stoffel_vm_types::core_types::{ArrayRef, ObjectRef, TableRef, Value};
pub struct ForeignArguments<'a> {
function: &'static str,
args: &'a [Value],
}
impl<'a> ForeignArguments<'a> {
pub(crate) fn new(function: &'static str, args: &'a [Value]) -> Self {
Self { function, args }
}
pub fn require_min(
&self,
min: usize,
expectation: &'static str,
) -> ForeignFunctionCallbackResult<()> {
if self.args.len() >= min {
Ok(())
} else {
Err(format!("{} expects {}", self.function, expectation).into())
}
}
pub fn require_exact(
&self,
expected: usize,
expectation: &'static str,
) -> ForeignFunctionCallbackResult<()> {
if self.args.len() == expected {
Ok(())
} else {
Err(format!("{} expects {}", self.function, expectation).into())
}
}
pub fn len(&self) -> usize {
self.args.len()
}
pub fn get(&self, index: usize) -> ForeignFunctionCallbackResult<&'a Value> {
self.args
.get(index)
.ok_or_else(|| format!("{} missing argument {}", self.function, index).into())
}
pub fn cloned(&self, index: usize) -> ForeignFunctionCallbackResult<Value> {
self.get(index).cloned()
}
pub fn string(
&self,
index: usize,
argument_name: &'static str,
) -> ForeignFunctionCallbackResult<&'a str> {
match self.get(index)? {
Value::String(value) => Ok(value),
_ => Err(format!("{argument_name} must be a string").into()),
}
}
pub fn cloned_string(
&self,
index: usize,
argument_name: &'static str,
) -> ForeignFunctionCallbackResult<String> {
Ok(self.string(index, argument_name)?.to_owned())
}
pub fn object_ref(
&self,
index: usize,
argument_name: &'static str,
) -> ForeignFunctionCallbackResult<ObjectRef> {
ObjectRef::try_from(self.get(index)?)
.map_err(|_| format!("{argument_name} must be an object").into())
}
pub fn array_ref(
&self,
index: usize,
argument_name: &'static str,
) -> ForeignFunctionCallbackResult<ArrayRef> {
ArrayRef::try_from(self.get(index)?)
.map_err(|_| format!("{argument_name} must be an array").into())
}
pub fn table_ref(
&self,
index: usize,
_argument_name: &'static str,
) -> ForeignFunctionCallbackResult<TableRef> {
Ok(TableRef::try_from(self.get(index)?)?)
}
pub fn array_id(
&self,
index: usize,
argument_name: &'static str,
) -> ForeignFunctionCallbackResult<usize> {
Ok(self.array_ref(index, argument_name)?.id())
}
pub fn usize(
&self,
index: usize,
argument_name: &'static str,
) -> ForeignFunctionCallbackResult<usize> {
Ok(value_to_usize(self.get(index)?, argument_name)?)
}
pub fn u64(
&self,
index: usize,
argument_name: &'static str,
) -> ForeignFunctionCallbackResult<u64> {
Ok(value_to_u64(self.get(index)?, argument_name)?)
}
pub fn bool(
&self,
index: usize,
argument_name: &'static str,
) -> ForeignFunctionCallbackResult<bool> {
match self.get(index)? {
Value::Bool(value) => Ok(*value),
_ => Err(format!("{argument_name} must be a boolean").into()),
}
}
pub fn tail_from(&self, index: usize) -> ForeignFunctionCallbackResult<&'a [Value]> {
self.args.get(index..).ok_or_else(|| {
format!("{} missing arguments starting at {}", self.function, index).into()
})
}
}