1 /*
2  * The MIT License (MIT)
3  *
4  * Copyright (c) 2014 Richard Andrew Cattermole
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 module dakka.base.impl.wrap;
25 import dakka.base.impl.defs;
26 import dakka.base.defs;
27 import std.traits : hasMember, ReturnType, ParameterIdentifierTuple;
28 
29 pure string getActorWrapImpl(T : Actor)(T t = T.init) {
30 	string ret;
31 
32 	foreach(m; __traits(allMembers, T)) {
33 		static if (__traits(getProtection, __traits(getMember, t, m)) == "public" && !hasMember!(Actor, m)) {
34 			static if (__traits(isVirtualFunction, __traits(getMember, t, m))) {
35 				static if (!isMethodLocalOnly!(T, m)) {
36                     ret ~= funcDeclText!(T, m)(!is(ReturnType!(mixin("t." ~ m)) == void));
37 
38 					switch(getCallUDA!(T, m).strategy) {
39 						case DakkaCallStrategy.Until:
40 							untilWrapStrategy!(T, m)(ret);
41 							break;
42 
43 						case DakkaCallStrategy.Sequentially:
44 						default:
45 							sequentialWrapStrategy!(T, m)(ret);
46 							break;
47 					}
48 
49 					ret ~= "    }\n";
50 				}
51 			}
52 		}
53 	}
54 
55 	return ret;
56 }
57 
58 pure DakkaCall_ getCallUDA(T : Actor, string m)() {
59 	enum T t = T.init;
60 	foreach(UDA; __traits(getAttributes, mixin("t." ~ m))) {
61 		if (typeText!(typeof(UDA)) == typeText!DakkaCall_) {
62 			return UDA;
63 		}
64 	}
65 
66 	return DakkaCall(DakkaCallStrategy.Sequentially);
67 }
68 
69 pure void sequentialWrapStrategy(T, string m)(ref string ret) {
70 	enum uda = getCallUDA!(T, m);
71 	enum T t = T.init;
72 
73 	string names;
74 	foreach(name; ParameterIdentifierTuple!(mixin("t." ~ m))) {
75 		names ~= name ~ ", ";
76 	}
77 	if (names.length > 0)
78 		names.length -= 2;
79 
80     if (is(ReturnType!(mixin("t." ~ m)) == void)) {
81     	ret ~= ("""
82      	checkForUpdatesToAddresses();
83 
84     	localRef." ~ m ~ "(" ~ names ~ ");
85     	foreach(actor; remoteRefs.values) {
86     		actor." ~ m ~ "(" ~ names ~ ");
87     	}
88 """)[1 .. $];
89     } else {
90         ret ~= ("""
91         checkForUpdatesToAddresses();
92         " ~ typeText!(ReturnType!(mixin("t." ~ m))) ~ "[] ret;
93 
94         ret ~= localRef." ~ m ~ "(" ~ names ~ ");
95         foreach(actor; remoteRefs.values) {
96             ret ~= actor." ~ m ~ "(" ~ names ~ ");
97         }
98         return ret;
99 """)[1 .. $];
100     }
101 }
102 
103 pure void untilWrapStrategy(T, string m)(ref string ret) {
104 	enum uda = getCallUDA!(T, m);
105 	enum T t = T.init;
106 	import std.conv : to;
107 	
108 	string names;
109 	foreach(name; ParameterIdentifierTuple!(mixin("t." ~ m))) {
110 		names ~= name ~ ", ";
111 	}
112 	if (names.length > 0)
113 		names.length -= 2;
114 	
115 	ret ~= ("""
116 	checkForUpdatesToAddresses();
117 	" ~ typeText!(ReturnType!(mixin("t." ~ m))) ~ "[] ret;
118 
119 	" ~ typeText!(ReturnType!(mixin("t." ~ m))) ~ " vcmp = Decerealizer(" ~ to!string(uda.data) ~ ").value!(" ~ typeText!(ReturnType!(mixin("t." ~ m))) ~ ");
120 
121 	ret ~= localRef." ~ m ~ "(" ~ names ~ ");
122 	if (ret[0] == vcmp)
123  	 	return ret;
124 
125 	foreach(actor; remoteRefs.values) {
126 		" ~ typeText!(ReturnType!(mixin("t." ~ m))) ~ " v = actor." ~ m ~ "(" ~ names ~ ");
127 		ret ~= v;
128 		if (v == vcmp)
129 			break;
130 	}
131  	return ret;
132 """)[1 .. $];
133 }