1 module as.addons.dwrap;
2 import as.def;
3 import as.engine;
4 import core.memory;
5 import core.stdc.stdlib : free;
6 import std.traits;
7 import std.format;
8 import std..string;
9 import std.stdio;
10 
11 private {
12     extern(C) void constructClassOrStruct(T)(T* self) {
13         import std.conv : emplace;
14         emplace!T(self);
15     }
16 
17     extern(C) void destructClassOrStruct(T)(T* self) {
18         destroy(self);
19     }
20 
21     extern(C) T structAssign(T)(ref T in_, ref T self) {
22         writeln(self, " ", in_);
23         self = in_;
24         return self;
25     }
26 
27     string toASType(string typeName) {
28         switch(typeName) {
29 
30             case "string":
31             case "int":
32             case "float":
33             case "double": return typeName;
34 
35             case "ubyte": return "byte";
36             case "ushort": return "uint16";
37             case "uint": return "uint";
38             case "ulong": return "uint64";
39             default: {
40                 while (typeName.endsWith("*")) {
41                     typeName.length--;
42                 }
43                 return typeName;
44             }
45         }
46     }
47 
48     string buildArgList(alias T)() {
49         string[] o;
50         static foreach(param; Parameters!T) {
51             o ~= toASType(param.stringof);
52         }
53         return o.length == 0 ? "" : o.join(", ");
54     }
55 }
56 
57 void registerDStruct(T, string namespace = "")(ScriptEngine engine) if (is(T == struct)) {
58     mixin("import ", moduleName!T, ";");
59 
60     static if (namespace.length != 0) {
61         string prevNamespace = engine.getDefaultNamespace();
62         scope(exit) engine.setDefaultNamespace(prevNamespace);
63         
64         // Set up namespace
65         engine.setDefaultNamespace(namespace);
66     }
67     
68     engine.registerObjectType(T.stringof, T.sizeof, asEObjTypeFlags.asOBJ_VALUE | asEObjTypeFlags.asOBJ_APP_CLASS_CDAK);
69     engine.registerObjectBehaviour(
70         T.stringof,
71         asEBehaviours.asBEHAVE_CONSTRUCT, 
72         "void f()",
73         cast(asFUNCTION_t)&constructClassOrStruct!T, 
74         DCallConvClass, 
75         null
76     );
77 
78     engine.registerObjectBehaviour(
79         T.stringof,
80         asEBehaviours.asBEHAVE_DESTRUCT, 
81         "void f()",
82         cast(asFUNCTION_t)&destructClassOrStruct!T, 
83         DCallConvClass, 
84         null
85     );
86     engine.registerObjectMethod(
87         T.stringof, 
88         "%s &opAssign(const %s &in)".format(T.stringof, T.stringof), 
89         &structAssign!T, 
90         DCallConvClassR
91     );
92     
93 
94     static foreach(member; __traits(allMembers, T)) {
95         {
96             alias mInstance = mixin(T.stringof, ".", member);
97             enum visibility = __traits(getProtection, mInstance);
98             static if (visibility == "public" || visibility == "static") {
99                 static if (is(typeof(mInstance) == function)) {
100                     {
101                         string retType = (ReturnType!mInstance).stringof;
102 
103                         engine.registerObjectMethod(T.stringof, "%s %s(%s)".format(toASType(retType), member, buildArgList!mInstance()), cast(asFUNCTION_t)&mInstance, DCallConvClassR, null);
104                     }
105                 } else static if(!is(typeof(mInstance) == struct) && !is(typeof(mInstance) == class)) {
106                     engine.registerObjectProperty(T.stringof, "%s %s".format(toASType(typeof(mInstance).stringof), member), mInstance.offsetof);
107                 } else static if(is(typeof(mInstance) == struct)) {
108                     // TODO: Auto register structs if needed
109                 }
110             }
111         }
112     }
113 
114 }