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): Figure out how to reasonably separate out the things | 7 // TODO(alanknight): Figure out how to reasonably separate out the things |
8 // that require reflection without making the API more awkward. Or if that is | 8 // that require reflection without making the API more awkward. Or if that is |
9 // in fact necessary. Maybe the tree-shaking will just remove it if unused. | 9 // in fact necessary. Maybe the tree-shaking will just remove it if unused. |
10 | 10 |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
223 * Extract the value of the field [fieldName] from the object reflected | 223 * Extract the value of the field [fieldName] from the object reflected |
224 * by [mirror]. | 224 * by [mirror]. |
225 */ | 225 */ |
226 // TODO(alanknight): The framework should be resilient if there are fields | 226 // TODO(alanknight): The framework should be resilient if there are fields |
227 // it expects that are missing, either for the case of de-serializing to a | 227 // it expects that are missing, either for the case of de-serializing to a |
228 // different definition, or for the case that tree-shaking has removed state. | 228 // different definition, or for the case that tree-shaking has removed state. |
229 // TODO(alanknight): This, and other places, rely on synchronous access to | 229 // TODO(alanknight): This, and other places, rely on synchronous access to |
230 // mirrors. Should be changed to use a synchronous API once one is available, | 230 // mirrors. Should be changed to use a synchronous API once one is available, |
231 // or to be async, but that would be extremely ugly. | 231 // or to be async, but that would be extremely ugly. |
232 _value(InstanceMirror mirror, _Field field) => field.valueIn(mirror); | 232 _value(InstanceMirror mirror, _Field field) => field.valueIn(mirror); |
233 | |
234 /** | |
235 * When reading from a flat format we are given [stream] and need to pull as | |
236 * much data from it as we need. Our format is that we have an integer N | |
237 * indicating the number of objects and then for each object N fields, which | |
238 * are references, where a reference is stored in the stream as two integers. | |
239 * Or, in the special case of null, two nulls. | |
240 */ | |
241 pullStateFrom(Iterator stream) { | |
242 stream.moveNext(); | |
243 var dataLength = stream.current; | |
244 var ruleData = new List(); | |
245 for (var i = 0; i < dataLength; i++) { | |
246 var subList = new List(); | |
247 ruleData.add(subList); | |
248 for (var j = 0; j < fields.length; j++) { | |
249 stream.moveNext(); | |
250 var a = stream.current; | |
251 stream.moveNext(); | |
252 var b = stream.current; | |
253 if (!(a is int)) { | |
254 // This wasn't a reference, so just use the first object as a literal. | |
255 // particularly used for the case of null. | |
256 subList.add(a); | |
257 } else { | |
258 subList.add(new Reference(this, a, b)); | |
259 } | |
260 } | |
261 } | |
262 return ruleData; | |
263 } | |
264 } | 233 } |
265 | 234 |
266 /** | 235 /** |
267 * This represents a field in an object. It is intended to be used as part of | 236 * This represents a field in an object. It is intended to be used as part of |
268 * a [_FieldList]. | 237 * a [_FieldList]. |
269 */ | 238 */ |
270 abstract class _Field implements Comparable { | 239 abstract class _Field implements Comparable { |
271 | 240 |
272 /** The FieldList that contains us. */ | 241 /** The FieldList that contains us. */ |
273 final _FieldList fieldList; | 242 final _FieldList fieldList; |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
356 * it is used in the constructor, or because it's been designated | 325 * it is used in the constructor, or because it's been designated |
357 * using [setFieldWith]. | 326 * using [setFieldWith]. |
358 */ | 327 */ |
359 bool get isEssential => super.isEssential || customSetter != null; | 328 bool get isEssential => super.isEssential || customSetter != null; |
360 | 329 |
361 /** Set the [value] of our field in the given mirrored [object]. */ | 330 /** Set the [value] of our field in the given mirrored [object]. */ |
362 void setValue(InstanceMirror object, value) { | 331 void setValue(InstanceMirror object, value) { |
363 setter(object, value); | 332 setter(object, value); |
364 } | 333 } |
365 | 334 |
366 valueIn(InstanceMirror mirror) { | 335 valueIn(InstanceMirror mirror) => |
367 var futureValue = deprecatedFutureValue(mirror.getField(name)); | 336 deprecatedFutureValue(mirror.getField(name)).reflectee; |
368 return futureValue.reflectee; | |
369 } | |
370 | 337 |
371 /** Return the function to use to set our value. */ | 338 /** Return the function to use to set our value. */ |
372 Function get setter => | 339 Function get setter => |
373 (customSetter != null) ? customSetter : defaultSetter; | 340 (customSetter != null) ? customSetter : defaultSetter; |
374 | 341 |
375 /** Return a default setter function. */ | 342 /** Return a default setter function. */ |
376 void defaultSetter(InstanceMirror object, value) { | 343 void defaultSetter(InstanceMirror object, value) { |
377 object.setField(name, reflect(value)); | 344 object.setField(name, reflect(value)); |
378 } | 345 } |
379 | 346 |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
468 if (fields == null || fields.isEmpty) return; | 435 if (fields == null || fields.isEmpty) return; |
469 if (allFields.length > _constructorFields.length) { | 436 if (allFields.length > _constructorFields.length) { |
470 throw "You can't specify both excludeFields and regular fields"; | 437 throw "You can't specify both excludeFields and regular fields"; |
471 } | 438 } |
472 _excludeFields = fields; | 439 _excludeFields = fields; |
473 } | 440 } |
474 | 441 |
475 int get length => allFields.length; | 442 int get length => allFields.length; |
476 | 443 |
477 /** Add all the fields which aren't on the exclude list. */ | 444 /** Add all the fields which aren't on the exclude list. */ |
478 void addAllNotExplicitlyExcluded(List<String> aCollection) { | 445 void addAllNotExplicitlyExcluded(Iterable<String> aCollection) { |
479 if (aCollection == null) return; | 446 if (aCollection == null) return; |
480 var names = aCollection; | 447 var names = aCollection; |
481 names = names.where((x) => !_excludeFields.contains(x)); | 448 names = names.where((x) => !_excludeFields.contains(x)); |
482 addAllByName(names); | 449 addAllByName(names); |
483 } | 450 } |
484 | 451 |
485 /** Add all the fields with the given names without any special properties. */ | 452 /** Add all the fields with the given names without any special properties. */ |
486 void addAllByName(Iterable<String> names) { | 453 void addAllByName(Iterable<String> names) { |
487 for (var each in names) { | 454 for (var each in names) { |
488 allFields.putIfAbsent(each, () => new _Field(each, this)); | 455 allFields.putIfAbsent(each, () => new _Field(each, this)); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
527 f(each); | 494 f(each); |
528 } | 495 } |
529 } | 496 } |
530 } | 497 } |
531 | 498 |
532 List get constructorFields => _constructorFields; | 499 List get constructorFields => _constructorFields; |
533 List constructorFieldNames() => | 500 List constructorFieldNames() => |
534 constructorFields.mappedBy((x) => x.name).toList(); | 501 constructorFields.mappedBy((x) => x.name).toList(); |
535 List constructorFieldIndices() => | 502 List constructorFieldIndices() => |
536 constructorFields.mappedBy((x) => x.index).toList(); | 503 constructorFields.mappedBy((x) => x.index).toList(); |
537 List regularFields() => | 504 List regularFields() => contents.where((x) => !x.usedInConstructor).toList(); |
538 contents.where((x) => !x.usedInConstructor).toList(); | 505 List regularFieldNames() => regularFields().mappedBy((x) => x.name).toList(); |
539 List regularFieldNames() => | |
540 regularFields().mappedBy((x) => x.name).toList(); | |
541 List regularFieldIndices() => | 506 List regularFieldIndices() => |
542 regularFields().mappedBy((x) => x.index).toList(); | 507 regularFields().mappedBy((x) => x.index).toList(); |
543 | 508 |
544 | |
545 /** | 509 /** |
546 * If we weren't given any non-constructor fields to use, figure out what | 510 * If we weren't given any non-constructor fields to use, figure out what |
547 * we think they ought to be, based on the class definition. | 511 * we think they ought to be, based on the class definition. |
548 * We find public fields, getters that have corresponding setters, and getters | 512 * We find public fields, getters that have corresponding setters, and getters |
549 * that are listed in the constructor fields. | 513 * that are listed in the constructor fields. |
550 */ | 514 */ |
551 void figureOutFields() { | 515 void figureOutFields() { |
552 List names(Collection<DeclarationMirror> mirrors) => | 516 Iterable names(Iterable<DeclarationMirror> mirrors) => |
553 mirrors.mappedBy((each) => each.simpleName).toList(); | 517 mirrors.mappedBy((each) => each.simpleName); |
554 | 518 |
555 if (!_shouldFigureOutFields || !regularFields().isEmpty) return; | 519 if (!_shouldFigureOutFields || !regularFields().isEmpty) return; |
556 var fields = publicFields(mirror); | 520 var fields = publicFields(mirror); |
557 var getters = publicGetters(mirror); | 521 var getters = publicGetters(mirror); |
558 var gettersWithSetters = getters.where( (each) | 522 var gettersWithSetters = getters.where( (each) |
559 => mirror.setters["${each.simpleName}="] != null).toList(); | 523 => mirror.setters["${each.simpleName}="] != null); |
560 var gettersThatMatchConstructor = getters.where((each) | 524 var gettersThatMatchConstructor = getters.where((each) |
561 => (named(each.simpleName) != null) && | 525 => (named(each.simpleName) != null) && |
562 (named(each.simpleName).usedInConstructor)).toList(); | 526 (named(each.simpleName).usedInConstructor)).toList(); |
563 addAllNotExplicitlyExcluded(names(fields)); | 527 addAllNotExplicitlyExcluded(names(fields)); |
564 addAllNotExplicitlyExcluded(names(gettersWithSetters)); | 528 addAllNotExplicitlyExcluded(names(gettersWithSetters)); |
565 addAllNotExplicitlyExcluded(names(gettersThatMatchConstructor)); | 529 addAllNotExplicitlyExcluded(names(gettersThatMatchConstructor)); |
566 } | 530 } |
567 } | 531 } |
568 | 532 |
569 /** | 533 /** |
(...skipping 30 matching lines...) Expand all Loading... |
600 } | 564 } |
601 | 565 |
602 /** | 566 /** |
603 * Find the field values in [state] and pass them to the constructor. | 567 * Find the field values in [state] and pass them to the constructor. |
604 * If any of [fieldNumbers] is not an int, then use it as a literal value. | 568 * If any of [fieldNumbers] is not an int, then use it as a literal value. |
605 */ | 569 */ |
606 constructFrom(state, Reader r) { | 570 constructFrom(state, Reader r) { |
607 // TODO(alanknight): Handle named parameters | 571 // TODO(alanknight): Handle named parameters |
608 Collection inflated = fieldNumbers.mappedBy( | 572 Collection inflated = fieldNumbers.mappedBy( |
609 (x) => (x is int) ? reflect(r.inflateReference(state[x])) : reflect(x)) | 573 (x) => (x is int) ? reflect(r.inflateReference(state[x])) : reflect(x)) |
610 .toList(); | 574 .toList(); |
611 var result = type.newInstance(name, inflated); | 575 var result = type.newInstance(name, inflated); |
612 return deprecatedFutureValue(result); | 576 return deprecatedFutureValue(result); |
613 } | 577 } |
614 } | 578 } |
615 | 579 |
616 /** | 580 /** |
617 * This wraps a map to make it indexable by integer field numbers. It translates | 581 * This wraps a map to make it indexable by integer field numbers. It translates |
618 * from the index into a field name and then looks it up in the map. | 582 * from the index into a field name and then looks it up in the map. |
619 */ | 583 */ |
620 class _MapWrapper { | 584 class _MapWrapper { |
621 Map<String, dynamic> _map = new Map<String, dynamic>(); | 585 Map<String, dynamic> _map = new Map<String, dynamic>(); |
622 List fieldList; | 586 List fieldList; |
623 _MapWrapper(this.fieldList); | 587 _MapWrapper(this.fieldList); |
624 _MapWrapper.fromMap(this._map, this.fieldList); | 588 _MapWrapper.fromMap(this._map, this.fieldList); |
625 | 589 |
626 operator [](key) => _map[fieldList[key].name]; | 590 operator [](key) => _map[fieldList[key].name]; |
627 operator []=(key, value) { _map[fieldList[key].name] = value; } | 591 operator []=(key, value) { _map[fieldList[key].name] = value; } |
628 get length => _map.length; | 592 get length => _map.length; |
629 | 593 |
630 asMap() => _map; | 594 asMap() => _map; |
631 } | 595 } |
OLD | NEW |