import std.metastrings; import std.conv; string encodeAsIdentifier(string s) { string ret; foreach(ch; s) if( (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') ) { ret ~= ch; } else { ret ~= "_"; ret ~= to!string(cast(int) ch); ret ~= "_"; } return ret; } string decodeIdentifier(string s) { string ret; bool inEscaped = false; string curr = ""; foreach(ch; s) if(inEscaped) { if(ch == '_') { inEscaped = false; assert(curr.length, ret); ret ~= cast(char) to!int(curr); } else { curr ~= ch; } } else { if( (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') ) { ret ~= ch; } else { assert(ch == '_'); inEscaped = true; curr = ""; } } return ret; } mixin template Note(alias symbol, string val) { mixin("enum _attr_mixin_" ~ encodeAsIdentifier(Format!( "%s ~= %s;", symbol.stringof, val)) ~ ";"); } string[] getNotesImpl(alias par, string s)() { string[] notes; enum prefix = "_attr_mixin_"; foreach(member; __traits(allMembers, par)) { static if(member.length > prefix.length && member[0 .. prefix.length] == prefix) { enum expression = decodeIdentifier(member[prefix.length .. $]); static if(expression.length > s.length && expression[0 .. s.length] == s) { enum magic = expression[s.length .. $]; mixin("notes " ~ magic); } } } return notes; } template getNotes(alias symbol) { enum getNotes = getNotesImpl!(__traits(parent, symbol), symbol.stringof ~ " "); } struct A { int a; int b; mixin Note!(a, q{ "NonSerialized" }); mixin Note!(a, q{ "Awesome" }); mixin Note!(b, q{ "Filthy Hack" }); } void main() { pragma(msg, getNotes!(A.a)); pragma(msg, getNotes!(A.b)); }