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

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: Changes from John's review 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>();
52 52
53 /** Return the list of rules we use. */ 53 /** Return the list of rules we use. */
54 List<SerializationRule> get rules => serialization.rules; 54 List<SerializationRule> get rules => serialization._rules;
55 55
56 /** 56 /**
57 * Creates a new [Writer] that uses the rules from its parent 57 * Creates a new [Writer] that uses the rules from its parent
58 * [Serialization]. Serializations are do not keep any state 58 * [Serialization]. Serializations are do not keep any state
59 * related to a particular read/write, so the same one can be used 59 * related to a particular read/write, so the same one can be used
60 * for multiple different Readers/Writers. 60 * for multiple different Readers/Writers.
61 */ 61 */
62 Writer(this.serialization) { 62 Writer(this.serialization) {
63 trace = new Trace(this); 63 trace = new Trace(this);
64 selfDescribing = serialization.selfDescribing; 64 selfDescribing = serialization.selfDescribing;
(...skipping 75 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 10 matching lines...) Expand all
240 * This effectively defines a custom JSON serialization format, although 240 * This effectively defines a custom JSON serialization format, although
241 * the details of the format vary depending which rules were used. 241 * the details of the format vary depending which rules were used.
242 */ 242 */
243 Map toMaps() { 243 Map toMaps() {
244 var result = new Map(); 244 var result = new Map();
245 var savedRules; 245 var savedRules;
246 if (selfDescribing) { 246 if (selfDescribing) {
247 var meta = serialization._ruleSerialization(); 247 var meta = serialization._ruleSerialization();
248 var writer = new Writer(meta); 248 var writer = new Writer(meta);
249 writer.selfDescribing = false; 249 writer.selfDescribing = false;
250 savedRules = writer.write(serialization.rules); 250 savedRules = writer.write(serialization._rules);
251 } 251 }
252 result["rules"] = savedRules; 252 result["rules"] = savedRules;
253 result["data"] = states; 253 result["data"] = states;
254 result["roots"] = _rootReferences(trace.roots); 254 result["roots"] = _rootReferences(trace.roots);
255 return result; 255 return result;
256 } 256 }
257 257
258 /** 258 /**
259 * Return a list of [Reference] objects pointing to our roots. This will be 259 * Return a list of [Reference] objects pointing to our roots. This will be
260 * stored in the output under "roots" in the default format. 260 * stored in the output under "roots" in the default format.
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) => references[object];
272 return references[o]; 272
273 } 273 /**
274 * Return true if the [namedObjects] collection has a reference to [object].
275 */
276 // TODO(alanknight): Should the writer also have its own namedObjects
277 // collection specific to the particular write, or is that just adding
278 // complexity for little value?
279 hasNameFor(object) => serialization._hasNameFor(object);
280
281 /**
282 * Return the name we have for this object in the [namedObjects] collection.
283 */
284 nameFor(object) => serialization._nameFor(object);
274 285
275 // For debugging/testing purposes. Find what state a reference points to. 286 // For debugging/testing purposes. Find what state a reference points to.
276 stateForReference(Reference r) => 287 stateForReference(Reference r) => states[r.ruleNumber][r.objectNumber];
277 states[r.ruleNumber][r.objectNumber];
278 } 288 }
279 289
280 /** 290 /**
281 * The main class responsible for reading. It holds 291 * The main class responsible for reading. It holds
282 * onto the necessary state and to the objects that have been inflated. 292 * onto the necessary state and to the objects that have been inflated.
283 */ 293 */
284 class Reader { 294 class Reader {
285 295
286 /** 296 /**
287 * The serialization that specifies how we read. Note that in contrast 297 * 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; 334 selfDescribing = serialization.selfDescribing;
325 } 335 }
326 336
327 /** 337 /**
328 * When we read, we may need to look up objects by name in order to link to 338 * 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, 339 * them. This is particularly true if we have references to classes,
330 * functions, mirrors, or other non-portable entities. The map in which we 340 * 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 341 * 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. 342 * provide a map here, and objects will be looked up in both places.
333 */ 343 */
334 Map externalObjects; 344 Map namedObjects;
335 345
336 /** 346 /**
337 * Look up the reference to an external object. This can be held either in 347 * 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 348 * the reader-specific list of externals or in the serializer's
339 */ 349 */
340 externalObjectNamed(key) { 350 objectNamed(key) {
341 var map = (externalObjects.containsKey(key)) 351 var map = (namedObjects.containsKey(key))
342 ? externalObjects : serialization.externalObjects; 352 ? namedObjects : serialization.namedObjects;
343 if (!map.containsKey(key)) { 353 if (!map.containsKey(key)) {
344 throw 'Cannot find named object to link to: $key'; 354 throw 'Cannot find named object to link to: $key';
345 } 355 }
346 return map[key]; 356 return map[key];
347 } 357 }
348 358
349 /** 359 /**
350 * Return the list of rules to be used when writing. These come from the 360 * Return the list of rules to be used when writing. These come from the
351 * [serialization]. 361 * [serialization].
352 */ 362 */
353 List<SerializationRule> get rules => serialization.rules; 363 List<SerializationRule> get rules => serialization._rules;
354 364
355 /** 365 /**
356 * Internal use only, for testing purposes. Set the data for this reader 366 * 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. 367 * to a List of Lists whose size must match the number of rules.
358 */ 368 */
359 // When we set the data, initialize the object storage to a matching size. 369 // When we set the data, initialize the object storage to a matching size.
360 void set data(List<List> newData) { 370 void set data(List<List> newData) {
361 _data = newData; 371 _data = newData;
362 objects = _data.map((x) => new List(x.length)); 372 objects = _data.map((x) => new List(x.length));
363 } 373 }
364 374
365 /** 375 /**
366 * This is the primary method for a [Reader]. It takes the input data, 376 * 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 377 * currently hard-coded to expect our custom JSON format, and returns
368 * the root objects. 378 * the root object.
369 */ 379 */
370 read(String input, [Map externals = const {}]) { 380 read(String input, [Map externals = const {}]) {
371 externalObjects = externals; 381 namedObjects = externals;
372 var topLevel = JSON.parse(input); 382 var topLevel = JSON.parse(input);
373 var ruleString = topLevel["rules"]; 383 var ruleString = topLevel["rules"];
374 readRules(ruleString, externals); 384 readRules(ruleString, externals);
375 data = topLevel["data"]; 385 data = topLevel["data"];
376 rules.forEach(inflateForRule); 386 rules.forEach(inflateForRule);
377 var roots = topLevel["roots"]; 387 var roots = topLevel["roots"];
378 return roots.map(inflateReference); 388 return inflateReference(roots.first);
379 } 389 }
380 390
381 /** 391 /**
382 * If the data we are reading from has rules written to it, read them back 392 * 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. 393 * and set them as the rules we will use.
384 */ 394 */
385 void readRules(String newRules, Map externals) { 395 void readRules(String newRules, Map externals) {
386 // TODO(alanknight): Replacing the serialization is kind of confusing. 396 // TODO(alanknight): Replacing the serialization is kind of confusing.
387 List rulesWeRead = (newRules == null) ? 397 List rulesWeRead = (newRules == null) ?
388 null : serialization._ruleSerialization().readOne(newRules, externals); 398 null : serialization._ruleSerialization().read(newRules, externals);
389 if (rulesWeRead != null && !rulesWeRead.isEmpty) { 399 if (rulesWeRead != null && !rulesWeRead.isEmpty) {
390 serialization = new Serialization.blank(); 400 serialization = new Serialization.blank();
391 rulesWeRead.forEach(serialization.addRule); 401 rulesWeRead.forEach(serialization.addRule);
392 } 402 }
393 } 403 }
394 404
395 /** 405 /**
396 * This is a hard-coded read method for a vaguely flat format. It's just a 406 * 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 407 * proof of concept of handling more flat formats right now, and needs a lot
398 * of fixing and generalization. 408 * of fixing and generalization.
399 */ 409 */
400 readFlat(List input, [Map externals = const {}]) { 410 readFlat(List input, [Map externals = const {}]) {
401 // TODO(alanknight): Way too much code duplication with read. Numerous 411 // TODO(alanknight): Way too much code duplication with read. Numerous
402 // code smells. 412 // code smells.
403 externalObjects = externals; 413 namedObjects = externals;
404 var topLevel = input; 414 var topLevel = input;
405 var ruleString = topLevel[0]; 415 var ruleString = topLevel[0];
406 readRules(ruleString, externals); 416 readRules(ruleString, externals);
407 var flatData = topLevel[1]; 417 var flatData = topLevel[1];
408 var stream = flatData.iterator(); 418 var stream = flatData.iterator();
409 var tempData = new List(rules.length); 419 var tempData = new List(rules.length);
410 for (var eachRule in rules) { 420 for (var eachRule in rules) {
411 tempData[eachRule.number] = eachRule.pullStateFrom(stream); 421 tempData[eachRule.number] = eachRule.pullStateFrom(stream);
412 } 422 }
413 data = tempData; 423 data = tempData;
414 for (var eachRule in rules) { 424 for (var eachRule in rules) {
415 inflateForRule(eachRule); 425 inflateForRule(eachRule);
416 } 426 }
417 var rootsAsInts = topLevel[2]; 427 var rootsAsInts = topLevel[2];
418 var rootStream = rootsAsInts.iterator(); 428 var rootStream = rootsAsInts.iterator();
419 var roots = new List(); 429 var roots = new List();
420 while (rootStream.hasNext) { 430 while (rootStream.hasNext) {
421 roots.add(new Reference(this, rootStream.next(), rootStream.next())); 431 roots.add(new Reference(this, rootStream.next(), rootStream.next()));
422 } 432 }
423 var x = inflateReference(roots[0]); 433 var x = inflateReference(roots[0]);
424 return roots.map((x) => inflateReference(x)); 434 return inflateReference(roots.first);
425 } 435 }
426 436
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 /** 437 /**
443 * Inflate all of the objects for [rule]. Does the essential state for all 438 * 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 439 * objects first, then the non-essential state. This avoids cycles in
445 * non-essential state, because all the objects will have already been 440 * non-essential state, because all the objects will have already been
446 * created. 441 * created.
447 */ 442 */
448 inflateForRule(rule) { 443 inflateForRule(rule) {
449 var dataForThisRule = _data[rule.number]; 444 var dataForThisRule = _data[rule.number];
450 keysAndValues(dataForThisRule).forEach((position, state) { 445 keysAndValues(dataForThisRule).forEach((position, state) {
451 inflateOne(rule, position, state); 446 inflateOne(rule, position, state);
452 }); 447 });
453 keysAndValues(dataForThisRule).forEach((position, state) { 448 keysAndValues(dataForThisRule).forEach((position, state) {
454 rule.inflateNonEssential(state, allObjectsForRule(rule)[position], this); 449 rule.inflateNonEssential(state, allObjectsForRule(rule)[position], this);
455 }); 450 });
456 } 451 }
457 452
458 /** 453 /**
459 * Create a new object, based on [rule] and [state], which will 454 * Create a new object, based on [rule] and [state], which will
460 * be stored in [position] in the storage for [rule]. This will 455 * be stored in [position] in the storage for [rule]. This will
461 * follow references and recursively inflate them, leaving Sentinel objects 456 * follow references and recursively inflate them, leaving Sentinel objects
462 * to detect cycles. 457 * to detect cycles.
463 */ 458 */
464 Object inflateOne(SerializationRule rule, position, state) { 459 inflateOne(SerializationRule rule, position, state) {
465 var existing = allObjectsForRule(rule)[position]; 460 var existing = allObjectsForRule(rule)[position];
466 // We may already be in progress and hitting this in a cycle. 461 // We may already be in progress and hitting this in a cycle.
467 if (existing is _Sentinel) { 462 if (existing is _Sentinel) {
468 throw new SerializationException('Cycle in essential state'); 463 throw new SerializationException('Cycle in essential state');
469 } 464 }
470 // We may have already inflated this object, at least its essential state. 465 // We may have already inflated this object, at least its essential state.
471 if (existing != null) return existing; 466 if (existing != null) return existing;
472 467
473 // Put a sentinel there to mark this in case of recursion. 468 // Put a sentinel there to mark this in case of recursion.
474 allObjectsForRule(rule)[position] = const _Sentinel(); 469 allObjectsForRule(rule)[position] = const _Sentinel();
475 var newObject = rule.inflateEssential(state, this); 470 var newObject = rule.inflateEssential(state, this);
476 allObjectsForRule(rule)[position] = newObject; 471 allObjectsForRule(rule)[position] = newObject;
477 return newObject; 472 return newObject;
478 } 473 }
479 474
480 /** 475 /**
481 * The parameter [possibleReference] might be a reference. If it isn't, just 476 * 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 477 * return it. If it is, then inflate the target of the reference and return
483 * the resulting object. 478 * the resulting object.
484 */ 479 */
485 Object inflateReference(possibleReference) { 480 inflateReference(possibleReference) {
486 // If this is a primitive, return it directly. 481 // If this is a primitive, return it directly.
487 // TODO This seems too complicated. 482 // TODO This seems too complicated.
488 return asReference(possibleReference, 483 return asReference(possibleReference,
489 ifReference: (reference) { 484 ifReference: (reference) {
490 var rule = ruleFor(reference); 485 var rule = ruleFor(reference);
491 var state = _stateFor(reference); 486 var state = _stateFor(reference);
492 inflateOne(rule, reference.objectNumber, state); 487 inflateOne(rule, reference.objectNumber, state);
493 return _objectFor(reference); 488 return _objectFor(reference);
494 }); 489 });
495 } 490 }
496 491
497 /** 492 /**
498 * Given [reference], return what we have stored as an object for it. Note 493 * 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. 494 * that, depending on the current state, this might be null or a Sentinel.
500 */ 495 */
501 Object _objectFor(Reference reference) => 496 _objectFor(Reference reference) =>
502 objects[reference.ruleNumber][reference.objectNumber]; 497 objects[reference.ruleNumber][reference.objectNumber];
503 498
504 /** Given [rule], return the storage for its objects. */ 499 /** Given [rule], return the storage for its objects. */
505 allObjectsForRule(SerializationRule rule) => objects[rule.number]; 500 allObjectsForRule(SerializationRule rule) => objects[rule.number];
506 501
507 /** Given [reference], return the the state we have stored for it. */ 502 /** Given [reference], return the the state we have stored for it. */
508 Object _stateFor(Reference reference) => 503 _stateFor(Reference reference) =>
509 _data[reference.ruleNumber][reference.objectNumber]; 504 _data[reference.ruleNumber][reference.objectNumber];
510 505
511 /** Given a reference, return the rule it references. */ 506 /** Given a reference, return the rule it references. */
512 SerializationRule ruleFor(Reference reference) => 507 SerializationRule ruleFor(Reference reference) =>
513 serialization.rules[reference.ruleNumber]; 508 serialization._rules[reference.ruleNumber];
514 509
515 /** 510 /**
516 * Given a possible reference [anObject], call either [ifReference] or 511 * Given a possible reference [anObject], call either [ifReference] or
517 * [ifNotReference], depending if it's a reference or not. This is the 512 * [ifNotReference], depending if it's a reference or not. This is the
518 * primary place that knows about the serialized representation of a 513 * primary place that knows about the serialized representation of a
519 * reference. 514 * reference.
520 */ 515 */
521 asReference(anObject, {Function ifReference: doNothing, 516 asReference(anObject, {Function ifReference: doNothing,
522 Function ifNotReference : doNothing}) { 517 Function ifNotReference : doNothing}) {
523 if (anObject is Reference) return ifReference(anObject); 518 if (anObject is Reference) return ifReference(anObject);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
561 /** The root objects from which we will be tracing. */ 556 /** The root objects from which we will be tracing. */
562 List roots = []; 557 List roots = [];
563 558
564 Trace(this.writer); 559 Trace(this.writer);
565 560
566 addRoot(object) { 561 addRoot(object) {
567 roots.add(object); 562 roots.add(object);
568 } 563 }
569 564
570 /** A convenience method to add a single root and trace it in one step. */ 565 /** A convenience method to add a single root and trace it in one step. */
571 trace(Object o) { 566 trace(object) {
572 addRoot(o); 567 addRoot(object);
573 traceAll(); 568 traceAll();
574 } 569 }
575 570
576 /** 571 /**
577 * Process all of the objects reachable from our roots via state that the 572 * Process all of the objects reachable from our roots via state that the
578 * serialization rules access. 573 * serialization rules access.
579 */ 574 */
580 traceAll() { 575 traceAll() {
581 queue.addAll(roots); 576 queue.addAll(roots);
582 while (!queue.isEmpty) { 577 while (!queue.isEmpty) {
583 var next = queue.removeFirst(); 578 var next = queue.removeFirst();
584 if (!hasProcessed(next)) writer._process(next, this); 579 if (!hasProcessed(next)) writer._process(next, this);
585 } 580 }
586 } 581 }
587 582
588 /** 583 /**
589 * Has this object been seen yet? We test for this by checking if the 584 * 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. 585 * writer has a reference for it. See comment for _hasIndexFor.
591 */ 586 */
592 bool hasProcessed(object) { 587 bool hasProcessed(object) {
593 return writer._hasIndexFor(object); 588 return writer._hasIndexFor(object);
594 } 589 }
595 590
596 /** Note that we've seen [value], and add it to the queue to be processed. */ 591 /** Note that we've seen [value], and add it to the queue to be processed. */
597 note(Object value) { 592 note(value) {
598 if (value != null) { 593 if (value != null) {
599 queue.add(value); 594 queue.add(value);
600 } 595 }
601 return value; 596 return value;
602 } 597 }
603 } 598 }
604 599
605 /** 600 /**
606 * Any pointers to objects that can't be represented directly in the 601 * 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 602 * 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 640 * 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. 641 * for an example. It knows how to return its object and how to filter.
647 */ 642 */
648 class DesignatedRuleForObject { 643 class DesignatedRuleForObject {
649 Function rulePredicate; 644 Function rulePredicate;
650 final target; 645 final target;
651 646
652 DesignatedRuleForObject(this.target, this.rulePredicate); 647 DesignatedRuleForObject(this.target, this.rulePredicate);
653 648
654 possibleRules(List rules) => rules.filter(rulePredicate); 649 possibleRules(List rules) => rules.filter(rulePredicate);
655 } 650 }
656
OLDNEW
« no previous file with comments | « pkg/serialization/lib/src/polyfill_identity_set.dart ('k') | pkg/serialization/lib/src/serialization_helpers.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698