1 /** 2 Tests for using CTFE mirror to wrap calling D code from a foreign language. 3 */ 4 module ut.ctfe.reflection.wrap; 5 6 7 import ut.ctfe.reflection; 8 9 10 @("blub.add1") 11 unittest { 12 import blub; 13 import std.format: format; 14 15 enum mod = module_!"modules.functions"; 16 enum add1 = mod.functionsByOverload[0]; 17 18 enum mixinStr = blubWrapperMixin(add1); 19 //pragma(msg, mixinStr); 20 mixin(mixinStr); 21 22 wrap(Blub(1), Blub(2)).should == Blub(4); 23 } 24 25 26 @("blub.concatFoo") 27 unittest { 28 import blub; 29 import std.format: format; 30 31 enum mod = module_!"modules.functions"; 32 enum concatFoo = mod.functionsByOverload[10]; 33 34 enum mixinStr = blubWrapperMixin(concatFoo); 35 //pragma(msg, mixinStr); 36 mixin(mixinStr); 37 38 wrap(Blub("hmmm"), Blub(42), Blub("quux")).should == Blub("hmmm42quuxfoo"); 39 } 40 41 42 // Returns a string to be mixed in that defines a function `wrap` 43 // That calls converts blub types to D ones, calls `function_` then 44 // converts the result from D to blub. 45 private string blubWrapperMixin(Function function_) @safe pure { 46 assert(__ctfe); 47 48 import std.array: join; 49 import std.algorithm: map; 50 import std.range: iota; 51 import std.format: format; 52 53 string[] lines; 54 55 static string argName(size_t i) { 56 import std.conv: text; 57 return text("arg", i); 58 } 59 60 const numParams = function_.parameters.length; 61 // what goes in the function signature between the parens 62 const wrapParams = numParams 63 .iota 64 .map!(i => "Blub " ~ argName(i)) 65 .join(", ") 66 ; 67 // the arguments to pass to the wrapped D function 68 const dArgs = numParams 69 .iota 70 .map!(i => argName(i) ~ ".to!(" ~ function_.parameters[i].type.name ~ ")") 71 .join(", ") 72 ; 73 74 return q{ 75 auto wrap(%s /*dArgs*/) 76 { 77 import blub: toBlub, to; 78 %s // import mixin 79 return %s.toBlub; 80 } 81 }.format( 82 wrapParams, 83 function_.importMixin, 84 function_.callMixin(dArgs) 85 ); 86 }