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

Side by Side Diff: pkg/serialization/lib/serialization.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
« no previous file with comments | « no previous file | pkg/serialization/lib/src/basic_rule.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 /** 5 /**
6 * This provides a general-purpose serialization facility for Dart objects. A 6 * This provides a general-purpose serialization facility for Dart objects. A
7 * [Serialization] is defined in terms of [SerializationRule]s and supports 7 * [Serialization] is defined in terms of [SerializationRule]s and supports
8 * reading and writing to different formats. 8 * reading and writing to different formats.
9 * 9 *
10 * Setup 10 * Setup
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
159 * This class defines a particular serialization scheme, in terms of 159 * This class defines a particular serialization scheme, in terms of
160 * [SerializationRule] instances, and supports reading and writing them. 160 * [SerializationRule] instances, and supports reading and writing them.
161 * See library comment for examples of usage. 161 * See library comment for examples of usage.
162 */ 162 */
163 class Serialization { 163 class Serialization {
164 164
165 /** 165 /**
166 * The serialization is controlled by the list of Serialization rules. These 166 * The serialization is controlled by the list of Serialization rules. These
167 * are most commonly added via [addRuleFor]. 167 * are most commonly added via [addRuleFor].
168 */ 168 */
169 List rules = []; 169 List _rules = [];
170
171 /**
172 * The serialization is controlled by the list of Serialization rules. These
173 * are most commonly added via [addRuleFor].
174 */
175 List get rules => _rules;
170 176
171 /** 177 /**
172 * When reading, we may need to resolve references to existing objects in 178 * When reading, we may need to resolve references to existing objects in
173 * the system. The right action may not be to create a new instance of 179 * the system. The right action may not be to create a new instance of
174 * something, but rather to find an existing instance and connect to it. 180 * something, but rather to find an existing instance and connect to it.
175 * For example, if we have are serializing an Email message and it has a 181 * For example, if we have are serializing an Email message and it has a
176 * link to the owning account, it may not be appropriate to try and serialize 182 * link to the owning account, it may not be appropriate to try and serialize
177 * the account. Instead we should just connect the de-serialized message 183 * the account. Instead we should just connect the de-serialized message
178 * object to the account object that already exists there. 184 * object to the account object that already exists there.
179 */ 185 */
180 Map<String, dynamic> externalObjects = {}; 186 Map<String, dynamic> namedObjects = {};
181 187
182 /** 188 /**
183 * When we write out data using this serialization, should we also write 189 * When we write out data using this serialization, should we also write
184 * out a description of the rules. 190 * out a description of the rules. This is on by default unless using
191 * CustomRule subclasses, in which case it requires additional setup and
192 * is off by default.
185 */ 193 */
186 bool selfDescribing = true; 194 bool _selfDescribing;
195
196 /**
197 * When we write out data using this serialization, should we also write
198 * out a description of the rules. This is on by default unless using
199 * CustomRule subclasses, in which case it requires additional setup and
200 * is off by default.
201 */
202 bool get selfDescribing {
203 if (_selfDescribing != null) return _selfDescribing;
204 return !_rules.some((x) => x is CustomRule);
205 }
206
207 /**
208 * When we write out data using this serialization, should we also write
209 * out a description of the rules. This is on by default unless using
210 * CustomRule subclasses, in which case it requires additional setup and
211 * is off by default.
212 */
213 set selfDescribing(x) => _selfDescribing = x;
187 214
188 /** 215 /**
189 * Creates a new serialization with a default set of rules for primitives 216 * Creates a new serialization with a default set of rules for primitives
190 * and lists. 217 * and lists.
191 */ 218 */
192 Serialization() { 219 Serialization() {
193 addDefaultRules(); 220 addDefaultRules();
194 } 221 }
195 222
196 /** 223 /**
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
249 addRule(new ListRuleEssential()); 276 addRule(new ListRuleEssential());
250 } 277 }
251 278
252 /** 279 /**
253 * Add a new SerializationRule [rule]. The addRuleFor method will probably 280 * Add a new SerializationRule [rule]. The addRuleFor method will probably
254 * handle most simple cases, but for adding an arbitrary rule, including 281 * handle most simple cases, but for adding an arbitrary rule, including
255 * a SerializationRule subclass which you have created, you can use this 282 * a SerializationRule subclass which you have created, you can use this
256 * method. 283 * method.
257 */ 284 */
258 void addRule(SerializationRule rule) { 285 void addRule(SerializationRule rule) {
259 rule.number = rules.length; 286 rule.number = _rules.length;
260 rules.add(rule); 287 _rules.add(rule);
261 } 288 }
262 289
263 /** 290 /**
264 * This is the basic method to write out an object graph rooted at 291 * This is the basic method to write out an object graph rooted at
265 * [object] and return the result. Right now this is hard-coded to return 292 * [object] and return the result. Right now this is hard-coded to return
266 * a String from a custom [JSON] format, but that is likely to change to be 293 * a String from a custom [JSON] format, but that is likely to change to be
267 * more pluggable in the near future. 294 * more pluggable in the near future.
268 */ 295 */
269 String write(Object object) { 296 String write(Object object) {
270 return newWriter().write(object); 297 return newWriter().write(object);
271 } 298 }
272 299
273 /** 300 /**
274 * Return a new [Writer] object for this serialization. This is useful if you 301 * Return a new [Writer] object for this serialization. This is useful if you
275 * want to do something more complex with the writer than just returning 302 * want to do something more complex with the writer than just returning
276 * the final result. 303 * the final result.
277 */ 304 */
278 Writer newWriter() => new Writer(this); 305 Writer newWriter() => new Writer(this);
279 306
280 /** 307 /**
281 * Write out the tree in a custom flat format, returning a list containing 308 * Write out the tree in a custom flat format, returning a list containing
282 * only "simple" types: num, String, and bool. 309 * only "simple" types: num, String, and bool.
283 */ 310 */
284 List writeFlat(Object object) { 311 List writeFlat(Object object) {
285 return newWriter().writeFlat(object); 312 return newWriter().writeFlat(object);
286 } 313 }
287 314
288 /** 315 /**
289 * Read the serialized data from [input] and return a List of the root 316 * Read the serialized data from [input] and return the root object
290 * objects from the result. If there are objects that need to be resolved 317 * from the result. If there are objects that need to be resolved
291 * in the current context, they should be provided in [externals] as a 318 * in the current context, they should be provided in [externals] as a
292 * Map from names to values. In particular, in the current implementation 319 * Map from names to values. In particular, in the current implementation
293 * any class mirrors needed should be provided in [externals] using the 320 * any class mirrors needed should be provided in [externals] using the
294 * class name as a key. In addition to the [externals] map provided here, 321 * class name as a key. In addition to the [externals] map provided here,
295 * values will be looked up in the [externalObjects] map. 322 * values will be looked up in the [externalObjects] map.
296 */ 323 */
297 List read(String input, [Map externals = const {}]) { 324 read(String input, [Map externals = const {}]) {
298 return newReader().read(input, externals); 325 return newReader().read(input, externals);
299 } 326 }
300 327
301 /** 328 /**
302 * In the most common case there is only a single root object to be read,
303 * and this method can be used to return just one object rather than
304 * a List. The [input] and [externals] parameters are the same as for the
305 * general [read] method.
306 */
307 Object readOne(String input, [Map externals = const {}]) {
308 return newReader().readOne(input, externals);
309 }
310
311 /**
312 * Return a new [Reader] object for this serialization. This is useful if 329 * Return a new [Reader] object for this serialization. This is useful if
313 * you want to do something more complex with the reader than just returning 330 * you want to do something more complex with the reader than just returning
314 * the final result. 331 * the final result.
315 */ 332 */
316 Reader newReader() => new Reader(this); 333 Reader newReader() => new Reader(this);
317 334
318 /** 335 /**
319 * Return the list of SerializationRule that apply to [object]. For 336 * Return the list of SerializationRule that apply to [object]. For
320 * internal use, but public because it's used in testing. 337 * internal use, but public because it's used in testing.
321 */ 338 */
322 List<SerializationRule> rulesFor(object) { 339 List<SerializationRule> rulesFor(object, Writer w) {
323 // This has a couple of edge cases. 340 // This has a couple of edge cases.
324 // 1) The owning object may have indicated we should use a different 341 // 1) The owning object may have indicated we should use a different
325 // rule than the default. 342 // rule than the default.
326 // 2) We may not have a rule, in which case we lazily create a BasicRule. 343 // 2) We may not have a rule, in which case we lazily create a BasicRule.
327 // 3) Rules are allowed to say mustBePrimary, meaning that they can be used 344 // 3) Rules are allowed to say mustBePrimary, meaning that they can be used
328 // iff no other rule was chosen first. 345 // iff no other rule was chosen first.
329 // TODO(alanknight): Can the mustBePrimary mechanism be removed or changed. 346 // TODO(alanknight): Can the mustBePrimary mechanism be removed or changed.
330 // It adds an order dependency to the rules, and is messy. Reconsider in the 347 // It adds an order dependency to the rules, and is messy. Reconsider in the
331 // light of a more general mechanism for multiple rules per object. 348 // light of a more general mechanism for multiple rules per object.
332 // TODO(alanknight): Finding which rules apply seems likely to be a 349 // TODO(alanknight): Finding which rules apply seems likely to be a
333 // bottleneck, particularly with the current reflective implementation. 350 // bottleneck, particularly with the current reflective implementation.
334 // Consider how to improve it. e.g. cache the list of rules by class. But 351 // Consider how to improve it. e.g. cache the list of rules by class. But
335 // be careful of issues like rules which have arbitrary predicates. Or 352 // be careful of issues like rules which have arbitrary predicates. Or
336 // consider having the arbitrary predicates be secondary to an initial 353 // consider having the arbitrary predicates be secondary to an initial
337 // class-based lookup mechanism. 354 // class-based lookup mechanism.
338 var target, candidateRules; 355 var target, candidateRules;
339 if (object is DesignatedRuleForObject) { 356 if (object is DesignatedRuleForObject) {
340 target = object.target; 357 target = object.target;
341 candidateRules = object.possibleRules(rules); 358 candidateRules = object.possibleRules(_rules);
342 } else { 359 } else {
343 target = object; 360 target = object;
344 candidateRules = rules; 361 candidateRules = _rules;
345 } 362 }
346 List applicable = candidateRules.filter((each) => each.appliesTo(target)); 363 List applicable = candidateRules.filter(
364 (each) => each.appliesTo(target, w));
347 365
348 if (applicable.isEmpty) { 366 if (applicable.isEmpty) {
349 return [addRuleFor(target)]; 367 return [addRuleFor(target)];
350 } 368 }
351 369
352 if (applicable.length == 1) return applicable; 370 if (applicable.length == 1) return applicable;
353 var first = applicable[0]; 371 var first = applicable[0];
354 var finalRules = applicable.filter( 372 var finalRules = applicable.filter(
355 (x) => !x.mustBePrimary || (x == first)); 373 (x) => !x.mustBePrimary || (x == first));
356 374
(...skipping 10 matching lines...) Expand all
367 */ 385 */
368 Serialization _ruleSerialization() { 386 Serialization _ruleSerialization() {
369 // TODO(alanknight): There's an extensibility issue here with new rules. 387 // TODO(alanknight): There's an extensibility issue here with new rules.
370 // TODO(alanknight): How to handle rules with closures? They have to 388 // TODO(alanknight): How to handle rules with closures? They have to
371 // exist on the other side, but we might be able to hook them up by name, 389 // exist on the other side, but we might be able to hook them up by name,
372 // or we might just be able to validate that they're correctly set up 390 // or we might just be able to validate that they're correctly set up
373 // on the other side. 391 // on the other side.
374 392
375 // Make some bogus rule instances so we have something to feed rule creation 393 // Make some bogus rule instances so we have something to feed rule creation
376 // and get their types. If only we had class literals implemented... 394 // and get their types. If only we had class literals implemented...
377 var closureRule = new ClosureToMapRule.stub([].runtimeType); 395 var basicRule = new BasicRule(reflect(null).type, '', [], [], []);
378 var basicRule = new BasicRule(reflect(null).type, '', [], [], []);
379 396
380 var meta = new Serialization() 397 var meta = new Serialization()
381 ..selfDescribing = false 398 ..selfDescribing = false
382 ..addRuleFor(new ListRule()) 399 ..addRuleFor(new ListRule())
383 ..addRuleFor(new PrimitiveRule()) 400 ..addRuleFor(new PrimitiveRule())
384 ..addRuleFor(new ListRuleEssential()) 401 ..addRuleFor(new ListRuleEssential())
385 ..addRuleFor(basicRule, 402 ..addRuleFor(basicRule,
386 constructorFields: ['typeWrapped', 403 constructorFields: ['typeWrapped',
387 'constructorName', 404 'constructorName',
388 'constructorFields', 'regularFields', []], 405 'constructorFields', 'regularFields', []],
389 fields: []) 406 fields: [])
390 ..addRule(new ClassMirrorRule()); 407 ..addRule(new NamedObjectRule())
391 meta.externalObjects = externalObjects; 408 ..addRule(new MirrorRule());
409 meta.namedObjects = namedObjects;
392 return meta; 410 return meta;
393 } 411 }
412
413 /** Return true if our [namedObjects] collection has an entry for [object].*/
414 bool _hasNameFor(object) {
415 var sentinel = const _Sentinel();
416 return _nameFor(object, () => sentinel) != sentinel;
417 }
418
419 /**
420 * Return the name we have for [object] in our [namedObjects] collection or
421 * the result of evaluating [ifAbsent] if there is no entry.
422 */
423 _nameFor(object, [ifAbsent]) {
424 for (var key in namedObjects.keys) {
425 if (identical(namedObjects[key], object)) return key;
426 }
427 return ifAbsent == null ? null : ifAbsent();
428 }
394 } 429 }
395 430
396 /** 431 /**
397 * An exception class for errors during serialization. 432 * An exception class for errors during serialization.
398 */ 433 */
399 class SerializationException implements Exception { 434 class SerializationException implements Exception {
400 final String message; 435 final String message;
401 const SerializationException([this.message]); 436 const SerializationException([this.message]);
402 } 437 }
OLDNEW
« no previous file with comments | « no previous file | pkg/serialization/lib/src/basic_rule.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698