Chromium Code Reviews| 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 19 matching lines...) Expand all Loading... | |
| 30 * value on the Serialization. | 30 * value on the Serialization. |
| 31 */ | 31 */ |
| 32 bool selfDescribing; | 32 bool selfDescribing; |
| 33 | 33 |
| 34 /** | 34 /** |
| 35 * Objects that cannot be represented in-place in the serialized form need | 35 * Objects that cannot be represented in-place in the serialized form need |
| 36 * to have references to them stored. The [Reference] objects are computed | 36 * to have references to them stored. The [Reference] objects are computed |
| 37 * once and stored here for each object. This provides some space-saving, | 37 * once and stored here for each object. This provides some space-saving, |
| 38 * but also serves to record which objects we have already seen. | 38 * but also serves to record which objects we have already seen. |
| 39 */ | 39 */ |
| 40 final Map<Object, Reference> references = | 40 final Map<dynamic, Reference> references = |
| 41 new IdentityMapPlus<Object, Reference>(); | 41 new IdentityMapPlus<dynamic, Reference>(); |
| 42 | 42 |
| 43 /** | 43 /** |
| 44 * The state of objects that need to be serialized is stored here. | 44 * The state of objects that need to be serialized is stored here. |
| 45 * Each rule has a number, and rules keep track of the objects that they | 45 * Each rule has a number, and rules keep track of the objects that they |
| 46 * serialize, in order. So the state of any object can be found by indexing | 46 * serialize, in order. So the state of any object can be found by indexing |
| 47 * from the rule number and the object number within the rule. | 47 * from the rule number and the object number within the rule. |
| 48 * The actual representation of the state is determined by the rule. Lists | 48 * The actual representation of the state is determined by the rule. Lists |
| 49 * and Maps are common, but it is arbitrary. | 49 * and Maps are common, but it is arbitrary. |
| 50 */ | 50 */ |
| 51 final List<List> states = new List<List>(); | 51 final List<List> states = new List<List>(); |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 140 } | 140 } |
| 141 } | 141 } |
| 142 | 142 |
| 143 /** | 143 /** |
| 144 * As the [trace] processes each object, it will call this method on us. | 144 * As the [trace] processes each object, it will call this method on us. |
| 145 * We find the rules for this object, and record the state of the object | 145 * We find the rules for this object, and record the state of the object |
| 146 * as determined by each rule. | 146 * as determined by each rule. |
| 147 */ | 147 */ |
| 148 void _process(object, Trace trace) { | 148 void _process(object, Trace trace) { |
| 149 var real = (object is DesignatedRuleForObject) ? object.target : object; | 149 var real = (object is DesignatedRuleForObject) ? object.target : object; |
| 150 for (var eachRule in serialization.rulesFor(object)) { | 150 for (var eachRule in serialization.rulesFor(object, this)) { |
| 151 _record(real, eachRule); | 151 _record(real, eachRule); |
| 152 } | 152 } |
| 153 } | 153 } |
| 154 | 154 |
| 155 /** | 155 /** |
| 156 * Record the state of [object] as determined by [rule] and keep | 156 * Record the state of [object] as determined by [rule] and keep |
| 157 * track of it. Generate a [Reference] for this object if required. | 157 * track of it. Generate a [Reference] for this object if required. |
| 158 * When it's required is up to the particular rule, but generally everything | 158 * When it's required is up to the particular rule, but generally everything |
| 159 * gets a reference except a primitive. | 159 * gets a reference except a primitive. |
| 160 * Note that at this point the states are just the same as the fields of the | 160 * Note that at this point the states are just the same as the fields of the |
| 161 * object, and haven't been flattened. | 161 * object, and haven't been flattened. |
| 162 */ | 162 */ |
| 163 void _record(Object object, SerializationRule rule) { | 163 void _record(object, SerializationRule rule) { |
| 164 if (rule.shouldUseReferenceFor(object, this)) { | 164 if (rule.shouldUseReferenceFor(object, this)) { |
| 165 references.putIfAbsent(object, () => | 165 references.putIfAbsent(object, () => |
| 166 new Reference(this, rule.number, _nextObjectNumberFor(rule))); | 166 new Reference(this, rule.number, _nextObjectNumberFor(rule))); |
| 167 var state = rule.extractState(object, trace.note); | 167 var state = rule.extractState(object, trace.note); |
| 168 _addStateForRule(rule, state); | 168 _addStateForRule(rule, state); |
| 169 } | 169 } |
| 170 } | 170 } |
| 171 | 171 |
| 172 /** | 172 /** |
| 173 * Should we store primitive objects directly or create references for them. | 173 * Should we store primitive objects directly or create references for them. |
| 174 * That depends on which format we're using, so a flat format will want | 174 * That depends on which format we're using, so a flat format will want |
| 175 * references, but the Map format can store them directly. | 175 * references, but the Map format can store them directly. |
| 176 */ | 176 */ |
| 177 bool shouldUseReferencesForPrimitives = false; | 177 bool shouldUseReferencesForPrimitives = false; |
| 178 | 178 |
| 179 /** Record a [state] entry for a particular rule. */ | 179 /** Record a [state] entry for a particular rule. */ |
| 180 void _addStateForRule(eachRule, Object state) { | 180 void _addStateForRule(eachRule, state) { |
| 181 _growStates(eachRule); | 181 _growStates(eachRule); |
| 182 states[eachRule.number].add(state); | 182 states[eachRule.number].add(state); |
| 183 } | 183 } |
| 184 | 184 |
| 185 /** Find what the object number for the thing we're about to add will be.*/ | 185 /** Find what the object number for the thing we're about to add will be.*/ |
| 186 int _nextObjectNumberFor(SerializationRule rule) { | 186 int _nextObjectNumberFor(SerializationRule rule) { |
| 187 _growStates(rule); | 187 _growStates(rule); |
| 188 return states[rule.number].length; | 188 return states[rule.number].length; |
| 189 } | 189 } |
| 190 | 190 |
| 191 /** | 191 /** |
| 192 * We store the states in a List, indexed by rule number. But rules can be | 192 * We store the states in a List, indexed by rule number. But rules can be |
| 193 * dynamically added, so we may have to grow the list. | 193 * dynamically added, so we may have to grow the list. |
| 194 */ | 194 */ |
| 195 void _growStates(eachRule) { | 195 void _growStates(eachRule) { |
| 196 while (states.length <= eachRule.number) states.add(new List()); | 196 while (states.length <= eachRule.number) states.add(new List()); |
| 197 } | 197 } |
| 198 | 198 |
| 199 /** | 199 /** |
| 200 * Return true if we have an object number for this object. This is used to | 200 * Return true if we have an object number for this object. This is used to |
| 201 * tell if we have processed the object or not. This relies on checking if we | 201 * tell if we have processed the object or not. This relies on checking if we |
| 202 * have a reference or not. That saves some space by not having to keep track | 202 * have a reference or not. That saves some space by not having to keep track |
| 203 * of simple objects, but means that if someone refers to the identical string | 203 * of simple objects, but means that if someone refers to the identical string |
| 204 * from several places, we will process it several times, and store it | 204 * from several places, we will process it several times, and store it |
| 205 * several times. That seems an acceptable tradeoff, and in cases where it | 205 * several times. That seems an acceptable tradeoff, and in cases where it |
| 206 * isn't, it's possible to apply a rule for String, or even for Strings larger | 206 * isn't, it's possible to apply a rule for String, or even for Strings larger |
| 207 * than x, which gives them references. | 207 * than x, which gives them references. |
| 208 */ | 208 */ |
| 209 bool _hasIndexFor(Object object) { | 209 bool _hasIndexFor(object) { |
| 210 return _objectNumberFor(object) != -1; | 210 return _objectNumberFor(object) != -1; |
| 211 } | 211 } |
| 212 | 212 |
| 213 /** | 213 /** |
| 214 * Given an object, find what number it has. The number is valid only in | 214 * Given an object, find what number it has. The number is valid only in |
| 215 * the context of a particular rule, and if the rule has more than one, | 215 * the context of a particular rule, and if the rule has more than one, |
| 216 * this will return the one for the primary rule, defined as the one that | 216 * this will return the one for the primary rule, defined as the one that |
| 217 * is listed in its canonical reference. | 217 * is listed in its canonical reference. |
| 218 */ | 218 */ |
| 219 int _objectNumberFor(Object object) { | 219 int _objectNumberFor(object) { |
| 220 var reference = references[object]; | 220 var reference = references[object]; |
| 221 return (reference == null) ? -1 : reference.objectNumber; | 221 return (reference == null) ? -1 : reference.objectNumber; |
| 222 } | 222 } |
| 223 | 223 |
| 224 /** | 224 /** |
| 225 * Return the serialized data in string format. Currently hard-coded to | 225 * Return the serialized data in string format. Currently hard-coded to |
| 226 * our custom JSON format. | 226 * our custom JSON format. |
| 227 */ | 227 */ |
| 228 String toStringFormat() { | 228 String toStringFormat() { |
| 229 return JSON.stringify(toMaps()); | 229 return JSON.stringify(toMaps()); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 261 */ | 261 */ |
| 262 _rootReferences(roots) => | 262 _rootReferences(roots) => |
| 263 roots.map(_referenceFor); | 263 roots.map(_referenceFor); |
| 264 | 264 |
| 265 /** | 265 /** |
| 266 * Given an object, return a reference for it if one exists. If there's | 266 * Given an object, return a reference for it if one exists. If there's |
| 267 * no reference, return null. Once we have finished the tracing step, all | 267 * no reference, return null. Once we have finished the tracing step, all |
| 268 * objects that should have a reference (roughly speaking, non-primitives) | 268 * objects that should have a reference (roughly speaking, non-primitives) |
| 269 * can be relied on to have a reference. | 269 * can be relied on to have a reference. |
| 270 */ | 270 */ |
| 271 _referenceFor(Object o) { | 271 _referenceFor(object) { |
| 272 return references[o]; | 272 return references[object]; |
|
Jennifer Messerly
2012/12/12 20:38:28
totally optional, but this could be:
_referenceF
Alan Knight
2012/12/12 21:19:33
Done.
| |
| 273 } | 273 } |
| 274 | 274 |
| 275 /** | |
| 276 * Return true if the [namedObjects] collection has a reference to [object]. | |
| 277 */ | |
| 278 // TODO(alanknight): Should the writer also have its own namedObjects | |
| 279 // collection specific to the particular write, or is that just adding | |
| 280 // complexity for little value? | |
| 281 hasNameFor(object) => serialization._hasNameFor(object); | |
| 282 | |
| 283 /** | |
| 284 * Return the name we have for this object in the [namedObjects] collection. | |
| 285 */ | |
| 286 nameFor(object) => serialization._nameFor(object); | |
| 287 | |
| 275 // For debugging/testing purposes. Find what state a reference points to. | 288 // For debugging/testing purposes. Find what state a reference points to. |
| 276 stateForReference(Reference r) => | 289 stateForReference(Reference r) => states[r.ruleNumber][r.objectNumber]; |
| 277 states[r.ruleNumber][r.objectNumber]; | |
| 278 } | 290 } |
| 279 | 291 |
| 280 /** | 292 /** |
| 281 * The main class responsible for reading. It holds | 293 * The main class responsible for reading. It holds |
| 282 * onto the necessary state and to the objects that have been inflated. | 294 * onto the necessary state and to the objects that have been inflated. |
| 283 */ | 295 */ |
| 284 class Reader { | 296 class Reader { |
| 285 | 297 |
| 286 /** | 298 /** |
| 287 * The serialization that specifies how we read. Note that in contrast | 299 * The serialization that specifies how we read. Note that in contrast |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 324 selfDescribing = serialization.selfDescribing; | 336 selfDescribing = serialization.selfDescribing; |
| 325 } | 337 } |
| 326 | 338 |
| 327 /** | 339 /** |
| 328 * When we read, we may need to look up objects by name in order to link to | 340 * When we read, we may need to look up objects by name in order to link to |
| 329 * them. This is particularly true if we have references to classes, | 341 * them. This is particularly true if we have references to classes, |
| 330 * functions, mirrors, or other non-portable entities. The map in which we | 342 * functions, mirrors, or other non-portable entities. The map in which we |
| 331 * look things up can be provided as an argument to read, but we can also | 343 * look things up can be provided as an argument to read, but we can also |
| 332 * provide a map here, and objects will be looked up in both places. | 344 * provide a map here, and objects will be looked up in both places. |
| 333 */ | 345 */ |
| 334 Map externalObjects; | 346 Map namedObjects; |
| 335 | 347 |
| 336 /** | 348 /** |
| 337 * Look up the reference to an external object. This can be held either in | 349 * Look up the reference to an external object. This can be held either in |
| 338 * the reader-specific list of externals or in the serializer's | 350 * the reader-specific list of externals or in the serializer's |
| 339 */ | 351 */ |
| 340 externalObjectNamed(key) { | 352 objectNamed(key) { |
| 341 var map = (externalObjects.containsKey(key)) | 353 var map = (namedObjects.containsKey(key)) |
| 342 ? externalObjects : serialization.externalObjects; | 354 ? namedObjects : serialization.namedObjects; |
| 343 if (!map.containsKey(key)) { | 355 if (!map.containsKey(key)) { |
| 344 throw 'Cannot find named object to link to: $key'; | 356 throw 'Cannot find named object to link to: $key'; |
| 345 } | 357 } |
| 346 return map[key]; | 358 return map[key]; |
| 347 } | 359 } |
| 348 | 360 |
| 349 /** | 361 /** |
| 350 * Return the list of rules to be used when writing. These come from the | 362 * Return the list of rules to be used when writing. These come from the |
| 351 * [serialization]. | 363 * [serialization]. |
| 352 */ | 364 */ |
| 353 List<SerializationRule> get rules => serialization.rules; | 365 List<SerializationRule> get rules => serialization.rules; |
| 354 | 366 |
| 355 /** | 367 /** |
| 356 * Internal use only, for testing purposes. Set the data for this reader | 368 * Internal use only, for testing purposes. Set the data for this reader |
| 357 * to a List of Lists whose size must match the number of rules. | 369 * to a List of Lists whose size must match the number of rules. |
| 358 */ | 370 */ |
| 359 // When we set the data, initialize the object storage to a matching size. | 371 // When we set the data, initialize the object storage to a matching size. |
| 360 void set data(List<List> newData) { | 372 void set data(List<List> newData) { |
| 361 _data = newData; | 373 _data = newData; |
| 362 objects = _data.map((x) => new List(x.length)); | 374 objects = _data.map((x) => new List(x.length)); |
| 363 } | 375 } |
| 364 | 376 |
| 365 /** | 377 /** |
| 366 * This is the primary method for a [Reader]. It takes the input data, | 378 * This is the primary method for a [Reader]. It takes the input data, |
| 367 * currently hard-coded to expect our custom JSON format, and returns | 379 * currently hard-coded to expect our custom JSON format, and returns |
| 368 * the root objects. | 380 * the root object. |
| 369 */ | 381 */ |
| 370 read(String input, [Map externals = const {}]) { | 382 read(String input, [Map externals = const {}]) { |
| 371 externalObjects = externals; | 383 namedObjects = externals; |
| 372 var topLevel = JSON.parse(input); | 384 var topLevel = JSON.parse(input); |
| 373 var ruleString = topLevel["rules"]; | 385 var ruleString = topLevel["rules"]; |
| 374 readRules(ruleString, externals); | 386 readRules(ruleString, externals); |
| 375 data = topLevel["data"]; | 387 data = topLevel["data"]; |
| 376 rules.forEach(inflateForRule); | 388 rules.forEach(inflateForRule); |
| 377 var roots = topLevel["roots"]; | 389 var roots = topLevel["roots"]; |
| 378 return roots.map(inflateReference); | 390 return inflateReference(roots.first); |
| 379 } | 391 } |
| 380 | 392 |
| 381 /** | 393 /** |
| 382 * If the data we are reading from has rules written to it, read them back | 394 * If the data we are reading from has rules written to it, read them back |
| 383 * and set them as the rules we will use. | 395 * and set them as the rules we will use. |
| 384 */ | 396 */ |
| 385 void readRules(String newRules, Map externals) { | 397 void readRules(String newRules, Map externals) { |
| 386 // TODO(alanknight): Replacing the serialization is kind of confusing. | 398 // TODO(alanknight): Replacing the serialization is kind of confusing. |
| 387 List rulesWeRead = (newRules == null) ? | 399 List rulesWeRead = (newRules == null) ? |
| 388 null : serialization._ruleSerialization().readOne(newRules, externals); | 400 null : serialization._ruleSerialization().read(newRules, externals); |
| 389 if (rulesWeRead != null && !rulesWeRead.isEmpty) { | 401 if (rulesWeRead != null && !rulesWeRead.isEmpty) { |
| 390 serialization = new Serialization.blank(); | 402 serialization = new Serialization.blank(); |
| 391 rulesWeRead.forEach(serialization.addRule); | 403 rulesWeRead.forEach(serialization.addRule); |
| 392 } | 404 } |
| 393 } | 405 } |
| 394 | 406 |
| 395 /** | 407 /** |
| 396 * This is a hard-coded read method for a vaguely flat format. It's just a | 408 * This is a hard-coded read method for a vaguely flat format. It's just a |
| 397 * proof of concept of handling more flat formats right now, and needs a lot | 409 * proof of concept of handling more flat formats right now, and needs a lot |
| 398 * of fixing and generalization. | 410 * of fixing and generalization. |
| 399 */ | 411 */ |
| 400 readFlat(List input, [Map externals = const {}]) { | 412 readFlat(List input, [Map externals = const {}]) { |
| 401 // TODO(alanknight): Way too much code duplication with read. Numerous | 413 // TODO(alanknight): Way too much code duplication with read. Numerous |
| 402 // code smells. | 414 // code smells. |
| 403 externalObjects = externals; | 415 namedObjects = externals; |
| 404 var topLevel = input; | 416 var topLevel = input; |
| 405 var ruleString = topLevel[0]; | 417 var ruleString = topLevel[0]; |
| 406 readRules(ruleString, externals); | 418 readRules(ruleString, externals); |
| 407 var flatData = topLevel[1]; | 419 var flatData = topLevel[1]; |
| 408 var stream = flatData.iterator(); | 420 var stream = flatData.iterator(); |
| 409 var tempData = new List(rules.length); | 421 var tempData = new List(rules.length); |
| 410 for (var eachRule in rules) { | 422 for (var eachRule in rules) { |
| 411 tempData[eachRule.number] = eachRule.pullStateFrom(stream); | 423 tempData[eachRule.number] = eachRule.pullStateFrom(stream); |
| 412 } | 424 } |
| 413 data = tempData; | 425 data = tempData; |
| 414 for (var eachRule in rules) { | 426 for (var eachRule in rules) { |
| 415 inflateForRule(eachRule); | 427 inflateForRule(eachRule); |
| 416 } | 428 } |
| 417 var rootsAsInts = topLevel[2]; | 429 var rootsAsInts = topLevel[2]; |
| 418 var rootStream = rootsAsInts.iterator(); | 430 var rootStream = rootsAsInts.iterator(); |
| 419 var roots = new List(); | 431 var roots = new List(); |
| 420 while (rootStream.hasNext) { | 432 while (rootStream.hasNext) { |
| 421 roots.add(new Reference(this, rootStream.next(), rootStream.next())); | 433 roots.add(new Reference(this, rootStream.next(), rootStream.next())); |
| 422 } | 434 } |
| 423 var x = inflateReference(roots[0]); | 435 var x = inflateReference(roots[0]); |
| 424 return roots.map((x) => inflateReference(x)); | 436 return inflateReference(roots.first); |
| 425 } | 437 } |
| 426 | 438 |
| 427 | |
| 428 /** | |
| 429 * A convenient alternative to [read] when you know there is only | |
| 430 * one object. | |
| 431 */ | |
| 432 readOne(String input, [Map externals = const {}]) => | |
| 433 read(input, externals).first; | |
| 434 | |
| 435 /** | |
| 436 * A convenient alternative to [readFlat] when you know there is only | |
| 437 * one object. | |
| 438 */ | |
| 439 readOneFlat(List input, [Map externals = const {}]) => | |
| 440 readFlat(input, externals).first; | |
| 441 | |
| 442 /** | 439 /** |
| 443 * Inflate all of the objects for [rule]. Does the essential state for all | 440 * Inflate all of the objects for [rule]. Does the essential state for all |
| 444 * objects first, then the non-essential state. This avoids cycles in | 441 * objects first, then the non-essential state. This avoids cycles in |
| 445 * non-essential state, because all the objects will have already been | 442 * non-essential state, because all the objects will have already been |
| 446 * created. | 443 * created. |
| 447 */ | 444 */ |
| 448 inflateForRule(rule) { | 445 inflateForRule(rule) { |
| 449 var dataForThisRule = _data[rule.number]; | 446 var dataForThisRule = _data[rule.number]; |
| 450 keysAndValues(dataForThisRule).forEach((position, state) { | 447 keysAndValues(dataForThisRule).forEach((position, state) { |
| 451 inflateOne(rule, position, state); | 448 inflateOne(rule, position, state); |
| 452 }); | 449 }); |
| 453 keysAndValues(dataForThisRule).forEach((position, state) { | 450 keysAndValues(dataForThisRule).forEach((position, state) { |
| 454 rule.inflateNonEssential(state, allObjectsForRule(rule)[position], this); | 451 rule.inflateNonEssential(state, allObjectsForRule(rule)[position], this); |
| 455 }); | 452 }); |
| 456 } | 453 } |
| 457 | 454 |
| 458 /** | 455 /** |
| 459 * Create a new object, based on [rule] and [state], which will | 456 * Create a new object, based on [rule] and [state], which will |
| 460 * be stored in [position] in the storage for [rule]. This will | 457 * be stored in [position] in the storage for [rule]. This will |
| 461 * follow references and recursively inflate them, leaving Sentinel objects | 458 * follow references and recursively inflate them, leaving Sentinel objects |
| 462 * to detect cycles. | 459 * to detect cycles. |
| 463 */ | 460 */ |
| 464 Object inflateOne(SerializationRule rule, position, state) { | 461 inflateOne(SerializationRule rule, position, state) { |
| 465 var existing = allObjectsForRule(rule)[position]; | 462 var existing = allObjectsForRule(rule)[position]; |
| 466 // We may already be in progress and hitting this in a cycle. | 463 // We may already be in progress and hitting this in a cycle. |
| 467 if (existing is _Sentinel) { | 464 if (existing is _Sentinel) { |
| 468 throw new SerializationException('Cycle in essential state'); | 465 throw new SerializationException('Cycle in essential state'); |
| 469 } | 466 } |
| 470 // We may have already inflated this object, at least its essential state. | 467 // We may have already inflated this object, at least its essential state. |
| 471 if (existing != null) return existing; | 468 if (existing != null) return existing; |
| 472 | 469 |
| 473 // Put a sentinel there to mark this in case of recursion. | 470 // Put a sentinel there to mark this in case of recursion. |
| 474 allObjectsForRule(rule)[position] = const _Sentinel(); | 471 allObjectsForRule(rule)[position] = const _Sentinel(); |
| 475 var newObject = rule.inflateEssential(state, this); | 472 var newObject = rule.inflateEssential(state, this); |
| 476 allObjectsForRule(rule)[position] = newObject; | 473 allObjectsForRule(rule)[position] = newObject; |
| 477 return newObject; | 474 return newObject; |
| 478 } | 475 } |
| 479 | 476 |
| 480 /** | 477 /** |
| 481 * The parameter [possibleReference] might be a reference. If it isn't, just | 478 * The parameter [possibleReference] might be a reference. If it isn't, just |
| 482 * return it. If it is, then inflate the target of the reference and return | 479 * return it. If it is, then inflate the target of the reference and return |
| 483 * the resulting object. | 480 * the resulting object. |
| 484 */ | 481 */ |
| 485 Object inflateReference(possibleReference) { | 482 inflateReference(possibleReference) { |
| 486 // If this is a primitive, return it directly. | 483 // If this is a primitive, return it directly. |
| 487 // TODO This seems too complicated. | 484 // TODO This seems too complicated. |
| 488 return asReference(possibleReference, | 485 return asReference(possibleReference, |
| 489 ifReference: (reference) { | 486 ifReference: (reference) { |
| 490 var rule = ruleFor(reference); | 487 var rule = ruleFor(reference); |
| 491 var state = _stateFor(reference); | 488 var state = _stateFor(reference); |
| 492 inflateOne(rule, reference.objectNumber, state); | 489 inflateOne(rule, reference.objectNumber, state); |
| 493 return _objectFor(reference); | 490 return _objectFor(reference); |
| 494 }); | 491 }); |
| 495 } | 492 } |
| 496 | 493 |
| 497 /** | 494 /** |
| 498 * Given [reference], return what we have stored as an object for it. Note | 495 * Given [reference], return what we have stored as an object for it. Note |
| 499 * that, depending on the current state, this might be null or a Sentinel. | 496 * that, depending on the current state, this might be null or a Sentinel. |
| 500 */ | 497 */ |
| 501 Object _objectFor(Reference reference) => | 498 _objectFor(Reference reference) => |
| 502 objects[reference.ruleNumber][reference.objectNumber]; | 499 objects[reference.ruleNumber][reference.objectNumber]; |
| 503 | 500 |
| 504 /** Given [rule], return the storage for its objects. */ | 501 /** Given [rule], return the storage for its objects. */ |
| 505 allObjectsForRule(SerializationRule rule) => objects[rule.number]; | 502 allObjectsForRule(SerializationRule rule) => objects[rule.number]; |
| 506 | 503 |
| 507 /** Given [reference], return the the state we have stored for it. */ | 504 /** Given [reference], return the the state we have stored for it. */ |
| 508 Object _stateFor(Reference reference) => | 505 _stateFor(Reference reference) => |
| 509 _data[reference.ruleNumber][reference.objectNumber]; | 506 _data[reference.ruleNumber][reference.objectNumber]; |
| 510 | 507 |
| 511 /** Given a reference, return the rule it references. */ | 508 /** Given a reference, return the rule it references. */ |
| 512 SerializationRule ruleFor(Reference reference) => | 509 SerializationRule ruleFor(Reference reference) => |
| 513 serialization.rules[reference.ruleNumber]; | 510 serialization.rules[reference.ruleNumber]; |
| 514 | 511 |
| 515 /** | 512 /** |
| 516 * Given a possible reference [anObject], call either [ifReference] or | 513 * Given a possible reference [anObject], call either [ifReference] or |
| 517 * [ifNotReference], depending if it's a reference or not. This is the | 514 * [ifNotReference], depending if it's a reference or not. This is the |
| 518 * primary place that knows about the serialized representation of a | 515 * primary place that knows about the serialized representation of a |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 561 /** The root objects from which we will be tracing. */ | 558 /** The root objects from which we will be tracing. */ |
| 562 List roots = []; | 559 List roots = []; |
| 563 | 560 |
| 564 Trace(this.writer); | 561 Trace(this.writer); |
| 565 | 562 |
| 566 addRoot(object) { | 563 addRoot(object) { |
| 567 roots.add(object); | 564 roots.add(object); |
| 568 } | 565 } |
| 569 | 566 |
| 570 /** A convenience method to add a single root and trace it in one step. */ | 567 /** A convenience method to add a single root and trace it in one step. */ |
| 571 trace(Object o) { | 568 trace(object) { |
| 572 addRoot(o); | 569 addRoot(object); |
| 573 traceAll(); | 570 traceAll(); |
| 574 } | 571 } |
| 575 | 572 |
| 576 /** | 573 /** |
| 577 * Process all of the objects reachable from our roots via state that the | 574 * Process all of the objects reachable from our roots via state that the |
| 578 * serialization rules access. | 575 * serialization rules access. |
| 579 */ | 576 */ |
| 580 traceAll() { | 577 traceAll() { |
| 581 queue.addAll(roots); | 578 queue.addAll(roots); |
| 582 while (!queue.isEmpty) { | 579 while (!queue.isEmpty) { |
| 583 var next = queue.removeFirst(); | 580 var next = queue.removeFirst(); |
| 584 if (!hasProcessed(next)) writer._process(next, this); | 581 if (!hasProcessed(next)) writer._process(next, this); |
| 585 } | 582 } |
| 586 } | 583 } |
| 587 | 584 |
| 588 /** | 585 /** |
| 589 * Has this object been seen yet? We test for this by checking if the | 586 * Has this object been seen yet? We test for this by checking if the |
| 590 * writer has a reference for it. See comment for _hasIndexFor. | 587 * writer has a reference for it. See comment for _hasIndexFor. |
| 591 */ | 588 */ |
| 592 bool hasProcessed(object) { | 589 bool hasProcessed(object) { |
| 593 return writer._hasIndexFor(object); | 590 return writer._hasIndexFor(object); |
| 594 } | 591 } |
| 595 | 592 |
| 596 /** Note that we've seen [value], and add it to the queue to be processed. */ | 593 /** Note that we've seen [value], and add it to the queue to be processed. */ |
| 597 note(Object value) { | 594 note(value) { |
| 598 if (value != null) { | 595 if (value != null) { |
| 599 queue.add(value); | 596 queue.add(value); |
| 600 } | 597 } |
| 601 return value; | 598 return value; |
| 602 } | 599 } |
| 603 } | 600 } |
| 604 | 601 |
| 605 /** | 602 /** |
| 606 * Any pointers to objects that can't be represented directly in the | 603 * Any pointers to objects that can't be represented directly in the |
| 607 * serialization format has to be stored as a reference. A reference encodes | 604 * serialization format has to be stored as a reference. A reference encodes |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 645 * referenced, and is a more or less internal collection. See ListRuleEssential | 642 * referenced, and is a more or less internal collection. See ListRuleEssential |
| 646 * for an example. It knows how to return its object and how to filter. | 643 * for an example. It knows how to return its object and how to filter. |
| 647 */ | 644 */ |
| 648 class DesignatedRuleForObject { | 645 class DesignatedRuleForObject { |
| 649 Function rulePredicate; | 646 Function rulePredicate; |
| 650 final target; | 647 final target; |
| 651 | 648 |
| 652 DesignatedRuleForObject(this.target, this.rulePredicate); | 649 DesignatedRuleForObject(this.target, this.rulePredicate); |
| 653 | 650 |
| 654 possibleRules(List rules) => rules.filter(rulePredicate); | 651 possibleRules(List rules) => rules.filter(rulePredicate); |
| 655 } | 652 } |
| 656 | |
| OLD | NEW |