Implement methods for iterating through a Table
This commit is contained in:
parent
70e2985cc4
commit
beea6c33fc
|
@ -37,6 +37,12 @@ pub use lref::*;
|
|||
pub mod variadic;
|
||||
pub use variadic::*;
|
||||
|
||||
pub mod table_iter;
|
||||
pub use table_iter::*;
|
||||
|
||||
pub mod table_pairs;
|
||||
pub use table_pairs::*;
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests;
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ use mlua_sys as lua;
|
|||
#[derive(Clone)]
|
||||
pub struct LuaRef<'a> {
|
||||
lref: Arc<i32>,
|
||||
state: &'a State,
|
||||
pub(crate) state: &'a State,
|
||||
}
|
||||
|
||||
impl<'a> Drop for LuaRef<'a> {
|
||||
|
|
20
src/table.rs
20
src/table.rs
|
@ -1,6 +1,6 @@
|
|||
use mlua_sys as lua;
|
||||
|
||||
use crate::{ensure_type, AsLua, Error, FromLua, FromLuaStack, LuaRef, PushToLuaStack, Result, StackGuard, State, Value};
|
||||
use crate::{ensure_type, AsLua, Error, FromLua, FromLuaStack, LuaRef, PushToLuaStack, Result, StackGuard, State, TableIter, TablePairs, Value};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Table<'a> {
|
||||
|
@ -287,8 +287,26 @@ impl<'a> Table<'a> {
|
|||
pub fn try_from<T: TableProxy + Sized>(state: &'a State, proxy: T) -> Result<Table<'a>> {
|
||||
proxy.as_table(state)
|
||||
}
|
||||
|
||||
/// Returns an iterator over the sequence values in the table, this does not execute any metamethods.
|
||||
///
|
||||
/// # Note
|
||||
/// elua cannot protect the table from mutation from another source
|
||||
pub fn sequence_iter<T: FromLua<'a>>(&self) -> TableIter<'a, T> {
|
||||
TableIter::new(self.lref.clone())
|
||||
}
|
||||
|
||||
/// Returns an iterator that returns the key value pairs of the Lua table.
|
||||
/// This is similar to lua's `pairs` method, but it doesn't execute the `__pairs` metamethod.
|
||||
///
|
||||
/// # Note
|
||||
/// elua cannot protect the table from mutation from another source
|
||||
pub fn pairs<K: FromLua<'a>, V: FromLua<'a>>(&self) -> TablePairs<'a, K, V> {
|
||||
TablePairs::new(self.lref.clone())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'a> PushToLuaStack<'a> for Table<'a> {
|
||||
unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()> {
|
||||
// no need to ensure stack, the LuaRef does it for us
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use crate::{FromLua, FromLuaStack, LuaRef, PushToLuaStack, StackGuard, Value};
|
||||
|
||||
use mlua_sys as lua;
|
||||
|
||||
pub struct TableIter<'a, T: FromLua<'a>> {
|
||||
lref: LuaRef<'a>,
|
||||
index: i64,
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'a, T: FromLua<'a>> TableIter<'a, T> {
|
||||
pub(crate) fn new(table_ref: LuaRef<'a>) -> Self {
|
||||
Self {
|
||||
lref: table_ref,
|
||||
index: 1,
|
||||
_marker: PhantomData::<T>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: FromLua<'a>> Iterator for TableIter<'a, T> {
|
||||
type Item = crate::Result<T>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
unsafe {
|
||||
let state = self.lref.state;
|
||||
let s = state.state_ptr();
|
||||
|
||||
if let Err(e) = state.ensure_stack(1) {
|
||||
return Some(Err(e));
|
||||
}
|
||||
let _g = StackGuard::new(state);
|
||||
|
||||
if let Err(e) = self.lref.push_to_lua_stack(state) {
|
||||
return Some(Err(e));
|
||||
}
|
||||
|
||||
match lua::lua_rawgeti(s, -1, self.index) {
|
||||
lua::LUA_TNIL => None,
|
||||
_ => {
|
||||
self.index += 1;
|
||||
match Value::from_lua_stack(state) {
|
||||
Ok(v) => Some(T::from_lua(state, v)),
|
||||
Err(e) => {
|
||||
return Some(Err(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use crate::{AsLua, FromLua, FromLuaStack, LuaRef, PushToLuaStack, StackGuard, Value};
|
||||
|
||||
use mlua_sys as lua;
|
||||
|
||||
pub struct TablePairs<'a, K: FromLua<'a>, V: FromLua<'a>> {
|
||||
lref: LuaRef<'a>,
|
||||
last_val: Option<Value<'a>>,
|
||||
_marker: PhantomData<(K, V)>
|
||||
}
|
||||
|
||||
impl<'a, K: FromLua<'a>, V: FromLua<'a>> TablePairs<'a, K, V> {
|
||||
pub(crate) fn new(table_ref: LuaRef<'a>) -> Self {
|
||||
Self {
|
||||
lref: table_ref,
|
||||
last_val: Some(Value::Nil),
|
||||
_marker: PhantomData::<(K, V)>,
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn get_item(&mut self) -> crate::Result<Option<(K, V)>> {
|
||||
let state = self.lref.state;
|
||||
let s = state.state_ptr();
|
||||
|
||||
let _g = StackGuard::new(state);
|
||||
state.ensure_stack(5)?;
|
||||
|
||||
self.lref.push_to_lua_stack(state)?;
|
||||
self.last_val.push_to_lua_stack(state)?;
|
||||
|
||||
if lua::lua_next(s, -2) != 0 {
|
||||
let right_val = Value::from_lua_stack(state)?;
|
||||
let left_val = Value::from_lua_stack(state)?;
|
||||
|
||||
self.last_val = Some(left_val.clone());
|
||||
|
||||
let right = V::from_lua(state, right_val)?;
|
||||
let left = K::from_lua(state, left_val)?;
|
||||
|
||||
Ok(Some((left, right)))
|
||||
} else {
|
||||
self.last_val = None;
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: FromLua<'a>, V: FromLua<'a>> Iterator for TablePairs<'a, K, V> {
|
||||
type Item = crate::Result<(K, V)>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let None = self.last_val {
|
||||
return None;
|
||||
}
|
||||
|
||||
match unsafe { self.get_item() } {
|
||||
Ok(Some(tup)) => {
|
||||
Some(Ok(tup))
|
||||
},
|
||||
Ok(None) => {
|
||||
None
|
||||
},
|
||||
Err(e) => {
|
||||
Some(Err(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue