| OLD | NEW |
| (Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 part of serialization; |
| 6 |
| 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 |
| 9 // in fact necessary. Maybe the tree-shaking will just remove it if unused. |
| 10 |
| 11 /** |
| 12 * This is the basic rule for handling "normal" objects, which have a list of |
| 13 * fields and a constructor, as opposed to simple types or collections. It uses |
| 14 * mirrors to access the state, and can also use them to figure out the list |
| 15 * of fields and the constructor if it's not provided. |
| 16 * |
| 17 * If you call [Serialization.addRule], this is what you get. |
| 18 * |
| 19 */ |
| 20 class BasicRule extends SerializationRule { |
| 21 /** |
| 22 * The [type] is used both to find fields and to verify if the object is one |
| 23 * that we handle. |
| 24 */ |
| 25 final ClassMirror type; |
| 26 |
| 27 /** Used to create new objects when reading. */ |
| 28 Constructor constructor; |
| 29 |
| 30 /** This holds onto our list of fields, and can also calculate them. */ |
| 31 _FieldList fields; |
| 32 |
| 33 /** |
| 34 * Instances can either use maps or lists to hold the object's state. The list |
| 35 * representation is much more compact and used by default. The map |
| 36 * representation is more human-readable. The default is to use lists. |
| 37 */ |
| 38 bool useMaps = false; |
| 39 |
| 40 // TODO(alanknight) Change the type parameter once we have class literals. |
| 41 // Issue 6282. |
| 42 // TODO(alanknight) Does the comment for this format properly? |
| 43 /** |
| 44 * Create this rule. Right now the user is obliged to pass a ClassMirror, |
| 45 * but once we allow class literals (Issue 6282) it will support that. The |
| 46 * other parameters can all be left as null, and are optional on the |
| 47 * [Serialization.addRule] method which is the normal caller for this. |
| 48 * [constructorName] is the constructor, if not the default. |
| 49 * [constructorFields] are the fields required to call the constructor, which |
| 50 * is the essential state. They don't have to be actual fields, |
| 51 * getter/setter pairs or getter/constructor pairs are fine. Note that |
| 52 * the constructorFields do not need to be strings, they can be arbitrary |
| 53 * values. For non-strings, these will be treated as constant values to be |
| 54 * used instead of data read from the objects. |
| 55 * [regularFields] are the non-essential fields. They don't have to be actual |
| 56 * fields, getter/setter pairs are fine. If this is null, it's assumed |
| 57 * that we should figure them out. |
| 58 * [excludeFields] lets you tell it to find the fields automatically, but |
| 59 * omit some that would otherwise be included. |
| 60 */ |
| 61 BasicRule(ClassMirror this.type, String constructorName, |
| 62 List constructorFields, List regularFields, |
| 63 List excludeFields) { |
| 64 _findFields(constructorFields, regularFields, excludeFields); |
| 65 constructor = new Constructor( |
| 66 type, constructorName, fields.constructorFieldIndices()); |
| 67 configureForLists(); |
| 68 } |
| 69 |
| 70 /** |
| 71 * Sometimes it's necessary to treat fields of an object differently, based |
| 72 * on the containing object. For example, by default a list treats its |
| 73 * contents as non-essential state, so it will be populated only after all |
| 74 * objects have been created. An object may have a list which is used in its |
| 75 * constructor and must be fully created before the owning object can be |
| 76 * created. Alternatively, it may not be possible to set a field directly, |
| 77 * and some other method must be called to set it, perhaps calling a method |
| 78 * on the owning object to add each individual element. |
| 79 * |
| 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, |
| 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 |
| 84 * each item individually and that will only work if those objects already |
| 85 * exist. |
| 86 * |
| 87 * For example, to serialize a Serialization, we need its rules to be |
| 88 * individually added rather than just setting the rules field. |
| 89 * ..addRuleFor(new Serialization()).specialTreatmentFor('rules', |
| 90 * (InstanceMirror s, List rules) { |
| 91 * rules.forEach((x) => s.reflectee.addRule(x)); |
| 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. |
| 94 */ |
| 95 specialTreatmentFor(String fieldName, SetWithFunction setWith) { |
| 96 fields.addAllByName([fieldName]); |
| 97 _Field field = fields.named(fieldName); |
| 98 Function setter = (setWith == null) ? field.defaultSetter : setWith; |
| 99 field.specialTreatment = setter; |
| 100 } |
| 101 |
| 102 // TODO(alanknight): Polyfill for the non-hashability of mirrors. Issue 6880. |
| 103 get typeWrapped => new ClassMirrorWrapper(type); |
| 104 |
| 105 /** Return the name of the constructor used to create new instances on read.*/ |
| 106 String get constructorName => constructor.name; |
| 107 |
| 108 /** Return the list of field names to be passed to the constructor.*/ |
| 109 List<String> get constructorFields => fields.constructorFieldNames(); |
| 110 |
| 111 /** Return the list of field names not used in the constructor. */ |
| 112 List<String> get regularFields => fields.regularFieldNames(); |
| 113 |
| 114 String toString() => "Basic Rule for ${type.simpleName}"; |
| 115 |
| 116 /** |
| 117 * Configure this instance to use maps by field name as its output. |
| 118 * Instances can either produce maps or lists. The list representation |
| 119 * is much more compact and used by default. The map representation is |
| 120 * much easier to debug. The default is to use lists. |
| 121 */ |
| 122 configureForMaps() { |
| 123 useMaps = true; |
| 124 } |
| 125 |
| 126 /** |
| 127 * Configure this instance to use lists accessing fields by index as its |
| 128 * output. Instances can either produce maps or lists. The list representation |
| 129 * is much more compact and used by default. The map representation is |
| 130 * much easier to debug. The default is to use lists. |
| 131 */ |
| 132 configureForLists() { |
| 133 useMaps = false; |
| 134 } |
| 135 |
| 136 /** Create either a list or a map to hold the object's state, depending |
| 137 * on the [useMaps] variable. If using a Map, we wrap it in order to keep |
| 138 * the protocol compatible. See [configureForLists]/[configureForMaps]. |
| 139 */ |
| 140 createStateHolder() => |
| 141 useMaps ? new _MapWrapper(fields.contents) : new List(fields.length); |
| 142 |
| 143 /** Wrap the state if it's passed in as a map. */ |
| 144 makeIndexableByNumber(state) => |
| 145 (state is Map) ? new _MapWrapper.fromMap(state, fields.contents) : state; |
| 146 |
| 147 /** |
| 148 * Extract the state from [object] using an instanceMirror and the field |
| 149 * names in [fields]. Call the function [callback] on each value. |
| 150 */ |
| 151 extractState(object, Function callback) { |
| 152 var result = createStateHolder(); |
| 153 var mirror = reflect(object); |
| 154 |
| 155 keysAndValues(fields).forEach( |
| 156 (index, field) { |
| 157 var value = _value(mirror, field); |
| 158 callback(checkForEssentialLists(index, value)); |
| 159 result[index] = value; |
| 160 }); |
| 161 return _unwrap(result); |
| 162 } |
| 163 |
| 164 /** |
| 165 * If the value is a List, and the field is a constructor field or |
| 166 * otherwise specially designated, we wrap it in something that indicates |
| 167 * a restriction on the rules that can be used. Which in this case amounts |
| 168 * to designating the rule, since we so far only have one rule per object. |
| 169 */ |
| 170 checkForEssentialLists(index, value) { |
| 171 if (value is List && fields.contents[index].isEssential) { |
| 172 return new DesignatedRuleForObject(value, |
| 173 (index) => index is ListRuleEssential); |
| 174 } else { |
| 175 return value; |
| 176 } |
| 177 } |
| 178 |
| 179 /** Remove any MapWrapper from the extracted state. */ |
| 180 _unwrap(result) => (result is _MapWrapper) ? result.asMap() : result; |
| 181 |
| 182 /** |
| 183 * Call the designated constructor with the appropriate fields from [state], |
| 184 * first resolving references in the context of [reader]. |
| 185 */ |
| 186 inflateEssential(state, Reader reader) { |
| 187 InstanceMirror mirror = constructor.constructFrom( |
| 188 makeIndexableByNumber(state), reader); |
| 189 return mirror.reflectee; |
| 190 } |
| 191 |
| 192 /** For all [state] not required in the constructor, set it in the [object], |
| 193 * resolving references in the context of [reader]. |
| 194 */ |
| 195 inflateNonEssential(rawState, object, Reader reader) { |
| 196 InstanceMirror mirror = reflect(object); |
| 197 var state = makeIndexableByNumber(rawState); |
| 198 fields.forEachRegularField( (_Field field) { |
| 199 var value = reader.inflateReference(state[field.index]); |
| 200 field.setValue(mirror, value); |
| 201 }); |
| 202 } |
| 203 |
| 204 /** |
| 205 * Determine if this rule applies to the object in question. In our case |
| 206 * this is true if the type mirrors are the same. |
| 207 */ |
| 208 // TODO(alanknight): This seems likely to be slow. Verify. Other options? |
| 209 bool appliesTo(object) => reflect(object).type == type; |
| 210 |
| 211 /** |
| 212 * Given the various field lists provided by the user, construct the list |
| 213 * of field names that we want. |
| 214 */ |
| 215 void _findFields(List constructorFields, List regularFields, |
| 216 List excludeFields) { |
| 217 fields = new _FieldList(type); |
| 218 fields.constructorFields = constructorFields; |
| 219 fields.regular = regularFields; |
| 220 // TODO(alanknight): The order of this matters. It shouldn't. |
| 221 fields.exclude = excludeFields; |
| 222 fields.figureOutFields(); |
| 223 } |
| 224 |
| 225 /** |
| 226 * Extract the value of the field [fieldName] from the object reflected |
| 227 * by [mirror]. |
| 228 */ |
| 229 // TODO (alanknight): The "is String" mechanism here should be more tightly |
| 230 // controlled to work on just constructor fields. |
| 231 // TODO(alanknight): The framework should be resilient if there are fields |
| 232 // it expects that are missing, either for the case of de-serializing to a |
| 233 // different definition, or for the case that tree-shaking has removed state. |
| 234 // TODO(alanknight): This, and other places, rely on synchronous access to |
| 235 // mirrors. Should be changed to use a synchronous API once one is available, |
| 236 // or to be async, but that would be extremely ugly. |
| 237 _value(InstanceMirror mirror, _Field field) { |
| 238 if (field.name is String) { |
| 239 return mirror.getField(field.name).value.reflectee; |
| 240 } else { |
| 241 return field.name; |
| 242 } |
| 243 } |
| 244 |
| 245 /** |
| 246 * When reading from a flat format we are given [stream] and need to pull as |
| 247 * much data from it as we need. Our format is that we have an integer N |
| 248 * indicating the number of objects and then for each object N fields, which |
| 249 * are references, where a reference is stored in the stream as two integers. |
| 250 * Or, in the special case of null, two nulls. |
| 251 */ |
| 252 pullStateFrom(Iterator stream) { |
| 253 var dataLength = stream.next(); |
| 254 var ruleData = new List(); |
| 255 for (var i = 0; i < dataLength; i++) { |
| 256 var subList = new List(); |
| 257 ruleData.add(subList); |
| 258 for (var j = 0; j < fields.length; j++) { |
| 259 var a = stream.next(); |
| 260 var b = stream.next(); |
| 261 if (!(a is int)) { |
| 262 // This wasn't a reference, so just use the first object as a literal. |
| 263 // particularly used for the case of null. |
| 264 subList.add(a); |
| 265 } else { |
| 266 subList.add(new Reference(this, a, b)); |
| 267 } |
| 268 } |
| 269 } |
| 270 return ruleData; |
| 271 } |
| 272 } |
| 273 |
| 274 /** |
| 275 * This represents a field in an object. It is intended to be used as part of |
| 276 * a [_FieldList]. |
| 277 */ |
| 278 class _Field implements Comparable { |
| 279 /** The name of the field (or getter) */ |
| 280 final name; |
| 281 |
| 282 /** The FieldList that contains us. */ |
| 283 final _FieldList fieldList; |
| 284 |
| 285 /** |
| 286 * Our position in the [contents] collection of [fieldList]. This is used |
| 287 * to index into the state, so it's extremely important. |
| 288 */ |
| 289 int index; |
| 290 |
| 291 /** Is this field used in the constructor? */ |
| 292 bool usedInConstructor = false; |
| 293 |
| 294 /** The special way to set this value registered, if this has a value. */ |
| 295 Function specialTreatment; |
| 296 |
| 297 _Field(this.name, this.fieldList); |
| 298 |
| 299 operator ==(x) => x is _Field && (name == x.name); |
| 300 int get hashCode => name.hashCode; |
| 301 |
| 302 // Note that the field 'name' may be an arbitrary constant value, so we have |
| 303 // to convert it to a string for sorting. |
| 304 compareTo(x) => name.toString().compareTo(x.name.toString()); |
| 305 |
| 306 // TODO(alanknight): Is this the right name, or is it confusing that essential |
| 307 // is not the inverse of regular. |
| 308 /** Return true if this is field is not used in the constructor. */ |
| 309 bool get isRegular => !usedInConstructor; |
| 310 |
| 311 /** |
| 312 * Return true if this field is treated as essential state, either because |
| 313 * it is used in the constructor, or because it's been designated |
| 314 * using [specialTreatmentFor]. |
| 315 */ |
| 316 bool get isEssential => usedInConstructor || specialTreatment != null; |
| 317 |
| 318 /** Set the [value] of our field in the given mirrored [object]. */ |
| 319 void setValue(InstanceMirror object, value) { |
| 320 setter(object, value); |
| 321 } |
| 322 |
| 323 /** Return the function to use to set our value. */ |
| 324 Function get setter => |
| 325 (specialTreatment != null) ? specialTreatment : defaultSetter; |
| 326 |
| 327 /** Return a default setter function. */ |
| 328 void defaultSetter(InstanceMirror object, value) { |
| 329 object.setField(name, reflect(value)); |
| 330 } |
| 331 |
| 332 String toString() => 'Field($name)'; |
| 333 } |
| 334 |
| 335 /** |
| 336 * The organization of fields in an object can be reasonably complex, so they |
| 337 * are kept in a separate object, which also has the ability to compute the |
| 338 * default fields to use reflectively. |
| 339 */ |
| 340 class _FieldList implements Iterable { |
| 341 /** |
| 342 * All of our fields, indexed by name. Note that the names are not |
| 343 * necessarily strings. |
| 344 */ |
| 345 Map<dynamic, _Field> allFields = new Map<dynamic, _Field>(); |
| 346 |
| 347 /** |
| 348 * The fields which are used in the constructor. The fields themselves also |
| 349 * know if they are constructor fields or not, but we need to keep this |
| 350 * information here because the order matters. |
| 351 */ |
| 352 List _constructorFields = const []; |
| 353 |
| 354 /** The list of fields to exclude if we are computing the list ourselves. */ |
| 355 List<String> _excludeFields = const []; |
| 356 |
| 357 /** The mirror we will use to compute the fields. */ |
| 358 final ClassMirror mirror; |
| 359 |
| 360 /** Cached, sorted list of fields. */ |
| 361 List<_Field> _contents; |
| 362 |
| 363 /** Should we compute the fields or just use whatever we were given. */ |
| 364 bool _shouldFigureOutFields = true; |
| 365 |
| 366 _FieldList(this.mirror); |
| 367 |
| 368 /** Look up a field by [name]. */ |
| 369 _Field named(String name) => allFields[name]; |
| 370 |
| 371 /** Set the fields to be used in the constructor. */ |
| 372 set constructorFields(List fields) { |
| 373 if (fields == null || fields.isEmpty) return; |
| 374 _constructorFields = []; |
| 375 for (var each in fields) { |
| 376 var field = new _Field(each, this)..usedInConstructor = true; |
| 377 allFields[each] = field; |
| 378 _constructorFields.add(field); |
| 379 } |
| 380 invalidate(); |
| 381 } |
| 382 |
| 383 /** Set the fields that aren't used in the constructor. */ |
| 384 set regular(List<String> fields) { |
| 385 if (fields == null) return; |
| 386 _shouldFigureOutFields = false; |
| 387 addAllByName(fields); |
| 388 } |
| 389 |
| 390 /** Set the fields to be excluded. This is mutually exclusive with setting |
| 391 * the regular fields. |
| 392 */ |
| 393 set exclude(List<String> fields) { |
| 394 // TODO(alanknight): This isn't well tested. |
| 395 if (fields == null || fields.isEmpty) return; |
| 396 if (allFields.length > _constructorFields.length) { |
| 397 throw "You can't specify both excludeFields and regular fields"; |
| 398 } |
| 399 _excludeFields = fields; |
| 400 } |
| 401 |
| 402 int get length => allFields.length; |
| 403 |
| 404 /** Add all the fields which aren't on the exclude list. */ |
| 405 void addAllNotExplicitlyExcluded(List<String> aCollection) { |
| 406 if (aCollection == null) return; |
| 407 var names = aCollection; |
| 408 names = names.filter((x) => x is String && !_excludeFields.contains(x)); |
| 409 addAllByName(names); |
| 410 } |
| 411 |
| 412 /** Add all the fields with the given names without any special properties. */ |
| 413 void addAllByName(List<String> names) { |
| 414 for (var each in names) { |
| 415 allFields.putIfAbsent(each, () => new _Field(each, this)); |
| 416 } |
| 417 invalidate(); |
| 418 } |
| 419 |
| 420 /** |
| 421 * Fields have been added. In case we had already forced calculation of the |
| 422 * list of contents, re-set it. |
| 423 */ |
| 424 void invalidate() { |
| 425 _contents = null; |
| 426 contents; |
| 427 } |
| 428 |
| 429 Iterator iterator() => contents.iterator(); |
| 430 |
| 431 /** Return a cached, sorted list of all the fields. */ |
| 432 List<_Field> get contents { |
| 433 if (_contents == null) { |
| 434 _contents = sorted(allFields.values); |
| 435 for (var i = 0; i < _contents.length; i++) |
| 436 _contents[i].index = i; |
| 437 } |
| 438 return _contents; |
| 439 } |
| 440 |
| 441 /** Iterate over the regular fields, i.e. those not used in the constructor.*/ |
| 442 void forEachRegularField(Function f) { |
| 443 for (var each in contents) { |
| 444 if (each.isRegular) { |
| 445 f(each); |
| 446 } |
| 447 } |
| 448 } |
| 449 |
| 450 /** Iterate over the fields used in the constructor. */ |
| 451 void forEachConstructorField(Function f) { |
| 452 for (var each in contents) { |
| 453 if (each.usedInConstructor) { |
| 454 f(each); |
| 455 } |
| 456 } |
| 457 } |
| 458 |
| 459 List get constructorFields => _constructorFields; |
| 460 List constructorFieldNames() => constructorFields.map((x) => x.name); |
| 461 List constructorFieldIndices() => constructorFields.map((x) => x.index); |
| 462 List regularFields() => contents.filter((x) => !x.usedInConstructor); |
| 463 List regularFieldNames() => regularFields().map((x) => x.name); |
| 464 List regularFieldIndices() => regularFields().map((x) => x.index); |
| 465 |
| 466 |
| 467 /** |
| 468 * If we weren't given any non-constructor fields to use, figure out what |
| 469 * we think they ought to be, based on the class definition. |
| 470 * We find public fields, getters that have corresponding setters, and getters |
| 471 * that are listed in the constructor fields. |
| 472 */ |
| 473 void figureOutFields() { |
| 474 List names(Collection<DeclarationMirror> mirrors) => |
| 475 mirrors.map((each) => each.simpleName); |
| 476 |
| 477 if (!_shouldFigureOutFields || !regularFields().isEmpty) return; |
| 478 var publicFields = publicFields(mirror); |
| 479 var getters = publicGetters(mirror); |
| 480 var gettersWithSetters = getters.filter( (each) |
| 481 => mirror.setters["${each.simpleName}="] != null); |
| 482 var gettersThatMatchConstructor = getters.filter((each) |
| 483 => (named(each.simpleName) != null) && |
| 484 (named(each.simpleName).usedInConstructor)); |
| 485 addAllNotExplicitlyExcluded(names(publicFields)); |
| 486 addAllNotExplicitlyExcluded(names(gettersWithSetters)); |
| 487 addAllNotExplicitlyExcluded(names(gettersThatMatchConstructor)); |
| 488 } |
| 489 } |
| 490 |
| 491 /** |
| 492 * Provide a typedef for the setWith argument to specialTreatmentFor. It would |
| 493 * be nice if we could put this closer to the definition. |
| 494 */ |
| 495 typedef SetWithFunction(InstanceMirror m, Object o); |
| 496 |
| 497 /** |
| 498 * This represents a constructor that is to be used when re-creating a |
| 499 * serialized object. |
| 500 */ |
| 501 class Constructor { |
| 502 /** The mirror of the class we construct. */ |
| 503 final ClassMirror type; |
| 504 |
| 505 /** The name of the constructor to use, if not the default constructor.*/ |
| 506 String name; |
| 507 |
| 508 /** |
| 509 * The indices of the fields used as constructor arguments. We will look |
| 510 * these up in the state by number. These correspond to the index in the |
| 511 * [contents] of the FieldList, which will be alphabetically sorted. |
| 512 */ |
| 513 List<int> fieldNumbers; |
| 514 |
| 515 /** |
| 516 * Creates a new constructor for the [type] with the constructor named [name] |
| 517 * and the [fieldNumbers] of the constructor fields. |
| 518 */ |
| 519 Constructor(this.type, this.name, this.fieldNumbers) { |
| 520 if (name == null) name = ''; |
| 521 if (fieldNumbers == null) fieldNumbers = const []; |
| 522 } |
| 523 |
| 524 /** |
| 525 * Find the field values in [state] and pass them to the constructor. |
| 526 * If any of [fieldNumbers] is not an int, then use it as a literal value. |
| 527 */ |
| 528 constructFrom(state, Reader r) { |
| 529 // TODO(alanknight): Handle named parameters |
| 530 Collection inflated = fieldNumbers.map( |
| 531 (x) => (x is int) ? reflect(r.inflateReference(state[x])) : reflect(x)); |
| 532 var result = type.newInstance(name, inflated); |
| 533 return result.value; |
| 534 } |
| 535 } |
| 536 |
| 537 /** |
| 538 * This wraps a map to make it indexable by integer field numbers. It translates |
| 539 * from the index into a field name and then looks it up in the map. |
| 540 */ |
| 541 class _MapWrapper { |
| 542 Map<String, dynamic> _map = new Map<String, dynamic>(); |
| 543 List fieldList; |
| 544 _MapWrapper(this.fieldList); |
| 545 _MapWrapper.fromMap(this._map, this.fieldList); |
| 546 |
| 547 operator [](key) => _map[fieldList[key].name]; |
| 548 operator []=(key, value) { _map[fieldList[key].name] = value; } |
| 549 get length => _map.length; |
| 550 |
| 551 asMap() => _map; |
| 552 } |
| OLD | NEW |