| OLD | NEW |
| 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 const Format(); | 9 const Format(); |
| 10 | 10 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 | 29 |
| 30 /** | 30 /** |
| 31 * Read the data from [input] in the context of [reader] and return it as a | 31 * Read the data from [input] in the context of [reader] and return it as a |
| 32 * Map with entries for "roots", "data" and "rules", which the reader knows | 32 * Map with entries for "roots", "data" and "rules", which the reader knows |
| 33 * how to interpret. The type of [input] will depend on the particular format. | 33 * how to interpret. The type of [input] will depend on the particular format. |
| 34 */ | 34 */ |
| 35 Map<String, dynamic> read(input, Reader reader); | 35 Map<String, dynamic> read(input, Reader reader); |
| 36 } | 36 } |
| 37 | 37 |
| 38 /** | 38 /** |
| 39 * A format that stores the data in maps which are converted into a JSON | 39 * This is the most basic format, which provides the internal representation |
| 40 * string. Note that the maps aren't nested, and it handles cyclic references | 40 * of the serialization, exposing the Reference objects. |
| 41 * by converting object references to [Reference] objects. If you want simple | |
| 42 * acyclic JSON look at [SimpleJsonFormat]. | |
| 43 */ | 41 */ |
| 44 class SimpleMapFormat extends Format { | 42 class InternalMapFormat extends Format { |
| 45 | 43 const InternalMapFormat(); |
| 46 const SimpleMapFormat(); | |
| 47 | 44 |
| 48 /** | 45 /** |
| 49 * Generate output for this format from [w] and return it as a String which | 46 * Generate output for this format from [w] and return it as a nested Map |
| 50 * is the [json] representation of a nested Map structure. The top level has | 47 * structure. The top level has |
| 51 * 3 fields, "rules" which may hold a definition of the rules used, | 48 * 3 fields, "rules" which may hold a definition of the rules used, |
| 52 * "data" which holds the serialized data, and "roots", which holds | 49 * "data" which holds the serialized data, and "roots", which holds |
| 53 * [Reference] objects indicating the root objects. Note that roots are | 50 * [Reference] objects indicating the root objects. Note that roots are |
| 54 * necessary because the data is organized in the same way as the object | 51 * necessary because the data is not organized in the same way as the object |
| 55 * structure, it's a list of lists holding self-contained maps which only | 52 * structure, it's a list of lists holding self-contained maps which only |
| 56 * refer to other parts via [Reference] objects. | 53 * refer to other parts via [Reference] objects. |
| 57 * This effectively defines a custom JSON serialization format, although | |
| 58 * the details of the format vary depending which rules were used. | |
| 59 */ | 54 */ |
| 60 Map<String, dynamic> generateOutput(Writer w) { | 55 Map<String, dynamic> generateOutput(Writer w) { |
| 61 var result = { | 56 var result = { |
| 62 "rules" : w.serializedRules(), | 57 "rules" : w.serializedRules(), |
| 63 "data" : w.states, | 58 "data" : w.states, |
| 64 "roots" : w._rootReferences() | 59 "roots" : w._rootReferences() |
| 65 }; | 60 }; |
| 66 return result; | 61 return result; |
| 67 } | 62 } |
| 68 | 63 |
| 69 /** | 64 /** |
| 70 * Read a [json] compatible representation of serialized data in this format | 65 * Read serialized data written from this format |
| 71 * and return the nested Map representation described in [generateOutput]. If | 66 * and return the nested Map representation described in [generateOutput]. If |
| 72 * the data also includes rule definitions, then these will replace the rules | 67 * the data also includes rule definitions, then these will replace the rules |
| 73 * in the [Serialization] for [reader]. | 68 * in the [Serialization] for [reader]. |
| 74 */ | 69 */ |
| 75 Map<String, dynamic> read(topLevel, Reader reader) { | 70 Map<String, dynamic> read(topLevel, Reader reader) { |
| 76 var ruleString = topLevel["rules"]; | 71 var ruleString = topLevel["rules"]; |
| 77 reader.readRules(ruleString); | 72 reader.readRules(ruleString); |
| 73 reader._data = topLevel["data"]; |
| 74 topLevel["roots"] = topLevel["roots"]; |
| 78 return topLevel; | 75 return topLevel; |
| 79 } | 76 } |
| 80 } | 77 } |
| 78 |
| 79 /** |
| 80 * A format that stores the data in maps which can be converted into a JSON |
| 81 * string or passed through an isolate. Note that this consists of maps, but |
| 82 * that they don't follow the original object structure or look like the nested |
| 83 * maps of a [json] representation. They are flat, and [Reference] objects |
| 84 * are converted into a map form that will not make sense to |
| 85 * anything but this format. For simple acyclic JSON that other programs |
| 86 * can read, use [SimpleJsonFormat]. This is the default format, and is |
| 87 * easier to read than the more efficient [SimpleFlatFormat]. |
| 88 */ |
| 89 class SimpleMapFormat extends InternalMapFormat { |
| 90 |
| 91 const SimpleMapFormat(); |
| 92 |
| 93 /** |
| 94 * Generate output for this format from [w] and return it as a String which |
| 95 * is the [json] representation of a nested Map structure. The top level has |
| 96 * 3 fields, "rules" which may hold a definition of the rules used, |
| 97 * "data" which holds the serialized data, and "roots", which holds |
| 98 * [Reference] objects indicating the root objects. Note that roots are |
| 99 * necessary because the data is not organized in the same way as the object |
| 100 * structure, it's a list of lists holding self-contained maps which only |
| 101 * refer to other parts via [Reference] objects. |
| 102 * This effectively defines a custom JSON serialization format, although |
| 103 * the details of the format vary depending which rules were used. |
| 104 */ |
| 105 Map<String, dynamic> generateOutput(Writer w) { |
| 106 forAllStates(w, (x) => x is Reference, referenceToMap); |
| 107 var result = super.generateOutput(w); |
| 108 result["roots"] = result["roots"].map( |
| 109 (x) => x is Reference ? referenceToMap(x) : x).toList(); |
| 110 return result; |
| 111 } |
| 112 |
| 113 /** |
| 114 * Convert the data generated by the rules to have maps with the fields |
| 115 * of [Reference] objects instead of the [Reference] so that the structure |
| 116 * can be serialized between isolates and json easily. |
| 117 */ |
| 118 forAllStates(ReaderOrWriter w, bool predicate(value), |
| 119 void transform(value)) { |
| 120 for (var eachRule in w.rules) { |
| 121 var ruleData = w.states[eachRule.number]; |
| 122 for (var data in ruleData) { |
| 123 keysAndValues(data).forEach((key, value) { |
| 124 if (predicate(value)) { |
| 125 data[key] = transform(value); |
| 126 } |
| 127 }); |
| 128 } |
| 129 } |
| 130 } |
| 131 |
| 132 /** Convert the reference to a [json] serializable form. */ |
| 133 Map<String, int> referenceToMap(Reference ref) => ref == null ? null : |
| 134 { |
| 135 "__Ref" : 0, |
| 136 "rule" : ref.ruleNumber, |
| 137 "object" : ref.objectNumber |
| 138 }; |
| 139 |
| 140 /** |
| 141 * Convert the [referenceToMap] form for a reference back to a [Reference] |
| 142 * object. |
| 143 */ |
| 144 Reference mapToReference(ReaderOrWriter parent, Map<String, int> ref) => |
| 145 ref == null ? null : new Reference(parent, ref["rule"], ref["object"]); |
| 146 |
| 147 /** |
| 148 * Read serialized data written in this format |
| 149 * and return the nested Map representation described in [generateOutput]. If |
| 150 * the data also includes rule definitions, then these will replace the rules |
| 151 * in the [Serialization] for [reader]. |
| 152 */ |
| 153 Map<String, dynamic> read(topLevel, Reader reader) { |
| 154 super.read(topLevel, reader); |
| 155 forAllStates(reader, |
| 156 (ref) => ref is Map && ref["__Ref"] != null, |
| 157 (ref) => mapToReference(reader, ref)); |
| 158 topLevel["roots"] = topLevel["roots"] |
| 159 .map((x) => x is Map<String, int> ? mapToReference(reader, x) : x) |
| 160 .toList(); |
| 161 return topLevel; |
| 162 } |
| 163 } |
| 81 | 164 |
| 82 /** | 165 /** |
| 83 * A format for "normal" [json] representation of objects. It stores | 166 * A format for "normal" [json] representation of objects. It stores |
| 84 * the fields of the objects as nested maps, and doesn't allow cycles. This can | 167 * the fields of the objects as nested maps, and doesn't allow cycles. This can |
| 85 * be useful in talking to existing APIs that expect [json] format data. The | 168 * be useful in talking to existing APIs that expect [json] format data. The |
| 86 * output will be either a simple object (string, num, bool), a List, or a Map, | 169 * output will be either a simple object (string, num, bool), a List, or a Map, |
| 87 * with nesting of those. | 170 * with nesting of those. |
| 88 * Note that since the classes of objects aren't normally stored, this isn't | 171 * Note that since the classes of objects aren't normally stored, this isn't |
| 89 * enough information to read back the objects. However, if the | 172 * enough information to read back the objects. However, if the |
| 90 * If the [storeRoundTripInfo] field of the format is set to true, then this | 173 * If the [storeRoundTripInfo] field of the format is set to true, then this |
| 91 * will store the rule number along with the data, allowing reconstruction. | 174 * will store the rule number along with the data, allowing reconstruction. |
| 92 */ | 175 */ |
| 93 class SimpleJsonFormat extends Format { | 176 class SimpleJsonFormat extends SimpleMapFormat { |
| 94 | 177 |
| 95 /** | 178 /** |
| 96 * Indicate if we should store rule numbers with map/list data so that we | 179 * Indicate if we should store rule numbers with map/list data so that we |
| 97 * will know how to reconstruct it with a read operation. If we don't, this | 180 * will know how to reconstruct it with a read operation. If we don't, this |
| 98 * will be more compliant with things that expect known format JSON as input, | 181 * will be more compliant with things that expect known format JSON as input, |
| 99 * but we won't be able to read back the objects. | 182 * but we won't be able to read back the objects. |
| 100 */ | 183 */ |
| 101 final bool storeRoundTripInfo; | 184 final bool storeRoundTripInfo; |
| 102 | 185 |
| 103 /** | 186 /** |
| (...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 469 return new Reference(r, a, b); | 552 return new Reference(r, a, b); |
| 470 } | 553 } |
| 471 } | 554 } |
| 472 | 555 |
| 473 /** Return the next element from the input. */ | 556 /** Return the next element from the input. */ |
| 474 _next(Iterator input) { | 557 _next(Iterator input) { |
| 475 input.moveNext(); | 558 input.moveNext(); |
| 476 return input.current; | 559 return input.current; |
| 477 } | 560 } |
| 478 } | 561 } |
| OLD | NEW |