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

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

Issue 13982012: Update pkg/serialization to use Symbols and synchronous mirrors (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 8 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 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
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()).setFieldWith('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 setFieldWith(String fieldName, SetWithFunction setWith) { 95 setFieldWith(String fieldName, SetWithFunction setWith) {
96 fields.addAllByName([fieldName]); 96 fields.addAllByName([fieldName]);
97 _NamedField field = fields.named(fieldName); 97 _NamedField field = fields.named(_asSymbol(fieldName));
98 Function setter = (setWith == null) ? field.defaultSetter : setWith; 98 Function setter = (setWith == null) ? field.defaultSetter : setWith;
99 field.customSetter = 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
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 } else { 303 } else {
304 return new _ConstantField._internal(value, fieldList); 304 return new _ConstantField._internal(value, fieldList);
305 } 305 }
306 } 306 }
307 307
308 /** 308 /**
309 * Determine if [value] represents a field or getter in the class that 309 * Determine if [value] represents a field or getter in the class that
310 * [fieldList] models. 310 * [fieldList] models.
311 */ 311 */
312 static bool _isReallyAField(value, _FieldList fieldList) { 312 static bool _isReallyAField(value, _FieldList fieldList) {
313 if (!(value is String)) return false; 313 var symbol = _asSymbol(value);
314 return hasField(value, fieldList.mirror) || 314 return hasField(symbol, fieldList.mirror) ||
315 hasGetter(value, fieldList.mirror); 315 hasGetter(symbol, fieldList.mirror);
316 } 316 }
317 317
318 /** Private constructor. */ 318 /** Private constructor. */
319 _Field._internal(this.fieldList); 319 _Field._internal(this.fieldList);
320 320
321 /** 321 /**
322 * Extracts the value for the field that this represents from the instance 322 * Extracts the value for the field that this represents from the instance
323 * mirrored by [mirror] and return it. 323 * mirrored by [mirror] and return it.
324 */ 324 */
325 valueIn(InstanceMirror mirror); 325 valueIn(InstanceMirror mirror);
(...skipping 19 matching lines...) Expand all
345 compareTo(_Field x) => toString().compareTo(x.toString()); 345 compareTo(_Field x) => toString().compareTo(x.toString());
346 } 346 }
347 347
348 /** 348 /**
349 * This represents a field in the object, either stored as a field or 349 * This represents a field in the object, either stored as a field or
350 * accessed via getter/setter/constructor parameter. It has a name and 350 * accessed via getter/setter/constructor parameter. It has a name and
351 * will attempt to access the state for that name using an [InstanceMirror]. 351 * will attempt to access the state for that name using an [InstanceMirror].
352 */ 352 */
353 class _NamedField extends _Field { 353 class _NamedField extends _Field {
354 /** The name of the field (or getter) */ 354 /** The name of the field (or getter) */
355 final name; 355 String _name;
356 Symbol nameSymbol;
356 357
357 /** The special way to set this value registered, if this has a value. */ 358 /**
359 * If this is set, then it is used as a way to set the value rather than
360 * using the default mechanism.
361 */
358 Function customSetter; 362 Function customSetter;
359 363
360 _NamedField._internal(this.name, fieldList) : super._internal(fieldList); 364 _NamedField._internal(fieldName, fieldList) : super._internal(fieldList) {
365 nameSymbol = _asSymbol(fieldName);
366 if (nameSymbol == null) {
367 throw new SerializationException("Invalid field name $fieldName");
368 }
369 }
361 370
362 operator ==(x) => x is _NamedField && (name == x.name); 371 String get name =>
372 _name == null ? _name = MirrorSystem.getName(nameSymbol) : _name;
373
374 operator ==(x) => x is _NamedField && (nameSymbol == x.nameSymbol);
363 int get hashCode => name.hashCode; 375 int get hashCode => name.hashCode;
364 376
365 /** 377 /**
366 * Return true if this field is treated as essential state, either because 378 * Return true if this field is treated as essential state, either because
367 * it is used in the constructor, or because it's been designated 379 * it is used in the constructor, or because it's been designated
368 * using [setFieldWith]. 380 * using [setFieldWith].
369 */ 381 */
370 bool get isEssential => super.isEssential || customSetter != null; 382 bool get isEssential => super.isEssential || customSetter != null;
371 383
372 /** Set the [value] of our field in the given mirrored [object]. */ 384 /** Set the [value] of our field in the given mirrored [object]. */
373 void setValue(InstanceMirror object, value) { 385 void setValue(InstanceMirror object, value) {
374 setter(object, value); 386 setter(object, value);
375 } 387 }
376 388
377 valueIn(InstanceMirror mirror) => 389 valueIn(InstanceMirror mirror) => mirror.getField(nameSymbol).reflectee;
378 deprecatedFutureValue(mirror.getFieldAsync(name)).reflectee;
379 390
380 /** Return the function to use to set our value. */ 391 /** Return the function to use to set our value. */
381 Function get setter => 392 Function get setter =>
382 (customSetter != null) ? customSetter : defaultSetter; 393 (customSetter != null) ? customSetter : defaultSetter;
383 394
384 /** Return a default setter function. */ 395 /** The default setter function. */
385 void defaultSetter(InstanceMirror object, value) { 396 void defaultSetter(InstanceMirror object, value) {
386 object.setFieldAsync(name, reflect(value)); 397 object.setField(nameSymbol, value);
387 } 398 }
388 399
389 String toString() => 'Field($name)'; 400 String toString() => 'Field($name)';
390 } 401 }
391 402
392 /** 403 /**
393 * This represents a constant value that will be passed as a constructor 404 * This represents a constant value that will be passed as a constructor
394 * parameter. Rather than having a name it has a constant value. 405 * parameter. Rather than having a name it has a constant value.
395 */ 406 */
396 class _ConstantField extends _Field { 407 class _ConstantField extends _Field {
(...skipping 17 matching lines...) Expand all
414 get name => value; 425 get name => value;
415 } 426 }
416 427
417 /** 428 /**
418 * The organization of fields in an object can be reasonably complex, so they 429 * The organization of fields in an object can be reasonably complex, so they
419 * are kept in a separate object, which also has the ability to compute the 430 * are kept in a separate object, which also has the ability to compute the
420 * default fields to use reflectively. 431 * default fields to use reflectively.
421 */ 432 */
422 class _FieldList extends IterableBase { 433 class _FieldList extends IterableBase {
423 /** 434 /**
424 * All of our fields, indexed by name. Note that the names are not 435 * All of our fields, indexed by name. Note that the names are
425 * necessarily strings. 436 * typically Symbols, but can also be arbitrary constants.
426 */ 437 */
427 Map<dynamic, _Field> allFields = new Map<dynamic, _Field>(); 438 Map<dynamic, _Field> allFields = new Map<dynamic, _Field>();
428 439
429 /** 440 /**
430 * The fields which are used in the constructor. The fields themselves also 441 * The fields which are used in the constructor. The fields themselves also
431 * know if they are constructor fields or not, but we need to keep this 442 * know if they are constructor fields or not, but we need to keep this
432 * information here because the order matters. 443 * information here because the order matters.
433 */ 444 */
434 List _constructorFields = const []; 445 List _constructorFields = const [];
435 446
436 /** The list of fields to exclude if we are computing the list ourselves. */ 447 /** The list of fields to exclude if we are computing the list ourselves. */
437 List<String> _excludeFields = const []; 448 List<Symbol> _excludedFieldNames = const [];
438 449
439 /** The mirror we will use to compute the fields. */ 450 /** The mirror we will use to compute the fields. */
440 final ClassMirror mirror; 451 final ClassMirror mirror;
441 452
442 /** Cached, sorted list of fields. */ 453 /** Cached, sorted list of fields. */
443 List<_Field> _contents; 454 List<_Field> _contents;
444 455
445 /** Should we compute the fields or just use whatever we were given. */ 456 /** Should we compute the fields or just use whatever we were given. */
446 bool _shouldFigureOutFields = true; 457 bool _shouldFigureOutFields = true;
447 458
448 _FieldList(this.mirror); 459 _FieldList(this.mirror);
449 460
450 /** Look up a field by [name]. */ 461 /** Look up a field by [name]. */
451 _Field named(String name) => allFields[name]; 462 _Field named(name) => allFields[name];
452 463
453 /** Set the fields to be used in the constructor. */ 464 /** Set the fields to be used in the constructor. */
454 set constructorFields(List fieldNames) { 465 set constructorFields(List fieldNames) {
455 if (fieldNames == null || fieldNames.isEmpty) return; 466 if (fieldNames == null || fieldNames.isEmpty) return;
456 _constructorFields = []; 467 _constructorFields = [];
457 for (var each in fieldNames) { 468 for (var each in fieldNames) {
458 var field = new _Field(each, this)..usedInConstructor = true; 469 var symbol = _asSymbol(each);
459 allFields[each] = field; 470 var name = _Field._isReallyAField(symbol, this) ? symbol : each;
471 var field = new _Field(name, this)..usedInConstructor = true;
472 allFields[name] = field;
460 _constructorFields.add(field); 473 _constructorFields.add(field);
461 } 474 }
462 invalidate(); 475 invalidate();
463 } 476 }
464 477
465 /** Set the fields that aren't used in the constructor. */ 478 /** Set the fields that aren't used in the constructor. */
466 set regular(List<String> fields) { 479 set regular(List<String> fields) {
467 if (fields == null) return; 480 if (fields == null) return;
468 _shouldFigureOutFields = false; 481 _shouldFigureOutFields = false;
469 addAllByName(fields); 482 addAllByName(fields);
470 } 483 }
471 484
472 /** Set the fields to be excluded. This is mutually exclusive with setting 485 /** Set the fields to be excluded. This is mutually exclusive with setting
473 * the regular fields. 486 * the regular fields.
474 */ 487 */
475 set exclude(List<String> fields) { 488 set exclude(List<String> fields) {
476 // TODO(alanknight): This isn't well tested. 489 // TODO(alanknight): This isn't well tested.
477 if (fields == null || fields.isEmpty) return; 490 if (fields == null || fields.isEmpty) return;
478 if (allFields.length > _constructorFields.length) { 491 if (allFields.length > _constructorFields.length) {
479 throw "You can't specify both excludeFields and regular fields"; 492 throw "You can't specify both excludeFields and regular fields";
480 } 493 }
481 _excludeFields = fields; 494 _excludedFieldNames = fields.map((x) => new Symbol(x)).toList();
482 } 495 }
483 496
484 int get length => allFields.length; 497 int get length => allFields.length;
485 498
486 /** Add all the fields which aren't on the exclude list. */ 499 /** Add all the fields which aren't on the exclude list. */
487 void addAllNotExplicitlyExcluded(Iterable<String> aCollection) { 500 void addAllNotExplicitlyExcluded(Iterable<String> aCollection) {
488 if (aCollection == null) return; 501 if (aCollection == null) return;
489 var names = aCollection; 502 var names = aCollection;
490 names = names.where((x) => !_excludeFields.contains(x)); 503 names = names.where((x) => !_excludedFieldNames.contains(x));
491 addAllByName(names); 504 addAllByName(names);
492 } 505 }
493 506
494 /** Add all the fields with the given names without any special properties. */ 507 /** Add all the fields with the given names without any special properties. */
495 void addAllByName(Iterable<String> names) { 508 void addAllByName(Iterable<String> names) {
496 for (var each in names) { 509 for (var each in names) {
497 allFields.putIfAbsent(each, () => new _Field(each, this)); 510 var symbol = _asSymbol(each);
511 var field = new _Field(symbol, this);
512 allFields.putIfAbsent(symbol, () => new _Field(symbol, this));
498 } 513 }
499 invalidate(); 514 invalidate();
500 } 515 }
501 516
502 /** 517 /**
503 * Fields have been added. In case we had already forced calculation of the 518 * Fields have been added. In case we had already forced calculation of the
504 * list of contents, re-set it. 519 * list of contents, re-set it.
505 */ 520 */
506 void invalidate() { 521 void invalidate() {
507 _contents = null; 522 _contents = null;
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
555 * that are listed in the constructor fields. 570 * that are listed in the constructor fields.
556 */ 571 */
557 void figureOutFields() { 572 void figureOutFields() {
558 Iterable names(Iterable<DeclarationMirror> mirrors) => 573 Iterable names(Iterable<DeclarationMirror> mirrors) =>
559 mirrors.map((each) => each.simpleName).toList(); 574 mirrors.map((each) => each.simpleName).toList();
560 575
561 if (!_shouldFigureOutFields || !regularFields().isEmpty) return; 576 if (!_shouldFigureOutFields || !regularFields().isEmpty) return;
562 var fields = publicFields(mirror); 577 var fields = publicFields(mirror);
563 var getters = publicGetters(mirror); 578 var getters = publicGetters(mirror);
564 var gettersWithSetters = getters.where( (each) 579 var gettersWithSetters = getters.where( (each)
565 => mirror.setters["${each.simpleName}="] != null); 580 => mirror.setters[
581 new Symbol("${MirrorSystem.getName(each.simpleName)}=")] != null);
566 var gettersThatMatchConstructor = getters.where((each) 582 var gettersThatMatchConstructor = getters.where((each)
567 => (named(each.simpleName) != null) && 583 => (named(each.simpleName) != null) &&
568 (named(each.simpleName).usedInConstructor)).toList(); 584 (named(each.simpleName).usedInConstructor)).toList();
569 addAllNotExplicitlyExcluded(names(fields)); 585 addAllNotExplicitlyExcluded(names(fields));
570 addAllNotExplicitlyExcluded(names(gettersWithSetters)); 586 addAllNotExplicitlyExcluded(names(gettersWithSetters));
571 addAllNotExplicitlyExcluded(names(gettersThatMatchConstructor)); 587 addAllNotExplicitlyExcluded(names(gettersThatMatchConstructor));
572 } 588 }
573 589
574 toString() => "FieldList($contents)"; 590 toString() => "FieldList($contents)";
575 } 591 }
576 592
577 /** 593 /**
578 * Provide a typedef for the setWith argument to setFieldWith. It would 594 * Provide a typedef for the setWith argument to setFieldWith. It would
579 * be nice if we could put this closer to the definition. 595 * be nice if we could put this closer to the definition.
580 */ 596 */
581 typedef SetWithFunction(InstanceMirror m, object); 597 typedef SetWithFunction(InstanceMirror m, object);
582 598
583 /** 599 /**
584 * This represents a constructor that is to be used when re-creating a 600 * This represents a constructor that is to be used when re-creating a
585 * serialized object. 601 * serialized object.
586 */ 602 */
587 class Constructor { 603 class Constructor {
588 /** The mirror of the class we construct. */ 604 /** The mirror of the class we construct. */
589 final ClassMirror type; 605 final ClassMirror type;
590 606
591 /** The name of the constructor to use, if not the default constructor.*/ 607 /** The name of the constructor to use, if not the default constructor.*/
592 String name; 608 String name;
609 Symbol nameSymbol;
593 610
594 /** 611 /**
595 * The indices of the fields used as constructor arguments. We will look 612 * The indices of the fields used as constructor arguments. We will look
596 * these up in the state by number. These correspond to the index in the 613 * these up in the state by number. These correspond to the index in the
597 * [contents] of the FieldList, which will be alphabetically sorted. 614 * [contents] of the FieldList, which will be alphabetically sorted.
598 */ 615 */
599 List<int> fieldNumbers; 616 List<int> fieldNumbers;
600 617
601 /** 618 /**
602 * Creates a new constructor for the [type] with the constructor named [name] 619 * Creates a new constructor for the [type] with the constructor named [name]
603 * and the [fieldNumbers] of the constructor fields. 620 * and the [fieldNumbers] of the constructor fields.
604 */ 621 */
605 Constructor(this.type, this.name, this.fieldNumbers) { 622 Constructor(this.type, this.name, this.fieldNumbers) {
606 if (name == null) name = ''; 623 if (name == null) name = '';
624 nameSymbol = new Symbol(name);
607 if (fieldNumbers == null) fieldNumbers = const []; 625 if (fieldNumbers == null) fieldNumbers = const [];
608 } 626 }
609 627
610 /** 628 /**
611 * Find the field values in [state] and pass them to the constructor. 629 * Find the field values in [state] and pass them to the constructor.
612 * If any of [fieldNumbers] is not an int, then use it as a literal value. 630 * If any of [fieldNumbers] is not an int, then use it as a literal value.
613 */ 631 */
614 constructFrom(state, Reader r) { 632 constructFrom(state, Reader r) {
615 // TODO(alanknight): Handle named parameters 633 // TODO(alanknight): Handle named parameters
616 Iterable inflated = fieldNumbers.map( 634 Iterable inflated = fieldNumbers.map(
617 (x) => (x is int) ? reflect(r.inflateReference(state[x])) : reflect(x)); 635 (x) => (x is int) ? r.inflateReference(state[x]) : x);
618 var result = type.newInstanceAsync(name, inflated.toList()); 636 var result;
619 return deprecatedFutureValue(result); 637 try {
638 result = type.newInstance(nameSymbol, inflated.toList());
639 } on MirroredError catch (e) {
640 // Mirrored "compile-time" errors do not get treated as exceptions
641 // in the debugger, so explicitly re-throw. Issue dartbug.com/10054.
642 throw e;
643 }
644 return result;
620 } 645 }
621 } 646 }
622 647
623 /** 648 /**
624 * This wraps a map to make it indexable by integer field numbers. It translates 649 * This wraps a map to make it indexable by integer field numbers. It translates
625 * from the index into a field name and then looks it up in the map. 650 * from the index into a field name and then looks it up in the map.
626 */ 651 */
627 class _MapWrapper { 652 class _MapWrapper {
628 final _map; 653 final _map;
629 List fieldList; 654 List fieldList;
630 _MapWrapper(this.fieldList) : _map = new Map(); 655 _MapWrapper(this.fieldList) : _map = new Map();
631 _MapWrapper.fromMap(this._map, this.fieldList); 656 _MapWrapper.fromMap(this._map, this.fieldList);
632 657
633 operator [](key) => _map[fieldList[key].name]; 658 operator [](key) => _map[fieldList[key].name];
634 659
635 operator []=(key, value) { _map[fieldList[key].name] = value; } 660 operator []=(key, value) { _map[fieldList[key].name] = value; }
636 get length => _map.length; 661 get length => _map.length;
637 662
638 asMap() => _map; 663 asMap() => _map;
639 } 664 }
665
666 /**
667 * Return a symbol corresponding to [value], which may be a String or a
668 * Symbol. If it is any other type, or if the string is an
669 * invalid symbol, return null;
670 */
671 _asSymbol(value) {
672 if (value is Symbol) return value;
673 if (value is String) {
674 try {
675 return new Symbol(value);
676 } on ArgumentError {
677 return null;
678 };
679 } else {
680 return null;
681 }
682 }
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