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 }