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