1 module zua.interop.table; 2 import zua.interop.classwrapper; 3 import zua.interop; 4 import zua.vm.engine; 5 import std.typecons; 6 7 /** Wrapper around Lua tables */ 8 struct Table { 9 10 /** The internal data for this Table; should seldom be accessed by user code */ 11 Value _internalTable; 12 13 package this(Value table) { 14 _internalTable = table; 15 } 16 17 @disable this(); 18 19 /** Create a new, empty Table */ 20 static Table create() { 21 return Table(Value(new TableValue)); 22 } 23 24 /** Get the metatable */ 25 Nullable!Table metatable() { 26 if (_internalTable.metatable) { 27 return Nullable!Table(Table(Value(_internalTable.metatable))); 28 } 29 else { 30 return Nullable!Table(); 31 } 32 } 33 34 /** Set the metatable */ 35 void metatable(Nullable!Table newMetatable) { 36 if (newMetatable.isNull) { 37 _internalTable.table.metatable = null; 38 } 39 else { 40 _internalTable.table.metatable = newMetatable.get._internalTable.table; 41 } 42 } 43 44 /** Set the metatable */ 45 pragma(inline) void metatable(Table newMetatable) { 46 metatable = newMetatable.Nullable!Table; 47 } 48 49 /** Set the metatable */ 50 pragma(inline) void metatable(typeof(null)) { 51 metatable = Nullable!Table(); 52 } 53 54 /** Get the length of this table */ 55 size_t length() { 56 return cast(size_t)_internalTable.table.length.num; 57 } 58 59 /** Invokes the metatable seamlessly when performing unary negation */ 60 DConsumable opUnary(string s)() if (s == "-") { 61 const Nullable!(Value[]) attempt = _internalTable.metacall("__unm", [v]); 62 if (attempt.isNull) { 63 throw new LuaError(Value("attempt to perform arithmetic on a table value")); 64 } 65 Value[] res = cast(Value[]) attempt.get; 66 if (res.length == 0) { 67 return makeConsumable(Value()); 68 } 69 else { 70 return makeConsumable(res[0]); 71 } 72 } 73 74 /** Seamless index of a table */ 75 DConsumable opIndex(T)(T value) if (isConvertible!T) { 76 return makeConsumable(_internalTable.table.get(DConsumable(value).makeInternalValue)); 77 } 78 79 /** Seamless assign to a table */ 80 void opIndexAssign(T, K)(T value, K key) if (isConvertible!T && isConvertible!K) { 81 DConsumable v; 82 static if (__traits(compiles, v.__ctor!(T, key)(value))) { 83 v.__ctor!(T, key)(value); 84 } 85 else { 86 v = DConsumable(value); 87 } 88 _internalTable.table.set(DConsumable(key).makeInternalValue, v.makeInternalValue); 89 } 90 91 /** Seamless assign to a table, passing a preferred name for the given value */ 92 void expose(string key, T)(T value) if (isConvertible!T) { 93 DConsumable v; 94 v.__ctor!(T, key)(value); 95 _internalTable.table.set(DConsumable(key).makeInternalValue, v.makeInternalValue); 96 } 97 98 /** Seamless assign to a table, passing a preferred name for the given value */ 99 void expose(string key, T)() if (is(T == class)) { 100 _internalTable.table.set(DConsumable(key).makeInternalValue, makeClassWrapper!T[0].makeInternalValue); 101 } 102 103 }