Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(229)

Side by Side Diff: pkg/serialization/lib/src/basic_rule.dart

Issue 11931030: Add a MapRule (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Changes from review comments Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/serialization/lib/serialization.dart ('k') | pkg/serialization/lib/src/format.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « pkg/serialization/lib/serialization.dart ('k') | pkg/serialization/lib/src/format.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698