Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
| 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. | |
| 4 | |
| 5 library protocol2; | |
| 6 | |
| 7 import 'dart:convert'; | |
| 8 | |
| 9 import 'protocol.dart'; | |
| 10 | |
| 11 part 'generated_protocol.dart'; | |
| 12 | |
| 13 /** | |
| 14 * Translate the input [map], applying [keyCallback] to all its keys, and | |
| 15 * [valueCallback] to all its values. | |
| 16 */ | |
| 17 _mapMap(Map map, {dynamic keyCallback(key), dynamic valueCallback(value)}) { | |
| 18 Map result = {}; | |
| 19 map.forEach((key, value) { | |
| 20 if (keyCallback != null) { | |
| 21 key = keyCallback(key); | |
| 22 } | |
| 23 if (valueCallback != null) { | |
| 24 value = valueCallback(value); | |
| 25 } | |
| 26 result[key] = value; | |
| 27 }); | |
| 28 return result; | |
| 29 } | |
| 30 | |
| 31 /** | |
| 32 * Jenkins hash function, optimized for small integers. Borrowed from | |
| 33 * sdk/lib/math/jenkins_smi_hash.dart. | |
| 34 * | |
| 35 * TODO(paulberry): Move to somewhere that can be shared with other code. | |
| 36 */ | |
| 37 class _JenkinsSmiHash { | |
| 38 static int combine(int hash, int value) { | |
| 39 hash = 0x1fffffff & (hash + value); | |
| 40 hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); | |
| 41 return hash ^ (hash >> 6); | |
| 42 } | |
| 43 | |
| 44 static int finish(int hash) { | |
| 45 hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); | |
| 46 hash = hash ^ (hash >> 11); | |
| 47 return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); | |
| 48 } | |
| 49 | |
| 50 static int hash2(a, b) => finish(combine(combine(0, a), b)); | |
| 51 | |
| 52 static int hash4(a, b, c, d) => | |
| 53 finish(combine(combine(combine(combine(0, a), b), c), d)); | |
| 54 } | |
| 55 | |
| 56 | |
| 57 /** | |
| 58 * Type of callbacks used to decode parts of JSON objects. [jsonPath] is a | |
| 59 * string describing the part of the JSON object being decoded, and [value] is | |
| 60 * the part to decode. | |
| 61 */ | |
| 62 typedef Object JsonDecoderCallback(String jsonPath, Object value); | |
| 63 | |
| 64 /** | |
| 65 * Base class for decoding JSON objects. The derived class must implement | |
| 66 * error reporting logic. | |
| 67 */ | |
| 68 abstract class JsonDecoderBase { | |
| 69 /** | |
| 70 * Create an exception to throw if the JSON object at [jsonPath] is missing | |
| 71 * the key [key]. | |
| 72 */ | |
| 73 dynamic missingKey(String jsonPath, String key); | |
| 74 | |
| 75 /** | |
| 76 * Create an exception to throw if the JSON object at [jsonPath] fails to | |
| 77 * match the API definition of [expected]. | |
| 78 */ | |
| 79 dynamic mismatch(String jsonPath, String expected); | |
| 80 | |
| 81 /** | |
| 82 * Decode a JSON object that is expected to be a Map. [keyDecoder] is used | |
| 83 * to decode the keys, and [valueDecoder] is used to decode the values. | |
| 84 */ | |
| 85 Map _decodeMap(String jsonPath, Object json, {JsonDecoderCallback keyDecoder, | |
| 86 JsonDecoderCallback valueDecoder}) { | |
| 87 if (json == null) { | |
| 88 return {}; | |
| 89 } else if (json is Map) { | |
| 90 Map result = {}; | |
| 91 json.forEach((String key, value) { | |
| 92 Object decodedKey; | |
| 93 if (keyDecoder != null) { | |
| 94 decodedKey = keyDecoder('$jsonPath.key', key); | |
| 95 } else { | |
| 96 decodedKey = key; | |
| 97 } | |
| 98 if (valueDecoder != null) { | |
| 99 value = valueDecoder('$jsonPath[${JSON.encode(key)}]', value); | |
| 100 } | |
| 101 result[decodedKey] = value; | |
| 102 }); | |
| 103 return result; | |
| 104 } else { | |
| 105 throw mismatch(jsonPath, 'Map'); | |
| 106 } | |
| 107 } | |
| 108 | |
| 109 /** | |
| 110 * Decode a JSON object that is expected to be a List. [decoder] is used to | |
| 111 * decode the items in the list. | |
| 112 */ | |
| 113 List _decodeList(String jsonPath, Object json, [JsonDecoderCallback decoder]) { | |
| 114 if (json == null) { | |
| 115 return []; | |
| 116 } else if (json is List) { | |
| 117 List result = []; | |
| 118 for (int i = 0; i < json.length; i++) { | |
| 119 result.add(decoder('$jsonPath[$i]', json[i])); | |
| 120 } | |
| 121 return result; | |
| 122 } else { | |
| 123 throw mismatch(jsonPath, 'List'); | |
| 124 } | |
| 125 } | |
| 126 | |
| 127 /** | |
| 128 * Decode a JSON object that is expected to be a string. | |
| 129 */ | |
| 130 String _decodeString(String jsonPath, Object json) { | |
| 131 if (json is String) { | |
| 132 return json; | |
| 133 } else { | |
| 134 throw mismatch(jsonPath, 'String'); | |
| 135 } | |
| 136 } | |
| 137 | |
| 138 /** | |
| 139 * Decode a JSON object that is expected to be a boolean. The strings "true" | |
| 140 * and "false" are also accepted. | |
| 141 */ | |
| 142 bool _decodeBool(String jsonPath, Object json) { | |
|
danrubel
2014/08/17 17:10:21
Do you want to sort the class memebers via cmd-1 -
Paul Berry
2014/08/18 21:58:03
Done.
| |
| 143 if (json is bool) { | |
| 144 return json; | |
| 145 } else if (json == 'true') { | |
| 146 return true; | |
| 147 } else if (json == 'false') { | |
| 148 return false; | |
| 149 } | |
| 150 throw mismatch(jsonPath, 'bool'); | |
| 151 } | |
| 152 | |
| 153 /** | |
| 154 * Decode a JSON object that is expected to be an integer. A string | |
| 155 * representation of an integer is also accepted. | |
| 156 */ | |
| 157 int _decodeInt(String jsonPath, Object json) { | |
| 158 if (json is int) { | |
| 159 return json; | |
| 160 } else if (json is String) { | |
| 161 return int.parse(json, onError: (String value) { | |
| 162 throw mismatch(jsonPath, 'int'); | |
| 163 }); | |
| 164 } | |
| 165 throw mismatch(jsonPath, 'int'); | |
| 166 } | |
| 167 | |
| 168 /** | |
| 169 * Decode a JSON object that is expected to be one of several choices, | |
| 170 * where the choices are disambiguated by the contents of the field [field]. | |
| 171 * [decoders] is a map from each possible string in the field to the decoder | |
| 172 * that should be used to decode the JSON object. | |
| 173 */ | |
| 174 Object _decodeUnion(String jsonPath, Map json, String field, | |
| 175 Map<String, JsonDecoderCallback> decoders) { | |
| 176 if (json is Map) { | |
| 177 if (!json.containsKey(field)) { | |
| 178 throw missingKey(jsonPath, field); | |
| 179 } | |
| 180 var disambiguatorPath = '$jsonPath[${JSON.encode(field)}]'; | |
| 181 String disambiguator = _decodeString(disambiguatorPath, | |
| 182 json[field]); | |
| 183 if (!decoders.containsKey(disambiguator)) { | |
| 184 throw mismatch(disambiguatorPath, 'One of: ${decoders.keys.toList()}'); | |
| 185 } | |
| 186 return decoders[disambiguator](jsonPath, json); | |
| 187 } else { | |
| 188 throw mismatch(jsonPath, 'Map'); | |
| 189 } | |
| 190 } | |
| 191 } | |
| 192 | |
| 193 /** | |
| 194 * JsonDecoder for decoding requests. Errors are reporting by throwing a | |
| 195 * [RequestFailure]. | |
| 196 */ | |
| 197 class RequestDecoder extends JsonDecoder { | |
| 198 /** | |
| 199 * The request being deserialized. | |
| 200 */ | |
| 201 final Request _request; | |
| 202 | |
| 203 RequestDecoder(this._request); | |
| 204 | |
| 205 @override | |
| 206 dynamic mismatch(String jsonPath, String expected) { | |
| 207 return new RequestFailure(new Response.invalidParameter(_request, jsonPath, | |
| 208 'be $expected')); | |
| 209 } | |
| 210 | |
| 211 @override | |
| 212 dynamic missingKey(String jsonPath, String key) { | |
| 213 return new RequestFailure(new Response.invalidParameter(_request, jsonPath, | |
| 214 'contain key ${JSON.encode(key)}')); | |
| 215 } | |
| 216 } | |
| 217 | |
| 218 /** | |
| 219 * JsonDecoder for decoding responses from the server. This is intended to be | |
| 220 * used only for testing. Errors are reported using bare [Exception] objects. | |
| 221 */ | |
| 222 class ResponseDecoder extends JsonDecoder { | |
| 223 @override | |
| 224 dynamic mismatch(String jsonPath, String expected) { | |
| 225 return new Exception('Expected $expected at $jsonPath'); | |
| 226 } | |
| 227 | |
| 228 @override | |
| 229 dynamic missingKey(String jsonPath, String key) { | |
| 230 return new Exception('Missing key $key at $jsonPath'); | |
| 231 } | |
| 232 } | |
| OLD | NEW |