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

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

Issue 11644030: Rename specialTreatmentFor, improve handling of constants as constructor parameters. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years 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
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 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
79 * 79 *
80 * This method lets you designate a function to use to set the value of a 80 * This method lets you designate a function to use to set the value of a
81 * field. It also makes the contents of that field be treated as essential, 81 * field. It also makes the contents of that field be treated as essential,
82 * which currently only has meaning if the field is a list. This is done 82 * which currently only has meaning if the field is a list. This is done
83 * because you might set a list field's special treatment function to add 83 * because you might set a list field's special treatment function to add
84 * each item individually and that will only work if those objects already 84 * each item individually and that will only work if those objects already
85 * exist. 85 * exist.
86 * 86 *
87 * For example, to serialize a Serialization, we need its rules to be 87 * For example, to serialize a Serialization, we need its rules to be
88 * individually added rather than just setting the rules field. 88 * individually added rather than just setting the rules field.
89 * ..addRuleFor(new Serialization()).specialTreatmentFor('rules', 89 * ..addRuleFor(new Serialization()).setFieldWith('rules',
90 * (InstanceMirror s, List rules) { 90 * (InstanceMirror s, List rules) {
91 * rules.forEach((x) => s.reflectee.addRule(x)); 91 * rules.forEach((x) => s.reflectee.addRule(x));
92 * Note that the function is passed the owning object as well as the field 92 * Note that the function is passed the owning object as well as the field
93 * value, but that it is passed as a mirror. 93 * value, but that it is passed as a mirror.
94 */ 94 */
95 specialTreatmentFor(String fieldName, SetWithFunction setWith) { 95 setFieldWith(String fieldName, SetWithFunction setWith) {
96 fields.addAllByName([fieldName]); 96 fields.addAllByName([fieldName]);
97 _Field field = fields.named(fieldName); 97 _NamedField field = fields.named(fieldName);
98 Function setter = (setWith == null) ? field.defaultSetter : setWith; 98 Function setter = (setWith == null) ? field.defaultSetter : setWith;
99 field.specialTreatment = setter; 99 field.customSetter = setter;
100 } 100 }
101 101
102 /** Return the name of the constructor used to create new instances on read.*/ 102 /** Return the name of the constructor used to create new instances on read.*/
103 String get constructorName => constructor.name; 103 String get constructorName => constructor.name;
104 104
105 /** Return the list of field names to be passed to the constructor.*/ 105 /** Return the list of field names to be passed to the constructor.*/
106 List<String> get constructorFields => fields.constructorFieldNames(); 106 List<String> get constructorFields => fields.constructorFieldNames();
107 107
108 /** Return the list of field names not used in the constructor. */ 108 /** Return the list of field names not used in the constructor. */
109 List<String> get regularFields => fields.regularFieldNames(); 109 List<String> get regularFields => fields.regularFieldNames();
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 fields.regular = regularFields; 216 fields.regular = regularFields;
217 // TODO(alanknight): The order of this matters. It shouldn't. 217 // TODO(alanknight): The order of this matters. It shouldn't.
218 fields.exclude = excludeFields; 218 fields.exclude = excludeFields;
219 fields.figureOutFields(); 219 fields.figureOutFields();
220 } 220 }
221 221
222 /** 222 /**
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 "is String" mechanism here should be more tightly 226 // TODO (alanknight): The "is String" mechanism here should be more tightly
Jennifer Messerly 2012/12/19 23:14:08 move/remove this todo?
Alan Knight 2012/12/21 18:30:01 Done.
227 // controlled to work on just constructor fields. 227 // controlled to work on just constructor fields.
228 // TODO(alanknight): The framework should be resilient if there are fields 228 // TODO(alanknight): The framework should be resilient if there are fields
229 // it expects that are missing, either for the case of de-serializing to a 229 // it expects that are missing, either for the case of de-serializing to a
230 // different definition, or for the case that tree-shaking has removed state. 230 // different definition, or for the case that tree-shaking has removed state.
231 // TODO(alanknight): This, and other places, rely on synchronous access to 231 // TODO(alanknight): This, and other places, rely on synchronous access to
232 // mirrors. Should be changed to use a synchronous API once one is available, 232 // mirrors. Should be changed to use a synchronous API once one is available,
233 // or to be async, but that would be extremely ugly. 233 // or to be async, but that would be extremely ugly.
234 _value(InstanceMirror mirror, _Field field) { 234 _value(InstanceMirror mirror, _Field field) => field.valueIn(mirror);
235 if (field.name is String) {
236 return mirror.getField(field.name).value.reflectee;
237 } else {
238 return field.name;
239 }
240 }
241 235
242 /** 236 /**
243 * When reading from a flat format we are given [stream] and need to pull as 237 * When reading from a flat format we are given [stream] and need to pull as
244 * much data from it as we need. Our format is that we have an integer N 238 * much data from it as we need. Our format is that we have an integer N
245 * indicating the number of objects and then for each object N fields, which 239 * indicating the number of objects and then for each object N fields, which
246 * are references, where a reference is stored in the stream as two integers. 240 * are references, where a reference is stored in the stream as two integers.
247 * Or, in the special case of null, two nulls. 241 * Or, in the special case of null, two nulls.
248 */ 242 */
249 pullStateFrom(Iterator stream) { 243 pullStateFrom(Iterator stream) {
250 var dataLength = stream.next(); 244 var dataLength = stream.next();
(...skipping 14 matching lines...) Expand all
265 } 259 }
266 } 260 }
267 return ruleData; 261 return ruleData;
268 } 262 }
269 } 263 }
270 264
271 /** 265 /**
272 * This represents a field in an object. It is intended to be used as part of 266 * This represents a field in an object. It is intended to be used as part of
273 * a [_FieldList]. 267 * a [_FieldList].
274 */ 268 */
275 class _Field implements Comparable { 269 abstract class _Field implements Comparable {
276 /** The name of the field (or getter) */
277 final name;
278 270
279 /** The FieldList that contains us. */ 271 /** The FieldList that contains us. */
280 final _FieldList fieldList; 272 final _FieldList fieldList;
281 273
282 /** 274 /**
283 * Our position in the [contents] collection of [fieldList]. This is used 275 * Our position in the [contents] collection of [fieldList]. This is used
284 * to index into the state, so it's extremely important. 276 * to index into the state, so it's extremely important.
285 */ 277 */
286 int index; 278 int index;
287 279
288 /** Is this field used in the constructor? */ 280 /** Is this field used in the constructor? */
289 bool usedInConstructor = false; 281 bool usedInConstructor = false;
290 282
291 /** The special way to set this value registered, if this has a value. */ 283 /**
292 Function specialTreatment; 284 * Create a new [_Field] instance. This will be either a [_NamedField] or a
285 * [_ConstantField] depending on whether or not [value] corresponds to a
286 * field in the class which [fieldList] models.
287 */
288 factory _Field(value, _FieldList fieldList) {
289 if (_isReallyAField(value, fieldList)) {
290 return new _NamedField._internal(value, fieldList);
291 } else {
292 return new _ConstantField._internal(value, fieldList);
293 }
294 }
293 295
294 _Field(this.name, this.fieldList); 296 /**
297 * Determine if [value] represents a field or getter in the class that
298 * [fieldList] models.
299 */
300 static bool _isReallyAField(value, _FieldList fieldList) {
301 if (!(value is String)) return false;
302 return hasField(value, fieldList.mirror) ||
303 hasGetter(value, fieldList.mirror);
304 }
295 305
296 operator ==(x) => x is _Field && (name == x.name); 306 /** Private constructor. */
297 int get hashCode => name.hashCode; 307 _Field._internal(this.fieldList);
298 308
299 // Note that the field 'name' may be an arbitrary constant value, so we have 309 /**
300 // to convert it to a string for sorting. 310 * Extracts the value for the field that this represents from the instance
301 compareTo(x) => name.toString().compareTo(x.name.toString()); 311 * mirrored by [mirror] and return it.
312 */
313 valueIn(InstanceMirror mirror);
302 314
303 // TODO(alanknight): Is this the right name, or is it confusing that essential 315 // TODO(alanknight): Is this the right name, or is it confusing that essential
304 // is not the inverse of regular. 316 // is not the inverse of regular.
305 /** Return true if this is field is not used in the constructor. */ 317 /** Return true if this is field is not used in the constructor. */
306 bool get isRegular => !usedInConstructor; 318 bool get isRegular => !usedInConstructor;
307 319
308 /** 320 /**
309 * Return true if this field is treated as essential state, either because 321 * Return true if this field is treated as essential state, either because
310 * it is used in the constructor, or because it's been designated 322 * it is used in the constructor, or because it's been designated
311 * using [specialTreatmentFor]. 323 * using [setFieldWith].
312 */ 324 */
313 bool get isEssential => usedInConstructor || specialTreatment != null; 325 bool get isEssential => usedInConstructor;
326
327 /** Set the [value] of our field in the given mirrored [object]. */
328 void setValue(InstanceMirror object, value);
329
330 // Because [x] may not be a named field, we compare the toString. We don't
331 // care that much where constants come in the sort order as long as it's
332 // consistent.
333 compareTo(_Field x) => toString().compareTo(x.toString());
334 }
335
336 /**
337 * This represents a field in the object, either stored as a field or
338 * accessed via getter/setter/constructor parameter. It has a name and
339 * will attempt to access the state for that name using an [InstanceMirror].
340 */
341 class _NamedField extends _Field {
342 /** The name of the field (or getter) */
343 final name;
344
345 /** The special way to set this value registered, if this has a value. */
346 Function customSetter;
347
348 _NamedField._internal(this.name, fieldList) : super._internal(fieldList);
349
350 operator ==(x) => x is _NamedField && (name == x.name);
351 int get hashCode => name.hashCode;
352
353 /**
354 * Return true if this field is treated as essential state, either because
355 * it is used in the constructor, or because it's been designated
356 * using [setFieldWith].
357 */
358 bool get isEssential => super.isEssential || customSetter != null;
314 359
315 /** Set the [value] of our field in the given mirrored [object]. */ 360 /** Set the [value] of our field in the given mirrored [object]. */
316 void setValue(InstanceMirror object, value) { 361 void setValue(InstanceMirror object, value) {
317 setter(object, value); 362 setter(object, value);
318 } 363 }
319 364
365 valueIn(InstanceMirror mirror) => mirror.getField(name).value.reflectee;
366
320 /** Return the function to use to set our value. */ 367 /** Return the function to use to set our value. */
321 Function get setter => 368 Function get setter =>
322 (specialTreatment != null) ? specialTreatment : defaultSetter; 369 (customSetter != null) ? customSetter : defaultSetter;
323 370
324 /** Return a default setter function. */ 371 /** Return a default setter function. */
325 void defaultSetter(InstanceMirror object, value) { 372 void defaultSetter(InstanceMirror object, value) {
326 object.setField(name, reflect(value)); 373 object.setField(name, reflect(value));
327 } 374 }
328 375
329 String toString() => 'Field($name)'; 376 String toString() => 'Field($name)';
330 } 377 }
331 378
332 /** 379 /**
380 * This represents a constant value that will be passed as a constructor
381 * parameter. Rather than having a name it has a constant value.
382 */
383 class _ConstantField extends _Field {
384
385 /** The value we always return.*/
386 final value;
387
388 _ConstantField._internal(this.value, fieldList) : super._internal(fieldList);
389
390 operator ==(x) => x is _ConstantField && (value == x.value);
391 int get hashCode => value.hashCode;
392 String toString() => 'ConstantField($value)';
393 valueIn(InstanceMirror mirror) => value;
394
395 /** We cannot be set, so setValue is a no-op. */
396 void setValue(InstanceMirror object, value) {}
397
398 /** There are places where the code expects us to have an identifier, so
399 * use the value for that.
400 */
401 get name => value;
402 }
403
404 /**
333 * The organization of fields in an object can be reasonably complex, so they 405 * The organization of fields in an object can be reasonably complex, so they
334 * are kept in a separate object, which also has the ability to compute the 406 * are kept in a separate object, which also has the ability to compute the
335 * default fields to use reflectively. 407 * default fields to use reflectively.
336 */ 408 */
337 class _FieldList implements Iterable { 409 class _FieldList implements Iterable {
338 /** 410 /**
339 * All of our fields, indexed by name. Note that the names are not 411 * All of our fields, indexed by name. Note that the names are not
340 * necessarily strings. 412 * necessarily strings.
341 */ 413 */
342 Map<dynamic, _Field> allFields = new Map<dynamic, _Field>(); 414 Map<dynamic, _Field> allFields = new Map<dynamic, _Field>();
(...skipping 16 matching lines...) Expand all
359 431
360 /** Should we compute the fields or just use whatever we were given. */ 432 /** Should we compute the fields or just use whatever we were given. */
361 bool _shouldFigureOutFields = true; 433 bool _shouldFigureOutFields = true;
362 434
363 _FieldList(this.mirror); 435 _FieldList(this.mirror);
364 436
365 /** Look up a field by [name]. */ 437 /** Look up a field by [name]. */
366 _Field named(String name) => allFields[name]; 438 _Field named(String name) => allFields[name];
367 439
368 /** Set the fields to be used in the constructor. */ 440 /** Set the fields to be used in the constructor. */
369 set constructorFields(List fields) { 441 set constructorFields(List fieldNames) {
370 if (fields == null || fields.isEmpty) return; 442 if (fieldNames == null || fieldNames.isEmpty) return;
371 _constructorFields = []; 443 _constructorFields = [];
372 for (var each in fields) { 444 for (var each in fieldNames) {
373 var field = new _Field(each, this)..usedInConstructor = true; 445 var field = new _Field(each, this)..usedInConstructor = true;
374 allFields[each] = field; 446 allFields[each] = field;
375 _constructorFields.add(field); 447 _constructorFields.add(field);
376 } 448 }
377 invalidate(); 449 invalidate();
378 } 450 }
379 451
380 /** Set the fields that aren't used in the constructor. */ 452 /** Set the fields that aren't used in the constructor. */
381 set regular(List<String> fields) { 453 set regular(List<String> fields) {
382 if (fields == null) return; 454 if (fields == null) return;
(...skipping 12 matching lines...) Expand all
395 } 467 }
396 _excludeFields = fields; 468 _excludeFields = fields;
397 } 469 }
398 470
399 int get length => allFields.length; 471 int get length => allFields.length;
400 472
401 /** Add all the fields which aren't on the exclude list. */ 473 /** Add all the fields which aren't on the exclude list. */
402 void addAllNotExplicitlyExcluded(List<String> aCollection) { 474 void addAllNotExplicitlyExcluded(List<String> aCollection) {
403 if (aCollection == null) return; 475 if (aCollection == null) return;
404 var names = aCollection; 476 var names = aCollection;
405 names = names.filter((x) => x is String && !_excludeFields.contains(x)); 477 names = names.filter((x) => !_excludeFields.contains(x));
406 addAllByName(names); 478 addAllByName(names);
407 } 479 }
408 480
409 /** Add all the fields with the given names without any special properties. */ 481 /** Add all the fields with the given names without any special properties. */
410 void addAllByName(List<String> names) { 482 void addAllByName(List<String> names) {
411 for (var each in names) { 483 for (var each in names) {
412 allFields.putIfAbsent(each, () => new _Field(each, this)); 484 allFields.putIfAbsent(each, () => new _Field(each, this));
413 } 485 }
414 invalidate(); 486 invalidate();
415 } 487 }
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
479 var gettersThatMatchConstructor = getters.filter((each) 551 var gettersThatMatchConstructor = getters.filter((each)
480 => (named(each.simpleName) != null) && 552 => (named(each.simpleName) != null) &&
481 (named(each.simpleName).usedInConstructor)); 553 (named(each.simpleName).usedInConstructor));
482 addAllNotExplicitlyExcluded(names(fields)); 554 addAllNotExplicitlyExcluded(names(fields));
483 addAllNotExplicitlyExcluded(names(gettersWithSetters)); 555 addAllNotExplicitlyExcluded(names(gettersWithSetters));
484 addAllNotExplicitlyExcluded(names(gettersThatMatchConstructor)); 556 addAllNotExplicitlyExcluded(names(gettersThatMatchConstructor));
485 } 557 }
486 } 558 }
487 559
488 /** 560 /**
489 * Provide a typedef for the setWith argument to specialTreatmentFor. It would 561 * Provide a typedef for the setWith argument to setFieldWith. It would
490 * be nice if we could put this closer to the definition. 562 * be nice if we could put this closer to the definition.
491 */ 563 */
492 typedef SetWithFunction(InstanceMirror m, object); 564 typedef SetWithFunction(InstanceMirror m, object);
493 565
494 /** 566 /**
495 * This represents a constructor that is to be used when re-creating a 567 * This represents a constructor that is to be used when re-creating a
496 * serialized object. 568 * serialized object.
497 */ 569 */
498 class Constructor { 570 class Constructor {
499 /** The mirror of the class we construct. */ 571 /** The mirror of the class we construct. */
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
540 List fieldList; 612 List fieldList;
541 _MapWrapper(this.fieldList); 613 _MapWrapper(this.fieldList);
542 _MapWrapper.fromMap(this._map, this.fieldList); 614 _MapWrapper.fromMap(this._map, this.fieldList);
543 615
544 operator [](key) => _map[fieldList[key].name]; 616 operator [](key) => _map[fieldList[key].name];
545 operator []=(key, value) { _map[fieldList[key].name] = value; } 617 operator []=(key, value) { _map[fieldList[key].name] = value; }
546 get length => _map.length; 618 get length => _map.length;
547 619
548 asMap() => _map; 620 asMap() => _map;
549 } 621 }
OLDNEW
« no previous file with comments | « pkg/serialization/lib/serialization.dart ('k') | pkg/serialization/lib/src/mirrors_helpers.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698