1 module tardy.refraction; 2 3 4 /** 5 Returns a string mixin that is the function pointer type of F, 6 with an extra void* (or const(void)*) first parameter. 7 */ 8 string vtableEntryRecipe(alias F)(in string symbolName = "") 9 in(__ctfe) 10 do 11 { 12 import std.conv: text; 13 import std.algorithm: canFind, among, filter; 14 import std.array: join; 15 16 const symbol = symbolForTraits!F(symbolName); 17 enum attrs = [ __traits(getFunctionAttributes, F) ]; 18 19 enum isConst = attrs.canFind("const"); 20 enum isImmutable = attrs.canFind("immutable"); 21 enum isShared = attrs.canFind("shared"); 22 23 enum selfType = isConst 24 ? `const(void)*` 25 : isImmutable 26 ? `immutable(void)*` 27 : isShared 28 ? `shared(void)*` 29 : `void*`; 30 31 static bool isMemberFunctionOnly(in string attr) { 32 return cast(bool) attr.among("const", "immutable", "shared", "inout", "return", "scope"); 33 } 34 35 const selfAttrs = attrs 36 .filter!(a => isMemberFunctionOnly(a) && !a.among("const", "immutable", "shared")) 37 .join(" "); 38 const vtableEntryAttrs = attrs 39 .filter!(a => !isMemberFunctionOnly(a)) 40 .join(" "); 41 42 return text(returnRecipe(symbol), 43 ` function(`, selfAttrs, " ", selfType, `, `, 44 parametersRecipe!F(symbol), `)`, 45 vtableEntryAttrs); 46 } 47 48 49 /** 50 Returns a string to be mixed in that replicates the signature 51 of F. The string is meant to be mixed in inside a struct or class 52 so as to be a member function. 53 */ 54 string methodRecipe(alias F)(in string symbolName = "") 55 in(__ctfe) 56 do 57 { 58 import std.conv: text; 59 import std.range: iota; 60 import std.algorithm: map; 61 import std.array: join; 62 63 const symbol = symbolForTraits!F(symbolName); 64 enum name = __traits(identifier, F); 65 enum attrs = [ __traits(getFunctionAttributes, F) ].join(" "); 66 67 return text(returnRecipe(symbol), ` `, 68 name, 69 `(`, parametersRecipe!F(symbol), `)`, 70 ` `, attrs); 71 } 72 73 74 private string symbolForTraits(alias F)(in string symbolName = "") 75 in(__ctfe) 76 do 77 { 78 import std.traits: fullyQualifiedName; 79 return symbolName == "" ? fullyQualifiedName!F : symbolName; 80 } 81 82 83 private string returnRecipe(in string symbol) 84 @safe pure 85 in(__ctfe) 86 do 87 { 88 return `std.traits.ReturnType!(` ~ symbol ~ `)`; 89 } 90 91 private string parametersRecipe(alias F)(in string symbol) 92 in(__ctfe) 93 do 94 { 95 96 import std.array: join; 97 import std.traits: Parameters; 98 99 string[] parameters; 100 101 static foreach(i; 0 .. Parameters!F.length) { 102 parameters ~= parameterRecipe!(F, i)(symbol); 103 } 104 105 return parameters.join(", "); 106 } 107 108 109 private string parameterRecipe(alias F, size_t i)(in string symbol) 110 in(__ctfe) 111 do 112 { 113 import std.array: join; 114 import std.conv: text; 115 import std.traits: ParameterDefaults; 116 117 const string[] storageClasses = [ __traits(getParameterStorageClasses, F, i) ]; 118 119 static string defaultValue(alias default_)() { 120 static if(is(default_ == void)) 121 return ""; 122 else 123 return text(" = ", default_); 124 } 125 126 127 return 128 text(storageClasses.join(" "), " ", 129 `std.traits.Parameters!(`, symbol, `)[`, i, `] `, 130 `arg`, i, 131 defaultValue!(ParameterDefaults!F[i]), 132 ); 133 }