1 module dvardumper.typevar; 2 3 import std.meta : Alias; 4 import std.traits; 5 6 template V(alias a) 7 { 8 enum string V = __traits(identifier, a); 9 } 10 11 TypeVar toTypeVar(T)(T var, string varname = "") 12 { 13 import std.conv : to; 14 15 TypeVar typeVar; 16 17 static if (isAggregateType!T) { 18 typeVar = new AggregateTypeVar(typeid(var)); 19 static foreach(member; __traits(allMembers, T)) 20 { 21 /* 22 static if (!isAccessible!(T, member)) { 23 pragma(msg, "Skipping non-accessible member " ~ T.stringof ~ "." ~ member); 24 } else */static if (isProperty!(T, member)) { 25 pragma(msg, "Dumping " ~ T.stringof ~ "." ~ member); 26 (cast(AggregateTypeVar)typeVar) 27 .addField(__traits(getMember, var, member).toTypeVar(member)); 28 } 29 } 30 31 } else static if (isBasicType!T) { 32 typeVar = new BasicTypeVar(typeid(var)) 33 .value(var.to!string); 34 } else static if (isPointer!T) { 35 typeVar = new PointerTypeVar(typeid(var)) 36 .pointer(cast(void*)var); 37 } else static if (isArray!T) { 38 typeVar = new ArrayTypeVar(typeid(var)) 39 .elementCount(var.length) 40 .elementSize(ArrayElementType!T.sizeof) 41 .isPrintable(isSomeString!T) 42 .array(cast(byte[])var); 43 } else { 44 typeVar = new UnknownTypeVar(typeid(var)); 45 } 46 47 typeVar.name(varname); 48 49 return typeVar; 50 } 51 52 @("Test basic type to TypeVar conversion") 53 unittest 54 { 55 import unit_threaded; 56 57 int i = 42; 58 TypeVar typeVar = i.toTypeVar("ivar"); 59 60 auto basicTypeVar = cast(BasicTypeVar)typeVar; 61 basicTypeVar.shouldNotBeNull; 62 63 basicTypeVar.name.should == "ivar"; 64 basicTypeVar.typeName.should == "int"; 65 basicTypeVar.size.should == int.sizeof; 66 basicTypeVar.value.should == "42"; 67 } 68 69 @("Test pointer type to TypeVar conversion") 70 unittest 71 { 72 import unit_threaded; 73 74 int* i = new int(5); 75 76 (*i).should == 5; 77 78 TypeVar typeVar = i.toTypeVar("pointer"); 79 80 auto pointerTypeVar = cast(PointerTypeVar)typeVar; 81 pointerTypeVar.shouldNotBeNull; 82 83 pointerTypeVar.name.should == "pointer"; 84 pointerTypeVar.typeName.should == "int*"; 85 pointerTypeVar.size.should == (int*).sizeof; 86 87 int* pointer = cast(int*)pointerTypeVar.pointer; 88 89 (cast(size_t)pointer).shouldBeGreaterThan(0); 90 (*pointer).should == 5; 91 } 92 93 @("Test array type to TypeVar conversion") 94 unittest 95 { 96 import unit_threaded; 97 98 int[] arr = [1,2,3]; 99 TypeVar typeVar = arr.toTypeVar("arr_array"); 100 101 auto arrayTypeVar = cast(ArrayTypeVar)typeVar; 102 arrayTypeVar.shouldNotBeNull; 103 104 arrayTypeVar.name.should == "arr_array"; 105 arrayTypeVar.typeName.should == "int[]"; 106 arrayTypeVar.size.should == size_t.sizeof + size_t.sizeof; 107 arrayTypeVar.elementCount.should == 3; 108 arrayTypeVar.elementSize.should == int.sizeof; 109 arrayTypeVar.isPrintable.should == false; 110 } 111 112 @("Test unknown type to TypeVar conversion") 113 unittest 114 { 115 import unit_threaded; 116 117 TypeVar typeVar = null.toTypeVar("unknown_type"); 118 119 auto unknownTypeVar = cast(UnknownTypeVar)typeVar; 120 unknownTypeVar.shouldNotBeNull; 121 122 unknownTypeVar.name.should == "unknown_type"; 123 unknownTypeVar.typeName.should == "typeof(null)"; 124 unknownTypeVar.size.should == typeof(null).sizeof; 125 } 126 127 struct S 128 { 129 int s1 = 4; 130 bool s2 = true; 131 } 132 133 @("Test aggregate type to TypeVar conversion") 134 unittest 135 { 136 import unit_threaded; 137 138 S s; 139 TypeVar typeVar = s.toTypeVar("s_struct"); 140 141 auto aggregateTypeVar = cast(AggregateTypeVar)typeVar; 142 aggregateTypeVar.shouldNotBeNull; 143 144 aggregateTypeVar.name.should == "s_struct"; 145 aggregateTypeVar.typeName.should == "dvardumper.typevar.S"; 146 aggregateTypeVar.size.should == S.sizeof; 147 aggregateTypeVar.fields.length.should == 2; 148 } 149 150 template isAccessible(T, string member) 151 { 152 enum isAccessible = __traits(getProtection, __traits(getMember, T, member)) == "public"; 153 } 154 155 template isProperty(T, string member) 156 { 157 alias fieldValue = Alias!(__traits(getMember, T, member)); 158 enum isProperty = !isType!fieldValue && !isFunction!fieldValue && !__traits(isTemplate, fieldValue); 159 } 160 161 template ArrayElementType(T : T[]) 162 { 163 alias T ArrayElementType; 164 } 165 166 abstract class TypeVar 167 { 168 protected: 169 TypeInfo _typeInfo; 170 string _name; // var name or field name 171 string _typeName; 172 size_t _size; 173 174 public: 175 this(TypeInfo typeInfo) 176 { 177 import std.conv : to; 178 179 this.typeName = typeInfo.to!string; 180 this.size = typeInfo.tsize; 181 } 182 183 this(string typeName, size_t size) 184 { 185 this.typeName(typeName); 186 this.size(size); 187 } 188 189 @property pure 190 string name() 191 { 192 return _name; 193 } 194 195 @property pure 196 typeof(this) name(string name) 197 { 198 _name = name; 199 200 return this; 201 } 202 203 @property pure 204 string typeName() 205 { 206 return _typeName; 207 } 208 209 @property pure 210 typeof(this) typeName(string typeName) 211 { 212 _typeName = typeName; 213 214 return this; 215 } 216 217 @property pure 218 size_t size() 219 { 220 return _size; 221 } 222 223 @property pure 224 typeof(this) size(size_t size) 225 { 226 _size = size; 227 228 return this; 229 } 230 } 231 232 class BasicTypeVar : TypeVar 233 { 234 protected: 235 string _value; 236 237 public: 238 this(TypeInfo typeInfo) 239 { 240 super(typeInfo); 241 } 242 243 @property pure 244 string value() 245 { 246 return _value; 247 } 248 249 @property pure 250 typeof(this) value(string value) 251 { 252 _value = value; 253 254 return this; 255 } 256 } 257 258 class PointerTypeVar : TypeVar 259 { 260 protected: 261 void* _pointer; 262 263 public: 264 this(TypeInfo typeInfo) 265 { 266 super(typeInfo); 267 } 268 269 @property pure 270 void* pointer() 271 { 272 return _pointer; 273 } 274 275 @property pure 276 typeof(this) pointer(void* ptr) 277 { 278 _pointer = ptr; 279 280 return this; 281 } 282 } 283 284 class ArrayTypeVar : TypeVar 285 { 286 protected: 287 byte[] _array; 288 size_t _elementCount; 289 size_t _elementSize; 290 bool _isPrintable; 291 size_t _maxPrintCount = 512; 292 293 public: 294 this(TypeInfo typeInfo) 295 in 296 { 297 assert(cast(TypeInfo_Array)typeInfo !is null 298 || cast(TypeInfo_StaticArray)typeInfo !is null); 299 } 300 body 301 { 302 super(typeInfo); 303 } 304 305 @property pure 306 byte[] array() 307 { 308 return _array; 309 } 310 311 @property pure 312 typeof(this) array(byte[] array) 313 { 314 _array = array; 315 316 return this; 317 } 318 319 size_t elementCount() 320 { 321 return _elementCount; 322 } 323 324 typeof(this) elementCount(size_t count) 325 { 326 _elementCount = count; 327 328 return this; 329 } 330 331 size_t elementSize() 332 { 333 return _elementSize; 334 } 335 336 typeof(this) elementSize(size_t size) 337 { 338 _elementSize = size; 339 340 return this; 341 } 342 343 bool isPrintable() 344 { 345 return _isPrintable; 346 } 347 348 typeof(this) isPrintable(bool isPrintable) 349 { 350 _isPrintable = isPrintable; 351 352 return this; 353 } 354 355 size_t maxPrintCount() 356 { 357 return _maxPrintCount; 358 } 359 } 360 361 class UnknownTypeVar : TypeVar 362 { 363 this(TypeInfo typeInfo) 364 { 365 super(typeInfo); 366 } 367 } 368 369 class AggregateTypeVar : TypeVar 370 { 371 protected: 372 TypeVar[string] _fields; 373 374 public: 375 this(TypeInfo typeInfo) 376 { 377 super(typeInfo); 378 } 379 380 pure 381 void addField(TypeVar typeVar) 382 in 383 { 384 assert(typeVar.name != ""); 385 } 386 body 387 { 388 _fields[typeVar.name] = typeVar; 389 } 390 391 @property pure 392 auto fields() 393 { 394 return _fields; 395 } 396 }