1 module autowrap.reflection; 2 3 4 public import autowrap.types: isModule, Modules, Module; 5 import std.meta: allSatisfy; 6 import std.typecons: Flag, No; 7 8 9 private enum isString(alias T) = is(typeof(T) == string); 10 11 12 template AllFunctions(Modules modules) { 13 import std.algorithm: map; 14 import std.array: join; 15 import std.typecons: Yes, No; // needed for Module.toString in the mixin 16 17 enum modulesList = modules.value.map!(a => a.toString).join(", "); 18 mixin(`alias AllFunctions = AllFunctions!(`, modulesList, `);`); 19 } 20 21 template AllFunctions(Modules...) if(allSatisfy!(isString, Modules)) { 22 import std.meta: staticMap; 23 enum module_(string name) = Module(name); 24 alias AllFunctions = staticMap!(Functions, staticMap!(module_, Modules)); 25 } 26 27 template AllFunctions(Modules...) if(allSatisfy!(isModule, Modules)) { 28 import std.meta: staticMap; 29 alias AllFunctions = staticMap!(Functions, Modules); 30 } 31 32 template Functions(Module module_) { 33 mixin(`import dmodule = ` ~ module_.name ~ `;`); 34 alias Functions = Functions!(dmodule, module_.alwaysExport); 35 } 36 37 template Functions(alias module_, Flag!"alwaysExport" alwaysExport = No.alwaysExport) 38 if(!is(typeof(module_) == string)) 39 { 40 import mirror.meta: MirrorModule = Module, FunctionSymbol; 41 import std.meta: staticMap, Filter; 42 import std.traits: moduleName; 43 44 alias mod = MirrorModule!(moduleName!module_); 45 enum isExport(alias F) = isExportFunction!(F.symbol, alwaysExport); 46 47 alias Functions = Filter!(isExport, mod.FunctionsBySymbol); 48 } 49 50 51 template AllAggregates(Modules modules) { 52 import std.algorithm: map; 53 import std.array: join; 54 import std.typecons: Yes, No; // needed for Module.toString in the mixin 55 56 enum modulesList = modules.value.map!(a => a.toString).join(", "); 57 mixin(`alias AllAggregates = AllAggregates!(`, modulesList, `);`); 58 } 59 60 template AllAggregates(ModuleNames...) if(allSatisfy!(isString, ModuleNames)) { 61 import std.meta: staticMap; 62 63 enum module_(string name) = Module(name); 64 enum Modules = staticMap!(module_, ModuleNames); 65 66 alias AllAggregates = AllAggregates!(staticMap!(module_, ModuleNames)); 67 } 68 69 template AllAggregates(Modules...) if(allSatisfy!(isModule, Modules)) { 70 import std.meta: Filter, NoDuplicates, staticMap; 71 import std.traits: isCopyable; 72 73 alias AllAggregates = Filter!(isCopyable, NoDuplicates!(staticMap!(AllAggregatesInModule, Modules))); 74 } 75 76 private template AllAggregatesInModule(Module module_) { 77 import mirror.meta: MirrorModule = Module; 78 import std.meta: NoDuplicates, Filter, staticMap; 79 80 alias mod = MirrorModule!(module_.name); 81 82 alias AllAggregatesInModule = 83 NoDuplicates!( 84 Filter!(isUserAggregate, 85 staticMap!(PrimordialType, mod.AllAggregates))); 86 } 87 88 89 // if a type is a struct or a class 90 template isUserAggregate(A...) if(A.length == 1) { 91 import std.datetime; 92 import std.traits: Unqual, isInstanceOf; 93 import std.typecons: Tuple; 94 import core.time: Duration; 95 96 alias T = A[0]; 97 98 enum isUserAggregate = 99 !is(Unqual!T == DateTime) && 100 !is(Unqual!T == Date) && 101 !is(Unqual!T == TimeOfDay) && 102 !is(Unqual!T == Duration) && 103 !isInstanceOf!(Tuple, T) && 104 (is(T == struct) || is(T == class) || is(T == enum)); 105 } 106 107 108 // T -> T, T[] -> T, T[][] -> T, T* -> T 109 template PrimordialType(T) { 110 import mirror.traits: FundamentalType; 111 import std.traits: Unqual; 112 alias PrimordialType = Unqual!(FundamentalType!T); 113 } 114 115 116 package template isExportFunction(alias F, Flag!"alwaysExport" alwaysExport = No.alwaysExport) { 117 import std.traits: isFunction; 118 119 static if(!isFunction!F) 120 enum isExportFunction = false; 121 else { 122 version(AutowrapAlwaysExport) { 123 enum linkage = __traits(getLinkage, F); 124 enum isExportFunction = linkage != "C" && linkage != "C++"; 125 } else version(AutowrapAlwaysExportC) { 126 enum linkage = __traits(getLinkage, F); 127 enum isExportFunction = linkage == "C" || linkage == "C++"; 128 } else 129 enum isExportFunction = isExportSymbol!(F, alwaysExport); 130 } 131 } 132 133 134 private template isExportSymbol(alias S, Flag!"alwaysExport" alwaysExport = No.alwaysExport) { 135 static if(__traits(compiles, __traits(getProtection, S))) 136 enum isExportSymbol = isPublicSymbol!S && (alwaysExport || __traits(getProtection, S) == "export"); 137 else 138 enum isExportSymbol = false; 139 } 140 141 142 private template isPublicSymbol(alias S) { 143 enum isPublicSymbol = __traits(getProtection, S) == "export" || __traits(getProtection, S) == "public"; 144 }