1 /++ 2 Type constructors. 3 4 Copyright: [JR](https://github.com/zorael) 5 License: [Boost Software License 1.0](https://www.boost.org/users/license.html) 6 7 Authors: 8 [JR](https://github.com/zorael) 9 +/ 10 module lu.typecons; 11 12 private: 13 14 public: 15 16 17 // UnderscoreOpDispatcher 18 /++ 19 Mixin template generating an `opDispatch` redirecting calls to members whose 20 names match the passed variable string but with an underscore prepended. 21 +/ 22 mixin template UnderscoreOpDispatcher() 23 { 24 version(unittest) 25 { 26 import lu.traits : MixinConstraints, MixinScope; 27 mixin MixinConstraints!( 28 (MixinScope.struct_ | MixinScope.class_ | MixinScope.union_), 29 typeof(this).stringof); 30 } 31 32 /++ 33 Mutator. 34 35 Params: 36 var = The variable name to set. 37 value = The value to set the variable to. 38 39 Returns: 40 A reference to the object which this is mixed into. 41 +/ 42 ref auto opDispatch(string var, T)(T value) 43 { 44 import std.traits : isArray, isAssociativeArray, isSomeString; 45 46 static if (!var.length) 47 { 48 import std.format : format; 49 enum pattern = "Empty variable name passed to `%s.opDispatch`"; 50 enum message = pattern.format(typeof(this).stringof); 51 static assert(0, message); 52 } 53 54 enum realVar = '_' ~ var; 55 alias V = typeof(mixin(realVar)); 56 57 static if (isAssociativeArray!V) 58 { 59 import lu.meld : MeldingStrategy, meldInto; 60 value.meldInto!(MeldingStrategy.overwriting)(mixin(realVar)); 61 } 62 else static if (isArray!V && !isSomeString!V) 63 { 64 mixin(realVar) ~= value; 65 } 66 else 67 { 68 mixin(realVar) = value; 69 } 70 71 return this; 72 } 73 74 /++ 75 Accessor. 76 77 Params: 78 var = The variable name to get. 79 80 Returns: 81 The value of the variable. 82 +/ 83 ref auto opDispatch(string var)() inout 84 { 85 static if (!var.length) 86 { 87 import std.format : format; 88 enum pattern = "Empty variable name passed to `%s.opDispatch`"; 89 enum message = pattern.format(typeof(this).stringof); 90 static assert(0, message); 91 } 92 93 enum realVar = '_' ~ var; 94 return mixin(realVar); 95 } 96 } 97 98 /// 99 unittest 100 { 101 { 102 struct Foo 103 { 104 int _i; 105 string _s; 106 bool _b; 107 string[] _add; 108 alias wordList = _add; 109 110 mixin UnderscoreOpDispatcher; 111 } 112 113 Foo f; 114 f.i = 42; // f.opDispatch!"i"(42); 115 f.s = "hello"; // f.opDispatch!"s"("hello"); 116 f.b = true; // f.opDispatch!"b"(true); 117 f.add("hello"); // f.opDispatch!"add"("hello"); 118 f.add("world"); // f.opDispatch!"add"("world"); 119 120 assert(f.i == 42); 121 assert(f.s == "hello"); 122 assert(f.b); 123 assert(f.wordList == [ "hello", "world" ]); 124 125 // ref auto allows this 126 ++f.i; 127 assert(f.i == 43); 128 129 /+ 130 Returns `this` by reference, so we can chain calls. 131 +/ 132 auto f2 = Foo() 133 .i(9001) 134 .s("world") 135 .b(false) 136 .add("hello") 137 .add("world"); 138 139 assert(f2.i == 9001); 140 assert(f2.s == "world"); 141 assert(!f2.b); 142 assert(f2.wordList == [ "hello", "world" ]); 143 } 144 { 145 struct Bar 146 { 147 string[string] _aa; 148 149 mixin UnderscoreOpDispatcher; 150 } 151 152 Bar bar; 153 bar.aa = [ "hello" : "world" ]; 154 bar.aa = [ "foo" : "bar" ]; 155 assert(bar.aa == [ "hello" : "world", "foo" : "bar"]); 156 } 157 }