use super::cjson::typename;
use mlua::{Lua, Value};
pub(super) enum Stop {
Plain(Vec<u8>),
Arg(usize, Vec<u8>),
Bare(Vec<u8>),
}
pub(super) type Answer<T> = Result<T, Stop>;
pub(super) fn expected(want: &str, what: &str) -> Vec<u8> {
format!("{want} expected, got {what}").into_bytes()
}
pub(super) fn text(lua: &Lua, args: &[Value], i: usize, missing: &str) -> Answer<Vec<u8>> {
let Some(value) = args.get(i - 1) else {
return Err(Stop::Arg(i, expected("string", missing)));
};
match lua.coerce_string(value.clone()) {
Ok(Some(s)) => Ok(s.as_bytes().to_vec()),
_ => Err(Stop::Arg(i, expected("string", typename(value)))),
}
}
pub(super) fn number(lua: &Lua, args: &[Value], i: usize, missing: &str) -> Answer<f64> {
let Some(value) = args.get(i - 1) else {
return Err(Stop::Arg(i, expected("number", missing)));
};
match lua.coerce_number(value.clone()) {
Ok(Some(n)) => Ok(n),
_ => Err(Stop::Arg(i, expected("number", typename(value)))),
}
}
pub(super) fn answer(lua: &Lua, given: Answer<Value>) -> mlua::Result<(i64, Value, Value)> {
match given {
Ok(value) => Ok((0, value, Value::Nil)),
Err(Stop::Plain(why)) => Ok((1, Value::String(lua.create_string(&why)?), Value::Nil)),
Err(Stop::Arg(at, why)) => Ok((
2,
Value::Integer(at as i64),
Value::String(lua.create_string(&why)?),
)),
Err(Stop::Bare(why)) => Ok((3, Value::String(lua.create_string(&why)?), Value::Nil)),
}
}
pub(super) fn behind(t: &mlua::Table) -> Option<mlua::Table> {
t.metatable()?
.raw_get::<Option<mlua::Table>>("__yo_real")
.ok()
.flatten()
}