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

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

Issue 11553012: Better ability to have hand-written custom rules and various cleanups. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years 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 /** 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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698