1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use td_clua;
use td_clua::lua_State;

use LuaPush;
use LuaRead;
use LuaTable;

use std::collections::{HashMap, HashSet};
use std::hash::Hash;

fn push_iter<V, I>(lua: *mut lua_State, iterator: I) -> i32
where
    V: LuaPush,
    I: Iterator<Item = V>,
{
    // creating empty table
    unsafe { td_clua::lua_newtable(lua) };

    for (elem, index) in iterator.zip(1..) {
        let size = elem.push_to_lua(lua);

        match size {
            0 => continue,
            1 => {
                let index = index as u32;
                index.push_to_lua(lua);
                unsafe { td_clua::lua_insert(lua, -2) }
                unsafe { td_clua::lua_settable(lua, -3) }
            }
            2 => unsafe { td_clua::lua_settable(lua, -3) },
            _ => unreachable!(),
        }
    }

    1
}

fn push_rec_iter<V, I>(lua: *mut lua_State, iterator: I) -> i32
where
    V: LuaPush,
    I: Iterator<Item = V>,
{
    let (nrec, _) = iterator.size_hint();

    // creating empty table with pre-allocated non-array elements
    unsafe { td_clua::lua_createtable(lua, 0, nrec as i32) };

    for elem in iterator {
        let size = elem.push_to_lua(lua);

        match size {
            0 => continue,
            2 => unsafe { td_clua::lua_settable(lua, -3) },
            _ => unreachable!(),
        }
    }

    1
}

impl<T> LuaPush for Vec<T>
where
    T: LuaPush,
{
    fn push_to_lua(self, lua: *mut lua_State) -> i32 {
        push_iter(lua, self.into_iter())
    }
}

impl<'a, T> LuaPush for &'a [T]
where
    T: Clone + LuaPush,
{
    fn push_to_lua(self, lua: *mut lua_State) -> i32 {
        push_iter(lua, self.iter().map(|e| e.clone()))
    }
}

impl<K, V> LuaPush for HashMap<K, V>
where
    K: LuaPush + Eq + Hash,
    V: LuaPush,
{
    fn push_to_lua(self, lua: *mut lua_State) -> i32 {
        push_rec_iter(lua, self.into_iter())
    }
}

impl<K> LuaPush for HashSet<K>
where
    K: LuaPush + Eq + Hash,
{
    fn push_to_lua(self, lua: *mut lua_State) -> i32 {
        use std::iter;
        push_rec_iter(lua, self.into_iter().zip(iter::repeat(true)))
    }
}

impl<T> LuaRead for Vec<T>
where
    T: LuaRead,
{
    fn lua_read_with_pop(lua: *mut lua_State, index: i32, _pop: i32) -> Option<Vec<T>> {
        let mut lua_table: LuaTable =
            unwrap_or!(LuaRead::lua_read_at_position(lua, index), return None);
        let mut result = vec![];
        let len = lua_table.table_len();
        for i in 1..(len + 1) {
            let val: T = unwrap_or!(lua_table.query(i), return None);
            result.push(val);
        }
        Some(result)
    }
}