1 /** Various suppressing hacks.
2  */
3 module nxt.suppressing;
4 
5 enum SuppressOptions
6 {
7     destructor = 1,
8     postblit = 2
9 }
10 
11 /** Suppress.
12  *
13  * See_Also: http://forum.dlang.org/post/dxakoknmzblxpgiibfmu@forum.dlang.org
14  */
15 struct Suppress(T, SuppressOptions options)
16 if (options != 0)
17 {
18     private enum suppressPostblit   = (options & SuppressOptions.postblit)   != 0;
19     private enum suppressDestructor = (options & SuppressOptions.destructor) != 0;
20     private enum postblitName = __traits(hasMember, T, "__xpostblit") ? "__xpostblit" : "__postblit";
21 
22     // Disguise T as a humble array.
23     private ubyte[T.sizeof] _payload;
24 
25     // Create from instance of T.
26     this(T arg)
27     {
28         _payload = *cast(ubyte[T.sizeof]*)&arg;
29     }
30 
31     // Or forward constructor arguments to T's constructor.
32     static if (__traits(hasMember, T, "__ctor"))
33     {
34         this(Args...)(Args args)
35             if (__traits(compiles, (Args e){__traits(getMember, T.init, "__ctor")(e);}))
36         {
37             __traits(getMember, get, "__ctor")(args);
38         }
39     }
40 
41     // Call dtor
42     static if (!suppressDestructor)
43     {
44         ~this() @nogc
45         {
46             destroy(get);
47         }
48     }
49 
50     // Call postblit
51     static if (!suppressPostblit)
52     {
53         static if (!__traits(isCopyable, T))
54         {
55             @disable this(this);
56         }
57         else static if (__traits(hasMember, T, postblitName))
58         {
59             this(this)
60             {
61                 __traits(getMember, get, postblitName)();
62             }
63         }
64     }
65 
66     // Pretend to be a T.
67     @property
68     ref T get()
69     {
70         return *cast(T*)_payload.ptr;
71     }
72 
73     alias get this;
74 }
75 
76 struct S1
77 {
78     @disable this(this);
79     ~this() @nogc
80     {
81         assert("Don't touch my destructor!");
82     }
83 }
84 
85 unittest
86 {
87     import std.exception;
88     static assert(!__traits(compiles, (Suppress!S1 a) { auto b = a; }));
89     static assert(__traits(compiles, (Suppress!(S1, SuppressOptions.postblit) a) { auto b = a; }));
90 
91     // TODO: assertThrown({ Suppress!(S1, SuppressOptions.postblit) a; }());
92     assertNotThrown({ Suppress!(S1, SuppressOptions.postblit | SuppressOptions.destructor) a; }());
93 }