1 /** Various debug printing tools for debug printing in `@safe pure nothrow @nogc` code. 2 * 3 * Copyright: Per Nordlöw 2018-. 4 * License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 5 * Authors: $(WEB Per Nordlöw) 6 * 7 * See_Also: https://forum.dlang.org/post/svjjawiezudnugdyriig@forum.dlang.org 8 */ 9 module nxt.dbgio; 10 11 // version = show; 12 13 @safe pure: 14 15 /** Debug print `Names` all being compile-time strings that are mixed in. 16 * 17 * Similar to Rust's `dbg` macro introduced in version 1.32. 18 * 19 * See_Also: https://blog.rust-lang.org/2019/01/17/Rust-1.32.0.html#the-dbg-macro 20 * See_Also: https://forum.dlang.org/post/svjjawiezudnugdyriig@forum.dlang.org 21 */ 22 mixin template dumpObseleted(Names...) 23 { 24 auto dumpObseleted = 25 { 26 import std.stdio : stderr, write; 27 debug write(__FILE__, ":", __LINE__, ": Info: "); 28 foreach (immutable i, name; Names) 29 { 30 debug write(typeof(name).stringof, " ", name, ": ", mixin(name), (i < Names.length-1) ? ", " : "\n"); 31 } 32 return false; 33 }(); 34 } 35 36 /// 37 version(show) 38 @safe pure unittest 39 { 40 const int x = 42; 41 int[2] y = [42, 43]; 42 mixin dumpObseleted!("x", "y"); 43 } 44 45 /** Debug print `args` followed by a newline. 46 * 47 * Similar to Rust's `dbg` macro introduced in version 1.32. 48 * 49 * See_Also: https://blog.rust-lang.org/2019/01/17/Rust-1.32.0.html#the-dbg-macro 50 * See_Also: https://forum.dlang.org/post/svjjawiezudnugdyriig@forum.dlang.org 51 */ 52 void dbg(string file = __FILE__, 53 uint line = __LINE__, 54 string fun = __FUNCTION__, 55 Args...)(Args args) @safe pure nothrow @nogc 56 { 57 try 58 { 59 import std.stdio : stderr, writeln; 60 debug stderr.writeln(file, ":", line, ":", " Info: ", args); 61 } 62 catch (Exception) { } 63 } 64 65 /// 66 @safe pure nothrow @nogc unittest 67 { 68 // int x = 42; 69 // dbg("x: ", x); 70 static assert(__traits(compiles, { dbg(); })); // ok for dln to discard function qualifiers 71 } 72 73 /** Show the symbol name and variable of $(D Args). 74 * 75 * See_Also: http://forum.dlang.org/thread/yczwqrbkxdiqijtiynrh@forum.dlang.org?page=1 76 * 77 * TODO use https://forum.dlang.org/post/ypxsqtddxvdxunsoluas@forum.dlang.org 78 * 79 * TODO is using this https://dlang.org/changelog/2.079.0.html#default_after_variadic preferred? 80 * 81 * TODO instead use 82 * 83 * void show_(Args...)(Args args, 84 * string file = __FILE__, 85 * uint line = __LINE__, 86 * string fun = __FUNCTION__) 87 * 88 */ 89 template show(Args...) 90 if (Args.length >= 1) 91 { 92 void show(string file = __FILE__, 93 uint line = __LINE__, 94 string fun = __FUNCTION__) 95 { 96 import std.stdio: write, writeln; 97 try 98 { 99 debug write(file, ":",line, ":" /* , ": in ",fun */, " debug: "); 100 foreach (const i, Arg; Args) 101 { 102 if (i) debug write(", "); // separator 103 debug write(Args[i].stringof, ":", Arg); 104 } 105 debug writeln(); 106 } 107 catch (Exception) { } 108 } 109 } 110 111 version(show) 112 @safe pure unittest 113 { 114 const x = 11; 115 const y = 12; 116 const z = 13; 117 show!x; 118 show!y; 119 show!z; 120 } 121 122 version(show) unittest 123 { 124 const x = 11, y = 12, z = 13; 125 show!(x, y, z); 126 } 127 128 import std.stdio; 129 130 /** Debug dump arguments `args` to standard error output (`stderr`). 131 * 132 * See_Also: https://forum.dlang.org/post/myxzyfgtcewixwbhvalp@forum.dlang.org 133 */ 134 template dump(args...) 135 { 136 alias dbgImpl!(args).print dump; 137 } 138 139 template dbgImpl(args...) 140 { 141 import std.traits : isBuiltinType, isAggregateType, FieldNameTuple; 142 143 private void print(string file = __FILE__, uint line = __LINE__, string fun = __FUNCTION__) 144 { 145 static foreach (arg; args) 146 { 147 static if (isBuiltinType!(typeof(arg))) 148 { 149 debug stderr.writefln("[%s:%s (%s)] %s = %s", 150 file, line, fun, 151 __traits(identifier, arg), arg); 152 } 153 else static if (isAggregateType!(typeof(arg))) 154 { 155 debug stderr.writefln("[%s:%s (%s)] %s = %s", 156 file, line, fun, 157 __traits(identifier, arg), 158 toDbgString(arg)); 159 } 160 } 161 } 162 163 private string toDbgString(Arg)(Arg o) 164 { 165 string dbgstr = "("; 166 import std.format; 167 static foreach(f; FieldNameTuple!(typeof(o))) 168 { 169 static if (isBuiltinType!(typeof(__traits(getMember, o, f)))) 170 { 171 dbgstr ~= format("%s:%s, ", f, __traits(getMember, o, f)); 172 } 173 else static if (isAggregateType!(typeof(__traits(getMember, o, f)))) 174 { 175 dbgstr ~= format("%s = %s, ", f, toDbgString(__traits(getMember, o, f))); 176 } 177 } 178 return dbgstr[0..$-2] ~ ")"; 179 } 180 } 181 182 /// 183 version(show) 184 @safe pure unittest 185 { 186 struct Bar { auto c = 'c';} 187 struct Foo { int s = 2; bool b = false; Bar bar;} 188 class FooBar { int t; Foo f; } 189 190 int i; 191 float f = 3.14; 192 string s = "some string"; 193 Foo foo; 194 Bar bar; 195 196 dump!(i, f, s, foo, 1+3, foo, bar); 197 198 // prints: 199 // [dump.d:54 (dump.main)] i = 0 200 // [dump.d:54 (dump.main)] f = 3.14 201 // [dump.d:54 (dump.main)] s = some string 202 // [dump.d:54 (dump.main)] foo = (s:2, b:false, bar = (c:c)) 203 // [dump.d:54 (dump.main)] _ = 4 204 // [dump.d:54 (dump.main)] foo = (s:2, b:false, bar = (c:c)) 205 // [dump.d:54 (dump.main)] bar = (c:c) 206 // [dump.d:54 (dump.main)] fb = (t:0, f = (s:2, b:false, bar = (c:c))) 207 }