Line data Source code
1 : // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 2 : // for details. All rights reserved. Use of this source code is governed by a 3 : // BSD-style license that can be found in the LICENSE file. 4 : 5 : import 'dart:async'; 6 : 7 : import 'capture_sink.dart'; 8 : import 'capture_transformer.dart'; 9 : import 'error.dart'; 10 : import 'release_sink.dart'; 11 : import 'release_transformer.dart'; 12 : import 'value.dart'; 13 : import '../stream_sink_transformer.dart'; 14 : 15 : /// The result of a computation. 16 : /// 17 : /// Capturing a result (either a returned value or a thrown error) means 18 : /// converting it into a [Result] - either a [ValueResult] or an [ErrorResult]. 19 : /// 20 : /// This value can release itself by writing itself either to a [EventSink] or a 21 : /// [Completer], or by becoming a [Future]. 22 : /// 23 : /// A [Future] represents a potential result, one that might not have been 24 : /// computed yet, and a [Result] is always a completed and available result. 25 : abstract class Result<T> { 26 : /// A stream transformer that captures a stream of events into [Result]s. 27 : /// 28 : /// The result of the transformation is a stream of [Result] values and no 29 : /// error events. This is the transformer used by [captureStream]. 30 : static const StreamTransformer<Object, Result<Object>> 31 : captureStreamTransformer = CaptureStreamTransformer<Object>(); 32 : 33 : /// A stream transformer that releases a stream of result events. 34 : /// 35 : /// The result of the transformation is a stream of values and error events. 36 : /// This is the transformer used by [releaseStream]. 37 : static const StreamTransformer<Result<Object>, Object> 38 : releaseStreamTransformer = ReleaseStreamTransformer<Object>(); 39 : 40 : /// A sink transformer that captures events into [Result]s. 41 : /// 42 : /// The result of the transformation is a sink that only forwards [Result] 43 : /// values and no error events. 44 : static const StreamSinkTransformer<Object, Result<Object>> 45 : captureSinkTransformer = 46 : StreamSinkTransformer<Object, Result<Object>>.fromStreamTransformer( 47 : CaptureStreamTransformer<Object>()); 48 : 49 : /// A sink transformer that releases result events. 50 : /// 51 : /// The result of the transformation is a sink that forwards of values and 52 : /// error events. 53 : static const StreamSinkTransformer<Result<Object>, Object> 54 : releaseSinkTransformer = 55 : StreamSinkTransformer<Result<Object>, Object>.fromStreamTransformer( 56 : ReleaseStreamTransformer<Object>()); 57 : 58 : /// Creates a `Result` with the result of calling [computation]. 59 : /// 60 : /// This generates either a [ValueResult] with the value returned by 61 : /// calling `computation`, or an [ErrorResult] with an error thrown by 62 : /// the call. 63 0 : factory Result(T Function() computation) { 64 : try { 65 0 : return ValueResult<T>(computation()); 66 : } on Object catch (e, s) { 67 0 : return ErrorResult(e, s); 68 : } 69 : } 70 : 71 : /// Creates a `Result` holding a value. 72 : /// 73 : /// Alias for [ValueResult.ValueResult]. 74 : factory Result.value(T value) = ValueResult<T>; 75 : 76 : /// Creates a `Result` holding an error. 77 : /// 78 : /// Alias for [ErrorResult.ErrorResult]. 79 0 : factory Result.error(Object error, [StackTrace? stackTrace]) => 80 0 : ErrorResult(error, stackTrace); 81 : 82 : /// Captures the result of a future into a `Result` future. 83 : /// 84 : /// The resulting future will never have an error. 85 : /// Errors have been converted to an [ErrorResult] value. 86 0 : static Future<Result<T>> capture<T>(Future<T> future) { 87 0 : return future.then((value) => ValueResult(value), 88 0 : onError: (Object error, StackTrace stackTrace) => 89 0 : ErrorResult(error, stackTrace)); 90 : } 91 : 92 : /// Captures each future in [elements], 93 : /// 94 : /// Returns a (future of) a list of results for each element in [elements], 95 : /// in iteration order. 96 : /// Each future in [elements] is [capture]d and each non-future is 97 : /// wrapped as a [Result.value]. 98 : /// The returned future will never have an error. 99 0 : static Future<List<Result<T>>> captureAll<T>(Iterable<FutureOr<T>> elements) { 100 0 : var results = <Result<T>?>[]; 101 : var pending = 0; 102 : late Completer<List<Result<T>>> completer; 103 0 : for (var element in elements) { 104 0 : if (element is Future<T>) { 105 0 : var i = results.length; 106 0 : results.add(null); 107 0 : pending++; 108 0 : Result.capture<T>(element).then((result) { 109 0 : results[i] = result; 110 0 : if (--pending == 0) { 111 0 : completer.complete(List.from(results)); 112 : } 113 : }); 114 : } else { 115 0 : results.add(Result<T>.value(element)); 116 : } 117 : } 118 0 : if (pending == 0) { 119 0 : return Future.value(List.from(results)); 120 : } 121 0 : completer = Completer<List<Result<T>>>(); 122 0 : return completer.future; 123 : } 124 : 125 : /// Releases the result of a captured future. 126 : /// 127 : /// Converts the [Result] value of the given [future] to a value or error 128 : /// completion of the returned future. 129 : /// 130 : /// If [future] completes with an error, the returned future completes with 131 : /// the same error. 132 0 : static Future<T> release<T>(Future<Result<T>> future) => 133 0 : future.then<T>((result) => result.asFuture); 134 : 135 : /// Captures the results of a stream into a stream of [Result] values. 136 : /// 137 : /// The returned stream will not have any error events. 138 : /// Errors from the source stream have been converted to [ErrorResult]s. 139 0 : static Stream<Result<T>> captureStream<T>(Stream<T> source) => 140 0 : source.transform(CaptureStreamTransformer<T>()); 141 : 142 : /// Releases a stream of [result] values into a stream of the results. 143 : /// 144 : /// `Result` values of the source stream become value or error events in 145 : /// the returned stream as appropriate. 146 : /// Errors from the source stream become errors in the returned stream. 147 0 : static Stream<T> releaseStream<T>(Stream<Result<T>> source) => 148 0 : source.transform(ReleaseStreamTransformer<T>()); 149 : 150 : /// Releases results added to the returned sink as data and errors on [sink]. 151 : /// 152 : /// A [Result] added to the returned sink is added as a data or error event 153 : /// on [sink]. Errors added to the returned sink are forwarded directly to 154 : /// [sink] and so is the [EventSink.close] calls. 155 0 : static EventSink<Result<T>> releaseSink<T>(EventSink<T> sink) => 156 0 : ReleaseSink<T>(sink); 157 : 158 : /// Captures the events of the returned sink into results on [sink]. 159 : /// 160 : /// Data and error events added to the returned sink are captured into 161 : /// [Result] values and added as data events on the provided [sink]. 162 : /// No error events are ever added to [sink]. 163 : /// 164 : /// When the returned sink is closed, so is [sink]. 165 0 : static EventSink<T> captureSink<T>(EventSink<Result<T>> sink) => 166 0 : CaptureSink<T>(sink); 167 : 168 : /// Converts a result of a result to a single result. 169 : /// 170 : /// If the result is an error, or it is a `Result` value 171 : /// which is then an error, then a result with that error is returned. 172 : /// Otherwise both levels of results are value results, and a single 173 : /// result with the value is returned. 174 0 : static Result<T> flatten<T>(Result<Result<T>> result) { 175 0 : if (result.isValue) return result.asValue!.value; 176 0 : return result.asError!; 177 : } 178 : 179 : /// Converts a sequence of results to a result of a list. 180 : /// 181 : /// Returns either a list of values if [results] doesn't contain any errors, 182 : /// or the first error result in [results]. 183 0 : static Result<List<T>> flattenAll<T>(Iterable<Result<T>> results) { 184 0 : var values = <T>[]; 185 0 : for (var result in results) { 186 0 : if (result.isValue) { 187 0 : values.add(result.asValue!.value); 188 : } else { 189 0 : return result.asError!; 190 : } 191 : } 192 0 : return Result<List<T>>.value(values); 193 : } 194 : 195 : /// Whether this result is a value result. 196 : /// 197 : /// Always the opposite of [isError]. 198 : bool get isValue; 199 : 200 : /// Whether this result is an error result. 201 : /// 202 : /// Always the opposite of [isValue]. 203 : bool get isError; 204 : 205 : /// If this is a value result, returns itself. 206 : /// 207 : /// Otherwise returns `null`. 208 : ValueResult<T>? get asValue; 209 : 210 : /// If this is an error result, returns itself. 211 : /// 212 : /// Otherwise returns `null`. 213 : ErrorResult? get asError; 214 : 215 : /// Completes a completer with this result. 216 : void complete(Completer<T> completer); 217 : 218 : /// Adds this result to an [EventSink]. 219 : /// 220 : /// Calls the sink's `add` or `addError` method as appropriate. 221 : void addTo(EventSink<T> sink); 222 : 223 : /// A future that has been completed with this result as a value or an error. 224 : Future<T> get asFuture; 225 : }