1 /* 2 * Copyright (c) 2011-2017 Contributors to the Eclipse Foundation 3 * 4 * This program and the accompanying materials are made available under the 5 * terms of the Eclipse Public License 2.0 which is available at 6 * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 7 * which is available at https://www.apache.org/licenses/LICENSE-2.0. 8 * 9 * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 10 */ 11 module hunt.database.base.AsyncResult; 12 13 import hunt.Exceptions; 14 import hunt.Functions; 15 import hunt.Object; 16 17 alias AsyncResultHandler(T) = Action1!(AsyncResult!T); 18 alias AsyncVoidHandler = AsyncResultHandler!Void; 19 alias VoidAsyncResult = AsyncResult!Void; 20 21 interface IAsyncResult { 22 23 /** 24 * A Throwable describing failure. This will be null if the operation succeeded. 25 * 26 * @return the cause or null if the operation succeeded. 27 */ 28 Throwable cause(); 29 30 /** 31 * Did it succeed? 32 * 33 * @return true if it succeded or false otherwise 34 */ 35 bool succeeded(); 36 37 /** 38 * Did it fail? 39 * 40 * @return true if it failed or false otherwise 41 */ 42 bool failed(); 43 44 } 45 46 /** 47 * Encapsulates the result of an asynchronous operation. 48 * <p> 49 * Many operations in Vert.x APIs provide results back by passing an instance of this in a {@link hunt.net.Handler}. 50 * <p> 51 * The result can either have failed or succeeded. 52 * <p> 53 * If it failed then the cause of the failure is available with {@link #cause}. 54 * <p> 55 * If it succeeded then the actual result is available with {@link #result} 56 * 57 * @author <a href="http://tfox.org">Tim Fox</a> 58 */ 59 interface AsyncResult(T) : IAsyncResult { 60 61 /** 62 * The result of the operation. This will be null if the operation failed. 63 * 64 * @return the result or null if the operation failed. 65 */ 66 T result(); 67 68 /** 69 * Apply a {@code mapper} function on this async result.<p> 70 * 71 * The {@code mapper} is called with the completed value and this mapper returns a value. This value will complete the result returned by this method call.<p> 72 * 73 * When this async result is failed, the failure will be propagated to the returned async result and the {@code mapper} will not be called. 74 * 75 * @param mapper the mapper function 76 * @return the mapped async result 77 */ 78 final AsyncResult!(U) map(U)(Function!(T, U) mapper) { 79 if (mapper is null) { 80 throw new NullPointerException(); 81 } 82 return new class AsyncResult!(U) { 83 override U result() { 84 if (succeeded()) { 85 return mapper(this.outer.result()); 86 } else { 87 return null; 88 } 89 } 90 91 override Throwable cause() { 92 return this.outer.cause(); 93 } 94 95 override bool succeeded() { 96 return this.outer.succeeded(); 97 } 98 99 override bool failed() { 100 return this.outer.failed(); 101 } 102 }; 103 } 104 105 /** 106 * Map the result of this async result to a specific {@code value}.<p> 107 * 108 * When this async result succeeds, this {@code value} will succeeed the async result returned by this method call.<p> 109 * 110 * When this async result fails, the failure will be propagated to the returned async result. 111 * 112 * @param value the value that eventually completes the mapped async result 113 * @return the mapped async result 114 */ 115 final AsyncResult!(V) map(V)(V value) { 116 return map!(V)((t) => value); 117 } 118 119 /** 120 * Map the result of this async result to {@code null}.<p> 121 * 122 * This is a convenience for {@code asyncResult.map((T) null)} or {@code asyncResult.map((Void) null)}.<p> 123 * 124 * When this async result succeeds, {@code null} will succeeed the async result returned by this method call.<p> 125 * 126 * When this async result fails, the failure will be propagated to the returned async result. 127 * 128 * @return the mapped async result 129 */ 130 final AsyncResult!(V) mapEmpty(V)() { 131 return map!(V)(V.init); 132 } 133 134 /** 135 * Apply a {@code mapper} function on this async result.<p> 136 * 137 * The {@code mapper} is called with the failure and this mapper returns a value. This value will complete the result returned by this method call.<p> 138 * 139 * When this async result is succeeded, the value will be propagated to the returned async result and the {@code mapper} will not be called. 140 * 141 * @param mapper the mapper function 142 * @return the mapped async result 143 */ 144 final AsyncResult!(T) otherwise(Function!(Throwable, T) mapper) { 145 if (mapper is null) { 146 throw new NullPointerException(); 147 } 148 return new class AsyncResult!(T) { 149 override T result() { 150 if (this.outer.succeeded()) { 151 return this.outer.result(); 152 } else if (this.outer.failed()) { 153 return mapper(this.outer.cause()); 154 } else { 155 static if(is(T == class) || is(T == interface)) { 156 return null; 157 } else { 158 return T.init; 159 } 160 } 161 } 162 163 override Throwable cause() { 164 return null; 165 } 166 167 override bool succeeded() { 168 return this.outer.succeeded() || this.outer.failed(); 169 } 170 171 override bool failed() { 172 return false; 173 } 174 }; 175 } 176 177 /** 178 * Map the failure of this async result to a specific {@code value}.<p> 179 * 180 * When this async result fails, this {@code value} will succeeed the async result returned by this method call.<p> 181 * 182 * When this async succeeds, the result will be propagated to the returned async result. 183 * 184 * @param value the value that eventually completes the mapped async result 185 * @return the mapped async result 186 */ 187 final AsyncResult!(T) otherwise(T value) { 188 return otherwise((err) => value); 189 } 190 191 /** 192 * Map the failure of this async result to {@code null}.<p> 193 * 194 * This is a convenience for {@code asyncResult.otherwise((T) null)}.<p> 195 * 196 * When this async result fails, the {@code null} will succeeed the async result returned by this method call.<p> 197 * 198 * When this async succeeds, the result will be propagated to the returned async result. 199 * 200 * @return the mapped async result 201 */ 202 final AsyncResult!(T) otherwiseEmpty() { 203 return otherwise((err) => T.init); 204 } 205 206 } 207 208 AsyncResult!T succeededResult(T)(T v) { 209 return new class AsyncResult!(T) { 210 override T result() { 211 return v; 212 } 213 214 override Throwable cause() { 215 return null; 216 } 217 218 override bool succeeded() { 219 return true; 220 } 221 222 override bool failed() { 223 return false; 224 } 225 }; 226 } 227 228 229 AsyncResult!T failedResult(T)(Throwable t) { 230 return new class AsyncResult!(T) { 231 override T result() { 232 static if(is(T == class) || is(T == interface)) { 233 return null; 234 } else { 235 return T.init; 236 } 237 } 238 239 override Throwable cause() { 240 return t; 241 } 242 243 override bool succeeded() { 244 return false; 245 } 246 247 override bool failed() { 248 return true; 249 } 250 }; 251 }