| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of serialization; | 5 part of serialization; |
| 6 | 6 |
| 7 // 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 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 * object's constructor. It is up to the rule what state is considered | 100 * object's constructor. It is up to the rule what state is considered |
| 101 * essential. | 101 * essential. |
| 102 */ | 102 */ |
| 103 inflateEssential(state, Reader reader); | 103 inflateEssential(state, Reader reader); |
| 104 | 104 |
| 105 /** | 105 /** |
| 106 * The [object] has already been created. Set any of its non-essential | 106 * The [object] has already been created. Set any of its non-essential |
| 107 * variables from the representation in [state]. Where there are references | 107 * variables from the representation in [state]. Where there are references |
| 108 * to other objects they are resolved in the context of [reader]. | 108 * to other objects they are resolved in the context of [reader]. |
| 109 */ | 109 */ |
| 110 inflateNonEssential(state, object, Reader reader); | 110 void inflateNonEssential(state, object, Reader reader); |
| 111 | 111 |
| 112 /** | 112 /** |
| 113 * If we have [object] as part of our state, should we represent that | 113 * If we have [object] as part of our state, should we represent that |
| 114 * directly, or should we make a reference for it. By default, true. | 114 * directly, or should we make a reference for it. By default, true. |
| 115 * This may also delegate to [writer]. | 115 * This may also delegate to [writer]. |
| 116 */ | 116 */ |
| 117 bool shouldUseReferenceFor(object, Writer writer) => true; | 117 bool shouldUseReferenceFor(object, Writer writer) => true; |
| 118 | 118 |
| 119 /** | 119 /** |
| 120 * Return true if the data this rule returns is variable length, so a | 120 * Return true if the data this rule returns is variable length, so a |
| (...skipping 27 matching lines...) Expand all Loading... |
| 148 result.add(each); | 148 result.add(each); |
| 149 f(each); | 149 f(each); |
| 150 } | 150 } |
| 151 return result; | 151 return result; |
| 152 } | 152 } |
| 153 | 153 |
| 154 inflateEssential(List state, Reader r) => new List(); | 154 inflateEssential(List state, Reader r) => new List(); |
| 155 | 155 |
| 156 // For a list, we consider all of its state non-essential and add it | 156 // For a list, we consider all of its state non-essential and add it |
| 157 // after creation. | 157 // after creation. |
| 158 inflateNonEssential(List state, List newList, Reader r) { | 158 void inflateNonEssential(List state, List newList, Reader r) { |
| 159 populateContents(state, newList, r); | 159 populateContents(state, newList, r); |
| 160 } | 160 } |
| 161 | 161 |
| 162 void populateContents(List state, List newList, Reader r) { | 162 void populateContents(List state, List newList, Reader r) { |
| 163 for(var each in state) { | 163 for(var each in state) { |
| 164 newList.add(r.inflateReference(each)); | 164 newList.add(r.inflateReference(each)); |
| 165 } | 165 } |
| 166 } | 166 } |
| 167 | 167 |
| 168 bool get hasVariableLengthEntries => true; | 168 bool get hasVariableLengthEntries => true; |
| 169 } | 169 } |
| 170 | 170 |
| 171 /** | 171 /** |
| 172 * This is a subclass of ListRule where all of the list's contents are | 172 * This is a subclass of ListRule where all of the list's contents are |
| 173 * considered essential state. This is needed if an object X contains a List L, | 173 * considered essential state. This is needed if an object X contains a List L, |
| 174 * but it expects L's contents to be fixed when X's constructor is called. | 174 * but it expects L's contents to be fixed when X's constructor is called. |
| 175 */ | 175 */ |
| 176 class ListRuleEssential extends ListRule { | 176 class ListRuleEssential extends ListRule { |
| 177 | 177 |
| 178 /** Create the new List and also inflate all of its contents. */ | 178 /** Create the new List and also inflate all of its contents. */ |
| 179 inflateEssential(List state, Reader r) { | 179 inflateEssential(List state, Reader r) { |
| 180 var object = super.inflateEssential(state, r); | 180 var object = super.inflateEssential(state, r); |
| 181 populateContents(state, object, r); | 181 populateContents(state, object, r); |
| 182 return object; | 182 return object; |
| 183 } | 183 } |
| 184 | 184 |
| 185 /** Does nothing, because all the work has been done in inflateEssential. */ | 185 /** Does nothing, because all the work has been done in inflateEssential. */ |
| 186 inflateNonEssential(state, newList, reader) {} | 186 void inflateNonEssential(state, newList, reader) {} |
| 187 | 187 |
| 188 bool get mustBePrimary => true; | 188 bool get mustBePrimary => true; |
| 189 } | 189 } |
| 190 | 190 |
| 191 /** | 191 /** |
| 192 * This rule handles things that implement Map. It will recreate them as | 192 * This rule handles things that implement Map. It will recreate them as |
| 193 * whatever the default implemenation of Map is on the target platform. If a | 193 * whatever the default implemenation of Map is on the target platform. If a |
| 194 * map has string keys it will attempt to retain it as a map for JSON formats, | 194 * map has string keys it will attempt to retain it as a map for JSON formats, |
| 195 * otherwise it will store it as a list of references to keys and values. | 195 * otherwise it will store it as a list of references to keys and values. |
| 196 */ | 196 */ |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 230 newState.add(writer._referenceFor(value)); | 230 newState.add(writer._referenceFor(value)); |
| 231 }); | 231 }); |
| 232 return newState; | 232 return newState; |
| 233 } | 233 } |
| 234 } | 234 } |
| 235 | 235 |
| 236 inflateEssential(state, Reader r) => new Map(); | 236 inflateEssential(state, Reader r) => new Map(); |
| 237 | 237 |
| 238 // For a map, we consider all of its state non-essential and add it | 238 // For a map, we consider all of its state non-essential and add it |
| 239 // after creation. | 239 // after creation. |
| 240 inflateNonEssential(state, Map newMap, Reader r) { | 240 void inflateNonEssential(state, Map newMap, Reader r) { |
| 241 if (state is List) { | 241 if (state is List) { |
| 242 inflateNonEssentialFromList(state, newMap, r); | 242 inflateNonEssentialFromList(state, newMap, r); |
| 243 } else { | 243 } else { |
| 244 inflateNonEssentialFromMap(state, newMap, r); | 244 inflateNonEssentialFromMap(state, newMap, r); |
| 245 } | 245 } |
| 246 } | 246 } |
| 247 | 247 |
| 248 void inflateNonEssentialFromList(List state, Map newMap, Reader r) { | 248 void inflateNonEssentialFromList(List state, Map newMap, Reader r) { |
| 249 var key; | 249 var key; |
| 250 for (var each in state) { | 250 for (var each in state) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 269 /** | 269 /** |
| 270 * This rule handles primitive types, defined as those that we can normally | 270 * This rule handles primitive types, defined as those that we can normally |
| 271 * represent directly in the output format. We hard-code that to mean | 271 * represent directly in the output format. We hard-code that to mean |
| 272 * num, String, and bool. | 272 * num, String, and bool. |
| 273 */ | 273 */ |
| 274 class PrimitiveRule extends SerializationRule { | 274 class PrimitiveRule extends SerializationRule { |
| 275 bool appliesTo(object, Writer w) => isPrimitive(object); | 275 bool appliesTo(object, Writer w) => isPrimitive(object); |
| 276 extractState(object, Function f, Writer w) => object; | 276 extractState(object, Function f, Writer w) => object; |
| 277 flatten(object, Writer writer) {} | 277 flatten(object, Writer writer) {} |
| 278 inflateEssential(state, Reader r) => state; | 278 inflateEssential(state, Reader r) => state; |
| 279 inflateNonEssential(object, _, Reader r) {} | 279 void inflateNonEssential(object, _, Reader r) {} |
| 280 | 280 |
| 281 bool get storesStateAsPrimitives => true; | 281 bool get storesStateAsPrimitives => true; |
| 282 | 282 |
| 283 /** | 283 /** |
| 284 * Indicate whether we should save pointers to this object as references | 284 * Indicate whether we should save pointers to this object as references |
| 285 * or store the object directly. For primitives this depends on the format, | 285 * or store the object directly. For primitives this depends on the format, |
| 286 * so we delegate to the writer. | 286 * so we delegate to the writer. |
| 287 */ | 287 */ |
| 288 bool shouldUseReferenceFor(object, Writer w) => | 288 bool shouldUseReferenceFor(object, Writer w) => |
| 289 w.shouldUseReferencesForPrimitives; | 289 w.shouldUseReferencesForPrimitives; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 303 /** | 303 /** |
| 304 * This is a rule where the extraction and creation are hard-coded as | 304 * This is a rule where the extraction and creation are hard-coded as |
| 305 * closures. The result is expected to be a map indexed by field name. | 305 * closures. The result is expected to be a map indexed by field name. |
| 306 */ | 306 */ |
| 307 class ClosureRule extends CustomRule { | 307 class ClosureRule extends CustomRule { |
| 308 | 308 |
| 309 /** The runtimeType of objects that this rule applies to. Used in appliesTo.*/ | 309 /** The runtimeType of objects that this rule applies to. Used in appliesTo.*/ |
| 310 final Type type; | 310 final Type type; |
| 311 | 311 |
| 312 /** The function for constructing new objects when reading. */ | 312 /** The function for constructing new objects when reading. */ |
| 313 ConstructType construct; | 313 final ConstructType construct; |
| 314 | 314 |
| 315 /** The function for returning an object's state as a Map. */ | 315 /** The function for returning an object's state as a Map. */ |
| 316 GetStateType getStateFunction; | 316 final GetStateType getStateFunction; |
| 317 | 317 |
| 318 /** The function for setting an object's state from a Map. */ | 318 /** The function for setting an object's state from a Map. */ |
| 319 NonEssentialStateType setNonEssentialState; | 319 final NonEssentialStateType setNonEssentialState; |
| 320 | 320 |
| 321 /** | 321 /** |
| 322 * Create a ClosureToMapRule for the given [type] which gets an object's | 322 * Create a ClosureToMapRule for the given [type] which gets an object's |
| 323 * state by calling [getState], creates a new object by calling [construct] | 323 * state by calling [getState], creates a new object by calling [construct] |
| 324 * and sets the new object's state by calling [setNonEssentialState]. | 324 * and sets the new object's state by calling [setNonEssentialState]. |
| 325 */ | 325 */ |
| 326 ClosureRule(this.type, this.getStateFunction, this.construct, | 326 ClosureRule(this.type, this.getStateFunction, this.construct, |
| 327 this.setNonEssentialState); | 327 this.setNonEssentialState); |
| 328 | 328 |
| 329 bool appliesTo(object, Writer w) => object.runtimeType == type; | 329 bool appliesTo(object, Writer w) => object.runtimeType == type; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 367 // proven necessary. | 367 // proven necessary. |
| 368 flatten(state, Writer writer) { | 368 flatten(state, Writer writer) { |
| 369 state[0] = writer._referenceFor(state[0]); | 369 state[0] = writer._referenceFor(state[0]); |
| 370 } | 370 } |
| 371 | 371 |
| 372 /** Look up the named object and return it. */ | 372 /** Look up the named object and return it. */ |
| 373 inflateEssential(state, Reader r) => | 373 inflateEssential(state, Reader r) => |
| 374 r.objectNamed(r.resolveReference(state.first)); | 374 r.objectNamed(r.resolveReference(state.first)); |
| 375 | 375 |
| 376 /** Set any non-essential state on the object. For this rule, a no-op. */ | 376 /** Set any non-essential state on the object. For this rule, a no-op. */ |
| 377 inflateNonEssential(state, object, Reader r) {} | 377 void inflateNonEssential(state, object, Reader r) {} |
| 378 | 378 |
| 379 /** Return the name for this object in the Writer. */ | 379 /** Return the name for this object in the Writer. */ |
| 380 String nameFor(object, Writer writer) => writer.nameFor(object); | 380 String nameFor(object, Writer writer) => writer.nameFor(object); |
| 381 } | 381 } |
| 382 | 382 |
| 383 /** | 383 /** |
| 384 * This rule handles the special case of Mirrors. It stores the mirror by its | 384 * This rule handles the special case of Mirrors. It stores the mirror by its |
| 385 * qualifiedName and attempts to look it up in both the namedObjects | 385 * qualifiedName and attempts to look it up in both the namedObjects |
| 386 * collection, or if it's not found there, by looking it up in the mirror | 386 * collection, or if it's not found there, by looking it up in the mirror |
| 387 * system. When reading, the user is responsible for supplying the appropriate | 387 * system. When reading, the user is responsible for supplying the appropriate |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 489 create(state) => new Symbol(state[0]); | 489 create(state) => new Symbol(state[0]); |
| 490 void setState(symbol, state) {} | 490 void setState(symbol, state) {} |
| 491 int get dataLength => 1; | 491 int get dataLength => 1; |
| 492 bool get hasVariableLengthEntries => false; | 492 bool get hasVariableLengthEntries => false; |
| 493 } | 493 } |
| 494 | 494 |
| 495 /** A hard-coded rule for DateTime. */ | 495 /** A hard-coded rule for DateTime. */ |
| 496 class DateTimeRule extends CustomRule { | 496 class DateTimeRule extends CustomRule { |
| 497 bool appliesTo(instance, _) => instance is DateTime; | 497 bool appliesTo(instance, _) => instance is DateTime; |
| 498 List getState(DateTime date) => [date.millisecondsSinceEpoch, date.isUtc]; | 498 List getState(DateTime date) => [date.millisecondsSinceEpoch, date.isUtc]; |
| 499 create(List state) => | 499 DateTime create(List state) => |
| 500 new DateTime.fromMillisecondsSinceEpoch(state[0], isUtc: state[1]); | 500 new DateTime.fromMillisecondsSinceEpoch(state[0], isUtc: state[1]); |
| 501 void setState(date, state) {} | 501 void setState(date, state) {} |
| 502 // Let the system know we don't have to store a length for these. | 502 // Let the system know we don't have to store a length for these. |
| 503 int get dataLength => 2; | 503 int get dataLength => 2; |
| 504 bool get hasVariableLengthEntries => false; | 504 bool get hasVariableLengthEntries => false; |
| 505 } | 505 } |
| 506 | 506 |
| 507 /** Create a lazy list/map that will inflate its items on demand in [r]. */ | 507 /** Create a lazy list/map that will inflate its items on demand in [r]. */ |
| 508 _lazy(l, Reader r) { | 508 _lazy(l, Reader r) { |
| 509 if (l is List) return new _LazyList(l, r); | 509 if (l is List) return new _LazyList(l, r); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 551 void addAll(Map other) => _throw(); | 551 void addAll(Map other) => _throw(); |
| 552 } | 552 } |
| 553 | 553 |
| 554 /** | 554 /** |
| 555 * This provides an implementation of List that wraps a list which may | 555 * This provides an implementation of List that wraps a list which may |
| 556 * contain references to (potentially) non-inflated objects. If these | 556 * contain references to (potentially) non-inflated objects. If these |
| 557 * are accessed it will inflate them. This allows us to pass something that | 557 * are accessed it will inflate them. This allows us to pass something that |
| 558 * looks like it's just a list of objects to a [CustomRule] without needing | 558 * looks like it's just a list of objects to a [CustomRule] without needing |
| 559 * to inflate all the references in advance. | 559 * to inflate all the references in advance. |
| 560 */ | 560 */ |
| 561 class _LazyList extends IterableBase with ListMixin implements List { | 561 class _LazyList extends ListBase { |
| 562 _LazyList(this._raw, this._reader); | 562 _LazyList(this._raw, this._reader); |
| 563 | 563 |
| 564 final List _raw; | 564 final List _raw; |
| 565 final Reader _reader; | 565 final Reader _reader; |
| 566 | 566 |
| 567 operator [](int x) => _reader.inflateReference(_raw[x]); | 567 operator [](int x) => _reader.inflateReference(_raw[x]); |
| 568 int get length => _raw.length; | 568 int get length => _raw.length; |
| 569 | 569 |
| 570 void set length(int value) => _throw(); | 570 void set length(int value) => _throw(); |
| 571 | 571 |
| 572 void operator []=(int index, value) => _throw(); | 572 void operator []=(int index, value) => _throw(); |
| 573 | 573 |
| 574 void _throw() { | 574 void _throw() { |
| 575 throw new UnsupportedError("Not modifiable"); | 575 throw new UnsupportedError("Not modifiable"); |
| 576 } | 576 } |
| 577 } | 577 } |
| OLD | NEW |