Add stack pack and unpack methods
This commit is contained in:
parent
e801ee468b
commit
173149f2f7
@ -851,6 +851,85 @@ impl Stack {
|
|||||||
unsafe { lua_rawseti(self.as_ptr(), table.index(), n) }
|
unsafe { lua_rawseti(self.as_ptr(), table.index(), n) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Packs the array-part of the table at index `idx` from the stack.
|
||||||
|
///
|
||||||
|
/// This pops `n` values at the top of the stack, sets them as the fields of the table at index
|
||||||
|
/// `idx` at indices `1` to `n` inclusive, then sets the field `"n"` to `n`. Any existing values
|
||||||
|
/// in the table are overwritten. If the table already has more than `n` values in its
|
||||||
|
/// array-part, these values are **not** cleared. The number of values popped is returned, which
|
||||||
|
/// is always equal to `n`.
|
||||||
|
///
|
||||||
|
/// This method does not invoke any metamethods.
|
||||||
|
///
|
||||||
|
/// Equivalent to `table.pack(...)`.
|
||||||
|
///
|
||||||
|
/// # Panic
|
||||||
|
///
|
||||||
|
/// Panics if `n` is negative, there are not enough values on the stack, or the value at index
|
||||||
|
/// `idx` is not a table.
|
||||||
|
pub fn pack(&mut self, idx: c_int, n: c_int) -> c_int {
|
||||||
|
assert!(n >= 0, "n must be nonnegative");
|
||||||
|
let size = self.size();
|
||||||
|
let table = self.slot(idx);
|
||||||
|
assert!(
|
||||||
|
table.type_of() == Type::Table,
|
||||||
|
"expected table at index {idx}: {self:?}"
|
||||||
|
);
|
||||||
|
assert!(n <= size, "expected {n} values: {self:?}");
|
||||||
|
assert!(idx <= size - n, "cannot pack a table into itself: {self:?}");
|
||||||
|
unsafe {
|
||||||
|
(0..n).for_each(|i| lua_rawseti(self.as_ptr(), table.index(), n - i));
|
||||||
|
self.ensure(2);
|
||||||
|
lua_pushliteral(self.as_ptr(), "n");
|
||||||
|
lua_pushinteger(self.as_ptr(), n as lua_Integer);
|
||||||
|
lua_rawset(self.as_ptr(), table.index());
|
||||||
|
n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unpacks the array-part of the table at index `idx` onto the stack.
|
||||||
|
///
|
||||||
|
/// If `j` is [`None`], then it is set to be the value of the field `"n"` interpreted as an
|
||||||
|
/// integer. If this field does not exist, then it is set to the be length of the table as
|
||||||
|
/// defined by the Lua `#` length operator. All values in indices `i` to `j` inclusive are
|
||||||
|
/// pushed at the top of the stack in ascending order. If `i > j`, then nothing is pushed.
|
||||||
|
/// Otherwise, `j - i + 1` values are pushed, and the number of values pushed is returned.
|
||||||
|
///
|
||||||
|
/// This method does not invoke any metamethods.
|
||||||
|
///
|
||||||
|
/// Equivalent to `table.unpack(list, i, j)`.
|
||||||
|
///
|
||||||
|
/// # Panic
|
||||||
|
///
|
||||||
|
/// Panics if the value at index `idx` is not a table.
|
||||||
|
pub fn unpack(&mut self, idx: c_int, i: c_int, j: Option<c_int>) -> c_int {
|
||||||
|
let table = self.slot(idx);
|
||||||
|
assert!(
|
||||||
|
table.type_of() == Type::Table,
|
||||||
|
"expected table at index {idx}: {self:?}"
|
||||||
|
);
|
||||||
|
let j = match j {
|
||||||
|
Some(j) => j,
|
||||||
|
None => unsafe {
|
||||||
|
self.ensure(1);
|
||||||
|
lua_pushliteral(self.as_ptr(), "n");
|
||||||
|
lua_rawget(self.as_ptr(), table.index());
|
||||||
|
let mut isnum = 0;
|
||||||
|
let n = lua_tointegerx(self.as_ptr(), -1, &raw mut isnum);
|
||||||
|
lua_pop(self.as_ptr(), 1);
|
||||||
|
(isnum != 0)
|
||||||
|
.then_some(n as c_int)
|
||||||
|
.unwrap_or_else(|| lua_objlen(self.as_ptr(), table.index()) as c_int)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let n = (j - i + 1).max(0);
|
||||||
|
if n > 0 {
|
||||||
|
self.ensure(n);
|
||||||
|
(0..n).for_each(|n| unsafe { lua_rawgeti(self.as_ptr(), table.index(), i + n) });
|
||||||
|
}
|
||||||
|
n
|
||||||
|
}
|
||||||
|
|
||||||
/// Pushes the given chunk as a function at the top of the stack.
|
/// Pushes the given chunk as a function at the top of the stack.
|
||||||
///
|
///
|
||||||
/// Equivalent to [`lua_loadx`].
|
/// Equivalent to [`lua_loadx`].
|
||||||
@ -1144,7 +1223,7 @@ impl Stack {
|
|||||||
///
|
///
|
||||||
/// Equivalent to [`luaL_traceback`].
|
/// Equivalent to [`luaL_traceback`].
|
||||||
pub fn backtrace(&self, level: c_int) -> Option<BString> {
|
pub fn backtrace(&self, level: c_int) -> Option<BString> {
|
||||||
assert!(level >= 0, "backtrace level must be nonnegative");
|
assert!(level >= 0, "level must be nonnegative");
|
||||||
self.ensure(LUA_MINSTACK);
|
self.ensure(LUA_MINSTACK);
|
||||||
unsafe {
|
unsafe {
|
||||||
luaL_traceback(self.as_ptr(), self.as_ptr(), ptr::null(), 0);
|
luaL_traceback(self.as_ptr(), self.as_ptr(), ptr::null(), 0);
|
||||||
@ -1590,8 +1669,8 @@ impl NewTable {
|
|||||||
impl Push for NewTable {
|
impl Push for NewTable {
|
||||||
fn push(&self, stack: &mut Stack) {
|
fn push(&self, stack: &mut Stack) {
|
||||||
let Self { narr, nrec } = *self;
|
let Self { narr, nrec } = *self;
|
||||||
assert!(0 <= narr, "size of table array part must be nonnegative");
|
assert!(0 <= narr, "narr must be nonnegative");
|
||||||
assert!(0 <= nrec, "size of table hash part must be nonnegative");
|
assert!(0 <= nrec, "nrec must be nonnegative");
|
||||||
stack.ensure(1);
|
stack.ensure(1);
|
||||||
unsafe { lua_createtable(stack.as_ptr(), narr, nrec) }
|
unsafe { lua_createtable(stack.as_ptr(), narr, nrec) }
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user