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 }