tomaka / hlua

Rust library to interface with Lua
MIT License
510 stars 48 forks source link

AnyLuaValue::LuaArray still can't be used in Lua #74

Closed SnirkImmington closed 7 years ago

SnirkImmington commented 8 years ago

I have a program that uses AnyLuaValues a lot. We have a data store that the Rust and Lua parts share back and forth across, and the easiest way to share data back and forth was through AnyLuaValues.

I'd written traits ToTable and FromTable for the conversions (using move semantics to avoid copies):

    #[derive(Debug, Clone, PartialEq, Eq, Hash)]
    struct Point {
        x: i32,
        y: u32
    }
    impl ToTable for Point {
        fn to_table(self) -> AnyLuaValue {
            LuaArray(vec![
                (LuaString("x".into()), LuaNumber(self.x as f64)),
                (LuaString("y".into()), LuaNumber(self.y as f64))
            ])
        }
    }
    impl FromTable for Point {
        fn from_table(decoder: LuaDecoder) -> ConvertResult<Point> {
            let (decoder, x) = try!(decoder.read_field("x".into()));
            let (_decoder, y) = try!(decoder.read_field("y".into()));
            Ok(Point { x: x, y: y })
        }
    }

This is also a great way to store structured data (like a slimmed-down JSON) and it made it easy to provide compatibility without using userdata, &mut Lua or PushGuard<L> or AsMutLua. I've even got a macro to generate a struct with these implementations automatically.

However, pushing and reading AnyLuaData::LuaArray is unsupported right now, with a little comment that mentions hitting a stack limit. Is there a way to implement it?

tomaka commented 8 years ago

If you're talking about https://github.com/tomaka/hlua/blob/master/hlua/src/any.rs#L30 Then it's because of a bug in rustc. Maybe it has been fixed now.

SnirkImmington commented 8 years ago

Would there also be runtime ways (i.e. a for loop, etc.) of doing it? I haven't looked at the code a whole lot but I'd be willing to give it a go, even if this bug still exists there should be a way around it.

tomaka commented 8 years ago

Well, it is the runtime way, as the actual content of the array is unknown. The compiler bug prevented it from working.

andybarron commented 8 years ago

Is this compiler bug known and/or fixed?

andybarron commented 8 years ago

I'm not sure this is a compiler bug? Since one variant of AnyLuaValue contains a Vec<(AnyLuaValue, AnyLuaValue)>, calling push_to_lua on that vector triggers an error related to polymorphic recursion. I think. I'm tinkering with it now...

tomaka commented 8 years ago

That code alone works: https://is.gd/rFFNLf

So I guess the problem has been fixed in rustc.

andybarron commented 8 years ago

However, un-commenting this line and running cargo test still gives the following error:

error: reached the recursion limit while instantiating `<hlua::any::AnyLuaValue as hlua::Push<L>><&mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut hlua::Lua>::push_to_lua`

😞

tomaka commented 7 years ago

So the problem is that in order to push a Vec on a L, each element of the Vec needs to be pushed individually on the L. But we can't just push elements on the L because pushing consumes the L. You could only push a single element and then the borrow checker would complain. Instead the where clause for Vec pushing requires that elements of the Vec must be pushable on &mut L, so that pushing each element consumes a &mut L and not a L.

So far so good.

Unfortunately the consequence is in order to push a Vec<(AnyLuaValue, AnyLuaValue)> on a L we need to call the function that pushes a AnyLuaValue on a &mut L. But if that AnyLuaValue contains a Vec<(AnyLuaValue, AnyLuaValue)>, then we need to call the function that pushes a AnyLuaValue on a &mut &mut L. But if that AnyLuaValue contains a Vec, then we need to call the function that pushes a AnyLuaValue on a &mut &mut &mut L. And so on. This is why we're reaching the recursion limit.

Unfortunately I don't see any obvious fix for now.

tomaka commented 7 years ago

Fixed in #106