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