1 module libd.util.errorhandling; 2 3 import libd.datastructures.sumtype; 4 import libd.datastructures..string, libd.data.conv, libd.memory, libd.meta; 5 6 @nogc nothrow: 7 8 struct BcError 9 { 10 String file; 11 String function_; 12 String module_; 13 size_t line; 14 int errorCode; // Function/Library specific. 15 String message; 16 } 17 18 struct SimpleResult(T) 19 { 20 static if(is(T == void)) 21 private bool _isValid = true; 22 else 23 private bool _isValid = false; 24 private BcError _error; 25 26 static if(!is(T == void)) 27 private T _value; 28 29 static if(__traits(hasCopyConstructor, T)) 30 { 31 @disable 32 this(this){} 33 } 34 35 @nogc nothrow: 36 37 static if(!is(T == void)) 38 this()(auto ref T value) 39 { 40 static if(isCopyable!T) 41 this._value = value; 42 else 43 move(value, this._value); 44 this._isValid = true; 45 } 46 47 this(BcError error) 48 { 49 this._error = error; 50 this._isValid = false; 51 } 52 53 @property @safe @nogc 54 bool isValid() nothrow pure const 55 { 56 return this._isValid; 57 } 58 59 static if(!is(T == void)) 60 @property 61 ref inout(T) value()() inout 62 { 63 assert(this._isValid, "Attempted to get value of invalid result."); 64 return this._value; 65 } 66 67 @property 68 BcError error() 69 { 70 assert(!this._isValid, "Attempted to get value of not-invalid result."); 71 return this._error; 72 } 73 } 74 75 SimpleResult!ValueT result(ValueT)(auto ref BcError error) 76 { 77 return typeof(return)(error); 78 } 79 80 SimpleResult!ValueT result(ValueT)(auto ref ValueT value) 81 { 82 return typeof(return)(value); 83 } 84 85 BcError raise(string File = __FILE_FULL_PATH__, string Function = __PRETTY_FUNCTION__, string Module = __MODULE__, size_t Line = __LINE__)( 86 bcstring message, 87 int errorCode = 0 88 ) 89 { 90 return raise!(File, Function, Module, Line)(String(message), errorCode); 91 } 92 93 BcError raise(string File = __FILE_FULL_PATH__, string Function = __PRETTY_FUNCTION__, string Module = __MODULE__, size_t Line = __LINE__)( 94 String message, 95 int errorCode = 0 96 ) 97 { 98 auto error = BcError( 99 String(File), 100 String(Function), 101 String(Module), 102 Line, 103 errorCode 104 ); 105 error.message = message; 106 107 return error; 108 } 109 110 auto assumeValid(ResultT)(auto ref ResultT result) 111 { 112 if(!result.isValid) 113 throwError(result.error); 114 115 static if(__traits(hasMember, ResultT, "value")) 116 return result.value; 117 } 118 /// 119 @("assumeValid") 120 unittest 121 { 122 SimpleResult!int a = 69.result; 123 SimpleResult!int b = raise("yolo swag").result!int; 124 125 assert(a.assumeValid == 69); 126 127 // bool threw; 128 // try b.assumeValid(); 129 // catch(Error e) threw = true; 130 // assert(threw); 131 } 132 133 void throwError(BcError error) 134 { 135 displayError(error); 136 assert(false); 137 } 138 139 void formatError(OutputRange)(ref OutputRange output, BcError error) 140 { 141 const part1 = "Unexpected error:\n"; 142 const part2 = " File: "; 143 const part3 = " Module: "; 144 const part4 = " Function: "; 145 const part5 = " Line: "; 146 const part6 = " Code: "; 147 const part7 = " Message: "; 148 const maxSizeT = "18446744073709551615"; 149 150 static if(__traits(hasMember, output, "reserve")) 151 output.reserve( 152 part1.length 153 + part2.length 154 + part3.length 155 + part4.length 156 + part5.length + maxSizeT.length 157 + part6.length + maxSizeT.length 158 + part7.length + error.message.length 159 + error.file.length + 2 // + 2 to include padding 160 + error.function_.length + 2 161 + error.module_.length + 2 162 ); 163 164 output.put(part1); 165 output.put(part2); output.put(error.file.range); output.put('\n'); 166 output.put(part3); output.put(error.module_.range); output.put('\n'); 167 output.put(part4); output.put(error.function_.range); output.put('\n'); 168 output.put(part5); output.put(error.line.to!String.range); output.put('\n'); 169 output.put(part6); output.put(error.errorCode.to!String.range); output.put('\n'); 170 output.put(part7); output.put(error.message.sliceUnsafe); 171 172 output.put('\0'); 173 } 174 175 void displayError(BcError error) 176 { 177 import libd.datastructures : Array; 178 import libd.console.io; 179 180 Array!char output; 181 formatError(output, error); 182 consoleWriteln(output[0..$]); 183 } 184 185 void bcAssert(string File = __FILE_FULL_PATH__, string Function = __PRETTY_FUNCTION__, string Module = __MODULE__, size_t Line = __LINE__)( 186 bool condition, 187 bcstring message = null 188 ) 189 { 190 if(!condition) 191 throwError(raise!(File, Function, Module, Line)(message)); 192 } 193 194 void onOutOfMemoryError(void* pretend_sideeffect) 195 { 196 assert(false); 197 }