1 /// Provide a discriminating union to be used inside a message buffer. 2 module oneof; 3 4 /// Create private anonymous union holding all requested types. 5 /// This has probably a fair share of TODOs, e.g. it cannot hold 6 /// multiple instances of the same type, the opEqual() is most 7 /// likely sub-optimal, and probably a bunch of other things that 8 /// I don't see as a D newbie. 9 struct Oneof(Types...) { 10 11 /// Mixin some required operations like assignment, copy constructor, value getter. 12 mixin GenOps; 13 14 /// Return the TypeInfo of the type stored in the oneof union. 15 const(TypeInfo) type() const { return _type; } 16 17 /// To make testing for equality work for Oneof based types. 18 bool opEquals(const ref typeof(this) other) const { 19 if (_type is null && other.type is null) 20 return true; 21 if (_type is null || other.type is null) 22 return false; 23 static foreach (idx, SubType; Types) { 24 if (this.has!SubType && other.has!SubType) { 25 return this.value!SubType == other.value!SubType; 26 } 27 } 28 return false; 29 } 30 31 private: 32 33 mixin template GenOps() { 34 static foreach (idx, SubType; Types) { 35 36 /// Assignment operator. 37 ref typeof(this) opAssign(SubType value) { 38 this.tupleof[idx] = value; 39 _type = typeid(SubType); 40 return this; 41 } 42 43 /// Return value of requested type. 44 ref auto value(T : SubType)() const { 45 assert(_type == typeid(T), "oneof doesn't hold a " ~ SubType.stringof); 46 return this.tupleof[idx]; 47 } 48 49 /// Create a Oneof given a value of a certain SubType. 50 this(SubType value) { 51 this.tupleof[idx] = value; 52 _type = typeid(SubType); 53 } 54 } 55 } 56 57 /// Types this Oneof instance can hold. 58 union { Types _data; } 59 60 /// Specific type this Oneof instance currently holds. 61 TypeInfo _type; 62 } 63 64 /// Test if Oneof of type T stores a value with the given SubType. 65 bool has(SubType, T)(ref T t) { 66 return (t._type == typeid(SubType)); 67 } 68 69 /// Retrieve value with the given SubType from Oneof of type T. 70 const(SubType) get(SubType, T)(ref T t) { 71 return t.value!SubType; 72 }