forked from jacobdufault/fullserializer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fsData.cs
388 lines (331 loc) · 11.7 KB
/
fsData.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace FullSerializer {
/// <summary>
/// The actual type that a JsonData instance can store.
/// </summary>
public enum fsDataType {
Array,
Object,
Double,
Int64,
Boolean,
String,
Null
}
/// <summary>
/// A union type that stores a serialized value. The stored type can be one of six different
/// types: null, boolean, double, Int64, string, Dictionary, or List.
/// </summary>
public sealed class fsData {
/// <summary>
/// The raw value that this serialized data stores. It can be one of six different types; a
/// boolean, a double, Int64, a string, a Dictionary, or a List.
/// </summary>
private readonly object _value;
#region Constructors
/// <summary>
/// Creates a fsData instance that holds null.
/// </summary>
public fsData() {
_value = null;
}
/// <summary>
/// Creates a fsData instance that holds a boolean.
/// </summary>
public fsData(bool boolean) {
_value = boolean;
}
/// <summary>
/// Creates a fsData instance that holds a double.
/// </summary>
public fsData(double f) {
_value = f;
}
/// <summary>
/// Creates a new fsData instance that holds an integer.
/// </summary>
public fsData(Int64 i) {
_value = i;
}
/// <summary>
/// Creates a fsData instance that holds a string.
/// </summary>
public fsData(string str) {
_value = str;
}
/// <summary>
/// Creates a fsData instance that holds a dictionary of values.
/// </summary>
public fsData(Dictionary<string, fsData> dict) {
_value = dict;
}
/// <summary>
/// Creates a fsData instance that holds a list of values.
/// </summary>
public fsData(List<fsData> list) {
_value = list;
}
#if UNITY_METRO
/// <summary>
/// Helper method to create a fsData instance that holds a dictionary.
/// </summary>
public static fsData CreateDictionary()
{
return new fsData(new Dictionary<string, fsData>(
fsConfig.IsCaseSensitive ? StringComparer.CurrentCulture : StringComparer.CurrentCultureIgnoreCase));
}
#else
/// <summary>
/// Helper method to create a fsData instance that holds a dictionary.
/// </summary>
public static fsData CreateDictionary() {
return new fsData(new Dictionary<string, fsData>(
fsConfig.IsCaseSensitive ? StringComparer.InvariantCulture : StringComparer.InvariantCultureIgnoreCase));
}
#endif
/// <summary>
/// Helper method to create a fsData instance that holds a list.
/// </summary>
public static fsData CreateList() {
return new fsData(new List<fsData>());
}
/// <summary>
/// Helper method to create a fsData instance that holds a list with the initial capacity.
/// </summary>
public static fsData CreateList(int capacity) {
return new fsData(new List<fsData>(capacity));
}
public readonly static fsData True = new fsData(true);
public readonly static fsData False = new fsData(true);
public readonly static fsData Null = new fsData();
#endregion
#region Casting Predicates
public fsDataType Type {
get {
if (_value == null) return fsDataType.Null;
if (_value is double) return fsDataType.Double;
if (_value is Int64) return fsDataType.Int64;
if (_value is bool) return fsDataType.Boolean;
if (_value is string) return fsDataType.String;
if (_value is Dictionary<string, fsData>) return fsDataType.Object;
if (_value is List<fsData>) return fsDataType.Array;
throw new InvalidOperationException("unknown JSON data type");
}
}
/// <summary>
/// Returns true if this fsData instance maps back to null.
/// </summary>
public bool IsNull {
get {
return _value == null;
}
}
/// <summary>
/// Returns true if this fsData instance maps back to a double.
/// </summary>
public bool IsDouble {
get {
return _value is double;
}
}
/// <summary>
/// Returns true if this fsData instance maps back to an Int64.
/// </summary>
public bool IsInt64 {
get {
return _value is Int64;
}
}
/// <summary>
/// Returns true if this fsData instance maps back to a boolean.
/// </summary>
public bool IsBool {
get {
return _value is bool;
}
}
/// <summary>
/// Returns true if this fsData instance maps back to a string.
/// </summary>
public bool IsString {
get {
return _value is string;
}
}
/// <summary>
/// Returns true if this fsData instance maps back to a Dictionary.
/// </summary>
public bool IsDictionary {
get {
return _value is Dictionary<string, fsData>;
}
}
/// <summary>
/// Returns true if this fsData instance maps back to a List.
/// </summary>
public bool IsList {
get {
return _value is List<fsData>;
}
}
#endregion
#region Casts
/// <summary>
/// Casts this fsData to a double. Throws an exception if it is not a double.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public double AsDouble {
get {
return Cast<double>();
}
}
/// <summary>
/// Casts this fsData to an Int64. Throws an exception if it is not an Int64.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public Int64 AsInt64 {
get {
return Cast<Int64>();
}
}
/// <summary>
/// Casts this fsData to a boolean. Throws an exception if it is not a boolean.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public bool AsBool {
get {
return Cast<bool>();
}
}
/// <summary>
/// Casts this fsData to a string. Throws an exception if it is not a string.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public string AsString {
get {
return Cast<string>();
}
}
/// <summary>
/// Casts this fsData to a Dictionary. Throws an exception if it is not a
/// Dictionary.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public Dictionary<string, fsData> AsDictionary {
get {
return Cast<Dictionary<string, fsData>>();
}
}
/// <summary>
/// Casts this fsData to a List. Throws an exception if it is not a List.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public List<fsData> AsList {
get {
return Cast<List<fsData>>();
}
}
/// <summary>
/// Internal helper method to cast the underlying storage to the given type or throw a
/// pretty printed exception on failure.
/// </summary>
private T Cast<T>() {
if (_value is T) {
return (T)_value;
}
throw new InvalidCastException("Unable to cast <" + this + "> (with type = " +
_value.GetType() + ") to type " + typeof(T));
}
#endregion
#region ToString Implementation
public override string ToString() {
return fsJsonPrinter.CompressedJson(this);
}
#endregion
#region Equality Comparisons
/// <summary>
/// Determines whether the specified object is equal to the current object.
/// </summary>
public override bool Equals(object obj) {
return Equals(obj as fsData);
}
/// <summary>
/// Determines whether the specified object is equal to the current object.
/// </summary>
public bool Equals(fsData other) {
if (other == null || Type != other.Type) {
return false;
}
switch (Type) {
case fsDataType.Null:
return true;
case fsDataType.Double:
return AsDouble == other.AsDouble || Math.Abs(AsDouble - other.AsDouble) < double.Epsilon;
case fsDataType.Int64:
return AsInt64 == other.AsInt64;
case fsDataType.Boolean:
return AsBool == other.AsBool;
case fsDataType.String:
return AsString == other.AsString;
case fsDataType.Array:
var thisList = AsList;
var otherList = other.AsList;
if (thisList.Count != otherList.Count) return false;
for (int i = 0; i < thisList.Count; ++i) {
if (thisList[i].Equals(otherList[i]) == false) {
return false;
}
}
return true;
case fsDataType.Object:
var thisDict = AsDictionary;
var otherDict = other.AsDictionary;
if (thisDict.Count != otherDict.Count) return false;
foreach (string key in thisDict.Keys) {
if (otherDict.ContainsKey(key) == false) {
return false;
}
if (thisDict[key].Equals(otherDict[key]) == false) {
return false;
}
}
return true;
}
throw new Exception("Unknown data type");
}
/// <summary>
/// Returns true iff a == b.
/// </summary>
public static bool operator ==(fsData a, fsData b) {
// If both are null, or both are same instance, return true.
if (ReferenceEquals(a, b)) {
return true;
}
// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null)) {
return false;
}
if (a.IsDouble && b.IsDouble) {
return Math.Abs(a.AsDouble - b.AsDouble) < double.Epsilon;
}
return a.Equals(b);
}
/// <summary>
/// Returns true iff a != b.
/// </summary>
public static bool operator !=(fsData a, fsData b) {
return !(a == b);
}
/// <summary>
/// Returns a hash code for this instance.
/// </summary>
/// <returns>A hash code for this instance, suitable for use in hashing algorithms and data
/// structures like a hash table.</returns>
public override int GetHashCode() {
return _value.GetHashCode();
}
#endregion
}
}