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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « sdk/lib/convert/convert_sources.gypi ('k') | sdk/lib/convert/json.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sdk/lib/convert/converter.dart
diff --git a/sdk/lib/convert/converter.dart b/sdk/lib/convert/converter.dart
new file mode 100644
index 0000000000000000000000000000000000000000..1e3f42c4cc8971f305d64e54665bee27cbdbf56c
--- /dev/null
+++ b/sdk/lib/convert/converter.dart
@@ -0,0 +1,194 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+abstract class Converter<S, T> {
+ // Synchronous conversion.
+ T convert(S input) {
+ T result;
+ ChunkedConversionSink outSink =
+ new ChunkedConversionSink.withCallback((x) { result = x; });
+ startChunkedConversion(outSink).addNonChunked(input);
+ return result;
+ }
+
+
+ // Can be implemented as other.fuseInput(this).
+ // The receiver can try to recognize [other] and optimize for it. If it
+ // doesn't recognize [other] it should always invoke `other.fuseInput(this)`.
+ Converter<S, dynamic> fuse(Converter<T, dynamic> other) {
+ return other.fuseInput(this);
+ }
+ // Double-dispatch method for [fuse]. Allows the successor to optimize
+ // in case it recognizes the source.
+ Converter<dynamic, T> fuseInput(Converter<dynamic, S> other) {
+ return new FusedConverter(other, this);
+ }
+
+ ChunkedConversionSink startChunkedConversion(ChunkedConversionSink sink) {
+ return new _NonChunkedSink<S, T>(this, sink);
+ }
+
+ ChunkedConversionInterface get inputInterface =>
+ ChunkedConversionSink.INTERFACE;
+ ChunkedConversionInterface get outputInterface =>
+ ChunkedConversionSink.INTERFACE;
+}
+
+abstract class ChunkedConversionInterface {
+ const ChunkedConversionInterface();
+
+ ChunkedConversionSink adapt(ChunkedConversionSink sink);
+ ChunkedConversionSink adaptEventSink(EventSink sink);
+}
+
+/** A chunked producer needs an interface to feed *one* value in. */
+abstract class ChunkedConversionSink<S> {
+ static const ChunkedConversionInterface INTERFACE =
+ const _NonChunkedInterface();
+
+ ChunkedConversionSink();
+ factory ChunkedConversionSink.withCallback(void f(S input)) = _CallbackSink;
+ void addNonChunked(S input);
+
+ ChunkedConversionInterface get interface => INTERFACE;
+
+ // The type is dynamic on purpose since sinks can chose to have a different
+ // chunk-input then the non-chunked input.
+ void add(o) { throw new UnsupportedError("add"); }
+ void close() { throw new UnsupportedError("close"); }
+}
+
+class _CallbackSink<S> extends ChunkedConversionSink<S> {
+ final Function _callback;
+ _CallbackSink(this._callback);
+ void addNonChunked(S input) { _callback(input); }
+}
+
+class _NonChunkedInterface extends ChunkedConversionInterface {
+ const _NonChunkedInterface();
+
+ ChunkedConversionSink adapt(ChunkedConversionSink sink) {
+ // Every sink is suitable as a non-chunked sink.
+ return sink;
+ }
+
+ ChunkedConversionSink adaptEventSink(EventSink eventSink) {
+ throw new UnsupportedError("close");
+ }
+}
+
+class _NonChunkedSink<S, T> extends ChunkedConversionSink<S> {
+ final Converter<S, T> _converter;
+ final ChunkedConversionSink<T> _output;
+
+ _NonChunkedSink(this._converter, this._output);
+
+ void addNonChunked(S input) {
+ _output.addNonChunked(_converter.convert(input));
+ }
+}
+
+class FusedConverter<S, T> extends Converter<S, T> {
+ final Converter first;
+ final Converter second;
+ FusedConverter(this.first, this.second);
+
+ T convert(S input) => second.convert(first.convert(input));
+
+ fuse(Converter other) => other.fuseInput(this);
+ fuseInput(Converter other) => new FusedConverter(other, this);
+
+ ChunkedConversionSink startChunkedConversion(ChunkedConversionSink sink) {
+ return first.startChunkedConversion(second.startChunkedConversion(sink));
+ }
+
+ ChunkedConversionInterface get inputInterface => first.inputInterface;
+ ChunkedConversionInterface get outputInterface => second.outputInterface;
+}
+
+class ConverterTransformer<S, T> implements StreamTransformer<S, T> {
+ // We can't put in the generic type of the converter since the synchronous
+ // conversion type is not necessarily the same as the chunked/streamed one.
+ final Converter _converter;
+ ConverterTransformer(Converter converter) : this._converter = converter;
+
+ Stream<T> bind(Stream<S> source) {
+ return new _ConverterTransformStream<S, T>(source, _converter);
+ }
+}
+
+class _ConverterTransformStream<S, T> extends EventTransformStream<S, T> {
+ final _ConverterStreamEventTransformer<S, T> _eventTransformer;
+
+ _ConverterTransformStream(Stream<S> source, Converter converter)
+ : this._withEventTransformer(
+ source,
+ new _ConverterStreamEventTransformer<S, T>(converter));
+
+ _ConverterTransformStream._withEventTransformer(
+ Stream<S> source,
+ _ConverterStreamEventTransformer<S, T> eventTransformer)
+ : _eventTransformer = eventTransformer,
+ super(source, eventTransformer);
+
+ StreamSubscription<T> listen(void onData(T data),
+ { void onError(error),
+ void onDone(),
+ bool cancelOnError }) {
+ _eventTransformer._start();
+ return super.listen(onData, onError: onError, onDone: onDone,
+ cancelOnError: cancelOnError);
+ }
+}
+
+class _ConverterStreamEventTransformer<S, T>
+ implements EventSink<T>, StreamEventTransformer<S, T> {
+ final Converter _converter;
+ EventSink _eventSink;
+ ChunkedConversionSink _chunkedSink;
+
+ _ConverterStreamEventTransformer(this._converter);
+
+ void _start() {
+ ChunkedConversionInterface outputInterface = _converter.outputInterface;
+ ChunkedConversionSink chunkedOutputSink =
+ outputInterface.adaptEventSink(this);
+ _chunkedSink = _converter.startChunkedConversion(chunkedOutputSink);
+ }
+
+ Stream bind(Stream otherStream) {
+ throw new UnsupportedError("Converter streams must not call bind");
+ }
+ void add(T o) => _eventSink.add(o);
+ void close() => _eventSink.close();
+ void addError(var error) {
+ throw new UnsupportedError("converters should not use `addError`.");
+ }
+
+ void handleData(S event, EventSink<T> eventSink) {
+ _eventSink = eventSink;
+ try {
+ _chunkedSink.add(event);
+ } catch(e) {
+ eventSink.addError(e);
+ }
+ _eventSink = null;
+ }
+
+ void handleDone(EventSink<T> eventSink) {
+ _eventSink = eventSink;
+ try {
+ _chunkedSink.close();
+ } catch(e) {
+ eventSink.addError(e);
+ }
+ _eventSink = null;
+ }
+
+ void handleError(var errorEvent, EventSink<T> eventSink) {
+ eventSink.addError(errorEvent);
+ }
+}
« 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