use crate::{FromLua, GlobalState, IntoLua, LuaResult};
pub(crate) fn into_single_value<T: IntoLua>(
vm: &mut GlobalState,
value: T,
api_name: &str,
) -> LuaResult<luars::LuaValue> {
let mut values = collect_values(vm, value)?;
if values.len() != 1 {
return Err(vm.main_state().error(format!(
"{} expects exactly one Lua value, got {}",
api_name,
values.len()
)));
}
Ok(values.pop().unwrap())
}
pub(crate) fn collect_values<T: IntoLua>(
vm: &mut GlobalState,
value: T,
) -> LuaResult<Vec<luars::LuaValue>> {
let base_top = vm.main_state().get_top();
let pushed = {
let state = vm.main_state();
match value.into_lua(state) {
Ok(pushed) => pushed,
Err(err) => {
state.set_top_raw(base_top);
return Err(state.error(err));
}
}
};
let mut values = Vec::with_capacity(pushed);
{
let state = vm.main_state();
for index in base_top..base_top + pushed {
let Some(value) = state.stack_get(index) else {
state.set_top_raw(base_top);
return Err(state
.error("internal error: failed to collect Lua values from stack".to_owned()));
};
values.push(value);
}
state.set_top_raw(base_top);
}
Ok(values)
}
pub(crate) fn from_value<T: FromLua>(
vm: &mut GlobalState,
value: luars::LuaValue,
api_name: &str,
) -> LuaResult<T> {
T::from_lua(value, vm.main_state())
.map_err(|msg| vm.main_state().error(format!("{}: {}", api_name, msg)))
}