1 /** 2 * Defines the `Future` type and related types 3 */ 4 module guillotine.future; 5 6 // TODO: Examine the below import which seemingly fixes stuff for libsnooze 7 import libsnooze.clib; 8 import libsnooze; 9 10 import guillotine.result : Result; 11 12 /** 13 * Defines the state of the `Future` 14 */ 15 public enum State 16 { 17 NOT_STARTED, 18 RUNNING, 19 FINISHED, 20 ERRORED 21 } 22 23 /** 24 * Defines a future 25 */ 26 public final class Future 27 { 28 /** 29 * `libsnooze` event 30 */ 31 private Event event; 32 33 /** 34 * State of the future 35 */ 36 package State state = State.NOT_STARTED; 37 38 /** 39 * The result of the task (on success) 40 */ 41 private Result result; // TODO: Volatile maybe? 42 43 /** 44 * The error result (on error) 45 */ 46 private Exception errResult; // TODO: Volatile maybe? 47 48 /** 49 * Constructs a new `Future` 50 */ 51 public this() 52 { 53 this.event = new Event(); 54 } 55 56 /** 57 * Awaits this future either returning the result 58 * from its computation throwing the exception which 59 * occurred during it. 60 * 61 * Returns: the `Result` from the computation 62 * Throws: 63 * `GuillotineException` on fatal error 64 * Throws: 65 * `Exception` the exception that occurred during 66 * computation 67 */ 68 public Result await() 69 { 70 // If we are already finished, return the value 71 if(this.state == State.FINISHED) 72 { 73 return this.result; 74 } 75 // If we had an error then throw the error 76 else if(this.state == State.ERRORED) 77 { 78 throw errResult; 79 } 80 // If we are in RUNNING or NOT_STARTED 81 // (Note: this can happen in executor usage too 82 // ( instead of just standalone usage as the time before 83 // the FutureTask sets to RUNNING and when our main thread 84 // calls await() can have it pickup on the NOT_STARTED case) 85 else 86 { 87 bool doneYet = false; 88 while(!doneYet) 89 { 90 try 91 { 92 event.wait(); 93 doneYet = true; 94 } 95 catch(InterruptedException e) 96 { 97 // Do nothing 98 } 99 catch(FatalException e) 100 { 101 // TODO: Throw a FatalGuillaotine here 102 // TODO: make a custom guillotine exception 103 } 104 } 105 106 // If we had an error then throw it 107 if(this.state == State.ERRORED) 108 { 109 throw this.errResult; 110 } 111 // If we finished successfully, then return the result 112 // (Note: That is the only way this branch would run) 113 else 114 { 115 return this.result; 116 } 117 } 118 } 119 120 /** 121 * Sets this `Future` as completed by storing the 122 * provided result into it and waking up anybody 123 * who was awaiting it 124 * 125 * Params: 126 * result = the task's result 127 * 128 * Throws: 129 * TODO: Handle the libsnooze event 130 */ 131 package void complete(Result result) 132 { 133 // Store the result 134 this.result = result; 135 136 // Set the state 137 this.state = State.FINISHED; 138 139 // Wake up any sleepers 140 this.event.notifyAll(); 141 } 142 143 /** 144 * Sets this `Future` into the error state and wakes 145 * up anybody who was awaiting it 146 * 147 * Params: 148 * errResult = the `Exception` which occurred 149 * Throws: 150 * TODO: handle the libsnooze event 151 */ 152 package void error(Exception errResult) 153 { 154 // Store the error 155 this.errResult = errResult; 156 157 // Set the state 158 this.state = State.ERRORED; 159 160 // Wake up any sleepers 161 this.event.notifyAll(); 162 } 163 }