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