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 mod variadic;
|
||||||
pub use variadic::*;
|
pub use variadic::*;
|
||||||
|
|
||||||
|
pub mod table_iter;
|
||||||
|
pub use table_iter::*;
|
||||||
|
|
||||||
|
pub mod table_pairs;
|
||||||
|
pub use table_pairs::*;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests;
|
pub mod tests;
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ use mlua_sys as lua;
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct LuaRef<'a> {
|
pub struct LuaRef<'a> {
|
||||||
lref: Arc<i32>,
|
lref: Arc<i32>,
|
||||||
state: &'a State,
|
pub(crate) state: &'a State,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Drop for LuaRef<'a> {
|
impl<'a> Drop for LuaRef<'a> {
|
||||||
|
|
20
src/table.rs
20
src/table.rs
|
@ -1,6 +1,6 @@
|
||||||
use mlua_sys as lua;
|
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)]
|
#[derive(Clone)]
|
||||||
pub struct Table<'a> {
|
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>> {
|
pub fn try_from<T: TableProxy + Sized>(state: &'a State, proxy: T) -> Result<Table<'a>> {
|
||||||
proxy.as_table(state)
|
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> {
|
impl<'a> PushToLuaStack<'a> for Table<'a> {
|
||||||
unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()> {
|
unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()> {
|
||||||
// no need to ensure stack, the LuaRef does it for us
|
// 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