Index: tool/input_sdk/lib/convert/chunked_conversion.dart |
diff --git a/tool/input_sdk/lib/convert/chunked_conversion.dart b/tool/input_sdk/lib/convert/chunked_conversion.dart |
index c933820d030e23fd5acf903727f6e13998122134..95e561c47d2941f1478e361dff1fe9908b7162fe 100644 |
--- a/tool/input_sdk/lib/convert/chunked_conversion.dart |
+++ b/tool/input_sdk/lib/convert/chunked_conversion.dart |
@@ -7,6 +7,57 @@ part of dart.convert; |
typedef void _ChunkedConversionCallback<T>(T accumulated); |
/** |
+ * A converter that supports chunked conversions. |
+ * |
+ * In addition to immediate conversions from [S] to [T], a chunked converter |
+ * also supports longer-running conversions from [S2] to [T2]. |
+ * |
+ * Frequently, the source and target types are the same, but this is not a |
+ * requirement. In particular, converters that work with lists in the |
+ * immediate conversion, could flatten the type for the chunked conversion. |
+ * |
+ * For example, the [LineSplitter] class returns a `List<String>` for the |
+ * immediate conversion, but returns individual `String`s in the chunked |
+ * conversion. |
+ */ |
+abstract class ChunkedConverter<S, T, S2, T2> extends Converter<S, T> { |
+ |
+ const ChunkedConverter(); |
+ |
+ /** |
+ * Starts a chunked conversion. |
+ * |
+ * The returned sink serves as input for the long-running conversion. The |
+ * given [sink] serves as output. |
+ */ |
+ ChunkedConversionSink<S2> startChunkedConversion(Sink<T2> sink) { |
+ throw new UnsupportedError( |
+ "This converter does not support chunked conversions: $this"); |
+ } |
+ |
+ Stream<T2> bind(Stream<S2> stream) { |
+ return new Stream<T2>.eventTransformed( |
+ stream, |
+ (EventSink<T2> sink) => |
+ new _ConverterStreamEventSink<S2, T2>(this, sink)); |
+ } |
+ |
+ /** |
+ * Fuses this instance with the given [other] converter. |
+ * |
+ * If [other] is a ChunkedConverter (with matching generic types), returns a |
+ * [ChunkedConverter]. |
+ */ |
+ Converter<S, dynamic> fuse(Converter<T, dynamic> other) { |
+ if (other is ChunkedConverter<T, dynamic, T2, dynamic>) { |
+ return new _FusedChunkedConverter<S, T, dynamic, S2, T2, dynamic>( |
+ this, other); |
+ } |
+ return super.fuse(other); |
+ } |
+} |
+ |
+/** |
* A [ChunkedConversionSink] is used to transmit data more efficiently between |
* two converters during chunked conversions. |
* |
@@ -20,7 +71,7 @@ typedef void _ChunkedConversionCallback<T>(T accumulated); |
abstract class ChunkedConversionSink<T> implements Sink<T> { |
ChunkedConversionSink(); |
factory ChunkedConversionSink.withCallback( |
- void callback(List<T> accumulated)) = _SimpleCallbackSink<T>; |
+ void callback(List<T> accumulated)) = _SimpleCallbackSink; |
/** |
* Adds chunked data to this sink. |
@@ -54,17 +105,8 @@ class _SimpleCallbackSink<T> extends ChunkedConversionSink<T> { |
void close() { _callback(_accumulated); } |
} |
-class _EventSinkAdapter<T> implements ChunkedConversionSink<T> { |
- final EventSink<T> _sink; |
- |
- _EventSinkAdapter(this._sink); |
- |
- void add(T data) => _sink.add(data); |
- void close() => _sink.close(); |
-} |
- |
/** |
- * This class converts implements the logic for a chunked conversion as a |
+ * This class implements the logic for a chunked conversion as a |
* stream transformer. |
* |
* It is used as strategy in the [EventTransformStream]. |
@@ -80,15 +122,34 @@ class _ConverterStreamEventSink<S, T> implements EventSink<S> { |
* The input sink for new data. All data that is received with |
* [handleData] is added into this sink. |
*/ |
- ChunkedConversionSink _chunkedSink; |
+ final ChunkedConversionSink<S> _chunkedSink; |
- _ConverterStreamEventSink(Converter converter, EventSink<T> sink) |
+ _ConverterStreamEventSink( |
+ Converter/*=ChunkedConverter<dynamic, dynamic, S, T>*/ converter, |
+ EventSink<T> sink) |
: this._eventSink = sink, |
_chunkedSink = converter.startChunkedConversion(sink); |
- void add(S o) => _chunkedSink.add(o); |
+ void add(S o) { _chunkedSink.add(o); } |
void addError(Object error, [StackTrace stackTrace]) { |
_eventSink.addError(error, stackTrace); |
} |
- void close() => _chunkedSink.close(); |
+ void close() { _chunkedSink.close(); } |
+} |
+ |
+/** |
+ * Fuses two chunked converters. |
+ */ |
+class _FusedChunkedConverter<S, M, T, S2, M2, T2> extends |
+ ChunkedConverter<S, T, S2, T2> { |
+ final ChunkedConverter<S, M, S2, M2> _first; |
+ final ChunkedConverter<M, T, M2, T2> _second; |
+ |
+ _FusedChunkedConverter(this._first, this._second); |
+ |
+ T convert(S input) => _second.convert(_first.convert(input)); |
+ |
+ ChunkedConversionSink<S2> startChunkedConversion(Sink<T2> sink) { |
+ return _first.startChunkedConversion(_second.startChunkedConversion(sink)); |
+ } |
} |