using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace Unity.VisualScripting.FullSerializer
{
///
/// The actual type that a JsonData instance can store.
///
public enum fsDataType
{
Array,
Object,
Double,
Int64,
Boolean,
String,
Null
}
///
/// 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.
///
public sealed class fsData
{
///
/// 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.
///
private object _value;
#region ToString Implementation
public override string ToString()
{
return fsJsonPrinter.CompressedJson(this);
}
#endregion ToString Implementation
#region Constructors
///
/// Creates a fsData instance that holds null.
///
public fsData()
{
_value = null;
}
///
/// Creates a fsData instance that holds a boolean.
///
public fsData(bool boolean)
{
_value = boolean;
}
///
/// Creates a fsData instance that holds a double.
///
public fsData(double f)
{
_value = f;
}
///
/// Creates a new fsData instance that holds an integer.
///
public fsData(Int64 i)
{
_value = i;
}
///
/// Creates a fsData instance that holds a string.
///
public fsData(string str)
{
_value = str;
}
///
/// Creates a fsData instance that holds a dictionary of values.
///
public fsData(Dictionary dict)
{
_value = dict;
}
///
/// Creates a fsData instance that holds a list of values.
///
public fsData(List list)
{
_value = list;
}
///
/// Helper method to create a fsData instance that holds a dictionary.
///
public static fsData CreateDictionary()
{
return new fsData(new Dictionary(
fsGlobalConfig.IsCaseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase));
}
///
/// Helper method to create a fsData instance that holds a list.
///
public static fsData CreateList()
{
return new fsData(new List());
}
///
/// Helper method to create a fsData instance that holds a list with the
/// initial capacity.
///
public static fsData CreateList(int capacity)
{
return new fsData(new List(capacity));
}
public readonly static fsData True = new fsData(true);
public readonly static fsData False = new fsData(false);
public readonly static fsData Null = new fsData();
#endregion Constructors
#region Internal Helper Methods
///
/// Transforms the internal fsData instance into a dictionary.
///
internal void BecomeDictionary()
{
_value = new Dictionary();
}
///
/// Returns a shallow clone of this data instance.
///
internal fsData Clone()
{
var clone = new fsData();
clone._value = _value;
return clone;
}
#endregion Internal Helper Methods
#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)
{
return fsDataType.Object;
}
if (_value is List)
{
return fsDataType.Array;
}
throw new InvalidOperationException("unknown JSON data type");
}
}
///
/// Returns true if this fsData instance maps back to null.
///
public bool IsNull => _value == null;
///
/// Returns true if this fsData instance maps back to a double.
///
public bool IsDouble => _value is double;
///
/// Returns true if this fsData instance maps back to an Int64.
///
public bool IsInt64 => _value is Int64;
///
/// Returns true if this fsData instance maps back to a boolean.
///
public bool IsBool => _value is bool;
///
/// Returns true if this fsData instance maps back to a string.
///
public bool IsString => _value is string;
///
/// Returns true if this fsData instance maps back to a Dictionary.
///
public bool IsDictionary => _value is Dictionary;
///
/// Returns true if this fsData instance maps back to a List.
///
public bool IsList => _value is List;
#endregion Casting Predicates
#region Casts
///
/// Casts this fsData to a double. Throws an exception if it is not a
/// double.
///
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public double AsDouble => Cast();
///
/// Casts this fsData to an Int64. Throws an exception if it is not an
/// Int64.
///
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public Int64 AsInt64 => Cast();
///
/// Casts this fsData to a boolean. Throws an exception if it is not a
/// boolean.
///
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public bool AsBool => Cast();
///
/// Casts this fsData to a string. Throws an exception if it is not a
/// string.
///
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public string AsString => Cast();
///
/// Casts this fsData to a Dictionary. Throws an exception if it is not a
/// Dictionary.
///
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public Dictionary AsDictionary => Cast>();
///
/// Casts this fsData to a List. Throws an exception if it is not a List.
///
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public List AsList => Cast>();
///
/// Internal helper method to cast the underlying storage to the given
/// type or throw a pretty printed exception on failure.
///
private T Cast()
{
if (_value is T)
{
return (T)_value;
}
throw new InvalidCastException("Unable to cast <" + this + "> (with type = " +
_value.GetType() + ") to type " + typeof(T));
}
#endregion Casts
#region Equality Comparisons
///
/// Determines whether the specified object is equal to the current
/// object.
///
public override bool Equals(object obj)
{
return Equals(obj as fsData);
}
///
/// Determines whether the specified object is equal to the current
/// object.
///
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 (var 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 (var 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");
}
///
/// Returns true iff a == b.
///
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);
}
///
/// Returns true iff a != b.
///
public static bool operator !=(fsData a, fsData b)
{
return !(a == b);
}
///
/// Returns a hash code for this instance.
///
///
/// A hash code for this instance, suitable for use in hashing algorithms
/// and data structures like a hash table.
///
public override int GetHashCode()
{
return _value.GetHashCode();
}
#endregion Equality Comparisons
}
}