1 /** Exception base class inspired by Adam Ruppe's exception.d
2 
3     Error messages include the names and values of relevant data, but no
4     further introspection capabilities.
5 */
6 module jsonrpc.exception; @safe:
7 
8 // I cannot define an exception within the unittest scope for testing/examples.
9 ///
10 unittest {
11     /* Where InvalidArgumment is defined as:
12     class InvalidArgument : Exception {
13         this() { super(""); }
14     }
15     */
16 
17     void func(bool one, bool two) {
18         if (one == two) {
19             raise!(InvalidArgument, one, two)("The values shouldn't match!");
20         }
21     }
22     func(false, true);
23 }
24 
25 /** Raised when invalid data is passed as an argument to a function. */
26 class InvalidArgument : Exception {
27     this() { super(""); }
28 }
29 
30 /** Raised when invalid data is received by the client or server. */
31 class InvalidDataReceived : Exception {
32     this() { super(""); }
33 }
34 
35 /** Raised when there's a network connection error. */
36 class ConnectionException : Exception {
37     this() { super(""); }
38 }
39 
40 /** Raised when a function call via RPCClient.opDispatch receives an error
41     response.
42 */
43 class RPCErrorResponse : Exception {
44     this() { super(""); }
45 }
46 
47 /** Raised when attempting to access a JSONValue via a different type than the
48     underlying type.
49 */
50 class IncorrectType : Exception {
51     this() { super(""); }
52 }
53 
54 package:
55 
56 /** Generate and throw an exception.
57 
58     Additional data can be provided, both for inspection by catching code and
59     for viewing/logging if unhandled.
60 
61     Template_Parameters:
62         ExceptionClass = The exception class to throw.
63         T...           = A list of objects to include as part of the exception.
64 
65     Params:
66         msg =   An optional message concerning the exception.
67         file =  The file in which the exception was raised.
68         line =  The line number at which the exception was raised.
69 */
70 void raise(ExceptionClass, T...)(
71         string msg = "",
72         string file = __FILE__,
73         size_t line = __LINE__) {
74 
75     class Except : ExceptionClass {
76         this(string message, string file, size_t line) {
77             super.file = file;
78             super.line = line;
79             msg ~= message ~ "\n  Data:";
80             foreach (i, obj; T) {
81                 import std.string : format;
82                 msg ~= "\n\t%s: %s".format(__traits(identifier, T[i]), obj);
83             }
84         }
85     }
86     throw new Except(msg, file, line);
87 }
88 
89 /** Raise the specified exception of the provided expression evaluates to false.
90 
91     Behavior is similar to $(D_INLINECODE assert() ) but throws an exception on
92     failure.
93 
94     Example:
95     ---
96     enforce!(OutOfRange, myvar)(myvar > 0, "myvar must be greater than 0");
97     ---
98 */
99 auto enforce(ExceptionClass, T...)(
100         bool val,
101         string msg = "",
102         string file = __FILE__,
103         size_t line = __LINE__) {
104     if (!val) raise!(ExceptionClass, T)(msg, file, line);
105     return val;
106 }