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

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

Issue 11931030: Add a MapRule (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Changes from review comments Created 7 years, 10 months 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.
11 */ 11 */
12 // TODO(alanknight): For simple serialization formats this does a lot of work 12 // TODO(alanknight): For simple serialization formats this does a lot of work
13 // that isn't necessary, e.g. detecting cycles and maintaining references. 13 // that isn't necessary, e.g. detecting cycles and maintaining references.
14 // Consider having an abstract superclass with the basic functionality and 14 // Consider having an abstract superclass with the basic functionality and
15 // simple serialization subclasses where we know there aren't cycles. 15 // simple serialization subclasses where we know there aren't cycles.
16 class Writer { 16 class Writer implements ReaderOrWriter {
17 /** 17 /**
18 * The [serialization] holds onto the rules that define how objects 18 * The [serialization] holds onto the rules that define how objects
19 * are serialized. 19 * are serialized.
20 */ 20 */
21 final Serialization serialization; 21 final Serialization serialization;
22 22
23 /** The [trace] object keeps track of the objects to be visited while finding 23 /** The [trace] object keeps track of the objects to be visited while finding
24 * the full set of objects to be written.*/ 24 * the full set of objects to be written.*/
25 Trace trace; 25 Trace trace;
26 26
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 /** 81 /**
82 * Given that we have fully populated the list of [states], and more 82 * Given that we have fully populated the list of [states], and more
83 * importantly, the list of [references], go through each state and turn 83 * importantly, the list of [references], go through each state and turn
84 * anything that requires a [Reference] into one. Since only the rules 84 * anything that requires a [Reference] into one. Since only the rules
85 * know the representation they use for state, delegate to them. 85 * know the representation they use for state, delegate to them.
86 */ 86 */
87 void _flatten() { 87 void _flatten() {
88 for (var eachRule in rules) { 88 for (var eachRule in rules) {
89 _growStates(eachRule); 89 _growStates(eachRule);
90 var index = eachRule.number; 90 var index = eachRule.number;
91 for (var eachState in states[index]) { 91 var statesForThisRule = states[index];
92 eachRule.flatten(eachState, this); 92 for (var i = 0; i < statesForThisRule.length; i++) {
93 var eachState = statesForThisRule[i];
94 var newState = eachRule.flatten(eachState, this);
95 if (newState != null) {
96 statesForThisRule[i] = newState;
97 }
93 } 98 }
94 } 99 }
95 } 100 }
96 101
97 /** 102 /**
98 * As the [trace] processes each object, it will call this method on us. 103 * As the [trace] processes each object, it will call this method on us.
99 * We find the rules for this object, and record the state of the object 104 * We find the rules for this object, and record the state of the object
100 * as determined by each rule. 105 * as determined by each rule.
101 */ 106 */
102 void _process(object, Trace trace) { 107 void _process(object, Trace trace) {
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
189 } 194 }
190 195
191 /** 196 /**
192 * Return a list of [Reference] objects pointing to our roots. This will be 197 * Return a list of [Reference] objects pointing to our roots. This will be
193 * stored in the output under "roots" in the default format. 198 * stored in the output under "roots" in the default format.
194 */ 199 */
195 _rootReferences() => trace.roots.mappedBy(_referenceFor).toList(); 200 _rootReferences() => trace.roots.mappedBy(_referenceFor).toList();
196 201
197 /** 202 /**
198 * Given an object, return a reference for it if one exists. If there's 203 * Given an object, return a reference for it if one exists. If there's
199 * no reference, return null. Once we have finished the tracing step, all 204 * no reference, return the object itself. Once we have finished the tracing
200 * objects that should have a reference (roughly speaking, non-primitives) 205 * step, all objects that should have a reference (roughly speaking,
201 * can be relied on to have a reference. 206 * non-primitives) can be relied on to have a reference.
202 */ 207 */
203 _referenceFor(object) => references[object]; 208 _referenceFor(object) {
209 var result = references[object];
210 return (result == null) ? object : result;
211 }
204 212
205 /** 213 /**
206 * Return true if the [namedObjects] collection has a reference to [object]. 214 * Return true if the [namedObjects] collection has a reference to [object].
207 */ 215 */
208 // TODO(alanknight): Should the writer also have its own namedObjects 216 // TODO(alanknight): Should the writer also have its own namedObjects
209 // collection specific to the particular write, or is that just adding 217 // collection specific to the particular write, or is that just adding
210 // complexity for little value? 218 // complexity for little value?
211 hasNameFor(object) => serialization._hasNameFor(object); 219 hasNameFor(object) => serialization._hasNameFor(object);
212 220
213 /** 221 /**
214 * Return the name we have for this object in the [namedObjects] collection. 222 * Return the name we have for this object in the [namedObjects] collection.
215 */ 223 */
216 nameFor(object) => serialization._nameFor(object); 224 nameFor(object) => serialization._nameFor(object);
217 225
218 // For debugging/testing purposes. Find what state a reference points to. 226 // For debugging/testing purposes. Find what state a reference points to.
219 stateForReference(Reference r) => states[r.ruleNumber][r.objectNumber]; 227 stateForReference(Reference r) => states[r.ruleNumber][r.objectNumber];
228
229 /** Return the state pointed to by [reference]. */
230 resolveReference(reference) => stateForReference(reference);
231 }
232
233 /**
234 * An abstract class for Reader and Writer, which primarily exists so we can
235 * type things that will refer to one or the other, depending on which
236 * operation we're doing.
237 */
238 abstract class ReaderOrWriter {
239 /** Return the list of serialization rules we are using.*/
240 List<SerializationRule> get rules;
241
242 /**
243 * Return the object, or state, that ref points to, depending on which
244 * we're generating.
245 */
246 resolveReference(Reference ref);
220 } 247 }
221 248
222 /** 249 /**
223 * The main class responsible for reading. It holds 250 * The main class responsible for reading. It holds
224 * onto the necessary state and to the objects that have been inflated. 251 * onto the necessary state and to the objects that have been inflated.
225 */ 252 */
226 class Reader { 253 class Reader implements ReaderOrWriter {
227 254
228 /** 255 /**
229 * The serialization that specifies how we read. Note that in contrast 256 * The serialization that specifies how we read. Note that in contrast
230 * to the Writer, this is not final. This is because we may be created 257 * to the Writer, this is not final. This is because we may be created
231 * with an empty [Serialization] and then read the rules from the data, 258 * with an empty [Serialization] and then read the rules from the data,
232 * if [selfDescribing] is true. 259 * if [selfDescribing] is true.
233 */ 260 */
234 Serialization serialization; 261 Serialization serialization;
235 262
236 /** 263 /**
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
381 // TODO This seems too complicated. 408 // TODO This seems too complicated.
382 return asReference(possibleReference, 409 return asReference(possibleReference,
383 ifReference: (reference) { 410 ifReference: (reference) {
384 var rule = ruleFor(reference); 411 var rule = ruleFor(reference);
385 var state = _stateFor(reference); 412 var state = _stateFor(reference);
386 inflateOne(rule, reference.objectNumber, state); 413 inflateOne(rule, reference.objectNumber, state);
387 return _objectFor(reference); 414 return _objectFor(reference);
388 }); 415 });
389 } 416 }
390 417
418 /** Return the object pointed to by [reference]. */
419 resolveReference(reference) => inflateReference(reference);
420
391 /** 421 /**
392 * Given [reference], return what we have stored as an object for it. Note 422 * Given [reference], return what we have stored as an object for it. Note
393 * that, depending on the current state, this might be null or a Sentinel. 423 * that, depending on the current state, this might be null or a Sentinel.
394 */ 424 */
395 _objectFor(Reference reference) => 425 _objectFor(Reference reference) =>
396 objects[reference.ruleNumber][reference.objectNumber]; 426 objects[reference.ruleNumber][reference.objectNumber];
397 427
398 /** Given [rule], return the storage for its objects. */ 428 /** Given [rule], return the storage for its objects. */
399 allObjectsForRule(SerializationRule rule) => objects[rule.number]; 429 allObjectsForRule(SerializationRule rule) => objects[rule.number];
400 430
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
511 } 541 }
512 542
513 /** 543 /**
514 * Any pointers to objects that can't be represented directly in the 544 * Any pointers to objects that can't be represented directly in the
515 * serialization format has to be stored as a reference. A reference encodes 545 * serialization format has to be stored as a reference. A reference encodes
516 * the rule number of the rule that saved it in the Serialization that was used 546 * the rule number of the rule that saved it in the Serialization that was used
517 * for writing, and the object number within that rule. 547 * for writing, and the object number within that rule.
518 */ 548 */
519 class Reference { 549 class Reference {
520 /** The [Reader] or [Writer] that owns this reference. */ 550 /** The [Reader] or [Writer] that owns this reference. */
521 final parent; 551 final ReaderOrWriter parent;
522 /** The position of the rule that controls this reference in [parent]. */ 552 /** The position of the rule that controls this reference in [parent]. */
523 final int ruleNumber; 553 final int ruleNumber;
524 /** The index of the referred-to object in the storage of [parent] */ 554 /** The index of the referred-to object in the storage of [parent] */
525 final int objectNumber; 555 final int objectNumber;
526 556
527 const Reference(this.parent, this.ruleNumber, this.objectNumber); 557 Reference(this.parent, this.ruleNumber, this.objectNumber) {
558 if (ruleNumber == null || objectNumber == null) {
559 throw new SerializationException("Invalid Reference");
560 }
561 if (parent.rules.length < ruleNumber) {
562 throw new SerializationException("Invalid Reference");
563 }
564 }
565
566 /**
567 * Return the thing this reference points to. Assumes that we have a valid
568 * parent and that it is a Reader, as inflating is not meaningful when
569 * writing.
570 */
571 inflated() => parent.resolveReference(this);
528 572
529 /** 573 /**
530 * Convert the reference to a map in JSON format. This is specific to the 574 * Convert the reference to a map in JSON format. This is specific to the
531 * custom JSON format we define, and must be consistent with the 575 * custom JSON format we define, and must be consistent with the
532 * [asReference] method. 576 * [asReference] method.
533 */ 577 */
534 // TODO(alanknight): This is a hack both in defining a toJson specific to a 578 // TODO(alanknight): This is a hack both in defining a toJson specific to a
535 // particular representation, and the use of a bogus sentinel "__Ref" 579 // particular representation, and the use of a bogus sentinel "__Ref"
536 toJson() => { 580 toJson() => {
537 "__Ref" : true, 581 "__Ref" : true,
538 "rule" : ruleNumber, 582 "rule" : ruleNumber,
539 "object" : objectNumber 583 "object" : objectNumber
540 }; 584 };
541 585
542 /** Write our information to [list]. Useful in writing to flat formats.*/ 586 /** Write our information to [list]. Useful in writing to flat formats.*/
543 writeToList(List list) { 587 writeToList(List list) {
544 list.add(ruleNumber); 588 list.add(ruleNumber);
545 list.add(objectNumber); 589 list.add(objectNumber);
546 } 590 }
547 591
548 toString() => "Reference $ruleNumber, $objectNumber"; 592 toString() => "Reference($ruleNumber, $objectNumber)";
549 } 593 }
550 594
551 /** 595 /**
552 * This is used during tracing to indicate that an object should be processed 596 * This is used during tracing to indicate that an object should be processed
553 * using a particular rule, rather than the one that might ordinarily be 597 * using a particular rule, rather than the one that might ordinarily be
554 * found for it. This normally only makes sense if the object is uniquely 598 * found for it. This normally only makes sense if the object is uniquely
555 * referenced, and is a more or less internal collection. See ListRuleEssential 599 * referenced, and is a more or less internal collection. See ListRuleEssential
556 * for an example. It knows how to return its object and how to filter. 600 * for an example. It knows how to return its object and how to filter.
557 */ 601 */
558 class DesignatedRuleForObject { 602 class DesignatedRuleForObject {
559 Function rulePredicate; 603 Function rulePredicate;
560 final target; 604 final target;
561 605
562 DesignatedRuleForObject(this.target, this.rulePredicate); 606 DesignatedRuleForObject(this.target, this.rulePredicate);
563 607
564 possibleRules(List rules) => rules.where(rulePredicate).toList(); 608 possibleRules(List rules) => rules.where(rulePredicate).toList();
565 } 609 }
OLDNEW
« no previous file with comments | « pkg/serialization/lib/src/format.dart ('k') | pkg/serialization/lib/src/serialization_rule.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698