Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(72)

Side by Side Diff: sdk/lib/convert/converter.dart

Issue 17580014: dart:convert library. Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Update Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sdk/lib/convert/convert_sources.gypi ('k') | sdk/lib/convert/json.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 }
OLDNEW
« no previous file with comments | « sdk/lib/convert/convert_sources.gypi ('k') | sdk/lib/convert/json.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698