use std::collections::BTreeMap;
use std::rc::Rc;
use harn_vm::VmValue;
use crate::error::HostlibError;
pub fn dict_arg(
builtin: &'static str,
args: &[VmValue],
) -> Result<Rc<BTreeMap<String, VmValue>>, HostlibError> {
match args.first() {
Some(VmValue::Dict(dict)) => Ok(dict.clone()),
Some(VmValue::Nil) | None => Ok(Rc::new(BTreeMap::new())),
Some(other) => Err(HostlibError::InvalidParameter {
builtin,
param: "params",
message: format!(
"expected a dict argument, got {} ({:?})",
other.type_name(),
other
),
}),
}
}
pub fn require_string(
builtin: &'static str,
dict: &BTreeMap<String, VmValue>,
key: &'static str,
) -> Result<String, HostlibError> {
match dict.get(key) {
Some(VmValue::String(s)) => Ok(s.to_string()),
Some(other) => Err(HostlibError::InvalidParameter {
builtin,
param: key,
message: format!("expected string, got {}", other.type_name()),
}),
None => Err(HostlibError::MissingParameter {
builtin,
param: key,
}),
}
}
pub fn optional_string(
builtin: &'static str,
dict: &BTreeMap<String, VmValue>,
key: &'static str,
) -> Result<Option<String>, HostlibError> {
match dict.get(key) {
None | Some(VmValue::Nil) => Ok(None),
Some(VmValue::String(s)) => Ok(Some(s.to_string())),
Some(other) => Err(HostlibError::InvalidParameter {
builtin,
param: key,
message: format!("expected string, got {}", other.type_name()),
}),
}
}
pub fn optional_bool(
builtin: &'static str,
dict: &BTreeMap<String, VmValue>,
key: &'static str,
default: bool,
) -> Result<bool, HostlibError> {
match dict.get(key) {
None | Some(VmValue::Nil) => Ok(default),
Some(VmValue::Bool(b)) => Ok(*b),
Some(other) => Err(HostlibError::InvalidParameter {
builtin,
param: key,
message: format!("expected bool, got {}", other.type_name()),
}),
}
}
pub fn optional_int(
builtin: &'static str,
dict: &BTreeMap<String, VmValue>,
key: &'static str,
default: i64,
) -> Result<i64, HostlibError> {
match dict.get(key) {
None | Some(VmValue::Nil) => Ok(default),
Some(VmValue::Int(n)) => Ok(*n),
Some(VmValue::Float(f)) if f.fract() == 0.0 => Ok(*f as i64),
Some(other) => Err(HostlibError::InvalidParameter {
builtin,
param: key,
message: format!("expected integer, got {}", other.type_name()),
}),
}
}
pub fn require_int(
builtin: &'static str,
dict: &BTreeMap<String, VmValue>,
key: &'static str,
) -> Result<i64, HostlibError> {
match dict.get(key) {
Some(VmValue::Int(n)) => Ok(*n),
Some(VmValue::Float(f)) if f.fract() == 0.0 => Ok(*f as i64),
Some(other) => Err(HostlibError::InvalidParameter {
builtin,
param: key,
message: format!("expected integer, got {}", other.type_name()),
}),
None => Err(HostlibError::MissingParameter {
builtin,
param: key,
}),
}
}
pub fn optional_string_list(
builtin: &'static str,
dict: &BTreeMap<String, VmValue>,
key: &'static str,
) -> Result<Vec<String>, HostlibError> {
match dict.get(key) {
None | Some(VmValue::Nil) => Ok(Vec::new()),
Some(VmValue::List(items)) => {
let mut out = Vec::with_capacity(items.len());
for item in items.iter() {
match item {
VmValue::String(s) => out.push(s.to_string()),
other => {
return Err(HostlibError::InvalidParameter {
builtin,
param: key,
message: format!(
"expected list of strings, got element {}",
other.type_name()
),
});
}
}
}
Ok(out)
}
Some(other) => Err(HostlibError::InvalidParameter {
builtin,
param: key,
message: format!("expected list of strings, got {}", other.type_name()),
}),
}
}
pub fn optional_int_list(
builtin: &'static str,
dict: &BTreeMap<String, VmValue>,
key: &'static str,
) -> Result<Vec<i64>, HostlibError> {
match dict.get(key) {
None | Some(VmValue::Nil) => Ok(Vec::new()),
Some(VmValue::List(items)) => {
let mut out = Vec::with_capacity(items.len());
for item in items.iter() {
match item {
VmValue::Int(n) => out.push(*n),
VmValue::Float(f) if f.fract() == 0.0 => out.push(*f as i64),
other => {
return Err(HostlibError::InvalidParameter {
builtin,
param: key,
message: format!(
"expected list of integers, got element {}",
other.type_name()
),
});
}
}
}
Ok(out)
}
Some(other) => Err(HostlibError::InvalidParameter {
builtin,
param: key,
message: format!("expected list of integers, got {}", other.type_name()),
}),
}
}
pub fn build_dict<I, K>(entries: I) -> VmValue
where
I: IntoIterator<Item = (K, VmValue)>,
K: Into<String>,
{
let mut map: BTreeMap<String, VmValue> = BTreeMap::new();
for (k, v) in entries {
map.insert(k.into(), v);
}
VmValue::Dict(Rc::new(map))
}
pub fn str_value(s: impl AsRef<str>) -> VmValue {
VmValue::String(Rc::from(s.as_ref()))
}