| 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 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 130 useMaps = false; | 130 useMaps = false; |
| 131 } | 131 } |
| 132 | 132 |
| 133 /** Create either a list or a map to hold the object's state, depending | 133 /** Create either a list or a map to hold the object's state, depending |
| 134 * on the [useMaps] variable. If using a Map, we wrap it in order to keep | 134 * on the [useMaps] variable. If using a Map, we wrap it in order to keep |
| 135 * the protocol compatible. See [configureForLists]/[configureForMaps]. | 135 * the protocol compatible. See [configureForLists]/[configureForMaps]. |
| 136 */ | 136 */ |
| 137 createStateHolder() => | 137 createStateHolder() => |
| 138 useMaps ? new _MapWrapper(fields.contents) : new List(fields.length); | 138 useMaps ? new _MapWrapper(fields.contents) : new List(fields.length); |
| 139 | 139 |
| 140 /** Wrap the state if it's passed in as a map. */ | 140 /** |
| 141 makeIndexableByNumber(state) => | 141 * Wrap the state if it's passed in as a map, and if the keys are references, |
| 142 (state is Map) ? new _MapWrapper.fromMap(state, fields.contents) : state; | 142 * resolve them to the strings we expect. We leave the previous keys in there |
| 143 * as well, as they shouldn't be harmful, and it costs more to remove them. |
| 144 */ |
| 145 makeIndexableByNumber(state) { |
| 146 if (!(state is Map)) return state; |
| 147 // TODO(alanknight): This is quite inefficient, and we do it twice per |
| 148 // instance. If the keys are references, we need to turn them into strings |
| 149 // before we can look at indexing them by field position. It's also eager, |
| 150 // but we know our keys are always primitives, so we don't have to worry |
| 151 // about their instances not having been created yet. |
| 152 for (var each in state.keys) { |
| 153 if (each is Reference) { |
| 154 var inflated = each.inflated(); |
| 155 state[inflated] = state[each]; |
| 156 } |
| 157 } |
| 158 return new _MapWrapper.fromMap(state, fields.contents); |
| 159 } |
| 143 | 160 |
| 144 /** | 161 /** |
| 145 * Extract the state from [object] using an instanceMirror and the field | 162 * Extract the state from [object] using an instanceMirror and the field |
| 146 * names in [fields]. Call the function [callback] on each value. | 163 * names in [fields]. Call the function [callback] on each value. |
| 147 */ | 164 */ |
| 148 extractState(object, Function callback) { | 165 extractState(object, Function callback) { |
| 149 var result = createStateHolder(); | 166 var result = createStateHolder(); |
| 150 var mirror = reflect(object); | 167 var mirror = reflect(object); |
| 151 | 168 |
| 152 keysAndValues(fields).forEach( | 169 keysAndValues(fields).forEach( |
| 153 (index, field) { | 170 (index, field) { |
| 154 var value = _value(mirror, field); | 171 var value = _value(mirror, field); |
| 172 callback(field.name); |
| 155 callback(checkForEssentialLists(index, value)); | 173 callback(checkForEssentialLists(index, value)); |
| 156 result[index] = value; | 174 result[index] = value; |
| 157 }); | 175 }); |
| 158 return _unwrap(result); | 176 return _unwrap(result); |
| 159 } | 177 } |
| 160 | 178 |
| 179 flatten(state, Writer writer) { |
| 180 if (state is List) { |
| 181 keysAndValues(state).forEach((index, value) { |
| 182 state[index] = writer._referenceFor(value); |
| 183 }); |
| 184 } else { |
| 185 var newState = new Map(); |
| 186 keysAndValues(state).forEach((key, value) { |
| 187 newState[writer._referenceFor(key)] = writer._referenceFor(value); |
| 188 }); |
| 189 return newState; |
| 190 } |
| 191 } |
| 192 |
| 161 /** | 193 /** |
| 162 * If the value is a List, and the field is a constructor field or | 194 * If the value is a List, and the field is a constructor field or |
| 163 * otherwise specially designated, we wrap it in something that indicates | 195 * otherwise specially designated, we wrap it in something that indicates |
| 164 * a restriction on the rules that can be used. Which in this case amounts | 196 * a restriction on the rules that can be used. Which in this case amounts |
| 165 * to designating the rule, since we so far only have one rule per object. | 197 * to designating the rule, since we so far only have one rule per object. |
| 166 */ | 198 */ |
| 167 checkForEssentialLists(index, value) { | 199 checkForEssentialLists(index, value) { |
| 168 if (value is List && fields.contents[index].isEssential) { | 200 if (value is List && fields.contents[index].isEssential) { |
| 169 return new DesignatedRuleForObject(value, | 201 return new DesignatedRuleForObject(value, |
| 170 (SerializationRule rule) => rule is ListRuleEssential); | 202 (SerializationRule rule) => rule is ListRuleEssential); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 212 void _findFields(List constructorFields, List regularFields, | 244 void _findFields(List constructorFields, List regularFields, |
| 213 List excludeFields) { | 245 List excludeFields) { |
| 214 fields = new _FieldList(type); | 246 fields = new _FieldList(type); |
| 215 fields.constructorFields = constructorFields; | 247 fields.constructorFields = constructorFields; |
| 216 fields.regular = regularFields; | 248 fields.regular = regularFields; |
| 217 // TODO(alanknight): The order of this matters. It shouldn't. | 249 // TODO(alanknight): The order of this matters. It shouldn't. |
| 218 fields.exclude = excludeFields; | 250 fields.exclude = excludeFields; |
| 219 fields.figureOutFields(); | 251 fields.figureOutFields(); |
| 220 } | 252 } |
| 221 | 253 |
| 254 bool get hasVariableLengthEntries => false; |
| 255 |
| 256 int get dataLength => fields.length; |
| 257 |
| 222 /** | 258 /** |
| 223 * Extract the value of the field [fieldName] from the object reflected | 259 * Extract the value of [field] from the object reflected |
| 224 * by [mirror]. | 260 * by [mirror]. |
| 225 */ | 261 */ |
| 226 // TODO(alanknight): The framework should be resilient if there are fields | 262 // 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 | 263 // 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. | 264 // different definition, or for the case that tree-shaking has removed state. |
| 229 // TODO(alanknight): This, and other places, rely on synchronous access to | 265 // 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, | 266 // mirrors. Should be changed to use a synchronous API once one is available, |
| 231 // or to be async, but that would be extremely ugly. | 267 // or to be async, but that would be extremely ugly. |
| 232 _value(InstanceMirror mirror, _Field field) => field.valueIn(mirror); | 268 _value(InstanceMirror mirror, _Field field) => field.valueIn(mirror); |
| 233 } | 269 } |
| (...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 507 regularFields().mappedBy((x) => x.index).toList(); | 543 regularFields().mappedBy((x) => x.index).toList(); |
| 508 | 544 |
| 509 /** | 545 /** |
| 510 * If we weren't given any non-constructor fields to use, figure out what | 546 * If we weren't given any non-constructor fields to use, figure out what |
| 511 * we think they ought to be, based on the class definition. | 547 * we think they ought to be, based on the class definition. |
| 512 * We find public fields, getters that have corresponding setters, and getters | 548 * We find public fields, getters that have corresponding setters, and getters |
| 513 * that are listed in the constructor fields. | 549 * that are listed in the constructor fields. |
| 514 */ | 550 */ |
| 515 void figureOutFields() { | 551 void figureOutFields() { |
| 516 Iterable names(Iterable<DeclarationMirror> mirrors) => | 552 Iterable names(Iterable<DeclarationMirror> mirrors) => |
| 517 mirrors.mappedBy((each) => each.simpleName); | 553 mirrors.mappedBy((each) => each.simpleName).toList(); |
| 518 | 554 |
| 519 if (!_shouldFigureOutFields || !regularFields().isEmpty) return; | 555 if (!_shouldFigureOutFields || !regularFields().isEmpty) return; |
| 520 var fields = publicFields(mirror); | 556 var fields = publicFields(mirror); |
| 521 var getters = publicGetters(mirror); | 557 var getters = publicGetters(mirror); |
| 522 var gettersWithSetters = getters.where( (each) | 558 var gettersWithSetters = getters.where( (each) |
| 523 => mirror.setters["${each.simpleName}="] != null); | 559 => mirror.setters["${each.simpleName}="] != null); |
| 524 var gettersThatMatchConstructor = getters.where((each) | 560 var gettersThatMatchConstructor = getters.where((each) |
| 525 => (named(each.simpleName) != null) && | 561 => (named(each.simpleName) != null) && |
| 526 (named(each.simpleName).usedInConstructor)).toList(); | 562 (named(each.simpleName).usedInConstructor)).toList(); |
| 527 addAllNotExplicitlyExcluded(names(fields)); | 563 addAllNotExplicitlyExcluded(names(fields)); |
| 528 addAllNotExplicitlyExcluded(names(gettersWithSetters)); | 564 addAllNotExplicitlyExcluded(names(gettersWithSetters)); |
| 529 addAllNotExplicitlyExcluded(names(gettersThatMatchConstructor)); | 565 addAllNotExplicitlyExcluded(names(gettersThatMatchConstructor)); |
| 530 } | 566 } |
| 567 |
| 568 toString() => "FieldList($contents)"; |
| 531 } | 569 } |
| 532 | 570 |
| 533 /** | 571 /** |
| 534 * Provide a typedef for the setWith argument to setFieldWith. It would | 572 * Provide a typedef for the setWith argument to setFieldWith. It would |
| 535 * be nice if we could put this closer to the definition. | 573 * be nice if we could put this closer to the definition. |
| 536 */ | 574 */ |
| 537 typedef SetWithFunction(InstanceMirror m, object); | 575 typedef SetWithFunction(InstanceMirror m, object); |
| 538 | 576 |
| 539 /** | 577 /** |
| 540 * This represents a constructor that is to be used when re-creating a | 578 * This represents a constructor that is to be used when re-creating a |
| (...skipping 22 matching lines...) Expand all Loading... |
| 563 if (fieldNumbers == null) fieldNumbers = const []; | 601 if (fieldNumbers == null) fieldNumbers = const []; |
| 564 } | 602 } |
| 565 | 603 |
| 566 /** | 604 /** |
| 567 * Find the field values in [state] and pass them to the constructor. | 605 * Find the field values in [state] and pass them to the constructor. |
| 568 * If any of [fieldNumbers] is not an int, then use it as a literal value. | 606 * If any of [fieldNumbers] is not an int, then use it as a literal value. |
| 569 */ | 607 */ |
| 570 constructFrom(state, Reader r) { | 608 constructFrom(state, Reader r) { |
| 571 // TODO(alanknight): Handle named parameters | 609 // TODO(alanknight): Handle named parameters |
| 572 Collection inflated = fieldNumbers.mappedBy( | 610 Collection inflated = fieldNumbers.mappedBy( |
| 573 (x) => (x is int) ? reflect(r.inflateReference(state[x])) : reflect(x)) | 611 (x) => (x is int) ? reflect(r.inflateReference(state[x])) : reflect(x)); |
| 574 .toList(); | 612 var result = type.newInstance(name, inflated.toList()); |
| 575 var result = type.newInstance(name, inflated); | |
| 576 return deprecatedFutureValue(result); | 613 return deprecatedFutureValue(result); |
| 577 } | 614 } |
| 578 } | 615 } |
| 579 | 616 |
| 580 /** | 617 /** |
| 581 * This wraps a map to make it indexable by integer field numbers. It translates | 618 * This wraps a map to make it indexable by integer field numbers. It translates |
| 582 * from the index into a field name and then looks it up in the map. | 619 * from the index into a field name and then looks it up in the map. |
| 583 */ | 620 */ |
| 584 class _MapWrapper { | 621 class _MapWrapper { |
| 585 Map<String, dynamic> _map = new Map<String, dynamic>(); | 622 final _map; |
| 586 List fieldList; | 623 List fieldList; |
| 587 _MapWrapper(this.fieldList); | 624 _MapWrapper(this.fieldList) : _map = new Map(); |
| 588 _MapWrapper.fromMap(this._map, this.fieldList); | 625 _MapWrapper.fromMap(this._map, this.fieldList); |
| 589 | 626 |
| 590 operator [](key) => _map[fieldList[key].name]; | 627 operator [](key) => _map[fieldList[key].name]; |
| 628 |
| 591 operator []=(key, value) { _map[fieldList[key].name] = value; } | 629 operator []=(key, value) { _map[fieldList[key].name] = value; } |
| 592 get length => _map.length; | 630 get length => _map.length; |
| 593 | 631 |
| 594 asMap() => _map; | 632 asMap() => _map; |
| 595 } | 633 } |
| OLD | NEW |