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