1 module unecht.meta.uda;
2 
3 alias aliasHelper(alias T) = T;
4 alias aliasHelper(T) = T;
5 
6 ///
7 private template getUDAIndex(alias UDA, ATTR...)
8 {
9     template findUDA(int i)
10     {
11         static if(ATTR.length == 0)
12         {
13             enum findUDA = -1;
14         }
15         else static if(i >= ATTR.length)
16         {
17             enum findUDA = -1;
18         }
19         else
20         {
21             static if(is(aliasHelper!(ATTR[i]) == UDA) || is(typeof(ATTR[i]) == UDA))
22             {
23                 enum findUDA = i;
24             }
25             else
26             {
27                 enum findUDA = findUDA!(i+1);
28             }
29         }
30     }
31 
32     enum getUDAIndex = findUDA!(0);
33 }
34 
35 ///
36 template hasUDA(alias T, alias UDA)
37 {
38     enum hasUDA = getUDAIndex!(UDA,__traits(getAttributes, T)) != -1;
39 }
40 
41 ///
42 template getUDA(alias T, alias UDA)
43 {
44     template findUDA(ATTR...)
45     {
46         static if(hasUDA!(T, UDA))
47         {
48             enum findUDA = ATTR[getUDAIndex!(UDA, ATTR)];
49         }
50         else
51         {
52             import std..string:format;
53             static assert(0, format("UDA '%s' not found for Type '%s'", UDA.stringof, T.stringof));
54         }
55     }
56     enum getUDA = findUDA!(__traits(getAttributes, T));
57 }
58 
59 unittest
60 {
61     struct e{}
62 
63     struct A{
64         @A
65         string bar;
66     }
67 
68     @e
69     struct Foo
70     {
71         @A("foo")
72         int i;
73     }
74 
75     static assert(!hasUDA!(Foo, A));
76     static assert(hasUDA!(Foo, e));
77     static assert(hasUDA!(Foo.i, A));
78     static assert(getUDA!(Foo.i, A).bar == "foo");
79 
80     //even UDA-Inception works :P
81     static assert(hasUDA!(getUDA!(Foo.i, A).bar, A));
82     static assert(!hasUDA!(getUDA!(Foo.i, A).bar, e));
83 }