Mercurial > projects > qtd
diff d2/qtd/meta/Runtime.d @ 351:59d847a814e3
added meta subdir
author | Max Samukha <maxter@spambox.com> |
---|---|
date | Thu, 20 May 2010 15:54:06 +0300 |
parents | |
children | a084e2df3776 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/d2/qtd/meta/Runtime.d Thu May 20 15:54:06 2010 +0300 @@ -0,0 +1,292 @@ +/************************************************************************** + Copyright: Copyright Max Samukha, 2010 + Authors: Max Samukha + License: Boost Software License 1.0 +**************************************************************************/ +module qtd.meta.Runtime; +//TODO: Probably replace switch dispatch with pointer dispatch +//and leave switch dispatch only in C interface + +import + qtd.meta.Compiletime, + + std.typetuple, + std.conv, + std.variant, + core.sync.rwmutex; + +private __gshared ReadWriteMutex lock; +shared static this() +{ + lock = new ReadWriteMutex; +} + +/** + IDs of the built-in basic types. +*/ +enum BasicTypeId +{ + /// + void_, + /// + bool_, + /// + byte_, + /// + ubyte_, + /// + short_, + /// + ushort_, + /// + int_, + /// + uint_, + /// + long_, + /// + ulong_, + /// + cent_, + /// + ucent_, + /// + float_, + /// + double_, + /// + real_, + /// + ifloat_, + /// + idouble_, + /// + ireal_, + /// + cfloat_, + /// + cdouble_, + /// + creal_, + /// + char_, + /// + wchar_, + /// + dchar_ +} + +/** + Thrown on meta-system errors. +*/ +class MetaException : Exception +{ + this(string msg) + { + super(msg); + } +} + +abstract class Meta +{ + alias typeof(this) This; + + string name; + MetaAttribute[] attributes; + Meta[] members; + + template createImpl(M : This) + { + static M createImpl(alias symbol)() + { + auto m = new M; + m.construct!symbol; + return m; + } + } + + private void createAttrs(alias symbol)() + { + alias GetAttributes!symbol attrs; + enum len = attrs.length; // COMPILER BUG + foreach (i, _; Repeat!(void, len)) + { + alias TypeTuple!(attrs[i].tuple) attr; + // if the third element of the attribute data is a MetaAttribute subclass, + // use that to create the attribute instance. + static if (attr.length > 2 && (is(attr[2] : MetaAttribute))) + { + alias attr[2] MA; + alias TypeTuple!(attr[0..2], attr[3..$]) args; + attributes ~= MA /*COMPILER BUG: tuple element as tuple*/[0].create!args(); + } + } + } + + protected void construct(alias symbol)() + { + createAttrs!symbol; + } +} + +/** + Base class for run time attributes. + */ +abstract class MetaAttribute +{ + alias typeof(this) This; + + string name; + AttributeOptions options; + + This create(string name, AttributeOptions opts, A...)() + { + auto ma = new This; + ma.construct!(name, opts, A)(); + return ma; + } + + void construct(string name, AttributeOptions opts)() + { + this.name = name; + options = opts; + } +} + +abstract class MetaType : Meta +{ +} + +abstract class MetaAggregate : MetaType +{ +} + +class MetaClass : MetaAggregate +{ + alias typeof(this) This; + alias createImpl!This create; +} + +class MetaStruct : MetaAggregate +{ + alias typeof(this) This; + alias createImpl!This create; +} + +@property +auto meta(alias symbol, M : Meta)() +{ + __gshared static M m; + + { + lock.reader.lock; + scope(exit) + lock.reader.unlock; + if (m) + return m; + } + + lock.writer.lock; + scope(exit) + lock.writer.unlock; + + if (!m) + m = M.create!symbol; + return m; +} + +// only classes and structs for now +@property +auto meta(T)() +{ + static if (is(typeof(T.staticMetaObject))) + return T.staticMetaObject; + else static if (is(T == class)) + return meta!(T, MetaClass); + else static if (is(T == struct)) + return meta!(T, MetaStruct); + else + static assert(false, "No meta object for symbol " ~ T.stringof); +} + +/** + A run time attribute implementation that stores the attribute data in an + array of variants. + */ +class MetaVariantAttribute : MetaAttribute +{ + Variant[] values; + + private this() + { + } + + static MetaVariantAttribute create(string category, AttributeOptions opts, A...)() + { + auto ret = new MetaVariantAttribute; + ret.construct!(category, opts)(); + foreach(i, _; A) + { + static if (__traits(compiles, { ret.values ~= Variant(A[i]); } )) + ret.values ~= Variant(A[i]); + } + return ret; + } +} + +/** + A run time attribute implementation that stores the attribute data in an + assiciative array of variants. + */ +class MetaVariantDictAttribute : MetaAttribute +{ + Variant[string] values; + alias typeof(this) This; + + private this() + { + } + + static This create(string category, AttributeOptions opts, A...)() + { + auto ret = new This; + ret.construct!(category, opts)(); + foreach(i, _; A) + { + static if (i % 2 == 0 && __traits(compiles, { ret.values[A[i]] = Variant(A[i + 1]); } )) + ret.values[A[i]] = Variant(A[i + 1]); // PHOBOS BUG: phobos asserts on this + } + return ret; + } +} + +version (QtdUnittest) +{ + unittest + { + static void foo() {} + + static class C + { + mixin InnerAttribute!("variantAttribute", MetaVariantAttribute, "22", foo, 33); + mixin InnerAttribute!("variantDictAttribute", MetaVariantDictAttribute, + //"a", "33", // PHOBOS BUG: variant is unusable with AAs + "b", foo + //"c", 44 + ); + } + + auto attrs = meta!(C).attributes; + assert(attrs.length == 2); + auto attr = cast(MetaVariantAttribute)attrs[0]; + + assert(attr.name == "variantAttribute"); + assert(attr.values[0] == "22"); + assert(attr.values[1] == 33); + + auto attr2 = cast(MetaVariantDictAttribute) attrs[1]; + assert(attr2.name == "variantDictAttribute"); + //assert(attr2.values["a"] == "33"); + //assert(attr2.values["c"] == 44); + } +} \ No newline at end of file