using System; using System.Collections.Generic; using System.Diagnostics; namespace Gaia.FullSerializer { public sealed class fsData { private object _value; public static readonly fsData True = new fsData(boolean: true); public static readonly fsData False = new fsData(boolean: false); public static readonly fsData Null = new fsData(); public fsDataType Type { get { if (_value == null) { return fsDataType.Null; } if (_value is double) { return fsDataType.Double; } if (_value is long) { return fsDataType.Int64; } if (_value is ulong) { return fsDataType.UInt64; } if (_value is bool) { return fsDataType.Boolean; } if (_value is string) { return fsDataType.String; } if (_value is Dictionary) { return fsDataType.Object; } if (_value is List) { return fsDataType.Array; } throw new InvalidOperationException("unknown JSON data type"); } } public bool IsNull => _value == null; public bool IsDouble => _value is double; public bool IsInt64 => _value is long; public bool IsUInt64 => _value is ulong; public bool IsBool => _value is bool; public bool IsString => _value is string; public bool IsDictionary => _value is Dictionary; public bool IsList => _value is List; [DebuggerBrowsable(DebuggerBrowsableState.Never)] public double AsDouble => Cast(); [DebuggerBrowsable(DebuggerBrowsableState.Never)] public long AsInt64 => Cast(); [DebuggerBrowsable(DebuggerBrowsableState.Never)] public ulong AsUInt64 => Cast(); [DebuggerBrowsable(DebuggerBrowsableState.Never)] public bool AsBool => Cast(); [DebuggerBrowsable(DebuggerBrowsableState.Never)] public string AsString => Cast(); [DebuggerBrowsable(DebuggerBrowsableState.Never)] public Dictionary AsDictionary => Cast>(); [DebuggerBrowsable(DebuggerBrowsableState.Never)] public List AsList => Cast>(); public fsData() { _value = null; } public fsData(bool boolean) { _value = boolean; } public fsData(double f) { _value = f; } public fsData(long i) { _value = i; } public fsData(ulong i) { _value = i; } public fsData(string str) { _value = str; } public fsData(Dictionary dict) { _value = dict; } public fsData(List list) { _value = list; } public static fsData CreateDictionary() { return new fsData(new Dictionary(fsConfig.IsCaseSensitive ? StringComparer.CurrentCulture : StringComparer.CurrentCultureIgnoreCase)); } public static fsData CreateList() { return new fsData(new List()); } public static fsData CreateList(int capacity) { return new fsData(new List(capacity)); } internal void BecomeDictionary() { _value = new Dictionary(); } internal fsData Clone() { return new fsData { _value = _value }; } private T Cast() { if (_value is T) { return (T)_value; } throw new InvalidCastException("Unable to cast <" + this?.ToString() + "> (with type = " + _value.GetType()?.ToString() + ") to type " + typeof(T)); } public override string ToString() { return fsJsonPrinter.CompressedJson(this); } public override bool Equals(object obj) { return Equals(obj as fsData); } public bool Equals(fsData other) { if (other == null || Type != other.Type) { return false; } switch (Type) { case fsDataType.Null: return true; case fsDataType.Double: if (AsDouble != other.AsDouble) { return Math.Abs(AsDouble - other.AsDouble) < double.Epsilon; } return true; case fsDataType.Int64: return AsInt64 == other.AsInt64; case fsDataType.UInt64: return AsUInt64 == other.AsUInt64; case fsDataType.Boolean: return AsBool == other.AsBool; case fsDataType.String: return AsString == other.AsString; case fsDataType.Array: { List asList = AsList; List asList2 = other.AsList; if (asList.Count != asList2.Count) { return false; } for (int i = 0; i < asList.Count; i++) { if (!asList[i].Equals(asList2[i])) { return false; } } return true; } case fsDataType.Object: { Dictionary asDictionary = AsDictionary; Dictionary asDictionary2 = other.AsDictionary; if (asDictionary.Count != asDictionary2.Count) { return false; } foreach (string key in asDictionary.Keys) { if (!asDictionary2.ContainsKey(key)) { return false; } if (!asDictionary[key].Equals(asDictionary2[key])) { return false; } } return true; } default: throw new Exception("Unknown data type"); } } public static bool operator ==(fsData a, fsData b) { if ((object)a == b) { return true; } 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); } public static bool operator !=(fsData a, fsData b) { return !(a == b); } public override int GetHashCode() { return _value.GetHashCode(); } } }