using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Unity.VisualScripting
{
public abstract class ReflectedCloner : Cloner<object>
{
public override bool Handles(Type type)
{
return false; // Should only be used as a fallback cloner
}
public override void FillClone(Type type, ref object clone, object original, CloningContext context)
{
if (PlatformUtility.supportsJit)
{
foreach (var accessor in GetOptimizedAccessors(type))
{
if (context.tryPreserveInstances)
{
var cloneProperty = accessor.GetValue(clone);
Cloning.CloneInto(context, ref cloneProperty, accessor.GetValue(original));
accessor.SetValue(clone, cloneProperty);
}
else
{
accessor.SetValue(clone, Cloning.Clone(context, accessor.GetValue(original)));
}
}
}
else
{
foreach (var accessor in GetAccessors(type))
{
if (accessor is FieldInfo)
{
var field = (FieldInfo)accessor;
if (context.tryPreserveInstances)
{
var cloneProperty = field.GetValue(clone);
Cloning.CloneInto(context, ref cloneProperty, field.GetValue(original));
field.SetValue(clone, cloneProperty);
}
else
{
field.SetValue(clone, Cloning.Clone(context, field.GetValue(original)));
}
}
else if (accessor is PropertyInfo)
{
var property = (PropertyInfo)accessor;
if (context.tryPreserveInstances)
{
var cloneProperty = property.GetValue(clone, null);
Cloning.CloneInto(context, ref cloneProperty, property.GetValue(original, null));
property.SetValue(clone, cloneProperty, null);
}
else
{
property.SetValue(clone, Cloning.Clone(context, property.GetValue(original, null)), null);
}
}
}
}
}
private readonly Dictionary<Type, MemberInfo[]> accessors = new Dictionary<Type, MemberInfo[]>();
private MemberInfo[] GetAccessors(Type type)
{
if (!accessors.ContainsKey(type))
{
accessors.Add(type, GetMembers(type).ToArray());
}
return accessors[type];
}
private readonly Dictionary<Type, IOptimizedAccessor[]> optimizedAccessors = new Dictionary<Type, IOptimizedAccessor[]>();
private IOptimizedAccessor[] GetOptimizedAccessors(Type type)
{
if (!optimizedAccessors.ContainsKey(type))
{
var list = new List<IOptimizedAccessor>();
foreach (var member in GetMembers(type))
{
if (member is FieldInfo)
{
list.Add(((FieldInfo)member).Prewarm());
}
else if (member is PropertyInfo)
{
list.Add(((PropertyInfo)member).Prewarm());
}
}
optimizedAccessors.Add(type, list.ToArray());
}
return optimizedAccessors[type];
}
protected virtual IEnumerable<MemberInfo> GetMembers(Type type)
{
var bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
return LinqUtility.Concat<MemberInfo>
(
type.GetFields(bindingFlags).Where(IncludeField),
type.GetProperties(bindingFlags).Where(IncludeProperty)
);
}
protected virtual bool IncludeField(FieldInfo field)
{
return false;
}
protected virtual bool IncludeProperty(PropertyInfo property)
{
return false;
}
}
}