1 2 module witchcraft.mixins.fields; 3 4 mixin template WitchcraftField() 5 { 6 import witchcraft; 7 8 import std.meta; 9 import std.traits; 10 import std.variant; 11 12 static class FieldMixin(alias T, string name) : Field 13 { 14 private: 15 alias member = Alias!(__traits(getMember, T, name)); 16 17 enum bool writable = __traits(compiles, { 18 T instance = void; 19 typeof(member) value = void; 20 21 __traits(getMember, instance, name) = value; 22 }); 23 24 public: 25 override Variant get(Variant instance) const 26 { 27 static if(is(T == class)) 28 { 29 auto this_ = cast(ClassInfo) typeid(T); 30 auto other = cast(ClassInfo) instance.type; 31 32 // Ensure both types exist and can be converted. 33 if(!this_ || !other || !(_d_isbaseof(this_, other) || _d_isbaseof(other, this_))) 34 { 35 assert(0, "Instance isn't type of `" ~ T.stringof ~ "`."); 36 } 37 38 auto obj = instance.coerce!T; 39 } 40 else static if(is(T)) 41 { 42 auto obj = instance.get!T; 43 } 44 else 45 { 46 alias obj = T; 47 } 48 49 return Variant(__traits(getMember, obj, name)); 50 } 51 52 const(Attribute)[] getAttributes() const 53 { 54 alias attributes = AliasSeq!(__traits(getAttributes, member)); 55 auto values = new Attribute[attributes.length]; 56 57 foreach(index, attribute; attributes) 58 { 59 values[index] = new AttributeImpl!attribute; 60 } 61 62 return values; 63 } 64 65 const(Type) getDeclaringType() const 66 { 67 alias Parent = Alias!(__traits(parent, member)); 68 69 return inspect!Parent; 70 } 71 72 const(TypeInfo) getDeclaringTypeInfo() const 73 { 74 alias Parent = Alias!(__traits(parent, member)); 75 76 static if(__traits(compiles, typeid(Parent))) 77 { 78 return typeid(Parent); 79 } 80 else 81 { 82 return null; 83 } 84 } 85 86 @property 87 string getName() const 88 { 89 return name; 90 } 91 92 string getFullName() const 93 { 94 return fullyQualifiedName!member; 95 } 96 97 string getProtection() const 98 { 99 return __traits(getProtection, __traits(getMember, T, name)); 100 } 101 102 override const(Type) getValueType() const 103 { 104 return inspect!(typeof(member)); 105 } 106 107 override const(TypeInfo) getValueTypeInfo() const 108 { 109 return typeid(typeof(member)); 110 } 111 112 @property 113 final bool isAccessible() const 114 { 115 return true; 116 } 117 118 @property 119 override bool isStatic() const 120 { 121 return __traits(compiles, { 122 auto value = __traits(getMember, T, name); 123 }); 124 } 125 126 @property 127 override bool isWritable() const 128 { 129 return writable; 130 } 131 132 override void set(Variant instance, Variant value) const 133 { 134 static if(is(T == class)) 135 { 136 auto this_ = cast(ClassInfo) typeid(T); 137 auto other = cast(ClassInfo) instance.type; 138 139 // Ensure both types exist and can be converted. 140 if(!this_ || !other || !(_d_isbaseof(this_, other) || _d_isbaseof(other, this_))) 141 { 142 assert(0, "Instance isn't type of `" ~ T.stringof ~ "`."); 143 } 144 145 auto obj = instance.coerce!T; 146 } 147 else static if(is(T)) 148 { 149 auto obj = instance.get!T; 150 } 151 else 152 { 153 alias obj = T; 154 } 155 156 static if(writable) 157 { 158 __traits(getMember, obj, name) = value.get!(typeof(member)); 159 } 160 else 161 { 162 assert("Field " ~ name ~ " is not writable."); 163 } 164 } 165 } 166 }