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

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

Issue 11931030: Add a MapRule (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Adds another test 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 part of serialization; 1 part of serialization;
2 2
3 /** 3 /**
4 * An abstract class for serialization formats. Subclasses define how data 4 * An abstract class for serialization formats. Subclasses define how data
5 * is read or written to a particular output mechanism. 5 * is read or written to a particular output mechanism.
6 */ 6 */
7 abstract class Format { 7 abstract class Format {
8 /** 8 /**
9 * Return true if this format stores primitives in their own area and uses 9 * Return true if this format stores primitives in their own area and uses
10 * references to them (e.g. [SimpleFlatFormat]) and false if primitives 10 * references to them (e.g. [SimpleFlatFormat]) and false if primitives
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
150 * entries for "rules", "data", and "roots". Nested lists/maps will be 150 * entries for "rules", "data", and "roots". Nested lists/maps will be
151 * converted into Reference objects. Note that if the data was not written 151 * converted into Reference objects. Note that if the data was not written
152 * with [storeRoundTripInfo] true this will fail. 152 * with [storeRoundTripInfo] true this will fail.
153 */ 153 */
154 Map<String, dynamic> read(String input, Reader r) { 154 Map<String, dynamic> read(String input, Reader r) {
155 var data = json.parse(input); 155 var data = json.parse(input);
156 var result = {}; 156 var result = {};
157 result["rules"] = null; 157 result["rules"] = null;
158 var ruleData = 158 var ruleData =
159 new List(r.serialization.rules.length).mappedBy((x) => []).toList(); 159 new List(r.serialization.rules.length).mappedBy((x) => []).toList();
160 var rootRule = data["__rule"]; 160 var rootRule = (data is Map) ? data["__rule"] : data.last;
Jennifer Messerly 2013/01/25 01:19:59 hmmm. Do we know for sure "data" is an Iterable or
Alan Knight 2013/01/26 01:33:38 Done.
161 var top = recursivelyFixUp(data, r, ruleData); 161 var top = recursivelyFixUp(data, r, ruleData);
162 result["data"] = ruleData; 162 result["data"] = ruleData;
163 result["roots"] = [top]; 163 result["roots"] = [top];
164 return result; 164 return result;
165 } 165 }
166 166
167 /** 167 /**
168 * Convert nested references in [data] into [Reference] objects. 168 * Convert nested references in [data] into [Reference] objects.
169 */ 169 */
170 recursivelyFixUp(data, Reader r, List result) { 170 recursivelyFixUp(data, Reader r, List result) {
171 if (isPrimitive(data)) { 171 if (isPrimitive(data)) {
172 result[r._primitiveRule().number].add(data); 172 result[r._primitiveRule().number].add(data);
173 return data; 173 return data;
174 } 174 }
175 var ruleNumber = 175 var ruleNumber =
176 (data is List) ? data.removeLast() : data.remove("__rule"); 176 (data is List) ? data.removeLast() : data.remove("__rule");
177 var newData = values(data).mappedBy( 177 var newData = values(data).mappedBy(
178 (x) => recursivelyFixUp(x, r, result)); 178 (x) => recursivelyFixUp(x, r, result));
179 // TODO(alanknight): Ugh. Get rid of this if we can resolve bug 7982/7940.
Jennifer Messerly 2013/01/25 01:19:59 or http://dartbug.com/8113 :)
180 if (newData is MappedList) {
181 newData = newData.toList();
182 }
179 result[ruleNumber].add(newData); 183 result[ruleNumber].add(newData);
180 return new Reference(this, ruleNumber, result[ruleNumber].length - 1); 184 return new Reference(r, ruleNumber, result[ruleNumber].length - 1);
181 } 185 }
182 } 186 }
183 187
184 /** 188 /**
185 * Writes to a simple mostly-flat format. Details are subject to change. 189 * Writes to a simple mostly-flat format. Details are subject to change.
186 * Right now this produces a List containing null, num, and String. This is 190 * Right now this produces a List containing null, num, and String. This is
187 * more space-efficient than the map formats, but much less human-readable. 191 * more space-efficient than the map formats, but much less human-readable.
188 * Simple usage is to turn this into JSON for transmission. 192 * Simple usage is to turn this into JSON for transmission.
189 */ 193 */
190 class SimpleFlatFormat extends Format { 194 class SimpleFlatFormat extends Format {
(...skipping 27 matching lines...) Expand all
218 w._rootReferences().forEach((x) => x.writeToList(result[2])); 222 w._rootReferences().forEach((x) => x.writeToList(result[2]));
219 return result; 223 return result;
220 } 224 }
221 225
222 /** 226 /**
223 * Writes the data from [rule] into the [target] list. 227 * Writes the data from [rule] into the [target] list.
224 */ 228 */
225 void writeStateInto(SerializationRule rule, List ruleData, List target) { 229 void writeStateInto(SerializationRule rule, List ruleData, List target) {
226 if (!ruleData.isEmpty) { 230 if (!ruleData.isEmpty) {
227 var sample = ruleData.first; 231 var sample = ruleData.first;
228 if (sample is List) { 232 if (rule.storesStateAsLists || sample is List) {
229 writeLists(rule, ruleData, target); 233 writeLists(rule, ruleData, target);
230 } else if (sample is Map) { 234 } else if (rule.storesStateAsMaps || sample is Map) {
231 writeMaps(rule, ruleData, target); 235 writeMaps(rule, ruleData, target);
236 } else if (rule.storesStateAsPrimitives || isPrimitive(sample)) {
237 writeObjects(ruleData, target);
232 } else { 238 } else {
233 writeObjects(ruleData, target); 239 throw new SerializationException("Invalid data format");
234 } 240 }
235 } else { 241 } else {
236 // If there is no data, write a zero for the length. 242 // If there is no data, write a zero for the length.
237 target.add(0); 243 target.add(0);
238 } 244 }
239 } 245 }
240 246
241 /** 247 /**
242 * Write [entries], which contains Lists. Either the lists are variable 248 * Write [entries], which contains Lists. Either the lists are variable
243 * length, in which case we add a length field, or they are fixed length, in 249 * length, in which case we add a length field, or they are fixed length, in
(...skipping 20 matching lines...) Expand all
264 * right length when we read it back. Then we write alternating keys and 270 * right length when we read it back. Then we write alternating keys and
265 * values. We expect the values to be references, which we store as 271 * values. We expect the values to be references, which we store as
266 * two numbers. 272 * two numbers.
267 */ 273 */
268 writeMaps(SerializationRule rule, List<Map> entries, List target) { 274 writeMaps(SerializationRule rule, List<Map> entries, List target) {
269 target.add(STORED_AS_MAP); 275 target.add(STORED_AS_MAP);
270 for (var eachEntry in entries) { 276 for (var eachEntry in entries) {
271 if (rule.hasVariableLengthEntries) { 277 if (rule.hasVariableLengthEntries) {
272 target.add(eachEntry.length); 278 target.add(eachEntry.length);
273 } 279 }
274 // We take advantage of this being only a semi-flat format, and expecting
275 // that the keys here are field names, i.e. strings. So we write
276 // the keys as literals and the values as references. This duplicates the
277 // keys, so is quite inefficient. But generating maps rather than lists is
278 // not very efficient in the first place.
279 eachEntry.forEach((key, value) { 280 eachEntry.forEach((key, value) {
280 target.add(key); 281 writeReference(key, target);
281 writeReference(value, target); 282 writeReference(value, target);
282 }); 283 });
283 } 284 }
284 } 285 }
285 286
286 /** 287 /**
287 * Write [entries], which contains simple objects which we can put directly 288 * Write [entries], which contains simple objects which we can put directly
288 * into [target]. 289 * into [target].
289 */ 290 */
290 writeObjects(List entries, List target) { 291 writeObjects(List entries, List target) {
291 target.add(STORED_AS_PRIMITIVE); 292 target.add(STORED_AS_PRIMITIVE);
293 for (var each in entries) {
294 if (!isPrimitive(each)) throw new SerializationException("Invalid data");
295 }
292 target.addAll(entries); 296 target.addAll(entries);
293 } 297 }
294 298
295 /** 299 /**
296 * Write [eachRef] to [target]. It will be written as two ints. If [eachRef] 300 * Write [eachRef] to [target]. It will be written as two ints. If [eachRef]
297 * is null it will be written as two nulls. 301 * is null it will be written as two nulls.
298 */ 302 */
299 void writeReference(Reference eachRef, List target) { 303 void writeReference(Reference eachRef, List target) {
300 // TODO(alanknight): Writing nulls is problematic in a real flat format. 304 // TODO(alanknight): Writing nulls is problematic in a real flat format.
301 if (eachRef == null) { 305 if (eachRef == null) {
302 target..add(null)..add(null); 306 target..add(null)..add(null);
303 } else { 307 } else {
304 eachRef.writeToList(target); 308 eachRef.writeToList(target);
305 } 309 }
306 } 310 }
307 311
308 /** 312 /**
309 * Read the data from [rawInput] in the context of [r] and return it as a 313 * Read the data from [rawInput] in the context of [r] and return it as a
310 * Map with entries for "roots", "data" and "rules", which the reader knows 314 * Map with entries for "roots", "data" and "rules", which the reader knows
311 * how to interpret. We expect [rawInput] to have been generated from this 315 * how to interpret. We expect [rawInput] to have been generated from this
312 * format. 316 * format.
313 */ 317 */
314 Map<String, dynamic> read(List rawInput, Reader r) { 318 Map<String, dynamic> read(List rawInput, Reader r) {
319 // TODO(alanknight): It's annoying to have to pass the reader around so
320 // much, consider having the format be specific to a particular
321 // serialization operation along with the reader and having it as a field.
Jennifer Messerly 2013/01/25 01:19:59 yeah, it is kind of nice how Format is independent
Alan Knight 2013/01/26 01:33:38 For the moment I'll go with not worrying about it.
315 var input = {}; 322 var input = {};
316 input["rules"] = rawInput[0]; 323 input["rules"] = rawInput[0];
317 r.readRules(input["rules"]); 324 r.readRules(input["rules"]);
318 325
319 var flatData = rawInput[1]; 326 var flatData = rawInput[1];
320 var stream = flatData.iterator; 327 var stream = flatData.iterator;
321 var tempData = new List(r.rules.length); 328 var tempData = new List(r.rules.length);
322 for (var eachRule in r.rules) { 329 for (var eachRule in r.rules) {
323 tempData[eachRule.number] = readRuleDataFrom(stream, eachRule); 330 tempData[eachRule.number] = readRuleDataFrom(stream, eachRule, r);
324 } 331 }
325 input["data"] = tempData; 332 input["data"] = tempData;
326 333
327 var roots = []; 334 var roots = [];
328 var rootsAsInts = rawInput[2].iterator; 335 var rootsAsInts = rawInput[2].iterator;
329 do { 336 do {
330 roots.add(nextReferenceFrom(rootsAsInts)); 337 roots.add(nextReferenceFrom(rootsAsInts, r));
331 } while (rootsAsInts.current != null); 338 } while (rootsAsInts.current != null);
332 339
333 input["roots"] = roots; 340 input["roots"] = roots;
334 return input; 341 return input;
335 } 342 }
336 343
337 /** 344 /**
338 * Read the data for [rule] from [input] and return it. 345 * Read the data for [rule] from [input] and return it.
339 */ 346 */
340 readRuleDataFrom(Iterator input, SerializationRule rule) { 347 readRuleDataFrom(Iterator input, SerializationRule rule, Reader r) {
341 var numberOfEntries = _next(input); 348 var numberOfEntries = _next(input);
342 var entryType = _next(input); 349 var entryType = _next(input);
343 if (entryType == STORED_AS_LIST) { 350 if (entryType == STORED_AS_LIST) {
344 return readLists(input, rule, numberOfEntries); 351 return readLists(input, rule, numberOfEntries, r);
345 } 352 }
346 if (entryType == STORED_AS_MAP) { 353 if (entryType == STORED_AS_MAP) {
347 return readMaps(input, rule, numberOfEntries); 354 return readMaps(input, rule, numberOfEntries, r);
348 } 355 }
349 if (entryType == STORED_AS_PRIMITIVE) { 356 if (entryType == STORED_AS_PRIMITIVE) {
350 return readPrimitives(input, rule, numberOfEntries); 357 return readPrimitives(input, rule, numberOfEntries);
351 } 358 }
352 if (numberOfEntries == 0) { 359 if (numberOfEntries == 0) {
353 return []; 360 return [];
354 } else { 361 } else {
355 throw new SerializationException("Invalid data in serialization"); 362 throw new SerializationException("Invalid data in serialization");
356 } 363 }
357 } 364 }
358 365
359 /** 366 /**
360 * Read data for [rule] from [input] with [length] number of entries, 367 * Read data for [rule] from [input] with [length] number of entries,
361 * creating lists from the results. 368 * creating lists from the results.
362 */ 369 */
363 readLists(Iterator input, SerializationRule rule, int length) { 370 readLists(Iterator input, SerializationRule rule, int length, Reader r) {
364 var ruleData = []; 371 var ruleData = [];
365 for (var i = 0; i < length; i++) { 372 for (var i = 0; i < length; i++) {
366 var subLength = 373 var subLength =
367 rule.hasVariableLengthEntries ? _next(input) : rule.dataLength; 374 rule.hasVariableLengthEntries ? _next(input) : rule.dataLength;
368 var subList = []; 375 var subList = [];
369 ruleData.add(subList); 376 ruleData.add(subList);
370 for (var j = 0; j < subLength; j++) { 377 for (var j = 0; j < subLength; j++) {
371 subList.add(nextReferenceFrom(input)); 378 subList.add(nextReferenceFrom(input, r));
372 } 379 }
373 } 380 }
374 return ruleData; 381 return ruleData;
375 } 382 }
376 383
377 /** 384 /**
378 * Read data for [rule] from [input] with [length] number of entries, 385 * Read data for [rule] from [input] with [length] number of entries,
379 * creating maps from the results. 386 * creating maps from the results.
380 */ 387 */
381 readMaps(Iterator input, SerializationRule rule, int length) { 388 readMaps(Iterator input, SerializationRule rule, int length, Reader r) {
382 var ruleData = []; 389 var ruleData = [];
383 for (var i = 0; i < length; i++) { 390 for (var i = 0; i < length; i++) {
384 var subLength = 391 var subLength =
385 rule.hasVariableLengthEntries ? _next(input) : rule.dataLength; 392 rule.hasVariableLengthEntries ? _next(input) : rule.dataLength;
386 var map = {}; 393 var map = new Map();
387 ruleData.add(map); 394 ruleData.add(map);
388 for (var j = 0; j < subLength; j++) { 395 for (var j = 0; j < subLength; j++) {
389 map[_next(input)] = nextReferenceFrom(input); 396 var key = nextReferenceFrom(input, r);
397 var value = nextReferenceFrom(input, r);
398 map[key] = value;
390 } 399 }
391 } 400 }
392 return ruleData; 401 return ruleData;
393 } 402 }
394 403
395 /** 404 /**
396 * Read data for [rule] from [input] with [length] number of entries, 405 * Read data for [rule] from [input] with [length] number of entries,
397 * treating the data as primitives that can be returned directly. 406 * treating the data as primitives that can be returned directly.
398 */ 407 */
399 readPrimitives(Iterator input, SerializationRule rule, int length) { 408 readPrimitives(Iterator input, SerializationRule rule, int length) {
400 var ruleData = []; 409 var ruleData = [];
401 for (var i = 0; i < length; i++) { 410 for (var i = 0; i < length; i++) {
402 ruleData.add(_next(input)); 411 ruleData.add(_next(input));
403 } 412 }
404 return ruleData; 413 return ruleData;
405 } 414 }
406 415
407 /** Read the next Reference from the input. */ 416 /** Read the next Reference from the input. */
408 nextReferenceFrom(Iterator input) { 417 nextReferenceFrom(Iterator input, Reader r) {
409 var a = _next(input); 418 var a = _next(input);
410 var b = _next(input); 419 var b = _next(input);
411 if (a == null) { 420 if (a == null) {
412 return null; 421 return null;
413 } else { 422 } else {
414 return new Reference(this, a, b); 423 return new Reference(r, a, b);
415 } 424 }
416 } 425 }
417 426
418 /** Return the next element from the input. */ 427 /** Return the next element from the input. */
419 _next(Iterator input) { 428 _next(Iterator input) {
420 input.moveNext(); 429 input.moveNext();
421 return input.current; 430 return input.current;
422 } 431 }
423 } 432 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698