Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of dart.convert; | 5 part of dart.convert; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * Error thrown by JSON serialization if an object cannot be serialized. | 8 * Error thrown by JSON serialization if an object cannot be serialized. |
| 9 * | 9 * |
| 10 * The [unsupportedObject] field holds that object that failed to be serialized. | 10 * The [unsupportedObject] field holds that object that failed to be serialized. |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 132 * Converts [value] to a JSON string. | 132 * Converts [value] to a JSON string. |
| 133 * | 133 * |
| 134 * If value contains objects that are not directly encodable to a JSON | 134 * If value contains objects that are not directly encodable to a JSON |
| 135 * string (a value that is not a number, boolean, string, null, list or a map | 135 * string (a value that is not a number, boolean, string, null, list or a map |
| 136 * with string keys), the [toEncodable] function is used to convert it to an | 136 * with string keys), the [toEncodable] function is used to convert it to an |
| 137 * object that must be directly encodable. | 137 * object that must be directly encodable. |
| 138 * | 138 * |
| 139 * If [toEncodable] is omitted, it defaults to a function that returns the | 139 * If [toEncodable] is omitted, it defaults to a function that returns the |
| 140 * result of calling `.toJson()` on the unencodable object. | 140 * result of calling `.toJson()` on the unencodable object. |
| 141 */ | 141 */ |
| 142 String encode(Object value, {toEncodable(var object)}) { | 142 String encode(Object value, {dynamic toEncodable(dynamic object)}) { |
|
Lasse Reichstein Nielsen
2016/05/11 09:06:14
Can you just remove the "dynamic" here?
Or does th
floitsch
2016/05/11 11:20:44
I had to add it. I'm not really sure which one is
floitsch
2016/05/11 14:14:54
As discussed in person: removed them again.
| |
| 143 if (toEncodable == null) toEncodable = _toEncodable; | 143 if (toEncodable == null) toEncodable = _toEncodable; |
| 144 if (toEncodable == null) return encoder.convert(value); | 144 if (toEncodable == null) return encoder.convert(value); |
| 145 return new JsonEncoder(toEncodable).convert(value); | 145 return new JsonEncoder(toEncodable).convert(value); |
| 146 } | 146 } |
| 147 | 147 |
| 148 JsonEncoder get encoder { | 148 JsonEncoder get encoder { |
| 149 if (_toEncodable == null) return const JsonEncoder(); | 149 if (_toEncodable == null) return const JsonEncoder(); |
| 150 return new JsonEncoder(_toEncodable); | 150 return new JsonEncoder(_toEncodable); |
| 151 } | 151 } |
| 152 | 152 |
| 153 JsonDecoder get decoder { | 153 JsonDecoder get decoder { |
| 154 if (_reviver == null) return const JsonDecoder(); | 154 if (_reviver == null) return const JsonDecoder(); |
| 155 return new JsonDecoder(_reviver); | 155 return new JsonDecoder(_reviver); |
| 156 } | 156 } |
| 157 } | 157 } |
| 158 | 158 |
| 159 /** | 159 /** |
| 160 * This class converts JSON objects to strings. | 160 * This class converts JSON objects to strings. |
| 161 */ | 161 */ |
| 162 class JsonEncoder extends ChunkedConverter<Object, String, Object, String> { | 162 class JsonEncoder extends Converter<Object, String> { |
| 163 /** | 163 /** |
| 164 * The string used for indention. | 164 * The string used for indention. |
| 165 * | 165 * |
| 166 * When generating multi-line output, this string is inserted once at the | 166 * When generating multi-line output, this string is inserted once at the |
| 167 * beginning of each indented line for each level of indentation. | 167 * beginning of each indented line for each level of indentation. |
| 168 * | 168 * |
| 169 * If `null`, the output is encoded as a single line. | 169 * If `null`, the output is encoded as a single line. |
| 170 */ | 170 */ |
| 171 final String indent; | 171 final String indent; |
| 172 | 172 |
| 173 /** | 173 /** |
| 174 * Function called on non-encodable objects to return a replacement | 174 * Function called on non-encodable objects to return a replacement |
| 175 * encodable object that will be encoded in the orignal's place. | 175 * encodable object that will be encoded in the orignal's place. |
| 176 */ | 176 */ |
| 177 final Function _toEncodable; | 177 final _ToEncodable _toEncodable; |
| 178 | 178 |
| 179 /** | 179 /** |
| 180 * Creates a JSON encoder. | 180 * Creates a JSON encoder. |
| 181 * | 181 * |
| 182 * The JSON encoder handles numbers, strings, booleans, null, lists and | 182 * The JSON encoder handles numbers, strings, booleans, null, lists and |
| 183 * maps directly. | 183 * maps directly. |
| 184 * | 184 * |
| 185 * Any other object is attempted converted by [toEncodable] to an | 185 * Any other object is attempted converted by [toEncodable] to an |
| 186 * object that is of one of the convertible types. | 186 * object that is of one of the convertible types. |
| 187 * | 187 * |
| 188 * If [toEncodable] is omitted, it defaults to calling `.toJson()` on | 188 * If [toEncodable] is omitted, it defaults to calling `.toJson()` on |
| 189 * the object. | 189 * the object. |
| 190 */ | 190 */ |
| 191 const JsonEncoder([Object toEncodable(Object nonSerializable)]) | 191 const JsonEncoder([dynamic toEncodable(dynamic nonSerializable)]) |
| 192 : this.indent = null, | 192 : this.indent = null, |
| 193 this._toEncodable = toEncodable; | 193 this._toEncodable = toEncodable; |
| 194 | 194 |
| 195 /** | 195 /** |
| 196 * Creates a JSON encoder that creates multi-line JSON. | 196 * Creates a JSON encoder that creates multi-line JSON. |
| 197 * | 197 * |
| 198 * The encoding of elements of lists and maps are indented and put on separate | 198 * The encoding of elements of lists and maps are indented and put on separate |
| 199 * lines. The [indent] string is prepended to these elements, once for each | 199 * lines. The [indent] string is prepended to these elements, once for each |
| 200 * level of indentation. | 200 * level of indentation. |
| 201 * | 201 * |
| 202 * If [indent] is `null`, the output is encoded as a single line. | 202 * If [indent] is `null`, the output is encoded as a single line. |
| 203 * | 203 * |
| 204 * The JSON encoder handles numbers, strings, booleans, null, lists and | 204 * The JSON encoder handles numbers, strings, booleans, null, lists and |
| 205 * maps directly. | 205 * maps directly. |
| 206 * | 206 * |
| 207 * Any other object is attempted converted by [toEncodable] to an | 207 * Any other object is attempted converted by [toEncodable] to an |
| 208 * object that is of one of the convertible types. | 208 * object that is of one of the convertible types. |
| 209 * | 209 * |
| 210 * If [toEncodable] is omitted, it defaults to calling `.toJson()` on | 210 * If [toEncodable] is omitted, it defaults to calling `.toJson()` on |
| 211 * the object. | 211 * the object. |
| 212 */ | 212 */ |
| 213 const JsonEncoder.withIndent(this.indent, | 213 const JsonEncoder.withIndent(this.indent, |
| 214 [Object toEncodable(Object nonSerializable)]) | 214 [dynamic toEncodable(dynamic nonSerializable)]) |
|
Lasse Reichstein Nielsen
2016/05/11 09:06:14
Is this necessary?
Is it because an int->int funct
floitsch
2016/05/11 11:20:45
Unfortunately necessary. Example output of the ana
| |
| 215 : this._toEncodable = toEncodable; | 215 : this._toEncodable = toEncodable; |
| 216 | 216 |
| 217 /** | 217 /** |
| 218 * Converts [object] to a JSON [String]. | 218 * Converts [object] to a JSON [String]. |
| 219 * | 219 * |
| 220 * Directly serializable values are [num], [String], [bool], and [Null], as | 220 * Directly serializable values are [num], [String], [bool], and [Null], as |
| 221 * well as some [List] and [Map] values. For [List], the elements must all be | 221 * well as some [List] and [Map] values. For [List], the elements must all be |
| 222 * serializable. For [Map], the keys must be [String] and the values must be | 222 * serializable. For [Map], the keys must be [String] and the values must be |
| 223 * serializable. | 223 * serializable. |
| 224 * | 224 * |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 261 return new _JsonUtf8EncoderSink(sink._sink, _toEncodable, | 261 return new _JsonUtf8EncoderSink(sink._sink, _toEncodable, |
| 262 JsonUtf8Encoder._utf8Encode(indent), | 262 JsonUtf8Encoder._utf8Encode(indent), |
| 263 JsonUtf8Encoder.DEFAULT_BUFFER_SIZE); | 263 JsonUtf8Encoder.DEFAULT_BUFFER_SIZE); |
| 264 } | 264 } |
| 265 return new _JsonEncoderSink(sink, _toEncodable, indent); | 265 return new _JsonEncoderSink(sink, _toEncodable, indent); |
| 266 } | 266 } |
| 267 | 267 |
| 268 // Override the base class's bind, to provide a better type. | 268 // Override the base class's bind, to provide a better type. |
| 269 Stream<String> bind(Stream<Object> stream) => super.bind(stream); | 269 Stream<String> bind(Stream<Object> stream) => super.bind(stream); |
| 270 | 270 |
| 271 Converter<Object, dynamic> fuse(Converter<String, dynamic> other) { | 271 Converter<Object, dynamic/*=T*/> fuse/*<T>*/( |
| 272 Converter<String, dynamic/*=T*/> other) { | |
| 272 if (other is Utf8Encoder) { | 273 if (other is Utf8Encoder) { |
| 273 return new JsonUtf8Encoder(indent, _toEncodable); | 274 return new JsonUtf8Encoder(indent, _toEncodable) |
| 275 as dynamic/*=Converter<Object, T>*/; | |
| 274 } | 276 } |
| 275 return super.fuse(other); | 277 return super.fuse/*<T>*/(other); |
| 276 } | 278 } |
| 277 } | 279 } |
| 278 | 280 |
| 279 /** | 281 /** |
| 280 * Encoder that encodes a single object as a UTF-8 encoded JSON string. | 282 * Encoder that encodes a single object as a UTF-8 encoded JSON string. |
| 281 * | 283 * |
| 282 * This encoder works equivalently to first converting the object to | 284 * This encoder works equivalently to first converting the object to |
| 283 * a JSON string, and then UTF-8 encoding the string, but without | 285 * a JSON string, and then UTF-8 encoding the string, but without |
| 284 * creating an intermediate string. | 286 * creating an intermediate string. |
| 285 */ | 287 */ |
| 286 class JsonUtf8Encoder extends | 288 class JsonUtf8Encoder extends Converter<Object, List<int>> { |
| 287 ChunkedConverter<Object, List<int>, Object, List<int>> { | |
| 288 /** Default buffer size used by the JSON-to-UTF-8 encoder. */ | 289 /** Default buffer size used by the JSON-to-UTF-8 encoder. */ |
| 289 static const int DEFAULT_BUFFER_SIZE = 256; | 290 static const int DEFAULT_BUFFER_SIZE = 256; |
| 290 /** Indentation used in pretty-print mode, `null` if not pretty. */ | 291 /** Indentation used in pretty-print mode, `null` if not pretty. */ |
| 291 final List<int> _indent; | 292 final List<int> _indent; |
| 292 /** Function called with each un-encodable object encountered. */ | 293 /** Function called with each un-encodable object encountered. */ |
| 293 final Function _toEncodable; | 294 final _ToEncodable _toEncodable; |
| 294 /** UTF-8 buffer size. */ | 295 /** UTF-8 buffer size. */ |
| 295 final int _bufferSize; | 296 final int _bufferSize; |
| 296 | 297 |
| 297 /** | 298 /** |
| 298 * Create converter. | 299 * Create converter. |
| 299 * | 300 * |
| 300 * If [indent] is non-`null`, the converter attempts to "pretty-print" the | 301 * If [indent] is non-`null`, the converter attempts to "pretty-print" the |
| 301 * JSON, and uses `indent` as the indentation. Otherwise the result has no | 302 * JSON, and uses `indent` as the indentation. Otherwise the result has no |
| 302 * whitespace outside of string literals. | 303 * whitespace outside of string literals. |
| 303 * If `indent` contains characters that are not valid JSON whitespace | 304 * If `indent` contains characters that are not valid JSON whitespace |
| 304 * characters, the result will not be valid JSON. JSON whitespace characters | 305 * characters, the result will not be valid JSON. JSON whitespace characters |
| 305 * are space (U+0020), tab (U+0009), line feed (U+000a) and carriage return | 306 * are space (U+0020), tab (U+0009), line feed (U+000a) and carriage return |
| 306 * (U+000d) ([ECMA | 307 * (U+000d) ([ECMA |
| 307 * 404](http://www.ecma-international.org/publications/standards/Ecma-404.htm) ). | 308 * 404](http://www.ecma-international.org/publications/standards/Ecma-404.htm) ). |
| 308 * | 309 * |
| 309 * The [bufferSize] is the size of the internal buffers used to collect | 310 * The [bufferSize] is the size of the internal buffers used to collect |
| 310 * UTF-8 code units. | 311 * UTF-8 code units. |
| 311 * If using [startChunkedConversion], it will be the size of the chunks. | 312 * If using [startChunkedConversion], it will be the size of the chunks. |
| 312 * | 313 * |
| 313 * The JSON encoder handles numbers, strings, booleans, null, lists and maps | 314 * The JSON encoder handles numbers, strings, booleans, null, lists and maps |
| 314 * directly. | 315 * directly. |
| 315 * | 316 * |
| 316 * Any other object is attempted converted by [toEncodable] to an object that | 317 * Any other object is attempted converted by [toEncodable] to an object that |
| 317 * is of one of the convertible types. | 318 * is of one of the convertible types. |
| 318 * | 319 * |
| 319 * If [toEncodable] is omitted, it defaults to calling `.toJson()` on the | 320 * If [toEncodable] is omitted, it defaults to calling `.toJson()` on the |
| 320 * object. | 321 * object. |
| 321 */ | 322 */ |
| 322 JsonUtf8Encoder([String indent, | 323 JsonUtf8Encoder([String indent, |
| 323 toEncodable(Object object), | 324 dynamic toEncodable(dynamic object), |
| 324 int bufferSize = DEFAULT_BUFFER_SIZE]) | 325 int bufferSize = DEFAULT_BUFFER_SIZE]) |
| 325 : _indent = _utf8Encode(indent), | 326 : _indent = _utf8Encode(indent), |
| 326 _toEncodable = toEncodable, | 327 _toEncodable = toEncodable, |
| 327 _bufferSize = bufferSize; | 328 _bufferSize = bufferSize; |
| 328 | 329 |
| 329 static List<int> _utf8Encode(String string) { | 330 static List<int> _utf8Encode(String string) { |
| 330 if (string == null) return null; | 331 if (string == null) return null; |
| 331 if (string.isEmpty) return new Uint8List(0); | 332 if (string.isEmpty) return new Uint8List(0); |
| 332 checkAscii: { | 333 checkAscii: { |
| 333 for (int i = 0; i < string.length; i++) { | 334 for (int i = 0; i < string.length; i++) { |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 388 byteSink = new ByteConversionSink.from(sink); | 389 byteSink = new ByteConversionSink.from(sink); |
| 389 } | 390 } |
| 390 return new _JsonUtf8EncoderSink(byteSink, _toEncodable, | 391 return new _JsonUtf8EncoderSink(byteSink, _toEncodable, |
| 391 _indent, _bufferSize); | 392 _indent, _bufferSize); |
| 392 } | 393 } |
| 393 | 394 |
| 394 // Override the base class's bind, to provide a better type. | 395 // Override the base class's bind, to provide a better type. |
| 395 Stream<List<int>> bind(Stream<Object> stream) { | 396 Stream<List<int>> bind(Stream<Object> stream) { |
| 396 return super.bind(stream); | 397 return super.bind(stream); |
| 397 } | 398 } |
| 398 | |
| 399 Converter<Object, dynamic> fuse(Converter<List<int>, dynamic> other) { | |
| 400 return super.fuse(other); | |
| 401 } | |
| 402 } | 399 } |
| 403 | 400 |
| 404 /** | 401 /** |
| 405 * Implements the chunked conversion from object to its JSON representation. | 402 * Implements the chunked conversion from object to its JSON representation. |
| 406 * | 403 * |
| 407 * The sink only accepts one value, but will produce output in a chunked way. | 404 * The sink only accepts one value, but will produce output in a chunked way. |
| 408 */ | 405 */ |
| 409 class _JsonEncoderSink extends ChunkedConversionSink<Object> { | 406 class _JsonEncoderSink extends ChunkedConversionSink<Object> { |
| 410 final String _indent; | 407 final String _indent; |
| 411 final Function _toEncodable; | 408 final _ToEncodable _toEncodable; |
| 412 final StringConversionSink _sink; | 409 final StringConversionSink _sink; |
| 413 bool _isDone = false; | 410 bool _isDone = false; |
| 414 | 411 |
| 415 _JsonEncoderSink(this._sink, this._toEncodable, this._indent); | 412 _JsonEncoderSink(this._sink, this._toEncodable, this._indent); |
| 416 | 413 |
| 417 /** | 414 /** |
| 418 * Encodes the given object [o]. | 415 * Encodes the given object [o]. |
| 419 * | 416 * |
| 420 * It is an error to invoke this method more than once on any instance. While | 417 * It is an error to invoke this method more than once on any instance. While |
| 421 * this makes the input effectly non-chunked the output will be generated in | 418 * this makes the input effectly non-chunked the output will be generated in |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 434 void close() { /* do nothing */ } | 431 void close() { /* do nothing */ } |
| 435 } | 432 } |
| 436 | 433 |
| 437 /** | 434 /** |
| 438 * Sink returned when starting a chunked conversion from object to bytes. | 435 * Sink returned when starting a chunked conversion from object to bytes. |
| 439 */ | 436 */ |
| 440 class _JsonUtf8EncoderSink extends ChunkedConversionSink<Object> { | 437 class _JsonUtf8EncoderSink extends ChunkedConversionSink<Object> { |
| 441 /** The byte sink receiveing the encoded chunks. */ | 438 /** The byte sink receiveing the encoded chunks. */ |
| 442 final ByteConversionSink _sink; | 439 final ByteConversionSink _sink; |
| 443 final List<int> _indent; | 440 final List<int> _indent; |
| 444 final Function _toEncodable; | 441 final _ToEncodable _toEncodable; |
| 445 final int _bufferSize; | 442 final int _bufferSize; |
| 446 bool _isDone = false; | 443 bool _isDone = false; |
| 447 _JsonUtf8EncoderSink(this._sink, this._toEncodable, this._indent, | 444 _JsonUtf8EncoderSink(this._sink, this._toEncodable, this._indent, |
| 448 this._bufferSize); | 445 this._bufferSize); |
| 449 | 446 |
| 450 /** Callback called for each slice of result bytes. */ | 447 /** Callback called for each slice of result bytes. */ |
| 451 void _addChunk(Uint8List chunk, int start, int end) { | 448 void _addChunk(Uint8List chunk, int start, int end) { |
| 452 _sink.addSlice(chunk, start, end, false); | 449 _sink.addSlice(chunk, start, end, false); |
| 453 } | 450 } |
| 454 | 451 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 467 if (!_isDone) { | 464 if (!_isDone) { |
| 468 _isDone = true; | 465 _isDone = true; |
| 469 _sink.close(); | 466 _sink.close(); |
| 470 } | 467 } |
| 471 } | 468 } |
| 472 } | 469 } |
| 473 | 470 |
| 474 /** | 471 /** |
| 475 * This class parses JSON strings and builds the corresponding objects. | 472 * This class parses JSON strings and builds the corresponding objects. |
| 476 */ | 473 */ |
| 477 class JsonDecoder extends ChunkedConverter<String, Object, String, Object> { | 474 class JsonDecoder extends Converter<String, Object> { |
| 478 final _Reviver _reviver; | 475 final _Reviver _reviver; |
| 479 /** | 476 /** |
| 480 * Constructs a new JsonDecoder. | 477 * Constructs a new JsonDecoder. |
| 481 * | 478 * |
| 482 * The [reviver] may be `null`. | 479 * The [reviver] may be `null`. |
| 483 */ | 480 */ |
| 484 const JsonDecoder([reviver(var key, var value)]) : this._reviver = reviver; | 481 const JsonDecoder([reviver(var key, var value)]) : this._reviver = reviver; |
| 485 | 482 |
| 486 /** | 483 /** |
| 487 * Converts the given JSON-string [input] to its corresponding object. | 484 * Converts the given JSON-string [input] to its corresponding object. |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 510 // Override the base class's bind, to provide a better type. | 507 // Override the base class's bind, to provide a better type. |
| 511 Stream<Object> bind(Stream<String> stream) => super.bind(stream); | 508 Stream<Object> bind(Stream<String> stream) => super.bind(stream); |
| 512 } | 509 } |
| 513 | 510 |
| 514 // Internal optimized JSON parsing implementation. | 511 // Internal optimized JSON parsing implementation. |
| 515 external _parseJson(String source, reviver(key, value)); | 512 external _parseJson(String source, reviver(key, value)); |
| 516 | 513 |
| 517 | 514 |
| 518 // Implementation of encoder/stringifier. | 515 // Implementation of encoder/stringifier. |
| 519 | 516 |
| 520 Object _defaultToEncodable(object) => object.toJson(); | 517 dynamic _defaultToEncodable(dynamic object) => object.toJson(); |
| 521 | 518 |
| 522 /** | 519 /** |
| 523 * JSON encoder that traverses an object structure and writes JSON source. | 520 * JSON encoder that traverses an object structure and writes JSON source. |
| 524 * | 521 * |
| 525 * This is an abstract implementation that doesn't decide on the output | 522 * This is an abstract implementation that doesn't decide on the output |
| 526 * format, but writes the JSON through abstract methods like [writeString]. | 523 * format, but writes the JSON through abstract methods like [writeString]. |
| 527 */ | 524 */ |
| 528 abstract class _JsonStringifier { | 525 abstract class _JsonStringifier { |
| 529 // Character code constants. | 526 // Character code constants. |
| 530 static const int BACKSPACE = 0x08; | 527 static const int BACKSPACE = 0x08; |
| 531 static const int TAB = 0x09; | 528 static const int TAB = 0x09; |
| 532 static const int NEWLINE = 0x0a; | 529 static const int NEWLINE = 0x0a; |
| 533 static const int CARRIAGE_RETURN = 0x0d; | 530 static const int CARRIAGE_RETURN = 0x0d; |
| 534 static const int FORM_FEED = 0x0c; | 531 static const int FORM_FEED = 0x0c; |
| 535 static const int QUOTE = 0x22; | 532 static const int QUOTE = 0x22; |
| 536 static const int CHAR_0 = 0x30; | 533 static const int CHAR_0 = 0x30; |
| 537 static const int BACKSLASH = 0x5c; | 534 static const int BACKSLASH = 0x5c; |
| 538 static const int CHAR_b = 0x62; | 535 static const int CHAR_b = 0x62; |
| 539 static const int CHAR_f = 0x66; | 536 static const int CHAR_f = 0x66; |
| 540 static const int CHAR_n = 0x6e; | 537 static const int CHAR_n = 0x6e; |
| 541 static const int CHAR_r = 0x72; | 538 static const int CHAR_r = 0x72; |
| 542 static const int CHAR_t = 0x74; | 539 static const int CHAR_t = 0x74; |
| 543 static const int CHAR_u = 0x75; | 540 static const int CHAR_u = 0x75; |
| 544 | 541 |
| 545 /** List of objects currently being traversed. Used to detect cycles. */ | 542 /** List of objects currently being traversed. Used to detect cycles. */ |
| 546 final List _seen = new List(); | 543 final List _seen = new List(); |
| 547 /** Function called for each un-encodable object encountered. */ | 544 /** Function called for each un-encodable object encountered. */ |
| 548 final Function _toEncodable; | 545 final _ToEncodable _toEncodable; |
| 549 | 546 |
| 550 _JsonStringifier(Object _toEncodable(Object o)) | 547 _JsonStringifier(dynamic toEncodable(dynamic o)) |
| 551 : _toEncodable = (_toEncodable != null) ? _toEncodable | 548 : _toEncodable = toEncodable ?? _defaultToEncodable; |
| 552 : _defaultToEncodable; | |
| 553 | 549 |
| 554 /** Append a string to the JSON output. */ | 550 /** Append a string to the JSON output. */ |
| 555 void writeString(String characters); | 551 void writeString(String characters); |
| 556 /** Append part of a string to the JSON output. */ | 552 /** Append part of a string to the JSON output. */ |
| 557 void writeStringSlice(String characters, int start, int end); | 553 void writeStringSlice(String characters, int start, int end); |
| 558 /** Append a single character, given by its code point, to the JSON output. */ | 554 /** Append a single character, given by its code point, to the JSON output. */ |
| 559 void writeCharCode(int charCode); | 555 void writeCharCode(int charCode); |
| 560 /** Write a number to the JSON output. */ | 556 /** Write a number to the JSON output. */ |
| 561 void writeNumber(num number); | 557 void writeNumber(num number); |
| 562 | 558 |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 712 writeObject(list[0]); | 708 writeObject(list[0]); |
| 713 for (int i = 1; i < list.length; i++) { | 709 for (int i = 1; i < list.length; i++) { |
| 714 writeString(','); | 710 writeString(','); |
| 715 writeObject(list[i]); | 711 writeObject(list[i]); |
| 716 } | 712 } |
| 717 } | 713 } |
| 718 writeString(']'); | 714 writeString(']'); |
| 719 } | 715 } |
| 720 | 716 |
| 721 /** Serialize a [Map]. */ | 717 /** Serialize a [Map]. */ |
| 722 bool writeMap(Map<String, Object> map) { | 718 bool writeMap(Map map) { |
| 723 if (map.isEmpty) { | 719 if (map.isEmpty) { |
| 724 writeString("{}"); | 720 writeString("{}"); |
| 725 return true; | 721 return true; |
| 726 } | 722 } |
| 727 List keyValueList = new List(map.length * 2); | 723 List keyValueList = new List(map.length * 2); |
| 728 int i = 0; | 724 int i = 0; |
| 729 bool allStringKeys = true; | 725 bool allStringKeys = true; |
| 730 map.forEach((key, value) { | 726 map.forEach((key, value) { |
| 731 if (key is! String) { | 727 if (key is! String) { |
| 732 allStringKeys = false; | 728 allStringKeys = false; |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 754 * [Map] objects using the specified indent value. | 750 * [Map] objects using the specified indent value. |
| 755 * | 751 * |
| 756 * Subclasses should implement [writeIndentation]. | 752 * Subclasses should implement [writeIndentation]. |
| 757 */ | 753 */ |
| 758 abstract class _JsonPrettyPrintMixin implements _JsonStringifier { | 754 abstract class _JsonPrettyPrintMixin implements _JsonStringifier { |
| 759 int _indentLevel = 0; | 755 int _indentLevel = 0; |
| 760 | 756 |
| 761 /** | 757 /** |
| 762 * Add [indentLevel] indentations to the JSON output. | 758 * Add [indentLevel] indentations to the JSON output. |
| 763 */ | 759 */ |
| 764 void writeIndentation(indentLevel); | 760 void writeIndentation(int indentLevel); |
| 765 | 761 |
| 766 void writeList(List list) { | 762 void writeList(List list) { |
| 767 if (list.isEmpty) { | 763 if (list.isEmpty) { |
| 768 writeString('[]'); | 764 writeString('[]'); |
| 769 } else { | 765 } else { |
| 770 writeString('[\n'); | 766 writeString('[\n'); |
| 771 _indentLevel++; | 767 _indentLevel++; |
| 772 writeIndentation(_indentLevel); | 768 writeIndentation(_indentLevel); |
| 773 writeObject(list[0]); | 769 writeObject(list[0]); |
| 774 for (int i = 1; i < list.length; i++) { | 770 for (int i = 1; i < list.length; i++) { |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 831 * Convert object to a string. | 827 * Convert object to a string. |
| 832 * | 828 * |
| 833 * The [toEncodable] function is used to convert non-encodable objects | 829 * The [toEncodable] function is used to convert non-encodable objects |
| 834 * to encodable ones. | 830 * to encodable ones. |
| 835 * | 831 * |
| 836 * If [indent] is not `null`, the resulting JSON will be "pretty-printed" | 832 * If [indent] is not `null`, the resulting JSON will be "pretty-printed" |
| 837 * with newlines and indentation. The `indent` string is added as indentation | 833 * with newlines and indentation. The `indent` string is added as indentation |
| 838 * for each indentation level. It should only contain valid JSON whitespace | 834 * for each indentation level. It should only contain valid JSON whitespace |
| 839 * characters (space, tab, carriage return or line feed). | 835 * characters (space, tab, carriage return or line feed). |
| 840 */ | 836 */ |
| 841 static String stringify(object, toEncodable(object), String indent) { | 837 static String stringify( |
| 838 object, dynamic toEncodable(dynamic o), String indent) { | |
| 842 StringBuffer output = new StringBuffer(); | 839 StringBuffer output = new StringBuffer(); |
| 843 printOn(object, output, toEncodable, indent); | 840 printOn(object, output, toEncodable, indent); |
| 844 return output.toString(); | 841 return output.toString(); |
| 845 } | 842 } |
| 846 | 843 |
| 847 /** | 844 /** |
| 848 * Convert object to a string, and write the result to the [output] sink. | 845 * Convert object to a string, and write the result to the [output] sink. |
| 849 * | 846 * |
| 850 * The result is written piecemally to the sink. | 847 * The result is written piecemally to the sink. |
| 851 */ | 848 */ |
| 852 static void printOn(object, StringSink output, toEncodable(object), | 849 static void printOn(object, StringSink output, dynamic toEncodable(dynamic o), |
| 853 String indent) { | 850 String indent) { |
| 854 var stringifier; | 851 var stringifier; |
| 855 if (indent == null) { | 852 if (indent == null) { |
| 856 stringifier = new _JsonStringStringifier(output, toEncodable); | 853 stringifier = new _JsonStringStringifier(output, toEncodable); |
| 857 } else { | 854 } else { |
| 858 stringifier = | 855 stringifier = |
| 859 new _JsonStringStringifierPretty(output, toEncodable, indent); | 856 new _JsonStringStringifierPretty(output, toEncodable, indent); |
| 860 } | 857 } |
| 861 stringifier.writeObject(object); | 858 stringifier.writeObject(object); |
| 862 } | 859 } |
| 863 | 860 |
| 864 void writeNumber(num number) { | 861 void writeNumber(num number) { |
| 865 _sink.write(number.toString()); | 862 _sink.write(number.toString()); |
| 866 } | 863 } |
| 867 void writeString(String string) { | 864 void writeString(String string) { |
| 868 _sink.write(string); | 865 _sink.write(string); |
| 869 } | 866 } |
| 870 void writeStringSlice(String string, int start, int end) { | 867 void writeStringSlice(String string, int start, int end) { |
| 871 _sink.write(string.substring(start, end)); | 868 _sink.write(string.substring(start, end)); |
| 872 } | 869 } |
| 873 void writeCharCode(int charCode) { | 870 void writeCharCode(int charCode) { |
| 874 _sink.writeCharCode(charCode); | 871 _sink.writeCharCode(charCode); |
| 875 } | 872 } |
| 876 } | 873 } |
| 877 | 874 |
| 878 class _JsonStringStringifierPretty extends _JsonStringStringifier | 875 class _JsonStringStringifierPretty extends _JsonStringStringifier |
| 879 with _JsonPrettyPrintMixin { | 876 with _JsonPrettyPrintMixin { |
| 880 final String _indent; | 877 final String _indent; |
| 881 | 878 |
| 882 _JsonStringStringifierPretty(StringSink sink, Function toEncodable, | 879 _JsonStringStringifierPretty(StringSink sink, dynamic toEncodable(dynamic o), |
| 883 this._indent) | 880 this._indent) |
| 884 : super(sink, toEncodable); | 881 : super(sink, toEncodable); |
| 885 | 882 |
| 886 void writeIndentation(int count) { | 883 void writeIndentation(int count) { |
| 887 for (int i = 0; i < count; i++) writeString(_indent); | 884 for (int i = 0; i < count; i++) writeString(_indent); |
| 888 } | 885 } |
| 889 } | 886 } |
| 890 | 887 |
| 888 typedef void _AddChunk(Uint8List list, int start, int end); | |
| 889 | |
| 891 /** | 890 /** |
| 892 * Specialization of [_JsonStringifier] that writes the JSON as UTF-8. | 891 * Specialization of [_JsonStringifier] that writes the JSON as UTF-8. |
| 893 * | 892 * |
| 894 * The JSON text is UTF-8 encoded and written to [Uint8List] buffers. | 893 * The JSON text is UTF-8 encoded and written to [Uint8List] buffers. |
| 895 * The buffers are then passed back to a user provided callback method. | 894 * The buffers are then passed back to a user provided callback method. |
| 896 */ | 895 */ |
| 897 class _JsonUtf8Stringifier extends _JsonStringifier { | 896 class _JsonUtf8Stringifier extends _JsonStringifier { |
| 898 final int bufferSize; | 897 final int bufferSize; |
| 899 final Function addChunk; | 898 final _AddChunk addChunk; |
| 900 Uint8List buffer; | 899 Uint8List buffer; |
| 901 int index = 0; | 900 int index = 0; |
| 902 | 901 |
| 903 _JsonUtf8Stringifier(toEncodable, int bufferSize, this.addChunk) | 902 _JsonUtf8Stringifier( |
| 903 dynamic toEncodable(dynamic o), int bufferSize, this.addChunk) | |
| 904 : this.bufferSize = bufferSize, | 904 : this.bufferSize = bufferSize, |
| 905 buffer = new Uint8List(bufferSize), | 905 buffer = new Uint8List(bufferSize), |
| 906 super(toEncodable); | 906 super(toEncodable); |
| 907 | 907 |
| 908 /** | 908 /** |
| 909 * Convert [object] to UTF-8 encoded JSON. | 909 * Convert [object] to UTF-8 encoded JSON. |
| 910 * | 910 * |
| 911 * Calls [addChunk] with slices of UTF-8 code units. | 911 * Calls [addChunk] with slices of UTF-8 code units. |
| 912 * These will typically have size [bufferSize], but may be shorter. | 912 * These will typically have size [bufferSize], but may be shorter. |
| 913 * The buffers are not reused, so the [addChunk] call may keep and reuse the | 913 * The buffers are not reused, so the [addChunk] call may keep and reuse the |
| 914 * chunks. | 914 * chunks. |
| 915 * | 915 * |
| 916 * If [indent] is non-`null`, the result will be "pretty-printed" with extra | 916 * If [indent] is non-`null`, the result will be "pretty-printed" with extra |
| 917 * newlines and indentation, using [indent] as the indentation. | 917 * newlines and indentation, using [indent] as the indentation. |
| 918 */ | 918 */ |
| 919 static void stringify(Object object, | 919 static void stringify(Object object, |
| 920 List<int> indent, | 920 List<int> indent, |
| 921 toEncodableFunction(Object o), | 921 dynamic toEncodable(dynamic o), |
| 922 int bufferSize, | 922 int bufferSize, |
| 923 void addChunk(Uint8List chunk, int start, int end)) { | 923 void addChunk(Uint8List chunk, int start, int end)) { |
| 924 _JsonUtf8Stringifier stringifier; | 924 _JsonUtf8Stringifier stringifier; |
| 925 if (indent != null) { | 925 if (indent != null) { |
| 926 stringifier = new _JsonUtf8StringifierPretty(toEncodableFunction, indent, | 926 stringifier = new _JsonUtf8StringifierPretty(toEncodable, indent, |
| 927 bufferSize, addChunk); | 927 bufferSize, addChunk); |
| 928 } else { | 928 } else { |
| 929 stringifier = new _JsonUtf8Stringifier(toEncodableFunction, | 929 stringifier = new _JsonUtf8Stringifier(toEncodable, bufferSize, addChunk); |
| 930 bufferSize, addChunk); | |
| 931 } | 930 } |
| 932 stringifier.writeObject(object); | 931 stringifier.writeObject(object); |
| 933 stringifier.flush(); | 932 stringifier.flush(); |
| 934 } | 933 } |
| 935 | 934 |
| 936 /** | 935 /** |
| 937 * Must be called at the end to push the last chunk to the [addChunk] | 936 * Must be called at the end to push the last chunk to the [addChunk] |
| 938 * callback. | 937 * callback. |
| 939 */ | 938 */ |
| 940 void flush() { | 939 void flush() { |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1030 buffer[index++] = byte; | 1029 buffer[index++] = byte; |
| 1031 } | 1030 } |
| 1032 } | 1031 } |
| 1033 | 1032 |
| 1034 /** | 1033 /** |
| 1035 * Pretty-printing version of [_JsonUtf8Stringifier]. | 1034 * Pretty-printing version of [_JsonUtf8Stringifier]. |
| 1036 */ | 1035 */ |
| 1037 class _JsonUtf8StringifierPretty extends _JsonUtf8Stringifier | 1036 class _JsonUtf8StringifierPretty extends _JsonUtf8Stringifier |
| 1038 with _JsonPrettyPrintMixin { | 1037 with _JsonPrettyPrintMixin { |
| 1039 final List<int> indent; | 1038 final List<int> indent; |
| 1040 _JsonUtf8StringifierPretty(toEncodableFunction, this.indent, | 1039 _JsonUtf8StringifierPretty( |
| 1041 bufferSize, addChunk) | 1040 dynamic toEncodableFunction(dynamic o), this.indent, |
| 1041 bufferSize, void addChunk(Uint8List buffer, int start, int end)) | |
| 1042 : super(toEncodableFunction, bufferSize, addChunk); | 1042 : super(toEncodableFunction, bufferSize, addChunk); |
| 1043 | 1043 |
| 1044 void writeIndentation(int count) { | 1044 void writeIndentation(int count) { |
| 1045 List<int> indent = this.indent; | 1045 List<int> indent = this.indent; |
| 1046 int indentLength = indent.length; | 1046 int indentLength = indent.length; |
| 1047 if (indentLength == 1) { | 1047 if (indentLength == 1) { |
| 1048 int char = indent[0]; | 1048 int char = indent[0]; |
| 1049 while (count > 0) { | 1049 while (count > 0) { |
| 1050 writeByte(char); | 1050 writeByte(char); |
| 1051 count -= 1; | 1051 count -= 1; |
| 1052 } | 1052 } |
| 1053 return; | 1053 return; |
| 1054 } | 1054 } |
| 1055 while (count > 0) { | 1055 while (count > 0) { |
| 1056 count--; | 1056 count--; |
| 1057 int end = index + indentLength; | 1057 int end = index + indentLength; |
| 1058 if (end <= buffer.length) { | 1058 if (end <= buffer.length) { |
| 1059 buffer.setRange(index, end, indent); | 1059 buffer.setRange(index, end, indent); |
| 1060 index = end; | 1060 index = end; |
| 1061 } else { | 1061 } else { |
| 1062 for (int i = 0; i < indentLength; i++) { | 1062 for (int i = 0; i < indentLength; i++) { |
| 1063 writeByte(indent[i]); | 1063 writeByte(indent[i]); |
| 1064 } | 1064 } |
| 1065 } | 1065 } |
| 1066 } | 1066 } |
| 1067 } | 1067 } |
| 1068 } | 1068 } |
| OLD | NEW |