| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2013, 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 part of dart.convert; |
| 6 |
| 7 abstract class Converter<S, T> { |
| 8 // Synchronous conversion. |
| 9 T convert(S input) { |
| 10 T result; |
| 11 ChunkedConversionSink outSink = |
| 12 new ChunkedConversionSink.withCallback((x) { result = x; }); |
| 13 startChunkedConversion(outSink).addNonChunked(input); |
| 14 return result; |
| 15 } |
| 16 |
| 17 |
| 18 // Can be implemented as other.fuseInput(this). |
| 19 // The receiver can try to recognize [other] and optimize for it. If it |
| 20 // doesn't recognize [other] it should always invoke `other.fuseInput(this)`. |
| 21 Converter<S, dynamic> fuse(Converter<T, dynamic> other) { |
| 22 return other.fuseInput(this); |
| 23 } |
| 24 // Double-dispatch method for [fuse]. Allows the successor to optimize |
| 25 // in case it recognizes the source. |
| 26 Converter<dynamic, T> fuseInput(Converter<dynamic, S> other) { |
| 27 return new FusedConverter(other, this); |
| 28 } |
| 29 |
| 30 ChunkedConversionSink startChunkedConversion(ChunkedConversionSink sink) { |
| 31 return new _NonChunkedSink<S, T>(this, sink); |
| 32 } |
| 33 |
| 34 ChunkedConversionInterface get inputInterface => |
| 35 ChunkedConversionSink.INTERFACE; |
| 36 ChunkedConversionInterface get outputInterface => |
| 37 ChunkedConversionSink.INTERFACE; |
| 38 } |
| 39 |
| 40 abstract class ChunkedConversionInterface { |
| 41 const ChunkedConversionInterface(); |
| 42 |
| 43 ChunkedConversionSink adapt(ChunkedConversionSink sink); |
| 44 ChunkedConversionSink adaptEventSink(EventSink sink); |
| 45 } |
| 46 |
| 47 /** A chunked producer needs an interface to feed *one* value in. */ |
| 48 abstract class ChunkedConversionSink<S> { |
| 49 static const ChunkedConversionInterface INTERFACE = |
| 50 const _NonChunkedInterface(); |
| 51 |
| 52 ChunkedConversionSink(); |
| 53 factory ChunkedConversionSink.withCallback(void f(S input)) = _CallbackSink; |
| 54 void addNonChunked(S input); |
| 55 |
| 56 ChunkedConversionInterface get interface => INTERFACE; |
| 57 |
| 58 // The type is dynamic on purpose since sinks can chose to have a different |
| 59 // chunk-input then the non-chunked input. |
| 60 void add(o) { throw new UnsupportedError("add"); } |
| 61 void close() { throw new UnsupportedError("close"); } |
| 62 } |
| 63 |
| 64 class _CallbackSink<S> extends ChunkedConversionSink<S> { |
| 65 final Function _callback; |
| 66 _CallbackSink(this._callback); |
| 67 void addNonChunked(S input) { _callback(input); } |
| 68 } |
| 69 |
| 70 class _NonChunkedInterface extends ChunkedConversionInterface { |
| 71 const _NonChunkedInterface(); |
| 72 |
| 73 ChunkedConversionSink adapt(ChunkedConversionSink sink) { |
| 74 // Every sink is suitable as a non-chunked sink. |
| 75 return sink; |
| 76 } |
| 77 |
| 78 ChunkedConversionSink adaptEventSink(EventSink eventSink) { |
| 79 throw new UnsupportedError("close"); |
| 80 } |
| 81 } |
| 82 |
| 83 class _NonChunkedSink<S, T> extends ChunkedConversionSink<S> { |
| 84 final Converter<S, T> _converter; |
| 85 final ChunkedConversionSink<T> _output; |
| 86 |
| 87 _NonChunkedSink(this._converter, this._output); |
| 88 |
| 89 void addNonChunked(S input) { |
| 90 _output.addNonChunked(_converter.convert(input)); |
| 91 } |
| 92 } |
| 93 |
| 94 class FusedConverter<S, T> extends Converter<S, T> { |
| 95 final Converter first; |
| 96 final Converter second; |
| 97 FusedConverter(this.first, this.second); |
| 98 |
| 99 T convert(S input) => second.convert(first.convert(input)); |
| 100 |
| 101 fuse(Converter other) => other.fuseInput(this); |
| 102 fuseInput(Converter other) => new FusedConverter(other, this); |
| 103 |
| 104 ChunkedConversionSink startChunkedConversion(ChunkedConversionSink sink) { |
| 105 return first.startChunkedConversion(second.startChunkedConversion(sink)); |
| 106 } |
| 107 |
| 108 ChunkedConversionInterface get inputInterface => first.inputInterface; |
| 109 ChunkedConversionInterface get outputInterface => second.outputInterface; |
| 110 } |
| 111 |
| 112 class ConverterTransformer<S, T> implements StreamTransformer<S, T> { |
| 113 // We can't put in the generic type of the converter since the synchronous |
| 114 // conversion type is not necessarily the same as the chunked/streamed one. |
| 115 final Converter _converter; |
| 116 ConverterTransformer(Converter converter) : this._converter = converter; |
| 117 |
| 118 Stream<T> bind(Stream<S> source) { |
| 119 return new _ConverterTransformStream<S, T>(source, _converter); |
| 120 } |
| 121 } |
| 122 |
| 123 class _ConverterTransformStream<S, T> extends EventTransformStream<S, T> { |
| 124 final _ConverterStreamEventTransformer<S, T> _eventTransformer; |
| 125 |
| 126 _ConverterTransformStream(Stream<S> source, Converter converter) |
| 127 : this._withEventTransformer( |
| 128 source, |
| 129 new _ConverterStreamEventTransformer<S, T>(converter)); |
| 130 |
| 131 _ConverterTransformStream._withEventTransformer( |
| 132 Stream<S> source, |
| 133 _ConverterStreamEventTransformer<S, T> eventTransformer) |
| 134 : _eventTransformer = eventTransformer, |
| 135 super(source, eventTransformer); |
| 136 |
| 137 StreamSubscription<T> listen(void onData(T data), |
| 138 { void onError(error), |
| 139 void onDone(), |
| 140 bool cancelOnError }) { |
| 141 _eventTransformer._start(); |
| 142 return super.listen(onData, onError: onError, onDone: onDone, |
| 143 cancelOnError: cancelOnError); |
| 144 } |
| 145 } |
| 146 |
| 147 class _ConverterStreamEventTransformer<S, T> |
| 148 implements EventSink<T>, StreamEventTransformer<S, T> { |
| 149 final Converter _converter; |
| 150 EventSink _eventSink; |
| 151 ChunkedConversionSink _chunkedSink; |
| 152 |
| 153 _ConverterStreamEventTransformer(this._converter); |
| 154 |
| 155 void _start() { |
| 156 ChunkedConversionInterface outputInterface = _converter.outputInterface; |
| 157 ChunkedConversionSink chunkedOutputSink = |
| 158 outputInterface.adaptEventSink(this); |
| 159 _chunkedSink = _converter.startChunkedConversion(chunkedOutputSink); |
| 160 } |
| 161 |
| 162 Stream bind(Stream otherStream) { |
| 163 throw new UnsupportedError("Converter streams must not call bind"); |
| 164 } |
| 165 void add(T o) => _eventSink.add(o); |
| 166 void close() => _eventSink.close(); |
| 167 void addError(var error) { |
| 168 throw new UnsupportedError("converters should not use `addError`."); |
| 169 } |
| 170 |
| 171 void handleData(S event, EventSink<T> eventSink) { |
| 172 _eventSink = eventSink; |
| 173 try { |
| 174 _chunkedSink.add(event); |
| 175 } catch(e) { |
| 176 eventSink.addError(e); |
| 177 } |
| 178 _eventSink = null; |
| 179 } |
| 180 |
| 181 void handleDone(EventSink<T> eventSink) { |
| 182 _eventSink = eventSink; |
| 183 try { |
| 184 _chunkedSink.close(); |
| 185 } catch(e) { |
| 186 eventSink.addError(e); |
| 187 } |
| 188 _eventSink = null; |
| 189 } |
| 190 |
| 191 void handleError(var errorEvent, EventSink<T> eventSink) { |
| 192 eventSink.addError(errorEvent); |
| 193 } |
| 194 } |
| OLD | NEW |