1 /// `Rebindable!T` is a container for `T` that permits managing `T`'s lifetime explicitly. 2 module rebindable.Rebindable; 3 4 import rebindable.DeepUnqual; 5 import std.traits; 6 7 /// `Rebindable!T` is a container for `T` that permits managing `T`'s lifetime explicitly. 8 public struct Rebindable(T) 9 { 10 private DeepUnqual!T store; 11 12 /// Construct a Rebindable from a value. 13 public this(T value) 14 { 15 set(value); 16 } 17 18 /** 19 * Move-return the stored value by value. 20 * This is equivalent to `get` followed by `destroy`. 21 * 22 * This operation invalidates the `Rebindable`. 23 * Until `set` is called again, `move` and `get` are undefined. 24 */ 25 public CopyConstness!(This, T) move(this This)() @safe 26 { 27 auto result = get; 28 29 destroy; 30 return result; 31 } 32 33 /** 34 * Replace a currently stored value with a new value. 35 * This is equivalent to `destroy` followed by `set`. 36 */ 37 public void replace()(T value) @safe 38 { 39 destroy; 40 set(value); 41 } 42 43 /** 44 * Get a copy of a previously stored value. 45 */ 46 public CopyConstness!(This, T) get(this This)() @nogc nothrow pure @safe 47 { 48 return reference; 49 } 50 51 /** 52 * Set the `Rebindable` to a new value. 53 * Calling this function while an existing value is stored is undefined. 54 * The passed value is copied. 55 */ 56 public void set(T value) @trusted 57 { 58 // Since DeepUnqual doesn't call destructors, we deliberately leak one copy. 59 static union BlindCopy 60 { 61 T value; 62 } 63 64 BlindCopy copy = BlindCopy(value); 65 this.store = *cast(DeepUnqual!T*)© 66 } 67 68 /** 69 * Destroys the stored value. 70 * This is equivalent to a variable going out of scope. 71 */ 72 public void destroy() @trusted 73 { 74 import std.typecons : No; 75 76 static if (is(T == class) || is(T == interface)) 77 { 78 reference = null; 79 } 80 else 81 { 82 // call possible struct destructors 83 .destroy!(No.initialize)(reference); 84 } 85 } 86 87 private ref CopyConstness!(This, T) reference(this This)() @nogc nothrow pure @trusted 88 { 89 return *cast(typeof(return)*)&this.store; 90 } 91 } 92 93 /// 94 unittest 95 { 96 import rebindable.Rebindable : Rebindable; 97 98 struct DataStructure(T) 99 { 100 private Rebindable!T store; 101 102 this(T value) 103 { 104 this.store.set(value); 105 } 106 107 ~this() 108 { 109 this.store.destroy; 110 } 111 112 T get() 113 { 114 return this.store.get; 115 } 116 117 void set(T value) 118 { 119 this.store.replace(value); 120 } 121 } 122 123 DataStructure!(const int) ds; 124 125 ds.set(5); 126 assert(ds.get == 5); 127 }