use mlua::{AnyUserData, ExternalError, FromLua, IntoLua, IntoLuaMulti, Lua, MetaMethod, UserData, UserDataMethods, UserDataRefMut, Value}; pub struct Iter, T> { iter: I, len: Option, count: usize, cache: Vec, } impl Iter where I: Iterator + 'static, T: IntoLua + 'static, { pub fn new(iter: I, len: Option) -> Self { Self { iter, len, count: 0, cache: vec![] } } } impl Iter where I: Iterator + 'static, T: FromLua + 'static, { pub fn into_iter(self, lua: &Lua) -> impl Iterator> { self .cache .into_iter() .map(|cached| T::from_lua(cached, lua)) .chain(self.iter.map(|rest| Ok(rest))) } } impl UserData for Iter where I: Iterator + 'static, T: IntoLua + 'static, { fn add_methods>(methods: &mut M) { methods.add_meta_method(MetaMethod::Len, |_, me, ()| { if let Some(len) = me.len { Ok(len) } else { Err(format!("Length is unknown for {}", std::any::type_name::()).into_lua_err()) } }); methods.add_meta_function(MetaMethod::Pairs, |lua, ud: AnyUserData| { let iter = lua.create_function(|lua, mut me: UserDataRefMut| { if let Some(next) = me.cache.get(me.count).cloned() { me.count += 1; (me.count, next).into_lua_multi(lua) } else if let Some(next) = me.iter.next() { let value = next.into_lua(lua)?; me.cache.push(value.clone()); me.count += 1; (me.count, value).into_lua_multi(lua) } else { ().into_lua_multi(lua) } })?; ud.borrow_mut::()?.count = 0; Ok((iter, ud)) }); } }