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

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: Removed obsolete TODO Created 7 years, 12 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
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
227 // controlled to work on just constructor fields.
228 // TODO(alanknight): The framework should be resilient if there are fields 226 // 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 227 // 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. 228 // different definition, or for the case that tree-shaking has removed state.
231 // TODO(alanknight): This, and other places, rely on synchronous access to 229 // 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, 230 // mirrors. Should be changed to use a synchronous API once one is available,
233 // or to be async, but that would be extremely ugly. 231 // or to be async, but that would be extremely ugly.
234 _value(InstanceMirror mirror, _Field field) { 232 _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 233
242 /** 234 /**
243 * When reading from a flat format we are given [stream] and need to pull as 235 * 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 236 * 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 237 * 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. 238 * are references, where a reference is stored in the stream as two integers.
247 * Or, in the special case of null, two nulls. 239 * Or, in the special case of null, two nulls.
248 */ 240 */
249 pullStateFrom(Iterator stream) { 241 pullStateFrom(Iterator stream) {
250 var dataLength = stream.next(); 242 var dataLength = stream.next();
(...skipping 14 matching lines...) Expand all
265 } 257 }
266 } 258 }
267 return ruleData; 259 return ruleData;
268 } 260 }
269 } 261 }
270 262
271 /** 263 /**
272 * This represents a field in an object. It is intended to be used as part of 264 * This represents a field in an object. It is intended to be used as part of
273 * a [_FieldList]. 265 * a [_FieldList].
274 */ 266 */
275 class _Field implements Comparable { 267 abstract class _Field implements Comparable {
276 /** The name of the field (or getter) */
277 final name;
278 268
279 /** The FieldList that contains us. */ 269 /** The FieldList that contains us. */
280 final _FieldList fieldList; 270 final _FieldList fieldList;
281 271
282 /** 272 /**
283 * Our position in the [contents] collection of [fieldList]. This is used 273 * Our position in the [contents] collection of [fieldList]. This is used
284 * to index into the state, so it's extremely important. 274 * to index into the state, so it's extremely important.
285 */ 275 */
286 int index; 276 int index;
287 277
288 /** Is this field used in the constructor? */ 278 /** Is this field used in the constructor? */
289 bool usedInConstructor = false; 279 bool usedInConstructor = false;
290 280
291 /** The special way to set this value registered, if this has a value. */ 281 /**
292 Function specialTreatment; 282 * Create a new [_Field] instance. This will be either a [_NamedField] or a
283 * [_ConstantField] depending on whether or not [value] corresponds to a
284 * field in the class which [fieldList] models.
285 */
286 factory _Field(value, _FieldList fieldList) {
287 if (_isReallyAField(value, fieldList)) {
288 return new _NamedField._internal(value, fieldList);
289 } else {
290 return new _ConstantField._internal(value, fieldList);
291 }
292 }
293 293
294 _Field(this.name, this.fieldList); 294 /**
295 * Determine if [value] represents a field or getter in the class that
296 * [fieldList] models.
297 */
298 static bool _isReallyAField(value, _FieldList fieldList) {
299 if (!(value is String)) return false;
300 return hasField(value, fieldList.mirror) ||
301 hasGetter(value, fieldList.mirror);
302 }
295 303
296 operator ==(x) => x is _Field && (name == x.name); 304 /** Private constructor. */
297 int get hashCode => name.hashCode; 305 _Field._internal(this.fieldList);
298 306
299 // Note that the field 'name' may be an arbitrary constant value, so we have 307 /**
300 // to convert it to a string for sorting. 308 * Extracts the value for the field that this represents from the instance
301 compareTo(x) => name.toString().compareTo(x.name.toString()); 309 * mirrored by [mirror] and return it.
310 */
311 valueIn(InstanceMirror mirror);
302 312
303 // TODO(alanknight): Is this the right name, or is it confusing that essential 313 // TODO(alanknight): Is this the right name, or is it confusing that essential
304 // is not the inverse of regular. 314 // is not the inverse of regular.
305 /** Return true if this is field is not used in the constructor. */ 315 /** Return true if this is field is not used in the constructor. */
306 bool get isRegular => !usedInConstructor; 316 bool get isRegular => !usedInConstructor;
307 317
308 /** 318 /**
309 * Return true if this field is treated as essential state, either because 319 * 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 320 * it is used in the constructor, or because it's been designated
311 * using [specialTreatmentFor]. 321 * using [setFieldWith].
312 */ 322 */
313 bool get isEssential => usedInConstructor || specialTreatment != null; 323 bool get isEssential => usedInConstructor;
324
325 /** Set the [value] of our field in the given mirrored [object]. */
326 void setValue(InstanceMirror object, value);
327
328 // Because [x] may not be a named field, we compare the toString. We don't
329 // care that much where constants come in the sort order as long as it's
330 // consistent.
331 compareTo(_Field x) => toString().compareTo(x.toString());
332 }
333
334 /**
335 * This represents a field in the object, either stored as a field or
336 * accessed via getter/setter/constructor parameter. It has a name and
337 * will attempt to access the state for that name using an [InstanceMirror].
338 */
339 class _NamedField extends _Field {
340 /** The name of the field (or getter) */
341 final name;
342
343 /** The special way to set this value registered, if this has a value. */
344 Function customSetter;
345
346 _NamedField._internal(this.name, fieldList) : super._internal(fieldList);
347
348 operator ==(x) => x is _NamedField && (name == x.name);
349 int get hashCode => name.hashCode;
350
351 /**
352 * Return true if this field is treated as essential state, either because
353 * it is used in the constructor, or because it's been designated
354 * using [setFieldWith].
355 */
356 bool get isEssential => super.isEssential || customSetter != null;
314 357
315 /** Set the [value] of our field in the given mirrored [object]. */ 358 /** Set the [value] of our field in the given mirrored [object]. */
316 void setValue(InstanceMirror object, value) { 359 void setValue(InstanceMirror object, value) {
317 setter(object, value); 360 setter(object, value);
318 } 361 }
319 362
363 valueIn(InstanceMirror mirror) => mirror.getField(name).value.reflectee;
364
320 /** Return the function to use to set our value. */ 365 /** Return the function to use to set our value. */
321 Function get setter => 366 Function get setter =>
322 (specialTreatment != null) ? specialTreatment : defaultSetter; 367 (customSetter != null) ? customSetter : defaultSetter;
323 368
324 /** Return a default setter function. */ 369 /** Return a default setter function. */
325 void defaultSetter(InstanceMirror object, value) { 370 void defaultSetter(InstanceMirror object, value) {
326 object.setField(name, reflect(value)); 371 object.setField(name, reflect(value));
327 } 372 }
328 373
329 String toString() => 'Field($name)'; 374 String toString() => 'Field($name)';
330 } 375 }
331 376
332 /** 377 /**
378 * This represents a constant value that will be passed as a constructor
379 * parameter. Rather than having a name it has a constant value.
380 */
381 class _ConstantField extends _Field {
382
383 /** The value we always return.*/
384 final value;
385
386 _ConstantField._internal(this.value, fieldList) : super._internal(fieldList);
387
388 operator ==(x) => x is _ConstantField && (value == x.value);
389 int get hashCode => value.hashCode;
390 String toString() => 'ConstantField($value)';
391 valueIn(InstanceMirror mirror) => value;
392
393 /** We cannot be set, so setValue is a no-op. */
394 void setValue(InstanceMirror object, value) {}
395
396 /** There are places where the code expects us to have an identifier, so
397 * use the value for that.
398 */
399 get name => value;
400 }
401
402 /**
333 * The organization of fields in an object can be reasonably complex, so they 403 * 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 404 * are kept in a separate object, which also has the ability to compute the
335 * default fields to use reflectively. 405 * default fields to use reflectively.
336 */ 406 */
337 class _FieldList implements Iterable { 407 class _FieldList implements Iterable {
338 /** 408 /**
339 * All of our fields, indexed by name. Note that the names are not 409 * All of our fields, indexed by name. Note that the names are not
340 * necessarily strings. 410 * necessarily strings.
341 */ 411 */
342 Map<dynamic, _Field> allFields = new Map<dynamic, _Field>(); 412 Map<dynamic, _Field> allFields = new Map<dynamic, _Field>();
(...skipping 16 matching lines...) Expand all
359 429
360 /** Should we compute the fields or just use whatever we were given. */ 430 /** Should we compute the fields or just use whatever we were given. */
361 bool _shouldFigureOutFields = true; 431 bool _shouldFigureOutFields = true;
362 432
363 _FieldList(this.mirror); 433 _FieldList(this.mirror);
364 434
365 /** Look up a field by [name]. */ 435 /** Look up a field by [name]. */
366 _Field named(String name) => allFields[name]; 436 _Field named(String name) => allFields[name];
367 437
368 /** Set the fields to be used in the constructor. */ 438 /** Set the fields to be used in the constructor. */
369 set constructorFields(List fields) { 439 set constructorFields(List fieldNames) {
370 if (fields == null || fields.isEmpty) return; 440 if (fieldNames == null || fieldNames.isEmpty) return;
371 _constructorFields = []; 441 _constructorFields = [];
372 for (var each in fields) { 442 for (var each in fieldNames) {
373 var field = new _Field(each, this)..usedInConstructor = true; 443 var field = new _Field(each, this)..usedInConstructor = true;
374 allFields[each] = field; 444 allFields[each] = field;
375 _constructorFields.add(field); 445 _constructorFields.add(field);
376 } 446 }
377 invalidate(); 447 invalidate();
378 } 448 }
379 449
380 /** Set the fields that aren't used in the constructor. */ 450 /** Set the fields that aren't used in the constructor. */
381 set regular(List<String> fields) { 451 set regular(List<String> fields) {
382 if (fields == null) return; 452 if (fields == null) return;
(...skipping 12 matching lines...) Expand all
395 } 465 }
396 _excludeFields = fields; 466 _excludeFields = fields;
397 } 467 }
398 468
399 int get length => allFields.length; 469 int get length => allFields.length;
400 470
401 /** Add all the fields which aren't on the exclude list. */ 471 /** Add all the fields which aren't on the exclude list. */
402 void addAllNotExplicitlyExcluded(List<String> aCollection) { 472 void addAllNotExplicitlyExcluded(List<String> aCollection) {
403 if (aCollection == null) return; 473 if (aCollection == null) return;
404 var names = aCollection; 474 var names = aCollection;
405 names = names.filter((x) => x is String && !_excludeFields.contains(x)); 475 names = names.filter((x) => !_excludeFields.contains(x));
406 addAllByName(names); 476 addAllByName(names);
407 } 477 }
408 478
409 /** Add all the fields with the given names without any special properties. */ 479 /** Add all the fields with the given names without any special properties. */
410 void addAllByName(List<String> names) { 480 void addAllByName(List<String> names) {
411 for (var each in names) { 481 for (var each in names) {
412 allFields.putIfAbsent(each, () => new _Field(each, this)); 482 allFields.putIfAbsent(each, () => new _Field(each, this));
413 } 483 }
414 invalidate(); 484 invalidate();
415 } 485 }
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
479 var gettersThatMatchConstructor = getters.filter((each) 549 var gettersThatMatchConstructor = getters.filter((each)
480 => (named(each.simpleName) != null) && 550 => (named(each.simpleName) != null) &&
481 (named(each.simpleName).usedInConstructor)); 551 (named(each.simpleName).usedInConstructor));
482 addAllNotExplicitlyExcluded(names(fields)); 552 addAllNotExplicitlyExcluded(names(fields));
483 addAllNotExplicitlyExcluded(names(gettersWithSetters)); 553 addAllNotExplicitlyExcluded(names(gettersWithSetters));
484 addAllNotExplicitlyExcluded(names(gettersThatMatchConstructor)); 554 addAllNotExplicitlyExcluded(names(gettersThatMatchConstructor));
485 } 555 }
486 } 556 }
487 557
488 /** 558 /**
489 * Provide a typedef for the setWith argument to specialTreatmentFor. It would 559 * Provide a typedef for the setWith argument to setFieldWith. It would
490 * be nice if we could put this closer to the definition. 560 * be nice if we could put this closer to the definition.
491 */ 561 */
492 typedef SetWithFunction(InstanceMirror m, object); 562 typedef SetWithFunction(InstanceMirror m, object);
493 563
494 /** 564 /**
495 * This represents a constructor that is to be used when re-creating a 565 * This represents a constructor that is to be used when re-creating a
496 * serialized object. 566 * serialized object.
497 */ 567 */
498 class Constructor { 568 class Constructor {
499 /** The mirror of the class we construct. */ 569 /** The mirror of the class we construct. */
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
540 List fieldList; 610 List fieldList;
541 _MapWrapper(this.fieldList); 611 _MapWrapper(this.fieldList);
542 _MapWrapper.fromMap(this._map, this.fieldList); 612 _MapWrapper.fromMap(this._map, this.fieldList);
543 613
544 operator [](key) => _map[fieldList[key].name]; 614 operator [](key) => _map[fieldList[key].name];
545 operator []=(key, value) { _map[fieldList[key].name] = value; } 615 operator []=(key, value) { _map[fieldList[key].name] = value; }
546 get length => _map.length; 616 get length => _map.length;
547 617
548 asMap() => _map; 618 asMap() => _map;
549 } 619 }
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