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

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

Issue 12136002: Some fixes to work better with the services framework (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Changes from review comments Created 7 years, 10 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
« no previous file with comments | « pkg/serialization/lib/src/basic_rule.dart ('k') | pkg/serialization/lib/src/reader_writer.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 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 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 * is the [json] representation of a nested Map structure. The top level has 45 * is the [json] representation of a nested Map structure. The top level has
46 * 3 fields, "rules" which may hold a definition of the rules used, 46 * 3 fields, "rules" which may hold a definition of the rules used,
47 * "data" which holds the serialized data, and "roots", which holds 47 * "data" which holds the serialized data, and "roots", which holds
48 * [Reference] objects indicating the root objects. Note that roots are 48 * [Reference] objects indicating the root objects. Note that roots are
49 * necessary because the data is organized in the same way as the object 49 * necessary because the data is organized in the same way as the object
50 * structure, it's a list of lists holding self-contained maps which only 50 * structure, it's a list of lists holding self-contained maps which only
51 * refer to other parts via [Reference] objects. 51 * refer to other parts via [Reference] objects.
52 * This effectively defines a custom JSON serialization format, although 52 * This effectively defines a custom JSON serialization format, although
53 * the details of the format vary depending which rules were used. 53 * the details of the format vary depending which rules were used.
54 */ 54 */
55 String generateOutput(Writer w) { 55 Map<String, dynamic> generateOutput(Writer w) {
56 var result = { 56 var result = {
57 "rules" : w.serializedRules(), 57 "rules" : w.serializedRules(),
58 "data" : w.states, 58 "data" : w.states,
59 "roots" : w._rootReferences() 59 "roots" : w._rootReferences()
60 }; 60 };
61 return json.stringify(result); 61 return result;
62 } 62 }
63 63
64 /** 64 /**
65 * Read a [json] encoded string representing serialized data in this format 65 * Read a [json] compatible representation of serialized data in this format
66 * and return the nested Map representation described in [generateOutput]. If 66 * and return the nested Map representation described in [generateOutput]. If
67 * 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
68 * in the [Serialization] for [reader]. 68 * in the [Serialization] for [reader].
69 */ 69 */
70 Map<String, dynamic> read(String input, Reader reader) { 70 Map<String, dynamic> read(topLevel, Reader reader) {
71 var topLevel = json.parse(input);
72 var ruleString = topLevel["rules"]; 71 var ruleString = topLevel["rules"];
73 reader.readRules(ruleString); 72 reader.readRules(ruleString);
74 return topLevel; 73 return topLevel;
75 } 74 }
76 } 75 }
77 76
78 /** 77 /**
79 * A format for "normal" JSON representation of objects. It stores 78 * A format for "normal" [json] representation of objects. It stores
80 * the fields of the objects as nested maps, and doesn't allow cycles. This can 79 * the fields of the objects as nested maps, and doesn't allow cycles. This can
81 * be useful in talking to existing APIs that expect JSON format data. However, 80 * be useful in talking to existing APIs that expect [json] format data. The
82 * note that since the classes of objects aren't stored, this isn't enough 81 * output will be either a simple object (string, num, bool), a List, or a Map,
83 * information to read back the objects. This format also doesn't support the 82 * with nesting of those.
84 * [selfDescriptive] option on the [Serialization], as storing the rules. 83 * Note that since the classes of objects aren't normally stored, this isn't
84 * enough information to read back the objects. However, if the
85 * If the [storeRoundTripData] field of the format is set to true, then this 85 * If the [storeRoundTripData] field of the format is set to true, then this
86 * will store the rule number along with the data, allowing reconstruction. 86 * will store the rule number along with the data, allowing reconstruction.
87 */ 87 */
88 class SimpleJsonFormat extends Format { 88 class SimpleJsonFormat extends Format {
89 89
90 /** 90 /**
91 * Indicate if we should store rule numbers with map/list data so that we 91 * Indicate if we should store rule numbers with map/list data so that we
92 * will know how to reconstruct it with a read operation. If we don't, this 92 * will know how to reconstruct it with a read operation. If we don't, this
93 * will be more compliant with things that expect known format JSON as input, 93 * will be more compliant with things that expect known format JSON as input,
94 * but we won't be able to read back the objects. 94 * but we won't be able to read back the objects.
95 */ 95 */
96 final bool storeRoundTripInfo; 96 final bool storeRoundTripInfo;
97 97
98 /** 98 /**
99 * If we store the rule numbers, what key should we use to store them. 99 * If we store the rule numbers, what key should we use to store them.
100 */ 100 */
101 String ruleIdentifier = "__rule"; 101 static final String RULE = "_rule";
102 static final String RULES = "_rules";
103 static final String DATA = "_data";
104 static final String ROOTS = "_root";
102 105
103 SimpleJsonFormat({this.storeRoundTripInfo : false}); 106 SimpleJsonFormat({this.storeRoundTripInfo : false});
104 107
105 /** 108 /**
106 * Generate output for this format from [w] and return it as a String which 109 * Generate output for this format from [w] and return it as
107 * is the [json] representation of a nested Map structure. 110 * the [json] representation of a nested Map structure.
108 */ 111 */
109 String generateOutput(Writer w) { 112 generateOutput(Writer w) {
110 jsonify(w); 113 jsonify(w);
111 return json.stringify(w.stateForReference(w._rootReferences().first)); 114 var root = w._rootReferences().first;
115 if (root is Reference) root = w.stateForReference(root);
116 if (w.selfDescribing && storeRoundTripInfo) {
117 root = new Map()
118 ..[RULES] = w.serializedRules()
119 ..[DATA] = root;
120 }
121 return root;
112 } 122 }
113 123
114 /** 124 /**
115 * Convert the data generated by the rules to have nested maps instead 125 * Convert the data generated by the rules to have nested maps instead
116 * of Reference objects and to add rule numbers if [storeRoundTripInfo] 126 * of Reference objects and to add rule numbers if [storeRoundTripInfo]
117 * is true. 127 * is true.
118 */ 128 */
119 jsonify(Writer w) { 129 jsonify(Writer w) {
120 for (var eachRule in w.rules) { 130 for (var eachRule in w.rules) {
121 var ruleData = w.states[eachRule.number]; 131 var ruleData = w.states[eachRule.number];
122 jsonifyForRule(ruleData, w, eachRule); 132 jsonifyForRule(ruleData, w, eachRule);
123 } 133 }
124 } 134 }
125 135
126 /** 136 /**
127 * For a particular [rule] modify the [ruleData] to conform to this format. 137 * For a particular [rule] modify the [ruleData] to conform to this format.
128 */ 138 */
129 jsonifyForRule(List ruleData, Writer w, SerializationRule rule) { 139 jsonifyForRule(List ruleData, Writer w, SerializationRule rule) {
130 for (var i = 0; i < ruleData.length; i++) { 140 for (var i = 0; i < ruleData.length; i++) {
131 var each = ruleData[i]; 141 var each = ruleData[i];
132 if (each is List) { 142 if (each is List) {
133 jsonifyEntry(each, w); 143 jsonifyEntry(each, w);
134 if (storeRoundTripInfo) ruleData[i].add(rule.number); 144 if (storeRoundTripInfo) ruleData[i].add(rule.number);
135 } else if (each is Map) { 145 } else if (each is Map) {
136 jsonifyEntry(each, w); 146 jsonifyEntry(each, w);
137 if (storeRoundTripInfo) each[ruleIdentifier] = rule.number; 147 if (storeRoundTripInfo) each[RULE] = rule.number;
138 } 148 }
139 } 149 }
140 } 150 }
141 151
142 /** 152 /**
143 * For one particular entry, which is either a Map or a List, update it 153 * For one particular entry, which is either a Map or a List, update it
144 * to turn References into a nested List/Map. 154 * to turn References into a nested List/Map.
145 */ 155 */
146 jsonifyEntry(map, Writer w) { 156 jsonifyEntry(map, Writer w) {
147 keysAndValues(map).forEach((key, value) { 157 keysAndValues(map).forEach((key, value) {
148 if (value is Reference) map[key] = w.stateForReference(value); 158 if (value is Reference) map[key] = w.stateForReference(value);
149 }); 159 });
150 } 160 }
151 161
152 /** 162 /**
153 * Read a [json] encoded string representing serialized data in this format 163 * Read serialized data saved in this format, which should look like
154 * and return the Map representation that the reader expects, with top-level 164 * either a simple type, a List or a Map and return the Map
165 * representation that the reader expects, with top-level
155 * entries for "rules", "data", and "roots". Nested lists/maps will be 166 * entries for "rules", "data", and "roots". Nested lists/maps will be
156 * converted into Reference objects. Note that if the data was not written 167 * converted into Reference objects. Note that if the data was not written
157 * with [storeRoundTripInfo] true this will fail. 168 * with [storeRoundTripInfo] true this will fail.
158 */ 169 */
159 Map<String, dynamic> read(String input, Reader r) { 170 Map<String, dynamic> read(data, Reader reader) {
160 var data = json.parse(input); 171 var result = new Map();
161 var result = {}; 172 // Check the case of having been written without additional data and
162 result["rules"] = null; 173 // read as if it had been written with storeRoundTripData set.
163 var ruleData = 174 if (reader.selfDescribing && !(data.containsKey(DATA))) {
164 new List(r.serialization.rules.length).map((x) => []).toList(); 175 throw new SerializationException("Missing $DATA entry, "
165 var top = recursivelyFixUp(data, r, ruleData); 176 "may mean this was written and read with different values "
177 "of selfDescribing.");
178 }
179 // If we are self-describing, we should have separate rule and data
180 // sections. If not, we assume that we have just the data at the top level.
181 var rules = reader.selfDescribing ? data[RULES] : null;
182 var actualData = reader.selfDescribing ? data[DATA] : data;
183 reader.readRules(rules);
184 var ruleData = new List(reader.rules.length).map((x) => []).toList();
185 var top = recursivelyFixUp(actualData, reader, ruleData);
166 result["data"] = ruleData; 186 result["data"] = ruleData;
167 result["roots"] = [top]; 187 result["roots"] = [top];
168 return result; 188 return result;
169 } 189 }
170 190
171 /** 191 /**
172 * Convert nested references in [data] into [Reference] objects. 192 * Convert nested references in [data] into [Reference] objects.
173 */ 193 */
174 recursivelyFixUp(data, Reader r, List result) { 194 recursivelyFixUp(input, Reader r, List result) {
195 var data = input;
175 if (isPrimitive(data)) { 196 if (isPrimitive(data)) {
176 result[r._primitiveRule().number].add(data); 197 result[r._primitiveRule().number].add(data);
177 return data; 198 return data;
178 } 199 }
179 var ruleNumber; 200 var ruleNumber;
201 // If we've added the rule number on as the last item in a list we have
202 // to get rid of it or it will be interpreted as extra data. For a map
203 // the library will be ok, but we need to get rid of the extra key before
204 // the data is shown to the user, so we destructively modify.
180 if (data is List) { 205 if (data is List) {
181 ruleNumber = data.removeLast(); 206 ruleNumber = data.last;
207 data = data.take(data.length -1);
182 } else if (data is Map) { 208 } else if (data is Map) {
183 ruleNumber = data.remove(ruleIdentifier); 209 ruleNumber = data.remove(RULE);
184 } else { 210 } else {
185 throw new SerializationException("Invalid data format"); 211 throw new SerializationException("Invalid data format");
186 } 212 }
187 var newData = mapValues(data, (x) => recursivelyFixUp(x, r, result)); 213 // Do not use mappedBy or other lazy operations for this. They do not play
214 // well with a function that destructively modifies its arguments.
215 var newData = mapValues(data, (each) => recursivelyFixUp(each, r, result));
188 result[ruleNumber].add(newData); 216 result[ruleNumber].add(newData);
189 return new Reference(r, ruleNumber, result[ruleNumber].length - 1); 217 return new Reference(r, ruleNumber, result[ruleNumber].length - 1);
190 } 218 }
191 } 219 }
192 220
193 /** 221 /**
194 * Writes to a simple mostly-flat format. Details are subject to change. 222 * Writes to a simple mostly-flat format. Details are subject to change.
195 * Right now this produces a List containing null, num, and String. This is 223 * Right now this produces a List containing null, num, and String. This is
196 * more space-efficient than the map formats, but much less human-readable. 224 * more space-efficient than the map formats, but much less human-readable.
197 * Simple usage is to turn this into JSON for transmission. 225 * Simple usage is to turn this into JSON for transmission.
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after
428 return new Reference(r, a, b); 456 return new Reference(r, a, b);
429 } 457 }
430 } 458 }
431 459
432 /** Return the next element from the input. */ 460 /** Return the next element from the input. */
433 _next(Iterator input) { 461 _next(Iterator input) {
434 input.moveNext(); 462 input.moveNext();
435 return input.current; 463 return input.current;
436 } 464 }
437 } 465 }
OLDNEW
« no previous file with comments | « pkg/serialization/lib/src/basic_rule.dart ('k') | pkg/serialization/lib/src/reader_writer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698