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

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

Issue 11578037: Replicating CL https://chromiumcodereview.appspot.com/11553012/ (Closed) Base URL: https://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 // TODO(alanknight): We should have an example and tests for subclassing 7 // TODO(alanknight): We should have an example and tests for subclassing
8 // serialization rule rather than using the hard-coded ClosureToMap rule. And 8 // serialization rule rather than using the hard-coded ClosureToMap rule. And
9 // possibly an abstract superclass that's designed to be subclassed that way. 9 // possibly an abstract superclass that's designed to be subclassed that way.
10 /** 10 /**
(...skipping 15 matching lines...) Expand all
26 /** 26 /**
27 * Rules belong uniquely to a particular Serialization instance, and can 27 * Rules belong uniquely to a particular Serialization instance, and can
28 * be identified within it by number. 28 * be identified within it by number.
29 */ 29 */
30 void set number(x) { 30 void set number(x) {
31 if (_number != null) throw 31 if (_number != null) throw
32 new SerializationException("Rule numbers cannot be changed, once set"); 32 new SerializationException("Rule numbers cannot be changed, once set");
33 _number = x; 33 _number = x;
34 } 34 }
35 35
36 /** Return true if this rule applies to this object, false otherwise. */ 36 /**
37 bool appliesTo(object); 37 * Return true if this rule applies to this object, in the context
38 * where we're writing it, false otherwise.
39 */
40 bool appliesTo(object, Writer writer);
38 41
39 /** 42 /**
40 * This extracts the state from the object, calling [f] for each value 43 * This extracts the state from the object, calling [f] for each value
41 * as it is extracted, and returning an object representing the whole 44 * as it is extracted, and returning an object representing the whole
42 * state at the end. The state that results will still have direct 45 * state at the end. The state that results will still have direct
43 * pointers to objects, rather than references. 46 * pointers to objects, rather than references.
44 */ 47 */
45 Object extractState(object, void f(value)); 48 extractState(object, void f(value));
46 49
47 /** 50 /**
48 * Given the variables representing the state of an object, flatten it 51 * Given the variables representing the state of an object, flatten it
49 * by turning object pointers into Reference objects where needed. This 52 * by turning object pointers into Reference objects where needed. This
50 * destructively modifies the state object. 53 * destructively modifies the state object.
51 * 54 *
52 * This has a default implementation which assumes that object is indexable, 55 * This has a default implementation which assumes that object is indexable,
53 * so either conforms to Map or List. Subclasses may override to do something 56 * so either conforms to Map or List. Subclasses may override to do something
54 * different. 57 * different.
55 */ 58 */
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 inflateEssential(state, Reader reader); 94 inflateEssential(state, Reader reader);
92 95
93 /** 96 /**
94 * The [object] has already been created. Set any of its non-essential 97 * The [object] has already been created. Set any of its non-essential
95 * variables from the representation in [state]. Where there are references 98 * variables from the representation in [state]. Where there are references
96 * to other objects they are resolved in the context of [reader]. 99 * to other objects they are resolved in the context of [reader].
97 */ 100 */
98 inflateNonEssential(state, object, Reader reader); 101 inflateNonEssential(state, object, Reader reader);
99 102
100 /** 103 /**
101 * If we have an object [o] as part of our state, should we represent that 104 * If we have [object] as part of our state, should we represent that
102 * directly, or should we make a reference for it. By default we use a 105 * directly, or should we make a reference for it. By default we use a
103 * reference for everything. 106 * reference for everything.
104 */ 107 */
105 bool shouldUseReferenceFor(Object o, Writer w) => true; 108 bool shouldUseReferenceFor(object, Writer w) => true;
106 109
107 /** 110 /**
108 * This writes the data from our internal representation into a List. 111 * This writes the data from our internal representation into a List.
109 * It is used in order to write to a flat format, and is likely to be 112 * It is used in order to write to a flat format, and is likely to be
110 * folded into a more general mechanism for supporting different output 113 * folded into a more general mechanism for supporting different output
111 * formats. 114 * formats.
112 */ 115 */
113 // TODO(alanknight): This really shouldn't exist, but is a temporary measure 116 // TODO(alanknight): This really shouldn't exist, but is a temporary measure
114 // for writing to a a flat format until that's more fleshed out. It takes 117 // for writing to a a flat format until that's more fleshed out. It takes
115 // the internal representation of the rule's state, which is particularly 118 // the internal representation of the rule's state, which is particularly
116 // bad. The default implementation treats the ruleData as a List of Lists 119 // bad. The default implementation treats the ruleData as a List of Lists
117 // of references. 120 // of references.
118 void dumpStateInto(List ruleData, List target) { 121 void dumpStateInto(List ruleData, List target) {
119 // Needing the intermediate is also bad for performance, but tricky 122 // Needing the intermediate is also bad for performance, but tricky
120 // to do otherwise without a mechanism to precalculate the size. 123 // to do otherwise without a mechanism to precalculate the size.
121 var intermediate = new List(); 124 var intermediate = new List();
122 var totalLength = 0; 125 var totalLength = 0;
123 for (var eachList in ruleData) { 126 for (var eachList in ruleData) {
124 // TODO(alanknight): Abstract this out better, this really won't scale. 127 if (writeLengthInFlatFormat) {
125 if (this is ListRule)
126 intermediate.add(eachList.length); 128 intermediate.add(eachList.length);
129 }
127 for (var eachRef in eachList) { 130 for (var eachRef in eachList) {
128 if (eachRef == null) { 131 if (eachRef == null) {
129 intermediate..add(null)..add(null); 132 intermediate..add(null)..add(null);
130 } else { 133 } else {
131 eachRef.writeToList(intermediate); 134 eachRef.writeToList(intermediate);
132 } 135 }
133 } 136 }
134 } 137 }
135 target.addAll(intermediate); 138 target.addAll(intermediate);
136 } 139 }
137 140
138 /** 141 /**
142 * Return true if this rule writes a length value before each entry in
143 * the flat format. Return false if the results are fixed length.
144 */
145 // TODO(alanknight): This should probably go away with more general formats.
146 bool get writeLengthInFlatFormat => false;
147
148 /**
139 * The inverse of dumpStateInto, this reads the rule's state from an 149 * The inverse of dumpStateInto, this reads the rule's state from an
140 * iterator in a flat format. 150 * iterator in a flat format.
141 */ 151 */
142 pullStateFrom(Iterator stream); 152 pullStateFrom(Iterator stream) {
153 var numberOfEntries = stream.next();
154 var ruleData = new List();
155 for (var i = 0; i < numberOfEntries; i++) {
156 var subLength = dataLengthIn(stream);
157 var subList = [];
158 ruleData.add(subList);
159 for (var j = 0; j < subLength; j++) {
160 var a = stream.next();
161 var b = stream.next();
162 if (!(a is int)) {
163 // This wasn't a reference, just use the first object as a literal.
164 // particularly used for the case of null.
165 subList.add(a);
166 } else {
167 subList.add(new Reference(this, a, b));
168 }
169 }
170 }
171 return ruleData;
172 }
173
174 /**
175 * Return the length of the list of data we expect to see on a particular
176 * iterator in a flat format. This may have been encoded in the stream if we
177 * are variable length, or it may be constant. Note that this is expressed in
178 *
179 */
180 dataLengthIn(Iterator stream) =>
181 writeLengthInFlatFormat ? stream.next() : dataLength;
182
183 /**
184 * If the data is fixed length, return it here. Unused in the non-flat
185 * format, or if the data is variable length.
186 */
187 int get dataLength => 0;
143 } 188 }
144 189
145 /** 190 /**
146 * This rule handles things that implement List. It will recreate them as 191 * This rule handles things that implement List. It will recreate them as
147 * whatever the default implemenation of List is on the target platform. 192 * whatever the default implemenation of List is on the target platform.
148 */ 193 */
149 class ListRule extends SerializationRule { 194 class ListRule extends SerializationRule {
150 195
151 appliesTo(object) => object is List; 196 appliesTo(object, Writer w) => object is List;
152 197
153 state(List list) => new List.from(list); 198 state(List list) => new List.from(list);
154 199
155 List extractState(List list, f) { 200 List extractState(List list, f) {
156 var result = new List(); 201 var result = new List();
157 for (var each in list) { 202 for (var each in list) {
158 result.add(each); 203 result.add(each);
159 f(each); 204 f(each);
160 } 205 }
161 return result; 206 return result;
(...skipping 17 matching lines...) Expand all
179 * When reading from a flat format we are given [stream] and need to pull as 224 * When reading from a flat format we are given [stream] and need to pull as
180 * much data from it as we need. Our format is that we have an integer N 225 * much data from it as we need. Our format is that we have an integer N
181 * indicating the number of objects and then for each object a length M, 226 * indicating the number of objects and then for each object a length M,
182 * and then M references, where a reference is stored in the stream as two 227 * and then M references, where a reference is stored in the stream as two
183 * integers. Or, in the special case of null, two nulls. 228 * integers. Or, in the special case of null, two nulls.
184 */ 229 */
185 pullStateFrom(Iterator stream) { 230 pullStateFrom(Iterator stream) {
186 // TODO(alanknight): This is much too close to the basicRule implementation, 231 // TODO(alanknight): This is much too close to the basicRule implementation,
187 // and I'd refactor them if I didn't think this whole mechanism needed to 232 // and I'd refactor them if I didn't think this whole mechanism needed to
188 // change soon. 233 // change soon.
189 var dataLength = stream.next(); 234 var length = stream.next();
190 var ruleData = new List(); 235 var ruleData = new List();
191 for (var i = 0; i < dataLength; i++) { 236 for (var i = 0; i < length; i++) {
192 var subLength = stream.next(); 237 var subLength = stream.next();
193 var subList = new List(); 238 var subList = new List();
194 ruleData.add(subList); 239 ruleData.add(subList);
195 for (var j = 0; j < subLength; j++) { 240 for (var j = 0; j < subLength; j++) {
196 var a = stream.next(); 241 var a = stream.next();
197 var b = stream.next(); 242 var b = stream.next();
198 if (!(a is int)) { 243 if (!(a is int)) {
199 // This wasn't a reference, just use the first object as a literal. 244 // This wasn't a reference, just use the first object as a literal.
200 // particularly used for the case of null. 245 // particularly used for the case of null.
201 subList.add(a); 246 subList.add(a);
202 } else { 247 } else {
203 subList.add(new Reference(this, a, b)); 248 subList.add(new Reference(this, a, b));
204 } 249 }
205 } 250 }
206 } 251 }
207 return ruleData; 252 return ruleData;
208 } 253 }
254
255 /**
256 * Return true because we need to write the length of each list in the flat
257 * format. */
258 bool get writeLengthInFlatFormat => true;
259
260 /** Return the length of the next list when reading the flat format. */
261 int dataLengthIn(Iterator stream) => stream.next();
209 } 262 }
210 263
211 /** 264 /**
212 * This is a subclass of ListRule where all of the list's contents are 265 * This is a subclass of ListRule where all of the list's contents are
213 * considered essential state. This is needed if an object X contains a List L, 266 * considered essential state. This is needed if an object X contains a List L,
214 * but it expects L's contents to be fixed when X's constructor is called. 267 * but it expects L's contents to be fixed when X's constructor is called.
215 */ 268 */
216 class ListRuleEssential extends ListRule { 269 class ListRuleEssential extends ListRule {
217 270
218 /** Create the new List and also inflate all of its contents. */ 271 /** Create the new List and also inflate all of its contents. */
219 inflateEssential(List state, Reader r) { 272 inflateEssential(List state, Reader r) {
220 var object = super.inflateEssential(state, r); 273 var object = super.inflateEssential(state, r);
221 populateContents(state, object, r); 274 populateContents(state, object, r);
222 return object; 275 return object;
223 } 276 }
224 277
225 /** Does nothing, because all the work has been done in inflateEssential. */ 278 /** Does nothing, because all the work has been done in inflateEssential. */
226 inflateNonEssential(state, newList, reader) {} 279 inflateNonEssential(state, newList, reader) {}
227 280
228 bool get mustBePrimary => true; 281 bool get mustBePrimary => true;
229 } 282 }
230 283
231 /** 284 /**
232 * This rule handles primitive types, defined as those that we can normally 285 * This rule handles primitive types, defined as those that we can normally
233 * represent directly in the output format. We hard-code that to mean 286 * represent directly in the output format. We hard-code that to mean
234 * num, String, and bool. 287 * num, String, and bool.
235 */ 288 */
236 class PrimitiveRule extends SerializationRule { 289 class PrimitiveRule extends SerializationRule {
237 appliesTo(object) { 290 appliesTo(object, Writer w) {
238 return isPrimitive(object); 291 return isPrimitive(object);
239 } 292 }
240 extractState(object, Function f) => object; 293 extractState(object, Function f) => object;
241 void flatten(object, Writer writer) {} 294 void flatten(object, Writer writer) {}
242 inflateEssential(state, Reader r) => state; 295 inflateEssential(state, Reader r) => state;
243 inflateNonEssential(object, _, Reader r) {} 296 inflateNonEssential(object, _, Reader r) {}
244 297
245 /** Indicate whether we should save pointers to this object as references 298 /**
299 * Indicate whether we should save pointers to this object as references
246 * or store the object directly. For primitives this depends on the format, 300 * or store the object directly. For primitives this depends on the format,
247 * so we delegate to the writer. 301 * so we delegate to the writer.
248 */ 302 */
249 bool shouldUseReferenceFor(Object o, Writer w) => 303 bool shouldUseReferenceFor(object, Writer w) =>
250 w.shouldUseReferencesForPrimitives; 304 w.shouldUseReferencesForPrimitives;
251 305
252 /** 306 /**
253 * This writes the data from our internal representation into a List. 307 * This writes the data from our internal representation into a List.
254 * It is used in order to write to a flat format, and is likely to be 308 * It is used in order to write to a flat format, and is likely to be
255 * folded into a more general mechanism for supporting different output 309 * folded into a more general mechanism for supporting different output
256 * formats. For primitives, the ruleData is our list of all the 310 * formats. For primitives, the ruleData is our list of all the
257 * primitives and just add it into the target. 311 * primitives and just add it into the target.
258 */ 312 */
259 void dumpStateInto(List ruleData, List target) { 313 void dumpStateInto(List ruleData, List target) {
260 target.addAll(ruleData); 314 target.addAll(ruleData);
261 } 315 }
262 316
263 /** 317 /**
264 * When reading from a flat format we are given [stream] and need to pull as 318 * When reading from a flat format we are given [stream] and need to pull as
265 * much data from it as we need. Our format is that we have an integer N 319 * much data from it as we need. Our format is that we have an integer N
266 * indicating the number of objects and then N simple objects. 320 * indicating the number of objects and then N simple objects.
267 */ 321 */
268 pullStateFrom(Iterator stream) { 322 pullStateFrom(Iterator stream) {
269 var dataLength = stream.next(); 323 var length = stream.next();
270 var ruleData = new List(); 324 var ruleData = new List();
271 for (var i = 0; i < dataLength; i++) { 325 for (var i = 0; i < length; i++) {
272 ruleData.add(stream.next()); 326 ruleData.add(stream.next());
273 } 327 }
274 return ruleData; 328 return ruleData;
275 } 329 }
276 } 330 }
277 331
278 /** Helper function for PrimitiveRule to tell which objects it applies to. */ 332 /** Helper function for PrimitiveRule to tell which objects it applies to. */
279 bool isPrimitive(Object object) { 333 bool isPrimitive(object) {
280 return object is num || object is String || object is bool; 334 return object is num || object is String || object is bool;
281 } 335 }
282 336
283 /** Typedef for the object construction closure used in ClosureToMapRule. */ 337 /** Typedef for the object construction closure used in ClosureRule. */
284 typedef Object ConstructType(Map m); 338 typedef ConstructType(Map m);
285 339
286 /** Typedef for the state-getting closure used in ClosureToMapRule. */ 340 /** Typedef for the state-getting closure used in ClosureToMapRule. */
287 typedef Map<String, Object> GetStateType(Object o); 341 typedef Map<String, dynamic> GetStateType(object);
288 342
289 /** Typedef for the state-setting closure used in ClosureToMapRule. */ 343 /** Typedef for the state-setting closure used in ClosureToMapRule. */
290 typedef void NonEssentialStateType(Object o, Map m); 344 typedef void NonEssentialStateType(object, Map m);
291 345
292 /** 346 /**
293 * This is a rule where the extraction and creation are hard-coded as 347 * This is a rule where the extraction and creation are hard-coded as
294 * closures. The result is expected to be a map indexed by field name. 348 * closures. The result is expected to be a map indexed by field name.
295 */ 349 */
296 class ClosureToMapRule extends SerializationRule { 350 class ClosureRule extends CustomRule {
297 351
298 /** The runtimeType of objects that this rule applies to. Used in appliesTo.*/ 352 /** The runtimeType of objects that this rule applies to. Used in appliesTo.*/
299 final Type type; 353 final Type type;
300 354
301 /** The function for constructing new objects when reading. */ 355 /** The function for constructing new objects when reading. */
302 ConstructType construct; 356 ConstructType construct;
303 357
304 /** The function for returning an object's state as a Map. */ 358 /** The function for returning an object's state as a Map. */
305 GetStateType getState; 359 GetStateType getStateFunction;
306 360
307 /** The function for setting an object's state from a Map. */ 361 /** The function for setting an object's state from a Map. */
308 NonEssentialStateType setNonEssentialState; 362 NonEssentialStateType setNonEssentialState;
309 363
310 /** 364 /**
311 * Create a ClosureToMapRule for the given [type] which gets an object's 365 * Create a ClosureToMapRule for the given [type] which gets an object's
312 * state by calling [getState], creates a new object by calling [construct] 366 * state by calling [getState], creates a new object by calling [construct]
313 * and sets the new object's state by calling [setNonEssentialState]. 367 * and sets the new object's state by calling [setNonEssentialState].
314 */ 368 */
315 ClosureToMapRule(this.type, this.getState, this.construct, 369 ClosureRule(this.type, this.getStateFunction, this.construct,
316 this.setNonEssentialState); 370 this.setNonEssentialState);
317 371
318 /** 372 bool appliesTo(object, Writer w) => object.runtimeType == type;
319 * If we deserialize a ClosureToMapRule we can't actually use it, because 373
320 * we don't have the closures, so generate a stub that just returns the 374 getState(object) => getStateFunction(object);
321 * raw state object. 375
322 */ 376 create(state) => construct(state);
323 ClosureToMapRule.stub(this.type) { 377
324 getState = (x) { throw new SerializationException( 378 setState(object, state) {
325 'Closures cannot be serialized'); }; 379 if (setNonEssentialState == null) return;
326 construct = (state) => state; 380 setNonEssentialState(object, state);
327 setNonEssentialState = (object, state) {}; 381 }
328 } 382 }
329 383
330 bool appliesTo(object) => object.runtimeType == type; 384 /**
331 385 * This rule handles things we can't pass directly, but only by reference.
332 extractState(object, Function f) { 386 * If objects are listed in the namedObjects in the writer or serialization,
333 Map state = getState(object); 387 * it will save the name rather than saving the state.
334 values(state).forEach(f); 388 */
389 class NamedObjectRule extends SerializationRule {
390 /**
391 * Return true if this rule applies to the object. Checked by looking up
392 * in the namedObjects collection.
393 */
394 bool appliesTo(object, Writer writer) {
395 return writer.hasNameFor(object);
396 }
397
398 /** Extract the state of the named objects as just the object itself. */
399 extractState(object, Function f) => [object];
400
401 /** When we flatten the state we save it as the name. */
402 // TODO(alanknight): This seems questionable. In a truly flat format we may
403 // want to have extracted the name as a string first and flatten it into a
404 // reference to that. But that requires adding the Writer as a parameter to
405 // extractState, and I'm reluctant to add yet another parameter until
406 // proven necessary.
407 void flatten(state, Writer writer) {
408 state[0] = nameFor(state.first, writer);
409 }
410
411 /** Look up the named object and return it. */
412 inflateEssential(state, Reader r) => r.objectNamed(state.first);
413
414 /** Set any non-essential state on the object. For this rule, a no-op. */
415 inflateNonEssential(state, object, Reader r) {}
416
417 /** Return the name for this object in the Writer. */
418 nameFor(object, Writer writer) => writer.nameFor(object);
419 }
420
421 /**
422 * This rule handles the special case of Mirrors, restricted to those that
423 * have a simpleName. It knows that it applies to any such mirror and
424 * automatically uses its simpleName as the key into the namedObjects.
425 * When reading, the user is still responsible for adding the appropriate
426 * mirrors to namedObject.
427 */
428 class MirrorRule extends NamedObjectRule {
429 bool appliesTo(object, Writer writer) => object is DeclarationMirror;
430 nameFor(DeclarationMirror object, Writer writer) => object.simpleName;
431 }
432
433 /**
434 * This provides an abstract superclass for writing your own rules specific to
435 * a class. It makes some assumptions about behaviour, and so can have a
436 * simpler set of methods that need to be implemented in order to subclass it.
437 *
438 */
439 abstract class CustomRule extends SerializationRule {
440 // TODO(alanknight): It would be nice if we could provide an implementation
441 // of appliesTo() here. If we add a type parameter to these classes
442 // we can "is" test against it, but we need to be able to rule out subclasses.
443 // => instance.runtimeType == T
444 // should work.
445 /**
446 * Return true if this rule applies to this object, in the context
447 * where we're writing it, false otherwise.
448 */
449 bool appliesTo(instance, Writer w);
450
451 /**
452 * Subclasses should implement this to return a list of the important fields
453 * in the object. The order of the fields doesn't matter, except that the
454 * create and setState methods need to know how to use it.
455 */
456 List getState(instance);
457
458 /**
459 * Given a [List] of the object's [state], re-create the object. This should
460 * do the minimum needed to create the object, just calling the constructor.
461 * Setting the remaining state of the object should be done in the [setState]
462 * method, which will be called only once all the objects are created, so
463 * it won't cause problems with cycles.
464 */
465 create(List state);
466
467 /**
468 * Set any state in [object] which wasn't set in the constructor. Between
469 * this method and [create] all of the information in [state] should be set
470 * in the new object.
471 */
472 void setState(object, List state);
473
474 extractState(instance, Function f) {
475 var state = getState(instance);
476 for (var each in values(state)) {
477 f(each);
478 }
335 return state; 479 return state;
336 } 480 }
337 481
338 // TODO(alanknight): We're inflating twice here. How to avoid doing 482 inflateEssential(state, Reader r) => create(_lazy(state, r));
339 // that without giving the user even more stuff to specify. 483
340 // Worse than that, by inflating everything in advance, we are are 484 void inflateNonEssential(state, object, Reader r) =>
341 // forcing all the state to be essential. 485 setState(object, _lazy(state, r));
342 Object inflateEssential(Map<String, Object> state, Reader r) { 486
343 var inflated = values(state).map((x) => r.inflateReference(x)); 487 // We don't want to have to make the end user tell us how long the list is
344 return construct(inflated); 488 // separately, so write it out for each object, even though they're all
345 } 489 // expected to be the same length.
346 490 get writeLengthInFlatFormat => true;
347 void inflateNonEssential(state, object, Reader r) { 491 }
348 if (setNonEssentialState == null) return; 492
349 var inflated = values(state).map((x) => r.inflateReference(x)); 493 /** Create a lazy list/map that will inflate its items on demand in [r]. */
350 setNonEssentialState(inflated, object); 494 _lazy(l, Reader r) {
351 } 495 if (l is List) return new _LazyList(l, r);
352 } 496 if (l is Map) return new _LazyMap(l, r);
353 497 throw new SerializationException("Invalid type: must be Map or List - $l");
354 /** 498 }
355 * This rule handles things we can't pass directly, but only by reference. 499
356 * It extracts an identifier we can use to pass them. 500 /**
357 */ 501 * This provides an implementation of Map that wraps a list which may
358 class ClassMirrorRule extends SerializationRule { 502 * contain references to (potentially) non-inflated objects. If these
359 // TODO(alanknight): This probably generalizes to any named object. 503 * are accessed it will inflate them. This allows us to pass something that
360 bool appliesTo(object) { 504 * looks like it's just a list of objects to a [CustomRule] without needing
361 return object is ClassMirror; 505 * to inflate all the references in advance.
362 } 506 */
363 extractState(object, Function f) => f(object.simpleName); 507 class _LazyMap implements Map {
364 void flatten(object, Writer writer) {} 508 _LazyMap(this._raw, this._reader);
365 inflateEssential(state, Reader r) => r.externalObjectNamed(state); 509
366 inflateNonEssential(state, object, Reader r) {} 510 Map _raw;
511 Reader _reader;
512
513 // This is the only operation that really matters.
514 operator [](x) => _reader.inflateReference(_raw[x]);
515
516 int get length => _raw.length;
517 bool get isEmpty => _raw.isEmpty;
518 List get keys => _raw.keys;
519 bool containsKey(x) => _raw.containsKey(x);
520
521 // These operations will work, but may be expensive, and are probably
522 // best avoided.
523 get _inflated => keysAndValues(_raw).map(_reader.inflateReference);
524 bool containsValue(x) => _inflated.containsValue(x);
525 List get values => _inflated.values;
526 void forEach(f) => _inflated.forEach(f);
527
528 // These operations are all invalid
529 _throw() => throw new UnsupportedError("Not modifiable");
530 operator []=(x, y) => _throw();
531 putIfAbsent(x, y) => _throw();
532 remove(x) => _throw();
533 clear() => _throw();
534 }
535
536 /**
537 * This provides an implementation of List that wraps a list which may
538 * contain references to (potentially) non-inflated objects. If these
539 * are accessed it will inflate them. This allows us to pass something that
540 * looks like it's just a list of objects to a [CustomRule] without needing
541 * to inflate all the references in advance.
542 */
543 class _LazyList implements List {
544 _LazyList(this._raw, this._reader);
545
546 List _raw;
547 Reader _reader;
548
549 // This is the only operation that really matters.
550 operator [](x) => _reader.inflateReference(_raw[x]);
551
552 int get length => _raw.length;
553 bool get isEmpty => _raw.isEmpty;
554 get first => _reader.inflateReference(_raw.first);
555 get last => _reader.inflateReference(_raw.last);
556
557 // These operations will work, but may be expensive, and are probably
558 // best avoided.
559 get _inflated => _raw.map(_reader.inflateReference);
560 map(f) => _inflated.map(f);
561 filter(f) => _inflated.filter(f);
562 bool contains(element) => _inflated.filter(element);
563 forEach(f) => _inflated.forEach(f);
564 reduce(x, f) => _inflated.reduce(x, f);
565 every(f) => _inflated(f);
566 some(f) => _inflated(f);
567 iterator() => _inflated.iterator();
568 indexOf(x, [pos = 0]) => _inflated.indexOf(x);
569 lastIndexOf(x, [pos]) => _inflated.lastIndexOf(x);
570
571 // These operations are all invalid
572 _throw() => throw new UnsupportedError("Not modifiable");
573 operator []=(x, y) => _throw();
574 add(x) => _throw();
575 addLast(x) => _throw();
576 addAll(x) => _throw();
577 sort([f]) => _throw();
578 clear() => _throw();
579 removeAt(x) => _throw();
580 removeLast() => _throw();
581 getRange(x, y) => _throw();
582 setRange(x, y, z, [a]) => _throw();
583 removeRange(x, y) => _throw();
584 insertRange(x, y, [z]) => _throw();
585 void set length(x) => _throw();
367 } 586 }
OLDNEW
« no previous file with comments | « pkg/serialization/lib/src/serialization_helpers.dart ('k') | pkg/serialization/test/serialization_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698