// --------------------------------------------------------------------------------------------------------------------
//
// Copyright (c) VRMADA, All rights reserved.
//
// --------------------------------------------------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using UltimateXR.Core;
using UltimateXR.Extensions.System.Collections;
using UltimateXR.Extensions.System.Math;
using UltimateXR.Extensions.Unity.Math;
using UnityEngine;
namespace UltimateXR.Extensions.System
{
///
/// extensions.
///
public static class ObjectExt
{
#region Public Methods
///
/// Compares two objects for equality, taking into account the content of collections for collection types.
///
/// The first object to compare
/// The second object to compare
/// True if the objects are equal; otherwise, false
public static bool ValuesEqual(this object a, object b)
{
return ValuesEqual(a, b, (ea, eb) => EnumerableExt.ContentEqual(ea, eb), (va, vb) => Equals(va, vb));
}
///
/// Same as but using a precision threshold for the following types:
///
///
/// float
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
/// The first object to compare
/// The second object to compare
///
/// The floating point precision threshold for the specific types listed above. The
/// constant can be used to provide a standard precision
/// across all calls.
///
/// True if the objects are equal; otherwise, false
public static bool ValuesEqual(this object a, object b, float precisionThreshold)
{
bool EqualsUsingPrecision(object a, object b, float precision)
{
// Check supported types with specific comparision using floating point precision
if (a is float fa && b is float fb)
{
return fa.EqualsUsingPrecision(fb, precision);
}
if (a is Vector3 v3a && b is Vector3 v3b)
{
return v3a.EqualsUsingPrecision(v3b, precision);
}
if (a is Quaternion qa && b is Quaternion qb)
{
return qa.EqualsUsingPrecision(qb, precision);
}
if (a is Vector2 v2a && b is Vector2 v2b)
{
return v2a.EqualsUsingPrecision(v2b, precision);
}
if (a is Vector4 v4a && b is Vector4 v4b)
{
return v4a.EqualsUsingPrecision(v4b, precision);
}
// Default comparison fallback
return Equals(a, b);
}
return ValuesEqual(a, b, (ea, eb) => EnumerableExt.ContentEqual(ea, eb, precisionThreshold), (va, vb) => EqualsUsingPrecision(va, vb, precisionThreshold));
}
///
/// Creates a deep copy of the specified object, including support for arrays, List<T>, and Dictionary<TKey,
/// TValue>.
///
/// The type of the object to be deep copied
/// The object to be deep copied
/// A deep copy of the original object
///
/// This method performs a deep copy, recursively copying all objects referenced by the original object.
/// Types derived from are not supported, and a reference to the same object will be returned
/// instead.
/// If the type of the object is an array, List<T>, or Dictionary<TKey, TValue>, it is handled natively.
/// If the type implements ICloneable, it uses the Clone method for copying.
/// For value types (primitive types and structs), the method returns the original object as they are inherently
/// deep-copied.
/// For other types, binary serialization is used for deep copying.
///
public static T DeepCopy(this T obj)
{
if (obj == null)
{
return default(T);
}
if (obj is Component)
{
return obj;
}
Type type = obj.GetType();
// Check if the type is an array
if (type.IsArray)
{
Type elementType = type.GetElementType();
Array originalArray = obj as Array;
Array copiedArray = Array.CreateInstance(elementType, originalArray.Length);
for (int i = 0; i < originalArray.Length; i++)
{
copiedArray.SetValue(DeepCopy(originalArray.GetValue(i)), i);
}
return (T)(object)copiedArray;
}
// Check if it's a List
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))
{
Type genericType = type.GetGenericArguments()[0];
IList originalList = (IList)obj;
IList copiedList = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(genericType));
foreach (object item in originalList)
{
copiedList.Add(DeepCopy(item));
}
return (T)copiedList;
}
// Check if it's a Dictionary
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>))
{
Type[] genericArguments = type.GetGenericArguments();
Type keyType = genericArguments[0];
Type valueType = genericArguments[1];
IDictionary originalDict = (IDictionary)obj;
IDictionary copiedDict = (IDictionary)Activator.CreateInstance(typeof(Dictionary<,>).MakeGenericType(keyType, valueType));
foreach (DictionaryEntry kvp in originalDict)
{
copiedDict.Add(DeepCopy(kvp.Key), DeepCopy(kvp.Value));
}
return (T)copiedDict;
}
// Check if it's a HashSet
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(HashSet<>))
{
IEnumerable originalSet = (IEnumerable)obj;
// Create a new HashSet with the same element type
HashSet