Steps towards making the convert library strong-mode compliant.

This version has a few deprecated methods. In a future release they will be removed.

See https://codereview.chromium.org/1827803002 for the final patch (once the deprecated methods have been removed).

R=leafp@google.com, lrn@google.com

Committed: 4ab1219bf9
Reverted: 045a375366

Review URL: https://codereview.chromium.org/1847843002 .
This commit is contained in:
Florian Loitsch 2016-04-12 20:59:21 +02:00
parent 688eeb555c
commit 50bdab3841
17 changed files with 147 additions and 57 deletions

View file

@ -8,6 +8,9 @@
* Added `SecurityContext.alpnSupported`, which is true if a platform
supports ALPN, and false otherwise.
* `dart:convert`
* Introduce `ChunkedConverter` and deprecate chunked methods on `Converter`.
### Analyzer
* Static checking of `for in` statements. These will now produce static

View file

@ -271,7 +271,9 @@ abstract class CommonInputConverter extends Converter<String, Operation> {
* into a series of operations to be sent to the analysis server.
* The input stream can be either an instrumenation or log file.
*/
class InputConverter extends Converter<String, Operation> {
class InputConverter
extends ChunkedConverter<String, Operation, String, Operation> {
final Logger logger = new Logger('InputConverter');
/**

View file

@ -85,12 +85,13 @@ abstract class ClientCommunicationChannel {
* Instances of the class [JsonStreamDecoder] convert JSON strings to JSON
* maps.
*/
class JsonStreamDecoder extends Converter<String, Map> {
class JsonStreamDecoder extends
ChunkedConverter<String, Map, String, Map> {
@override
Map convert(String text) => JSON.decode(text);
@override
ChunkedConversionSink startChunkedConversion(Sink sink) =>
ChunkedConversionSink<String> startChunkedConversion(Sink<Map> sink) =>
new ChannelChunkSink<String, Map>(this, sink);
}
@ -98,24 +99,26 @@ class JsonStreamDecoder extends Converter<String, Map> {
* Instances of the class [NotificationConverter] convert JSON maps to
* [Notification]s.
*/
class NotificationConverter extends Converter<Map, Notification> {
class NotificationConverter extends
ChunkedConverter<Map, Notification, Map, Notification> {
@override
Notification convert(Map json) => new Notification.fromJson(json);
@override
ChunkedConversionSink startChunkedConversion(Sink sink) =>
ChunkedConversionSink<Map> startChunkedConversion(Sink<Notification> sink) =>
new ChannelChunkSink<Map, Notification>(this, sink);
}
/**
* Instances of the class [ResponseConverter] convert JSON maps to [Response]s.
*/
class ResponseConverter extends Converter<Map, Response> {
class ResponseConverter extends
ChunkedConverter<Map, Response, Map, Response> {
@override
Response convert(Map json) => new Response.fromJson(json);
@override
ChunkedConversionSink startChunkedConversion(Sink sink) =>
ChunkedConversionSink<Map> startChunkedConversion(Sink<Response> sink) =>
new ChannelChunkSink<Map, Response>(this, sink);
}

View file

@ -39,13 +39,14 @@ patch class Utf8Decoder {
}
}
class _JsonUtf8Decoder extends Converter<List<int>, Object> {
class _JsonUtf8Decoder extends
ChunkedConverter<List<int>, Object, List<int>, Object> {
final _Reviver _reviver;
final bool _allowMalformed;
_JsonUtf8Decoder(this._reviver, this._allowMalformed);
dynamic convert(List<int> input) {
Object convert(List<int> input) {
var parser = _JsonUtf8DecoderSink._createParser(_reviver, _allowMalformed);
parser.chunk = input;
parser.chunkEnd = input.length;

View file

@ -69,7 +69,8 @@ class AsciiCodec extends Encoding {
// Superclass for [AsciiEncoder] and [Latin1Encoder].
// Generalizes common operations that only differ by a mask;
class _UnicodeSubsetEncoder extends Converter<String, List<int>> {
class _UnicodeSubsetEncoder extends
ChunkedConverter<String, List<int>, String, List<int>> {
final int _subsetMask;
const _UnicodeSubsetEncoder(this._subsetMask);
@ -154,7 +155,8 @@ class _UnicodeSubsetEncoderSink extends StringConversionSinkBase {
* This class converts Latin-1 bytes (lists of unsigned 8-bit integers)
* to a string.
*/
abstract class _UnicodeSubsetDecoder extends Converter<List<int>, String> {
abstract class _UnicodeSubsetDecoder extends
ChunkedConverter<List<int>, String, List<int>, String> {
final bool _allowInvalid;
final int _subsetMask;

View file

@ -70,7 +70,8 @@ class Base64Codec extends Codec<List<int>, String> {
*
* The results are ASCII strings using a restricted alphabet.
*/
class Base64Encoder extends Converter<List<int>, String> {
class Base64Encoder extends
ChunkedConverter<List<int>, String, List<int>, String> {
final bool _urlSafe;
const Base64Encoder() : _urlSafe = false;
@ -89,14 +90,6 @@ class Base64Encoder extends Converter<List<int>, String> {
}
return new _AsciiBase64EncoderSink(sink, _urlSafe);
}
Stream<String> bind(Stream<List<int>> stream) {
return new Stream<String>.eventTransformed(
stream,
(EventSink sink) =>
new _ConverterStreamEventSink<List<int>, String>(
this, sink));
}
}
/**
@ -348,7 +341,9 @@ class _Utf8Base64EncoderSink extends _Base64EncoderSink {
*
* The encoding is required to be properly padded.
*/
class Base64Decoder extends Converter<String, List<int>> {
class Base64Decoder extends
ChunkedConverter<String, List<int>, String, List<int>> {
const Base64Decoder();
List<int> convert(String input, [int start = 0, int end]) {

View file

@ -6,6 +6,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.
@ -55,7 +106,7 @@ class _SimpleCallbackSink<T> extends ChunkedConversionSink<T> {
}
/**
* 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].
@ -71,9 +122,11 @@ 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;
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);
@ -83,3 +136,20 @@ class _ConverterStreamEventSink<S, T> implements EventSink<S> {
}
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));
}
}

View file

@ -29,14 +29,22 @@ abstract class Converter<S, T> implements StreamTransformer {
}
/**
* Starts a chunked conversion.
* Deprecated.
*
* Use the [ChunkedConverter] interface instead.
*/
@deprecated
ChunkedConversionSink startChunkedConversion(Sink sink) {
throw new UnsupportedError(
"This converter does not support chunked conversions: $this");
}
// Subclasses are encouraged to provide better types.
/**
* Deprecated.
*
* Use the [ChunkedConverter] interface instead.
*/
@deprecated
Stream bind(Stream stream) {
return new Stream.eventTransformed(
stream,
@ -50,14 +58,10 @@ abstract class Converter<S, T> implements StreamTransformer {
* For a non-chunked conversion converts the input in sequence.
*/
class _FusedConverter<S, M, T> extends Converter<S, T> {
final Converter _first;
final Converter _second;
final Converter<S, M> _first;
final Converter<M, T> _second;
_FusedConverter(this._first, this._second);
T convert(S input) => _second.convert(_first.convert(input));
ChunkedConversionSink startChunkedConversion(Sink sink) {
return _first.startChunkedConversion(_second.startChunkedConversion(sink));
}
}

View file

@ -10,6 +10,9 @@ part of dart.convert;
abstract class Encoding extends Codec<String, List<int>> {
const Encoding();
ChunkedConverter<String, List<int>, String, List<int>> get encoder;
ChunkedConverter<List<int>, String, List<int>, String> get decoder;
Future<String> decodeStream(Stream<List<int>> byteStream) {
return byteStream
.transform(decoder)

View file

@ -152,7 +152,7 @@ class HtmlEscapeMode {
* found to be easier to read if greater-than is also escaped whenever
* less-than is.
*/
class HtmlEscape extends Converter<String, String> {
class HtmlEscape extends ChunkedConverter<String, String, String, String> {
/** The [HtmlEscapeMode] used by the converter. */
final HtmlEscapeMode mode;

View file

@ -159,7 +159,7 @@ class JsonCodec extends Codec<Object, String> {
/**
* This class converts JSON objects to strings.
*/
class JsonEncoder extends Converter<Object, String> {
class JsonEncoder extends ChunkedConverter<Object, String, Object, String> {
/**
* The string used for indention.
*
@ -283,7 +283,8 @@ class JsonEncoder extends Converter<Object, String> {
* a JSON string, and then UTF-8 encoding the string, but without
* creating an intermediate string.
*/
class JsonUtf8Encoder extends Converter<Object, List<int>> {
class JsonUtf8Encoder extends
ChunkedConverter<Object, List<int>, Object, List<int>> {
/** Default buffer size used by the JSON-to-UTF-8 encoder. */
static const int DEFAULT_BUFFER_SIZE = 256;
/** Indentation used in pretty-print mode, `null` if not pretty. */
@ -473,7 +474,7 @@ class _JsonUtf8EncoderSink extends ChunkedConversionSink<Object> {
/**
* This class parses JSON strings and builds the corresponding objects.
*/
class JsonDecoder extends Converter<String, Object> {
class JsonDecoder extends ChunkedConverter<String, Object, String, Object> {
final _Reviver _reviver;
/**
* Constructs a new JsonDecoder.

View file

@ -59,9 +59,9 @@ class Latin1Codec extends Encoding {
}
}
Converter<String, List<int>> get encoder => const Latin1Encoder();
Latin1Encoder get encoder => const Latin1Encoder();
Converter<List<int>, String> get decoder =>
Latin1Decoder get decoder =>
_allowInvalid ? const Latin1Decoder(allowInvalid: true)
: const Latin1Decoder(allowInvalid: false);
}

View file

@ -17,7 +17,8 @@ const int _CR = 13;
*
* The returned lines do not contain the line terminators.
*/
class LineSplitter extends Converter<String, List<String>> {
class LineSplitter extends
ChunkedConverter<String, List<String>, String, String> {
const LineSplitter();
@ -79,9 +80,6 @@ class LineSplitter extends Converter<String, List<String>> {
}
return new _LineSplitterSink(sink);
}
// Override the base-class' bind, to provide a better type.
Stream<String> bind(Stream<String> stream) => super.bind(stream);
}
// TODO(floitsch): deal with utf8.

View file

@ -76,7 +76,8 @@ class Utf8Codec extends Encoding {
* This class converts strings to their UTF-8 code units (a list of
* unsigned 8-bit integers).
*/
class Utf8Encoder extends Converter<String, List<int>> {
class Utf8Encoder extends
ChunkedConverter<String, List<int>, String, List<int>> {
const Utf8Encoder();
@ -304,7 +305,8 @@ class _Utf8EncoderSink extends _Utf8Encoder with StringConversionSinkMixin {
* This class converts UTF-8 code units (lists of unsigned 8-bit integers)
* to a string.
*/
class Utf8Decoder extends Converter<List<int>, String> {
class Utf8Decoder extends
ChunkedConverter<List<int>, String, List<int>, String> {
final bool _allowMalformed;
/**

View file

@ -147,7 +147,7 @@ class ZLibCodec extends Codec<List<int>, List<int>> {
/**
* Get a [ZLibEncoder] for encoding to `ZLib` compressed data.
*/
Converter<List<int>, List<int>> get encoder =>
ZLibEncoder get encoder =>
new ZLibEncoder(gzip: false, level: level, windowBits: windowBits,
memLevel: memLevel, strategy: strategy,
dictionary: dictionary, raw: raw);
@ -155,7 +155,7 @@ class ZLibCodec extends Codec<List<int>, List<int>> {
/**
* Get a [ZLibDecoder] for decoding `ZLib` compressed data.
*/
Converter<List<int>, List<int>> get decoder =>
ZLibDecoder get decoder =>
new ZLibDecoder(windowBits: windowBits, dictionary: dictionary, raw: raw);
}
@ -259,7 +259,7 @@ class GZipCodec extends Codec<List<int>, List<int>> {
/**
* Get a [ZLibEncoder] for encoding to `GZip` compressed data.
*/
Converter<List<int>, List<int>> get encoder =>
ZLibEncoder get encoder =>
new ZLibEncoder(gzip: true, level: level, windowBits: windowBits,
memLevel: memLevel, strategy: strategy,
dictionary: dictionary, raw: raw);
@ -267,7 +267,7 @@ class GZipCodec extends Codec<List<int>, List<int>> {
/**
* Get a [ZLibDecoder] for decoding `GZip` compressed data.
*/
Converter<List<int>, List<int>> get decoder =>
ZLibDecoder get decoder =>
new ZLibDecoder(windowBits: windowBits, dictionary: dictionary, raw: raw);
}
@ -275,7 +275,8 @@ class GZipCodec extends Codec<List<int>, List<int>> {
* The [ZLibEncoder] encoder is used by [ZLibCodec] and [GZipCodec] to compress
* data.
*/
class ZLibEncoder extends Converter<List<int>, List<int>> {
class ZLibEncoder extends
ChunkedConverter<List<int>, List<int>, List<int>, List<int>> {
/**
* When true, `GZip` frames will be added to the compressed data.
*/
@ -378,7 +379,8 @@ class ZLibEncoder extends Converter<List<int>, List<int>> {
/**
* The [ZLibDecoder] is used by [ZLibCodec] and [GZipCodec] to decompress data.
*/
class ZLibDecoder extends Converter<List<int>, List<int>> {
class ZLibDecoder extends
ChunkedConverter<List<int>, List<int>, List<int>, List<int>> {
/**
* Base two logarithm of the window size (the size of the history buffer). It
* should be in the range `8..15`. Larger values result in better compression

View file

@ -25,7 +25,7 @@ class SystemEncoding extends Encoding {
List<int> encode(String input) => encoder.convert(input);
String decode(List<int> encoded) => decoder.convert(encoded);
Converter<String, List<int>> get encoder {
ChunkedConverter<String, List<int>, String, List<int>> get encoder {
if (Platform.operatingSystem == "windows") {
return const _WindowsCodePageEncoder();
} else {
@ -33,7 +33,7 @@ class SystemEncoding extends Encoding {
}
}
Converter<List<int>, String> get decoder {
ChunkedConverter<List<int>, String, List<int>, String> get decoder {
if (Platform.operatingSystem == "windows") {
return const _WindowsCodePageDecoder();
} else {
@ -42,7 +42,8 @@ class SystemEncoding extends Encoding {
}
}
class _WindowsCodePageEncoder extends Converter<String, List<int>> {
class _WindowsCodePageEncoder
extends ChunkedConverter<String, List<int>, String, List<int>> {
const _WindowsCodePageEncoder();
@ -97,7 +98,8 @@ class _WindowsCodePageEncoderSink extends StringConversionSinkBase {
}
class _WindowsCodePageDecoder extends Converter<List<int>, String> {
class _WindowsCodePageDecoder
extends ChunkedConverter<List<int>, String, List<int>, String> {
const _WindowsCodePageDecoder();

View file

@ -54,7 +54,8 @@ class BoolAdapterSink extends MyChunkedBoolSink {
specialB(o) => add(o);
}
class IntBoolConverter1 extends Converter<List<int>, List<bool>> {
class IntBoolConverter1 extends
ChunkedConverter<List<int>, List<bool>, int, bool> {
List<bool> convert(List<int> input) => input.map((x) => x > 0).toList();
startChunkedConversion(sink) {
@ -63,7 +64,8 @@ class IntBoolConverter1 extends Converter<List<int>, List<bool>> {
}
}
class BoolIntConverter1 extends Converter<List<bool>, List<int>> {
class BoolIntConverter1 extends
ChunkedConverter<List<bool>, List<int>, bool, int> {
List<int> convert(List<bool> input) => input.map((x) => x ? 1 : 0).toList();
startChunkedConversion(sink) {
@ -104,7 +106,7 @@ class BoolIntConverter1Sink extends MyChunkedBoolSink {
close() => outSink.close();
}
class IdentityConverter extends Converter {
class IdentityConverter extends ChunkedConverter {
convert(x) => x;
startChunkedConversion(sink) {