| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 serialization; | 5 part of serialization; |
| 6 | 6 |
| 7 // TODO(alanknight): We should have an example and tests for subclassing | 7 // TODO(alanknight): We should have an example and tests for subclassing |
| 8 // serialization rule rather than using the hard-coded ClosureToMap rule. And | 8 // serialization rule rather than using the hard-coded ClosureToMap rule. And |
| 9 // possibly an abstract superclass that's designed to be subclassed that way. | 9 // possibly an abstract superclass that's designed to be subclassed that way. |
| 10 /** | 10 /** |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 * the flat format. Return false if the results are fixed length. | 143 * the flat format. Return false if the results are fixed length. |
| 144 */ | 144 */ |
| 145 // TODO(alanknight): This should probably go away with more general formats. | 145 // TODO(alanknight): This should probably go away with more general formats. |
| 146 bool get writeLengthInFlatFormat => false; | 146 bool get writeLengthInFlatFormat => false; |
| 147 | 147 |
| 148 /** | 148 /** |
| 149 * The inverse of dumpStateInto, this reads the rule's state from an | 149 * The inverse of dumpStateInto, this reads the rule's state from an |
| 150 * iterator in a flat format. | 150 * iterator in a flat format. |
| 151 */ | 151 */ |
| 152 pullStateFrom(Iterator stream) { | 152 pullStateFrom(Iterator stream) { |
| 153 var numberOfEntries = stream.next(); | 153 stream.moveNext(); |
| 154 var numberOfEntries = stream.current; |
| 154 var ruleData = new List(); | 155 var ruleData = new List(); |
| 155 for (var i = 0; i < numberOfEntries; i++) { | 156 for (var i = 0; i < numberOfEntries; i++) { |
| 156 var subLength = dataLengthIn(stream); | 157 var subLength = dataLengthIn(stream); |
| 157 var subList = []; | 158 var subList = []; |
| 158 ruleData.add(subList); | 159 ruleData.add(subList); |
| 159 for (var j = 0; j < subLength; j++) { | 160 for (var j = 0; j < subLength; j++) { |
| 160 var a = stream.next(); | 161 stream.moveNext(); |
| 161 var b = stream.next(); | 162 var a = stream.current; |
| 162 if (!(a is int)) { | 163 stream.moveNext(); |
| 164 var b = stream.current; |
| 165 if (a is! int) { |
| 163 // This wasn't a reference, just use the first object as a literal. | 166 // This wasn't a reference, just use the first object as a literal. |
| 164 // particularly used for the case of null. | 167 // particularly used for the case of null. |
| 165 subList.add(a); | 168 subList.add(a); |
| 166 } else { | 169 } else { |
| 167 subList.add(new Reference(this, a, b)); | 170 subList.add(new Reference(this, a, b)); |
| 168 } | 171 } |
| 169 } | 172 } |
| 170 } | 173 } |
| 171 return ruleData; | 174 return ruleData; |
| 172 } | 175 } |
| 173 | 176 |
| 174 /** | 177 /** |
| 175 * Return the length of the list of data we expect to see on a particular | 178 * Return the length of the list of data we expect to see on a particular |
| 176 * iterator in a flat format. This may have been encoded in the stream if we | 179 * iterator in a flat format. This may have been encoded in the stream if we |
| 177 * are variable length, or it may be constant. Note that this is expressed in | 180 * are variable length, or it may be constant. Returns null if the [Iterator] |
| 178 * | 181 * is empty. |
| 179 */ | 182 */ |
| 180 dataLengthIn(Iterator stream) => | 183 dataLengthIn(Iterator stream) => |
| 181 writeLengthInFlatFormat ? stream.next() : dataLength; | 184 writeLengthInFlatFormat ? (stream..moveNext()).current : dataLength; |
| 182 | 185 |
| 183 /** | 186 /** |
| 184 * If the data is fixed length, return it here. Unused in the non-flat | 187 * If the data is fixed length, return it here. Unused in the non-flat |
| 185 * format, or if the data is variable length. | 188 * format, or if the data is variable length. |
| 186 */ | 189 */ |
| 187 int get dataLength => 0; | 190 int get dataLength => 0; |
| 188 } | 191 } |
| 189 | 192 |
| 190 /** | 193 /** |
| 191 * This rule handles things that implement List. It will recreate them as | 194 * This rule handles things that implement List. It will recreate them as |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 224 * When reading from a flat format we are given [stream] and need to pull as | 227 * When reading from a flat format we are given [stream] and need to pull as |
| 225 * much data from it as we need. Our format is that we have an integer N | 228 * much data from it as we need. Our format is that we have an integer N |
| 226 * indicating the number of objects and then for each object a length M, | 229 * indicating the number of objects and then for each object a length M, |
| 227 * and then M references, where a reference is stored in the stream as two | 230 * and then M references, where a reference is stored in the stream as two |
| 228 * integers. Or, in the special case of null, two nulls. | 231 * integers. Or, in the special case of null, two nulls. |
| 229 */ | 232 */ |
| 230 pullStateFrom(Iterator stream) { | 233 pullStateFrom(Iterator stream) { |
| 231 // TODO(alanknight): This is much too close to the basicRule implementation, | 234 // TODO(alanknight): This is much too close to the basicRule implementation, |
| 232 // and I'd refactor them if I didn't think this whole mechanism needed to | 235 // and I'd refactor them if I didn't think this whole mechanism needed to |
| 233 // change soon. | 236 // change soon. |
| 234 var length = stream.next(); | 237 stream.moveNext(); |
| 238 var length = stream.current; |
| 235 var ruleData = new List(); | 239 var ruleData = new List(); |
| 236 for (var i = 0; i < length; i++) { | 240 for (var i = 0; i < length; i++) { |
| 237 var subLength = stream.next(); | 241 stream.moveNext(); |
| 242 var subLength = stream.current; |
| 238 var subList = new List(); | 243 var subList = new List(); |
| 239 ruleData.add(subList); | 244 ruleData.add(subList); |
| 240 for (var j = 0; j < subLength; j++) { | 245 for (var j = 0; j < subLength; j++) { |
| 241 var a = stream.next(); | 246 stream.moveNext(); |
| 242 var b = stream.next(); | 247 var a = stream.current; |
| 248 stream.moveNext(); |
| 249 var b = stream.current; |
| 243 if (!(a is int)) { | 250 if (!(a is int)) { |
| 244 // This wasn't a reference, just use the first object as a literal. | 251 // This wasn't a reference, just use the first object as a literal. |
| 245 // particularly used for the case of null. | 252 // particularly used for the case of null. |
| 246 subList.add(a); | 253 subList.add(a); |
| 247 } else { | 254 } else { |
| 248 subList.add(new Reference(this, a, b)); | 255 subList.add(new Reference(this, a, b)); |
| 249 } | 256 } |
| 250 } | 257 } |
| 251 } | 258 } |
| 252 return ruleData; | 259 return ruleData; |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 313 void dumpStateInto(List ruleData, List target) { | 320 void dumpStateInto(List ruleData, List target) { |
| 314 target.addAll(ruleData); | 321 target.addAll(ruleData); |
| 315 } | 322 } |
| 316 | 323 |
| 317 /** | 324 /** |
| 318 * When reading from a flat format we are given [stream] and need to pull as | 325 * When reading from a flat format we are given [stream] and need to pull as |
| 319 * much data from it as we need. Our format is that we have an integer N | 326 * much data from it as we need. Our format is that we have an integer N |
| 320 * indicating the number of objects and then N simple objects. | 327 * indicating the number of objects and then N simple objects. |
| 321 */ | 328 */ |
| 322 pullStateFrom(Iterator stream) { | 329 pullStateFrom(Iterator stream) { |
| 323 var length = stream.next(); | 330 stream.moveNext(); |
| 331 var length = stream.current; |
| 324 var ruleData = new List(); | 332 var ruleData = new List(); |
| 325 for (var i = 0; i < length; i++) { | 333 for (var i = 0; i < length; i++) { |
| 326 ruleData.add(stream.next()); | 334 stream.moveNext(); |
| 335 ruleData.add(stream.current); |
| 327 } | 336 } |
| 328 return ruleData; | 337 return ruleData; |
| 329 } | 338 } |
| 330 } | 339 } |
| 331 | 340 |
| 332 /** Typedef for the object construction closure used in ClosureRule. */ | 341 /** Typedef for the object construction closure used in ClosureRule. */ |
| 333 typedef ConstructType(Map m); | 342 typedef ConstructType(Map m); |
| 334 | 343 |
| 335 /** Typedef for the state-getting closure used in ClosureToMapRule. */ | 344 /** Typedef for the state-getting closure used in ClosureToMapRule. */ |
| 336 typedef Map<String, dynamic> GetStateType(object); | 345 typedef Map<String, dynamic> GetStateType(object); |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 480 setState(object, _lazy(state, r)); | 489 setState(object, _lazy(state, r)); |
| 481 | 490 |
| 482 // We don't want to have to make the end user tell us how long the list is | 491 // We don't want to have to make the end user tell us how long the list is |
| 483 // separately, so write it out for each object, even though they're all | 492 // separately, so write it out for each object, even though they're all |
| 484 // expected to be the same length. | 493 // expected to be the same length. |
| 485 get writeLengthInFlatFormat => true; | 494 get writeLengthInFlatFormat => true; |
| 486 } | 495 } |
| 487 | 496 |
| 488 /** Create a lazy list/map that will inflate its items on demand in [r]. */ | 497 /** Create a lazy list/map that will inflate its items on demand in [r]. */ |
| 489 _lazy(l, Reader r) { | 498 _lazy(l, Reader r) { |
| 490 if (l is List) return new _LazyList(l, r); | 499 if (l is List) return l.mappedBy(r.inflateReference); |
| 491 if (l is Map) return new _LazyMap(l, r); | 500 if (l is Map) return new _LazyMap(l, r); |
| 492 throw new SerializationException("Invalid type: must be Map or List - $l"); | 501 throw new SerializationException("Invalid type: must be Map or List - $l"); |
| 493 } | 502 } |
| 494 | 503 |
| 495 /** | 504 /** |
| 496 * This provides an implementation of Map that wraps a list which may | 505 * This provides an implementation of Map that wraps a list which may |
| 497 * contain references to (potentially) non-inflated objects. If these | 506 * contain references to (potentially) non-inflated objects. If these |
| 498 * are accessed it will inflate them. This allows us to pass something that | 507 * are accessed it will inflate them. This allows us to pass something that |
| 499 * looks like it's just a list of objects to a [CustomRule] without needing | 508 * looks like it's just a list of objects to a [CustomRule] without needing |
| 500 * to inflate all the references in advance. | 509 * to inflate all the references in advance. |
| 501 */ | 510 */ |
| 502 class _LazyMap implements Map { | 511 class _LazyMap implements Map { |
| 503 _LazyMap(this._raw, this._reader); | 512 _LazyMap(this._raw, this._reader); |
| 504 | 513 |
| 505 Map _raw; | 514 Map _raw; |
| 506 Reader _reader; | 515 Reader _reader; |
| 507 | 516 |
| 508 // This is the only operation that really matters. | 517 // This is the only operation that really matters. |
| 509 operator [](x) => _reader.inflateReference(_raw[x]); | 518 operator [](x) => _reader.inflateReference(_raw[x]); |
| 510 | 519 |
| 511 int get length => _raw.length; | 520 int get length => _raw.length; |
| 512 bool get isEmpty => _raw.isEmpty; | 521 bool get isEmpty => _raw.isEmpty; |
| 513 List get keys => _raw.keys; | 522 Iterable get keys => _raw.keys; |
| 514 bool containsKey(x) => _raw.containsKey(x); | 523 bool containsKey(x) => _raw.containsKey(x); |
| 515 | 524 |
| 516 // These operations will work, but may be expensive, and are probably | 525 // These operations will work, but may be expensive, and are probably |
| 517 // best avoided. | 526 // best avoided. |
| 518 get _inflated => keysAndValues(_raw).map(_reader.inflateReference); | 527 get _inflated => keysAndValues(_raw).map(_reader.inflateReference); |
| 519 bool containsValue(x) => _inflated.containsValue(x); | 528 bool containsValue(x) => _inflated.containsValue(x); |
| 520 List get values => _inflated.values; | 529 Iterable get values => _inflated.values; |
| 521 void forEach(f) => _inflated.forEach(f); | 530 void forEach(f) => _inflated.forEach(f); |
| 522 | 531 |
| 523 // These operations are all invalid | 532 // These operations are all invalid |
| 524 _throw() => throw new UnsupportedError("Not modifiable"); | 533 _throw() => throw new UnsupportedError("Not modifiable"); |
| 525 operator []=(x, y) => _throw(); | 534 operator []=(x, y) => _throw(); |
| 526 putIfAbsent(x, y) => _throw(); | 535 putIfAbsent(x, y) => _throw(); |
| 527 remove(x) => _throw(); | 536 remove(x) => _throw(); |
| 528 clear() => _throw(); | 537 clear() => _throw(); |
| 529 } | 538 } |
| 530 | |
| 531 /** | |
| 532 * This provides an implementation of List that wraps a list which may | |
| 533 * contain references to (potentially) non-inflated objects. If these | |
| 534 * are accessed it will inflate them. This allows us to pass something that | |
| 535 * looks like it's just a list of objects to a [CustomRule] without needing | |
| 536 * to inflate all the references in advance. | |
| 537 */ | |
| 538 class _LazyList implements List { | |
| 539 _LazyList(this._raw, this._reader); | |
| 540 | |
| 541 List _raw; | |
| 542 Reader _reader; | |
| 543 | |
| 544 // This is the only operation that really matters. | |
| 545 operator [](x) => _reader.inflateReference(_raw[x]); | |
| 546 | |
| 547 int get length => _raw.length; | |
| 548 bool get isEmpty => _raw.isEmpty; | |
| 549 get first => _reader.inflateReference(_raw.first); | |
| 550 get last => _reader.inflateReference(_raw.last); | |
| 551 | |
| 552 // These operations will work, but may be expensive, and are probably | |
| 553 // best avoided. | |
| 554 get _inflated => _raw.map(_reader.inflateReference); | |
| 555 map(f) => _inflated.map(f); | |
| 556 filter(f) => _inflated.filter(f); | |
| 557 bool contains(element) => _inflated.filter(element); | |
| 558 forEach(f) => _inflated.forEach(f); | |
| 559 reduce(x, f) => _inflated.reduce(x, f); | |
| 560 every(f) => _inflated(f); | |
| 561 some(f) => _inflated(f); | |
| 562 iterator() => _inflated.iterator(); | |
| 563 indexOf(x, [pos = 0]) => _inflated.indexOf(x); | |
| 564 lastIndexOf(x, [pos]) => _inflated.lastIndexOf(x); | |
| 565 | |
| 566 // These operations are all invalid | |
| 567 _throw() => throw new UnsupportedError("Not modifiable"); | |
| 568 operator []=(x, y) => _throw(); | |
| 569 add(x) => _throw(); | |
| 570 addLast(x) => _throw(); | |
| 571 addAll(x) => _throw(); | |
| 572 sort([f]) => _throw(); | |
| 573 clear() => _throw(); | |
| 574 removeAt(x) => _throw(); | |
| 575 removeLast() => _throw(); | |
| 576 getRange(x, y) => _throw(); | |
| 577 setRange(x, y, z, [a]) => _throw(); | |
| 578 removeRange(x, y) => _throw(); | |
| 579 insertRange(x, y, [z]) => _throw(); | |
| 580 void set length(x) => _throw(); | |
| 581 } | |
| OLD | NEW |