| OLD | NEW |
| 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 /** | 7 /** |
| 8 * This writes out the state of the objects to an external format. It holds | 8 * This writes out the state of the objects to an external format. It holds |
| 9 * all of the intermediate state needed. The primary API for it is the | 9 * all of the intermediate state needed. The primary API for it is the |
| 10 * [write] method. | 10 * [write] method. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 * the full set of objects to be written.*/ | 24 * the full set of objects to be written.*/ |
| 25 Trace trace; | 25 Trace trace; |
| 26 | 26 |
| 27 /** | 27 /** |
| 28 * When we write out objects, should we also write out a description | 28 * When we write out objects, should we also write out a description |
| 29 * of the rules for the serialization. This defaults to the corresponding | 29 * of the rules for the serialization. This defaults to the corresponding |
| 30 * value on the Serialization. | 30 * value on the Serialization. |
| 31 */ | 31 */ |
| 32 bool selfDescribing; | 32 bool selfDescribing; |
| 33 | 33 |
| 34 Format format = new SimpleMapFormat(); | 34 final Format format; |
| 35 | 35 |
| 36 /** | 36 /** |
| 37 * Objects that cannot be represented in-place in the serialized form need | 37 * Objects that cannot be represented in-place in the serialized form need |
| 38 * to have references to them stored. The [Reference] objects are computed | 38 * to have references to them stored. The [Reference] objects are computed |
| 39 * once and stored here for each object. This provides some space-saving, | 39 * once and stored here for each object. This provides some space-saving, |
| 40 * but also serves to record which objects we have already seen. | 40 * but also serves to record which objects we have already seen. |
| 41 */ | 41 */ |
| 42 final Map<dynamic, Reference> references = | 42 final Map<dynamic, Reference> references = |
| 43 new IdentityMap<Object, Reference>(); | 43 new IdentityMap<Object, Reference>(); |
| 44 | 44 |
| 45 /** | 45 /** |
| 46 * The state of objects that need to be serialized is stored here. | 46 * The state of objects that need to be serialized is stored here. |
| 47 * Each rule has a number, and rules keep track of the objects that they | 47 * Each rule has a number, and rules keep track of the objects that they |
| 48 * serialize, in order. So the state of any object can be found by indexing | 48 * serialize, in order. So the state of any object can be found by indexing |
| 49 * from the rule number and the object number within the rule. | 49 * from the rule number and the object number within the rule. |
| 50 * The actual representation of the state is determined by the rule. Lists | 50 * The actual representation of the state is determined by the rule. Lists |
| 51 * and Maps are common, but it is arbitrary. | 51 * and Maps are common, but it is arbitrary. |
| 52 */ | 52 */ |
| 53 final List<List> states = new List<List>(); | 53 final List<List> states = new List<List>(); |
| 54 | 54 |
| 55 /** Return the list of rules we use. */ | 55 /** Return the list of rules we use. */ |
| 56 List<SerializationRule> get rules => serialization._rules; | 56 List<SerializationRule> get rules => serialization.rules; |
| 57 | 57 |
| 58 /** | 58 /** |
| 59 * Creates a new [Writer] that uses the rules from its parent | 59 * Creates a new [Writer] that uses the rules from its parent |
| 60 * [Serialization]. Serializations do not keep any state | 60 * [Serialization]. Serializations do not keep any state |
| 61 * related to a particular read/write, so the same one can be used | 61 * related to a particular read/write, so the same one can be used |
| 62 * for multiple different Readers/Writers. | 62 * for multiple different Readers/Writers. |
| 63 */ | 63 */ |
| 64 Writer(this.serialization, [Format newFormat]) { | 64 Writer(this.serialization, [Format newFormat]) : |
| 65 format = (newFormat == null) ? const SimpleMapFormat() : newFormat { |
| 65 trace = new Trace(this); | 66 trace = new Trace(this); |
| 66 selfDescribing = serialization.selfDescribing; | 67 selfDescribing = serialization.selfDescribing; |
| 67 if (newFormat != null) format = newFormat; | |
| 68 } | 68 } |
| 69 | 69 |
| 70 /** | 70 /** |
| 71 * This is the main API for a [Writer]. It writes the objects and returns | 71 * This is the main API for a [Writer]. It writes the objects and returns |
| 72 * the serialized representation, as determined by [format]. | 72 * the serialized representation, as determined by [format]. |
| 73 */ | 73 */ |
| 74 write(anObject) { | 74 write(anObject) { |
| 75 trace.addRoot(anObject); | 75 trace.addRoot(anObject); |
| 76 trace.traceAll(); | 76 trace.traceAll(); |
| 77 _flatten(); | 77 _flatten(); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 138 | 138 |
| 139 /** | 139 /** |
| 140 * Returns a serialized version of the [SerializationRule]s used to write | 140 * Returns a serialized version of the [SerializationRule]s used to write |
| 141 * the data, if [selfDescribing] is true, otherwise returns null. | 141 * the data, if [selfDescribing] is true, otherwise returns null. |
| 142 */ | 142 */ |
| 143 serializedRules() { | 143 serializedRules() { |
| 144 if (!selfDescribing) return null; | 144 if (!selfDescribing) return null; |
| 145 var meta = serialization.ruleSerialization(); | 145 var meta = serialization.ruleSerialization(); |
| 146 var writer = new Writer(meta, format); | 146 var writer = new Writer(meta, format); |
| 147 writer.selfDescribing = false; | 147 writer.selfDescribing = false; |
| 148 return writer.write(serialization._rules); | 148 return writer.write(serialization.rules); |
| 149 } | 149 } |
| 150 | 150 |
| 151 /** Record a [state] entry for a particular rule. */ | 151 /** Record a [state] entry for a particular rule. */ |
| 152 void _addStateForRule(eachRule, state) { | 152 void _addStateForRule(eachRule, state) { |
| 153 _growStates(eachRule); | 153 _growStates(eachRule); |
| 154 states[eachRule.number].add(state); | 154 states[eachRule.number].add(state); |
| 155 } | 155 } |
| 156 | 156 |
| 157 /** Find what the object number for the thing we're about to add will be.*/ | 157 /** Find what the object number for the thing we're about to add will be.*/ |
| 158 int _nextObjectNumberFor(SerializationRule rule) { | 158 int _nextObjectNumberFor(SerializationRule rule) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 190 */ | 190 */ |
| 191 int _objectNumberFor(object) { | 191 int _objectNumberFor(object) { |
| 192 var reference = references[object]; | 192 var reference = references[object]; |
| 193 return (reference == null) ? -1 : reference.objectNumber; | 193 return (reference == null) ? -1 : reference.objectNumber; |
| 194 } | 194 } |
| 195 | 195 |
| 196 /** | 196 /** |
| 197 * Return a list of [Reference] objects pointing to our roots. This will be | 197 * Return a list of [Reference] objects pointing to our roots. This will be |
| 198 * stored in the output under "roots" in the default format. | 198 * stored in the output under "roots" in the default format. |
| 199 */ | 199 */ |
| 200 _rootReferences() => trace.roots.map(_referenceFor).toList(); | 200 List _rootReferences() => trace.roots.map(_referenceFor).toList(); |
| 201 | 201 |
| 202 /** | 202 /** |
| 203 * Given an object, return a reference for it if one exists. If there's | 203 * Given an object, return a reference for it if one exists. If there's |
| 204 * no reference, return the object itself. Once we have finished the tracing | 204 * no reference, return the object itself. Once we have finished the tracing |
| 205 * step, all objects that should have a reference (roughly speaking, | 205 * step, all objects that should have a reference (roughly speaking, |
| 206 * non-primitives) can be relied on to have a reference. | 206 * non-primitives) can be relied on to have a reference. |
| 207 */ | 207 */ |
| 208 _referenceFor(object) { | 208 _referenceFor(object) { |
| 209 var result = references[object]; | 209 var result = references[object]; |
| 210 return (result == null) ? object : result; | 210 return (result == null) ? object : result; |
| 211 } | 211 } |
| 212 | 212 |
| 213 /** | 213 /** |
| 214 * Return true if the [Serialization.namedObjects] collection has a | 214 * Return true if the [Serialization.namedObjects] collection has a |
| 215 * reference to [object]. | 215 * reference to [object]. |
| 216 */ | 216 */ |
| 217 // TODO(alanknight): Should the writer also have its own namedObjects | 217 // TODO(alanknight): Should the writer also have its own namedObjects |
| 218 // collection specific to the particular write, or is that just adding | 218 // collection specific to the particular write, or is that just adding |
| 219 // complexity for little value? | 219 // complexity for little value? |
| 220 hasNameFor(object) => serialization._hasNameFor(object); | 220 bool hasNameFor(object) => serialization._hasNameFor(object); |
| 221 | 221 |
| 222 /** | 222 /** |
| 223 * Return the name we have for this object in the [Serialization.namedObjects] | 223 * Return the name we have for this object in the [Serialization.namedObjects] |
| 224 * collection. | 224 * collection. |
| 225 */ | 225 */ |
| 226 nameFor(object) => serialization._nameFor(object); | 226 String nameFor(object) => serialization._nameFor(object); |
| 227 | 227 |
| 228 // For debugging/testing purposes. Find what state a reference points to. | 228 // For debugging/testing purposes. Find what state a reference points to. |
| 229 stateForReference(Reference r) => states[r.ruleNumber][r.objectNumber]; | 229 stateForReference(Reference r) => states[r.ruleNumber][r.objectNumber]; |
| 230 | 230 |
| 231 /** Return the state pointed to by [reference]. */ | 231 /** Return the state pointed to by [reference]. */ |
| 232 resolveReference(reference) => stateForReference(reference); | 232 resolveReference(reference) => stateForReference(reference); |
| 233 } | 233 } |
| 234 | 234 |
| 235 /** | 235 /** |
| 236 * An abstract class for Reader and Writer, which primarily exists so we can | 236 * An abstract class for Reader and Writer, which primarily exists so we can |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 278 */ | 278 */ |
| 279 List<List> _data; | 279 List<List> _data; |
| 280 | 280 |
| 281 /** | 281 /** |
| 282 * The resulting objects, indexed according to the same scheme as | 282 * The resulting objects, indexed according to the same scheme as |
| 283 * _data, where each rule has a number, and rules keep track of the objects | 283 * _data, where each rule has a number, and rules keep track of the objects |
| 284 * that they serialize, in order. | 284 * that they serialize, in order. |
| 285 */ | 285 */ |
| 286 List<List> objects; | 286 List<List> objects; |
| 287 | 287 |
| 288 Format format = new SimpleMapFormat(); | 288 final Format format; |
| 289 | 289 |
| 290 /** | 290 /** |
| 291 * Creates a new [Reader] that uses the rules from its parent | 291 * Creates a new [Reader] that uses the rules from its parent |
| 292 * [Serialization]. Serializations do not keep any state related to | 292 * [Serialization]. Serializations do not keep any state related to |
| 293 * a particular read or write operation, so the same one can be used | 293 * a particular read or write operation, so the same one can be used |
| 294 * for multiple different Writers/Readers. | 294 * for multiple different Writers/Readers. |
| 295 */ | 295 */ |
| 296 Reader(this.serialization, [Format newFormat]) { | 296 Reader(this.serialization, [Format newFormat]) : |
| 297 format = (newFormat == null) ? const SimpleMapFormat() : newFormat { |
| 297 selfDescribing = serialization.selfDescribing; | 298 selfDescribing = serialization.selfDescribing; |
| 298 if (newFormat != null) format = newFormat; | |
| 299 } | 299 } |
| 300 | 300 |
| 301 /** | 301 /** |
| 302 * When we read, we may need to look up objects by name in order to link to | 302 * When we read, we may need to look up objects by name in order to link to |
| 303 * them. This is particularly true if we have references to classes, | 303 * them. This is particularly true if we have references to classes, |
| 304 * functions, mirrors, or other non-portable entities. The map in which we | 304 * functions, mirrors, or other non-portable entities. The map in which we |
| 305 * look things up can be provided as an argument to read, but we can also | 305 * look things up can be provided as an argument to read, but we can also |
| 306 * provide a map here, and objects will be looked up in both places. | 306 * provide a map here, and objects will be looked up in both places. |
| 307 */ | 307 */ |
| 308 Map namedObjects; | 308 Map namedObjects; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 322 | 322 |
| 323 void keyNotFound(key) { | 323 void keyNotFound(key) { |
| 324 throw new SerializationException( | 324 throw new SerializationException( |
| 325 'Cannot find named object to link to: $key'); | 325 'Cannot find named object to link to: $key'); |
| 326 } | 326 } |
| 327 | 327 |
| 328 /** | 328 /** |
| 329 * Return the list of rules to be used when writing. These come from the | 329 * Return the list of rules to be used when writing. These come from the |
| 330 * [serialization]. | 330 * [serialization]. |
| 331 */ | 331 */ |
| 332 List<SerializationRule> get rules => serialization._rules; | 332 List<SerializationRule> get rules => serialization.rules; |
| 333 | 333 |
| 334 /** | 334 /** |
| 335 * Internal use only, for testing purposes. Set the data for this reader | 335 * Internal use only, for testing purposes. Set the data for this reader |
| 336 * to a List of Lists whose size must match the number of rules. | 336 * to a List of Lists whose size must match the number of rules. |
| 337 */ | 337 */ |
| 338 // When we set the data, initialize the object storage to a matching size. | 338 // When we set the data, initialize the object storage to a matching size. |
| 339 void set data(List<List> newData) { | 339 void set data(List<List> newData) { |
| 340 _data = newData; | 340 _data = newData; |
| 341 objects = _data.map((x) => new List(x.length)).toList(); | 341 objects = _data.map((x) => new List(x.length)).toList(); |
| 342 } | 342 } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 367 rulesWeRead.forEach(serialization.addRule); | 367 rulesWeRead.forEach(serialization.addRule); |
| 368 } | 368 } |
| 369 } | 369 } |
| 370 | 370 |
| 371 /** | 371 /** |
| 372 * Inflate all of the objects for [rule]. Does the essential state for all | 372 * Inflate all of the objects for [rule]. Does the essential state for all |
| 373 * objects first, then the non-essential state. This avoids cycles in | 373 * objects first, then the non-essential state. This avoids cycles in |
| 374 * non-essential state, because all the objects will have already been | 374 * non-essential state, because all the objects will have already been |
| 375 * created. | 375 * created. |
| 376 */ | 376 */ |
| 377 inflateForRule(rule) { | 377 void inflateForRule(rule) { |
| 378 var dataForThisRule = _data[rule.number]; | 378 var dataForThisRule = _data[rule.number]; |
| 379 keysAndValues(dataForThisRule).forEach((position, state) { | 379 keysAndValues(dataForThisRule).forEach((position, state) { |
| 380 inflateOne(rule, position, state); | 380 inflateOne(rule, position, state); |
| 381 }); | 381 }); |
| 382 keysAndValues(dataForThisRule).forEach((position, state) { | 382 keysAndValues(dataForThisRule).forEach((position, state) { |
| 383 rule.inflateNonEssential(state, allObjectsForRule(rule)[position], this); | 383 rule.inflateNonEssential(state, allObjectsForRule(rule)[position], this); |
| 384 }); | 384 }); |
| 385 } | 385 } |
| 386 | 386 |
| 387 /** | 387 /** |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 435 | 435 |
| 436 /** Given [rule], return the storage for its objects. */ | 436 /** Given [rule], return the storage for its objects. */ |
| 437 allObjectsForRule(SerializationRule rule) => objects[rule.number]; | 437 allObjectsForRule(SerializationRule rule) => objects[rule.number]; |
| 438 | 438 |
| 439 /** Given [reference], return the the state we have stored for it. */ | 439 /** Given [reference], return the the state we have stored for it. */ |
| 440 _stateFor(Reference reference) => | 440 _stateFor(Reference reference) => |
| 441 _data[reference.ruleNumber][reference.objectNumber]; | 441 _data[reference.ruleNumber][reference.objectNumber]; |
| 442 | 442 |
| 443 /** Given a reference, return the rule it references. */ | 443 /** Given a reference, return the rule it references. */ |
| 444 SerializationRule ruleFor(Reference reference) => | 444 SerializationRule ruleFor(Reference reference) => |
| 445 serialization._rules[reference.ruleNumber]; | 445 serialization.rules[reference.ruleNumber]; |
| 446 | 446 |
| 447 /** | 447 /** |
| 448 * Return the primitive rule we are using. This is an ugly mechanism to | 448 * Return the primitive rule we are using. This is an ugly mechanism to |
| 449 * support the extra information to reconstruct objects in the | 449 * support the extra information to reconstruct objects in the |
| 450 * [SimpleJsonFormat]. | 450 * [SimpleJsonFormat]. |
| 451 */ | 451 */ |
| 452 SerializationRule _primitiveRule() { | 452 SerializationRule _primitiveRule() { |
| 453 for (var each in rules) { | 453 for (var each in rules) { |
| 454 if (each.runtimeType == PrimitiveRule) { | 454 if (each.runtimeType == PrimitiveRule) { |
| 455 return each; | 455 return each; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 498 // this as a separate class? | 498 // this as a separate class? |
| 499 final Writer writer; | 499 final Writer writer; |
| 500 | 500 |
| 501 /** | 501 /** |
| 502 * This class works by doing a breadth-first traversal of the objects, | 502 * This class works by doing a breadth-first traversal of the objects, |
| 503 * with the traversal order maintained in [queue]. | 503 * with the traversal order maintained in [queue]. |
| 504 */ | 504 */ |
| 505 final Queue queue = new Queue(); | 505 final Queue queue = new Queue(); |
| 506 | 506 |
| 507 /** The root objects from which we will be tracing. */ | 507 /** The root objects from which we will be tracing. */ |
| 508 List roots = []; | 508 final List roots = []; |
| 509 | 509 |
| 510 Trace(this.writer); | 510 Trace(this.writer); |
| 511 | 511 |
| 512 addRoot(object) { | 512 addRoot(object) { |
| 513 roots.add(object); | 513 roots.add(object); |
| 514 } | 514 } |
| 515 | 515 |
| 516 /** A convenience method to add a single root and trace it in one step. */ | 516 /** A convenience method to add a single root and trace it in one step. */ |
| 517 trace(object) { | 517 trace(object) { |
| 518 addRoot(object); | 518 addRoot(object); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 578 */ | 578 */ |
| 579 inflated() => parent.resolveReference(this); | 579 inflated() => parent.resolveReference(this); |
| 580 | 580 |
| 581 /** | 581 /** |
| 582 * Convert the reference to a map in JSON format. This is specific to the | 582 * Convert the reference to a map in JSON format. This is specific to the |
| 583 * custom JSON format we define, and must be consistent with the | 583 * custom JSON format we define, and must be consistent with the |
| 584 * [Reader.asReference] method. | 584 * [Reader.asReference] method. |
| 585 */ | 585 */ |
| 586 // TODO(alanknight): This is a hack both in defining a toJson specific to a | 586 // TODO(alanknight): This is a hack both in defining a toJson specific to a |
| 587 // particular representation, and the use of a bogus sentinel "__Ref" | 587 // particular representation, and the use of a bogus sentinel "__Ref" |
| 588 toJson() => { | 588 Map<String, dynamic> toJson() => { |
| 589 "__Ref" : true, | 589 "__Ref" : true, |
| 590 "rule" : ruleNumber, | 590 "rule" : ruleNumber, |
| 591 "object" : objectNumber | 591 "object" : objectNumber |
| 592 }; | 592 }; |
| 593 | 593 |
| 594 /** Write our information to [list]. Useful in writing to flat formats.*/ | 594 /** Write our information to [list]. Useful in writing to flat formats.*/ |
| 595 writeToList(List list) { | 595 void writeToList(List list) { |
| 596 list.add(ruleNumber); | 596 list.add(ruleNumber); |
| 597 list.add(objectNumber); | 597 list.add(objectNumber); |
| 598 } | 598 } |
| 599 | 599 |
| 600 toString() => "Reference($ruleNumber, $objectNumber)"; | 600 String toString() => "Reference($ruleNumber, $objectNumber)"; |
| 601 } | 601 } |
| 602 | 602 |
| 603 /** | 603 /** |
| 604 * This is used during tracing to indicate that an object should be processed | 604 * This is used during tracing to indicate that an object should be processed |
| 605 * using a particular rule, rather than the one that might ordinarily be | 605 * using a particular rule, rather than the one that might ordinarily be |
| 606 * found for it. This normally only makes sense if the object is uniquely | 606 * found for it. This normally only makes sense if the object is uniquely |
| 607 * referenced, and is a more or less internal collection. See ListRuleEssential | 607 * referenced, and is a more or less internal collection. See ListRuleEssential |
| 608 * for an example. It knows how to return its object and how to filter. | 608 * for an example. It knows how to return its object and how to filter. |
| 609 */ | 609 */ |
| 610 class DesignatedRuleForObject { | 610 class DesignatedRuleForObject { |
| 611 Function rulePredicate; | 611 final Function rulePredicate; |
| 612 final target; | 612 final target; |
| 613 | 613 |
| 614 DesignatedRuleForObject(this.target, this.rulePredicate); | 614 DesignatedRuleForObject(this.target, this.rulePredicate); |
| 615 | 615 |
| 616 possibleRules(List rules) => rules.where(rulePredicate).toList(); | 616 List possibleRules(List rules) => rules.where(rulePredicate).toList(); |
| 617 } | 617 } |
| OLD | NEW |