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

Side by Side Diff: pkg/serialization/lib/src/serialization_rule.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, 11 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 // 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 10 matching lines...) Expand all
21 * Rules belong uniquely to a particular Serialization instance, and can 21 * Rules belong uniquely to a particular Serialization instance, and can
22 * be identified within it by number. 22 * be identified within it by number.
23 */ 23 */
24 int get number => _number; 24 int get number => _number;
25 25
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 && _number != x) 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 /** 36 /**
37 * Return true if this rule applies to this object, in the context 37 * Return true if this rule applies to this object, in the context
38 * where we're writing it, false otherwise. 38 * where we're writing it, false otherwise.
39 */ 39 */
40 bool appliesTo(object, Writer writer); 40 bool appliesTo(object, Writer writer);
41 41
42 /** 42 /**
43 * 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
44 * as it is extracted, and returning an object representing the whole 44 * as it is extracted, and returning an object representing the whole
45 * 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
46 * pointers to objects, rather than references. 46 * pointers to objects, rather than references.
47 */ 47 */
48 extractState(object, void f(value)); 48 extractState(object, void f(value));
49 49
50 /** 50 /**
51 * Allows rules to tell us how they expect to store their state. If this
52 * isn't specified we can also just look at the data to tell.
53 */
54 bool get storesStateAsLists => false;
55 bool get storesStateAsMaps => false;
56 bool get storesStateAsPrimitives => false;
57
58 /**
51 * Given the variables representing the state of an object, flatten it 59 * Given the variables representing the state of an object, flatten it
52 * by turning object pointers into Reference objects where needed. This 60 * by turning object pointers into Reference objects where needed. This
53 * destructively modifies the state object. 61 * destructively modifies the state object.
54 * 62 *
55 * This has a default implementation which assumes that object is indexable, 63 * This has a default implementation which assumes that object is indexable,
56 * so either conforms to Map or List. Subclasses may override to do something 64 * so either conforms to Map or List. Subclasses may override to do something
57 * different. 65 * different, including returning a new state object to be used in place
66 * of the original.
58 */ 67 */
59 // This has to be a separate operation from extracting, because we extract 68 // This has to be a separate operation from extracting, because we extract
60 // as we are traversing the objects, so we don't yet have the objects to 69 // as we are traversing the objects, so we don't yet have the objects to
61 // generate references for them. It might be possible to avoid that by 70 // generate references for them. It might be possible to avoid that by
62 // doing a depth-first rather than breadth-first traversal, but I'm not 71 // doing a depth-first rather than breadth-first traversal, but I'm not
63 // sure it's worth it. 72 // sure it's worth it.
64 void flatten(state, Writer writer) { 73 flatten(state, Writer writer) {
65 keysAndValues(state).forEach((key, value) { 74 keysAndValues(state).forEach((key, value) {
66 var reference = writer._referenceFor(value); 75 var reference = writer._referenceFor(value);
67 state[key] = (reference == null) ? value : reference; 76 state[key] = reference;
68 }); 77 });
69 } 78 }
70 79
71 /** Return true if this rule should only be applied when we are the first 80 /** Return true if this rule should only be applied when we are the first
72 * rule found that applies to this object. This may or may not be a hack 81 * rule found that applies to this object. This may or may not be a hack
73 * that will disappear once we have better support for multiple rules. 82 * that will disappear once we have better support for multiple rules.
74 * We want to have multiple different rules that apply to the same object. We 83 * We want to have multiple different rules that apply to the same object. We
75 * also want to have multiple different rules that might exclusively apply 84 * also want to have multiple different rules that might exclusively apply
76 * to the same object. So, we want either ListRule or ListRuleEssential, and 85 * to the same object. So, we want either ListRule or ListRuleEssential, and
77 * only one of them can be there. But on the other hand, we may want both 86 * only one of them can be there. But on the other hand, we may want both
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 } 133 }
125 134
126 /** 135 /**
127 * This rule handles things that implement List. It will recreate them as 136 * This rule handles things that implement List. It will recreate them as
128 * whatever the default implemenation of List is on the target platform. 137 * whatever the default implemenation of List is on the target platform.
129 */ 138 */
130 class ListRule extends SerializationRule { 139 class ListRule extends SerializationRule {
131 140
132 appliesTo(object, Writer w) => object is List; 141 appliesTo(object, Writer w) => object is List;
133 142
134 state(List list) => new List.from(list); 143 bool get storesStateAsLists => true;
135 144
136 List extractState(List list, f) { 145 List extractState(List list, f) {
137 var result = new List(); 146 var result = new List();
138 for (var each in list) { 147 for (var each in list) {
139 result.add(each); 148 result.add(each);
140 f(each); 149 f(each);
141 } 150 }
142 return result; 151 return result;
143 } 152 }
144 153
(...skipping 28 matching lines...) Expand all
173 return object; 182 return object;
174 } 183 }
175 184
176 /** Does nothing, because all the work has been done in inflateEssential. */ 185 /** Does nothing, because all the work has been done in inflateEssential. */
177 inflateNonEssential(state, newList, reader) {} 186 inflateNonEssential(state, newList, reader) {}
178 187
179 bool get mustBePrimary => true; 188 bool get mustBePrimary => true;
180 } 189 }
181 190
182 /** 191 /**
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
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.
196 */
197 class MapRule extends SerializationRule {
198
199 appliesTo(object, Writer w) => object is Map;
200
201 bool get storesStateAsMaps => true;
202
203 extractState(Map map, f) {
204 // Note that we make a copy here because flattening may be destructive.
205 var newMap = new Map.from(map);
206 newMap.forEach((key, value) {
207 f(key);
208 f(value);
209 });
210 return newMap;
211 }
212
213 /**
214 * Change the keys and values of [state] into references in [writer].
215 * If [state] is a map whose keys are all strings then we leave the keys
216 * as is so that JSON formats will be more readable. If the keys are
217 * arbitrary then we need to turn them into references and replace the
218 * state with a new Map whose keys are the references.
219 */
220 flatten(Map state, Writer writer) {
221 bool keysAreAllStrings = state.keys.every((x) => x is String);
222 if (keysAreAllStrings) {
223 keysAndValues(state).forEach(
224 (key, value) => state[key] = writer._referenceFor(value));
225 return state;
226 } else {
227 var newState = [];
228 keysAndValues(state).forEach((key, value) {
229 newState.add(writer._referenceFor(key));
230 newState.add(writer._referenceFor(value));
231 });
232 return newState;
233 }
234 }
235
236 inflateEssential(state, Reader r) => new Map();
237
238 // For a map, we consider all of its state non-essential and add it
239 // after creation.
240 inflateNonEssential(state, Map newMap, Reader r) {
241 if (state is List) {
242 inflateNonEssentialFromList(state, newMap, r);
243 } else {
244 inflateNonEssentialFromMap(state, newMap, r);
245 }
246 }
247
248 void inflateNonEssentialFromList(List state, Map newMap, Reader r) {
249 var key;
250 for (var each in state) {
251 if (key == null) {
252 key = each;
253 } else {
254 newMap[r.inflateReference(key)] = r.inflateReference(each);
255 key = null;
256 }
257 }
258 }
259
260 void inflateNonEssentialFromMap(Map state, Map newMap, Reader r) {
261 state.forEach((key, value) {
262 newMap[r.inflateReference(key)] = r.inflateReference(value);
263 });
264 }
265
266 bool get hasVariableLengthEntries => true;
267 }
268
269 /**
183 * 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
184 * 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
185 * num, String, and bool. 272 * num, String, and bool.
186 */ 273 */
187 class PrimitiveRule extends SerializationRule { 274 class PrimitiveRule extends SerializationRule {
188 appliesTo(object, Writer w) { 275 appliesTo(object, Writer w) {
189 return isPrimitive(object); 276 return isPrimitive(object);
190 } 277 }
191 extractState(object, Function f) => object; 278 extractState(object, Function f) => object;
192 void flatten(object, Writer writer) {} 279 flatten(object, Writer writer) {}
193 inflateEssential(state, Reader r) => state; 280 inflateEssential(state, Reader r) => state;
194 inflateNonEssential(object, _, Reader r) {} 281 inflateNonEssential(object, _, Reader r) {}
195 282
283 bool get storesStateAsPrimitives => true;
284
196 /** 285 /**
197 * Indicate whether we should save pointers to this object as references 286 * Indicate whether we should save pointers to this object as references
198 * or store the object directly. For primitives this depends on the format, 287 * or store the object directly. For primitives this depends on the format,
199 * so we delegate to the writer. 288 * so we delegate to the writer.
200 */ 289 */
201 bool shouldUseReferenceFor(object, Writer w) => 290 bool shouldUseReferenceFor(object, Writer w) =>
202 w.shouldUseReferencesForPrimitives; 291 w.shouldUseReferencesForPrimitives;
203 292
204 bool get hasVariableLengthEntries => false; 293 bool get hasVariableLengthEntries => false;
205 } 294 }
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 356
268 /** Extract the state of the named objects as just the object itself. */ 357 /** Extract the state of the named objects as just the object itself. */
269 extractState(object, Function f) => [object]; 358 extractState(object, Function f) => [object];
270 359
271 /** When we flatten the state we save it as the name. */ 360 /** When we flatten the state we save it as the name. */
272 // TODO(alanknight): This seems questionable. In a truly flat format we may 361 // TODO(alanknight): This seems questionable. In a truly flat format we may
273 // want to have extracted the name as a string first and flatten it into a 362 // want to have extracted the name as a string first and flatten it into a
274 // reference to that. But that requires adding the Writer as a parameter to 363 // reference to that. But that requires adding the Writer as a parameter to
275 // extractState, and I'm reluctant to add yet another parameter until 364 // extractState, and I'm reluctant to add yet another parameter until
276 // proven necessary. 365 // proven necessary.
277 void flatten(state, Writer writer) { 366 flatten(state, Writer writer) {
278 state[0] = nameFor(state.first, writer); 367 state[0] = nameFor(state.first, writer);
279 } 368 }
280 369
281 /** Look up the named object and return it. */ 370 /** Look up the named object and return it. */
282 inflateEssential(state, Reader r) => r.objectNamed(state.first); 371 inflateEssential(state, Reader r) => r.objectNamed(state.first);
283 372
284 /** Set any non-essential state on the object. For this rule, a no-op. */ 373 /** Set any non-essential state on the object. For this rule, a no-op. */
285 inflateNonEssential(state, object, Reader r) {} 374 inflateNonEssential(state, object, Reader r) {}
286 375
287 /** Return the name for this object in the Writer. */ 376 /** Return the name for this object in the Writer. */
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
438 _throw() { 527 _throw() {
439 throw new UnsupportedError("Not modifiable"); 528 throw new UnsupportedError("Not modifiable");
440 } 529 }
441 operator []=(x, y) => _throw(); 530 operator []=(x, y) => _throw();
442 add(x) => _throw(); 531 add(x) => _throw();
443 addLast(x) => _throw(); 532 addLast(x) => _throw();
444 addAll(x) => _throw(); 533 addAll(x) => _throw();
445 sort([f]) => _throw(); 534 sort([f]) => _throw();
446 clear() => _throw(); 535 clear() => _throw();
447 removeAt(x) => _throw(); 536 removeAt(x) => _throw();
537 remove(x) => _throw();
448 removeLast() => _throw(); 538 removeLast() => _throw();
449 remove(x) => _throw();
450 removeAll(x) => _throw(); 539 removeAll(x) => _throw();
451 retainAll(x) => _throw(); 540 retainAll(x) => _throw();
452 removeMatching(x) => _throw(); 541 removeMatching(x) => _throw();
453 retainMatching(x) => _throw(); 542 retainMatching(x) => _throw();
454 getRange(x, y) => _throw(); 543 getRange(x, y) => _throw();
455 setRange(x, y, z, [a]) => _throw(); 544 setRange(x, y, z, [a]) => _throw();
456 removeRange(x, y) => _throw(); 545 removeRange(x, y) => _throw();
457 insertRange(x, y, [z]) => _throw(); 546 insertRange(x, y, [z]) => _throw();
547 get reversed => _throw();
458 void set length(x) => _throw(); 548 void set length(x) => _throw();
459 List get reversed => _throw();
460 } 549 }
OLDNEW
« no previous file with comments | « pkg/serialization/lib/src/reader_writer.dart ('k') | pkg/serialization/test/serialization_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698