use super::error::{EvalResult, Flow, signal};
use super::intern::resolve_sym;
use super::value::{Value, ValueKind};
fn expect_args(name: &str, args: &[Value], n: usize) -> Result<(), Flow> {
if args.len() != n {
Err(signal(
"wrong-number-of-arguments",
vec![Value::symbol(name), Value::fixnum(args.len() as i64)],
))
} else {
Ok(())
}
}
fn expect_range_args(
name: &str,
args: &[Value],
min: usize,
max: Option<usize>,
) -> Result<(), Flow> {
let out_of_range = match max {
Some(max) => args.len() < min || args.len() > max,
None => args.len() < min,
};
if out_of_range {
Err(signal(
"wrong-number-of-arguments",
vec![Value::symbol(name), Value::fixnum(args.len() as i64)],
))
} else {
Ok(())
}
}
fn expect_symbolp(value: &Value) -> Result<String, Flow> {
match value.kind() {
ValueKind::Symbol(id) => Ok(resolve_sym(id).to_owned()),
other => Err(signal(
"wrong-type-argument",
vec![Value::symbol("symbolp"), *value],
)),
}
}
fn expect_wholenump(value: &Value) -> Result<i64, Flow> {
match value.kind() {
ValueKind::Fixnum(n) if n >= 0 => Ok(n),
other => Err(signal(
"wrong-type-argument",
vec![Value::symbol("wholenump"), *value],
)),
}
}
fn dbus_error(msg: &str, details: Value) -> Flow {
signal("dbus-error", vec![Value::string(msg), details])
}
fn recognized_bus_name(name: &str) -> bool {
matches!(name, ":system" | ":session")
}
pub(crate) fn builtin_dbus_init_bus(args: Vec<Value>) -> EvalResult {
expect_range_args("dbus--init-bus", &args, 1, Some(2))?;
let bus = expect_symbolp(&args[0])?;
if recognized_bus_name(&bus) {
Ok(Value::fixnum(2))
} else {
Err(dbus_error("Wrong bus name", Value::symbol(bus)))
}
}
pub(crate) fn builtin_dbus_get_unique_name(args: Vec<Value>) -> EvalResult {
expect_args("dbus-get-unique-name", &args, 1)?;
let bus = expect_symbolp(&args[0])?;
if recognized_bus_name(&bus) {
Err(dbus_error("No connection to bus", Value::symbol(bus)))
} else {
Err(dbus_error("Wrong bus name", Value::symbol(bus)))
}
}
pub(crate) fn builtin_dbus_message_internal(args: Vec<Value>) -> EvalResult {
expect_range_args("dbus-message-internal", &args, 4, None)?;
let _bus_id = expect_wholenump(&args[0])?;
match args[1].kind() {
ValueKind::Symbol(_) => Ok(Value::NIL),
ValueKind::String => {
let dest = args[1].as_str().unwrap().to_owned();
if !dest.contains(':') {
Err(signal(
"dbus-error",
vec![Value::string("Address does not contain a colon")],
))
} else if args.len() == 4 {
Err(signal(
"wrong-number-of-arguments",
vec![Value::symbol("dbus-message-internal"), Value::fixnum(4)],
))
} else {
Ok(Value::NIL)
}
}
other => Err(signal(
"wrong-type-argument",
vec![Value::symbol("symbolp"), args[1]],
)),
}
}
#[cfg(test)]
#[path = "dbus_test.rs"]
mod tests;