1 module msgpack.attribute; 2 3 import std.typetuple; // will use std.meta 4 import std.traits; 5 6 7 /** 8 * Attribute for specifying non pack/unpack field. 9 * This is an alternative approach of MessagePackable mixin. 10 * 11 * Example: 12 * ----- 13 * struct S 14 * { 15 * int num; 16 * // Packer/Unpacker ignores this field; 17 * @nonPacked string str; 18 * } 19 * ----- 20 */ 21 struct nonPacked {} 22 23 24 package template isPackedField(alias field) 25 { 26 enum isPackedField = (staticIndexOf!(nonPacked, __traits(getAttributes, field)) == -1) && (!isSomeFunction!(typeof(field))); 27 } 28 29 30 /** 31 * Attribute for specifying serialize/deserialize proxy for pack/unpack field. 32 * This is an alternative approach of registerPackHandler/registerUnpackHandler. 33 * 34 * Example: 35 * ----- 36 * struct Proxy 37 * { 38 * import std.conv; 39 * static void serialize(ref Packer p, ref int val) { p.pack(to!string(val)); } 40 * static void deserialize(ref Unpacker u, ref int val) { string tmp; u.unpack(tmp); val = to!int(tmp); } 41 * } 42 * struct S 43 * { 44 * // The Packer/Unpacker proxy handler is applied this field. 45 * @serializedAs!Proxy int num; 46 * string str; 47 * } 48 * ----- 49 */ 50 struct serializedAs(T){} 51 52 package enum bool isSerializedAs(A) = is(A : serializedAs!T, T); 53 package alias getSerializedAs(T : serializedAs!Proxy, Proxy) = Proxy; 54 package alias ProxyList(alias value) = staticMap!(getSerializedAs, Filter!(isSerializedAs, __traits(getAttributes, value))); 55 package template isSerializedAs(alias value) 56 { 57 static if ( __traits(compiles, __traits(getAttributes, value)) ) { 58 enum bool isSerializedAs = ProxyList!value.length > 0; 59 } else { 60 enum bool isSerializedAs = false; 61 } 62 } 63 package template getSerializedAs(alias value) 64 { 65 private alias _list = ProxyList!value; 66 static assert(_list.length <= 1, `Only single serialization proxy is allowed`); 67 alias getSerializedAs = _list[0]; 68 } 69 package template hasSerializedAs(alias value) 70 { 71 private enum _listLength = ProxyList!value.length; 72 static assert(_listLength <= 1, `Only single serialization proxy is allowed`); 73 enum bool hasSerializedAs = _listLength == 1; 74 } 75 76 unittest 77 { 78 import msgpack.packer, msgpack.unpacker; 79 struct Proxy 80 { 81 static void serialize(ref Packer p, ref int value) {} 82 static void deserialize(ref Unpacker u, ref int value) {} 83 } 84 struct A 85 { 86 @serializedAs!Proxy int a; 87 @(42) int b; 88 @(42) @serializedAs!Proxy int c; 89 } 90 static assert(is(getSerializedAs!(A.a) == Proxy)); 91 static assert(isSerializedAs!(__traits(getAttributes, A.a)[0])); 92 static assert(hasSerializedAs!(A.a)); 93 static assert(!hasSerializedAs!(A.b)); 94 static assert(hasSerializedAs!(A.c)); 95 }