1 /// Contains helpful templates relating to UDAs. 2 module jaster.cli.udas; 3 4 /++ 5 + Gets a single specified `UDA` from the given `Symbol`. 6 + 7 + Assertions: 8 + If the given `Symbol` has either 0, or more than 1 instances of the specified `UDA`, a detailed error message will be displayed. 9 + ++/ 10 template getSingleUDA(alias Symbol, alias UDA) 11 { 12 import std.traits : getUDAs; 13 14 // Check if they created an instance `@UDA()` 15 // 16 // or if they just attached the type itself `@UDA` 17 static if(__traits(compiles, {enum UDAs = getUDAs!(Symbol, UDA);})) 18 enum UDAs = getUDAs!(Symbol, UDA); 19 else 20 enum UDAs = [UDA.init]; 21 22 static if(UDAs.length == 0) 23 static assert(false, "The symbol `"~Symbol.stringof~"` does not have the `@"~UDA.stringof~"` UDA"); 24 else static if(UDAs.length > 1) 25 static assert(false, "The symbol `"~Symbol.stringof~"` contains more than one `@"~UDA.stringof~"` UDA"); 26 27 enum getSingleUDA = UDAs[0]; 28 } 29 /// 30 version(unittest) 31 { 32 import jaster.cli.infogen : Command; 33 34 private struct A {} 35 36 @Command("One") 37 private struct B {} 38 39 @Command("One") 40 @Command("Two") 41 private struct C {} 42 } 43 44 unittest 45 { 46 import jaster.cli.infogen : Command; 47 48 static assert(!__traits(compiles, getSingleUDA!(A, Command))); 49 static assert(!__traits(compiles, getSingleUDA!(C, Command))); 50 static assert(getSingleUDA!(B, Command).pattern.pattern == "One"); 51 } 52 53 /++ 54 + Sometimes code needs to support both `@UDA` and `@UDA()`, so this template is used 55 + to ensure that the given `UDA` is an actual object, not just a type. 56 + ++/ 57 template ctorUdaIfNeeded(alias UDA) 58 { 59 import std.traits : isType; 60 static if(isType!UDA) 61 enum ctorUdaIfNeeded = UDA.init; 62 else 63 alias ctorUdaIfNeeded = UDA; 64 } 65 66 /++ 67 + Gets all symbols that have specified UDA from all specified modules 68 + ++/ 69 template getSymbolsByUDAInModules(alias attribute, Modules...) 70 { 71 import std.meta: AliasSeq; 72 import std.traits: getSymbolsByUDA; 73 74 static if(Modules.length == 0) 75 { 76 alias getSymbolsByUDAInModules = AliasSeq!(); 77 } 78 else 79 { 80 alias tail = getSymbolsByUDAInModules!(attribute, Modules[1 .. $]); 81 82 alias getSymbolsByUDAInModules = AliasSeq!(getSymbolsByUDA!(Modules[0], attribute), tail); 83 } 84 } 85 86 unittest 87 { 88 import std.meta: AliasSeq; 89 import jaster.cli.infogen : Command; 90 91 static assert(is(getSymbolsByUDAInModules!(Command, jaster.cli.udas) == AliasSeq!(B, C))); 92 static assert(is(getSymbolsByUDAInModules!(Command, jaster.cli.udas, jaster.cli.udas) == AliasSeq!(B, C, B, C))); 93 }