1 /++ 2 This module adds declares a mixin template for automatically generating class constructor. 3 Generated constructor takes 1 argument per each field declared with `@wired` attribute. Later each argument gets assigned to its respective field. 4 Examples: 5 --- 6 class A { 7 @wired { 8 int a; 9 string b; 10 float c; 11 } 12 13 mixin wire; 14 } 15 auto a = new A(1, "hi", 42.0); 16 assert(a.a == 1 && a.b == "hi" && a.c == 42.0); 17 --- 18 +/ 19 module dc.wire; 20 21 import dc : from; 22 import dc.dotbuilder : d = dotBuilder; 23 24 unittest { 25 static assert(!__traits(compiles, { 26 struct B { 27 @wired ubyte a; 28 29 mixin wire; 30 } 31 })); 32 33 class A { 34 @wired { 35 int a; 36 string b; 37 float c; 38 } 39 40 mixin wire; 41 } 42 auto a = new A(1, "hi", 42.0); 43 assert(a.a == 1 && a.b == "hi" && a.c == 42.0); 44 } 45 /// An attribute to decorate fields about which `wire` should care 46 enum wired; 47 48 /// Mixin template that generates our class constructor 49 mixin template wire() { 50 static assert(is(typeof(this) == class), from!(d.std.traits).fullyQualifiedName!(typeof(this)) ~ " is not a class"); 51 private { 52 template WiredFields(T) { 53 import std.traits : hasUDA, FieldNameTuple; 54 import std.meta : Filter; 55 enum bool isWiredField(alias field) = hasUDA!(__traits(getMember, T, field), wired); 56 alias WiredFields = Filter!(isWiredField, FieldNameTuple!T); 57 } 58 59 template WiredTypes(T) { 60 import std.meta : staticMap; 61 alias GetType(alias field) = typeof(__traits(getMember, T, field)); 62 alias WiredTypes = staticMap!(GetType, WiredFields!T); 63 } 64 } 65 66 this(WiredTypes!(typeof(this)) args) { 67 alias This = typeof(this); 68 alias fields = WiredFields!This; 69 static foreach(i, field; fields) { 70 __traits(getMember, this, field) = args[i]; 71 } 72 } 73 }