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 |