1 module concurrency.error;
2 
3 // In order to handle Errors that get thrown on non-main threads we have to make a clone. There are cases where the Error is constructed in TLS, which either might be overwritten with another Error (if the thread continues work and hits another Error), or might point to invalid memory once the thread is cleaned up. In order to be safe we have to clone the Error.
4 
5 class ThrowableClone(T : Throwable) : T {
6   this(Args...)(Throwable.TraceInfo info, Args args) @safe nothrow {
7     super(args);
8     if (info)
9       this.info = new ClonedTraceInfo(info);
10   }
11 }
12 
13 // The reason it accepts a Throwable is because there might be classes that derive directly from Throwable but aren't Exceptions. We treat them as errors here.
14 Throwable clone(Throwable t) nothrow @safe {
15   import core.exception;
16   if (auto a = cast(AssertError)t)
17     return new ThrowableClone!AssertError(t.info, a.msg, a.file, a.line, a.next);
18   if (auto r = cast(RangeError)t)
19     return new ThrowableClone!RangeError(t.info, r.file, r.line, r.next);
20   if (auto e = cast(Error)t)
21     return new ThrowableClone!Error(t.info, t.msg, t.file, t.line, t.next);
22   return new ThrowableClone!Throwable(t.info, t.msg, t.file, t.line, t.next);
23 }
24 
25 class ClonedTraceInfo : Throwable.TraceInfo {
26   string[] buf;
27   this(Throwable.TraceInfo t) @trusted nothrow {
28     if (t) {
29       try {
30         foreach (i, line; t)
31           buf ~= line.idup();
32       } catch (Throwable t) {
33         // alas...
34       }
35     }
36   }
37   override int opApply(scope int delegate(ref const(char[])) dg) const {
38     return opApply((ref size_t, ref const(char[]) buf) => dg(buf));
39   }
40 
41   override int opApply(scope int delegate(ref size_t, ref const(char[])) dg) const {
42     foreach(i, line; buf) {
43       if (dg(i,line))
44         return 1;
45     }
46     return 0;
47   }
48 
49   override string toString() const {
50     string buf;
51     foreach ( i, line; this )
52       buf ~= i ? "\n" ~ line : line;
53     return buf;
54   }
55 }