using System;
using System.Reflection;
using Unity.VisualScripting.FullSerializer.Internal;
namespace Unity.VisualScripting.FullSerializer
{
///
/// A property or field on a MetaType. This unifies the FieldInfo and
/// PropertyInfo classes.
///
public class fsMetaProperty
{
internal fsMetaProperty(fsConfig config, FieldInfo field)
{
_memberInfo = field;
StorageType = field.FieldType;
MemberName = field.Name;
IsPublic = field.IsPublic;
IsReadOnly = field.IsInitOnly;
CanRead = true;
CanWrite = true;
CommonInitialize(config);
}
internal fsMetaProperty(fsConfig config, PropertyInfo property)
{
_memberInfo = property;
StorageType = property.PropertyType;
MemberName = property.Name;
IsPublic = property.GetGetMethod() != null && property.GetGetMethod().IsPublic && property.GetSetMethod() != null && property.GetSetMethod().IsPublic;
IsReadOnly = false;
CanRead = property.CanRead;
CanWrite = property.CanWrite;
CommonInitialize(config);
}
///
/// Internal handle to the reflected member.
///
internal MemberInfo _memberInfo;
///
/// The type of value that is stored inside of the property. For example,
/// for an int field, StorageType will be typeof(int).
///
public Type StorageType { get; private set; }
///
/// A custom fsBaseConverter instance to use for this field/property, if
/// requested. This will be null if the default converter selection
/// algorithm should be used. This is specified using the [fsObject]
/// annotation with the Converter field.
///
public Type OverrideConverterType { get; private set; }
///
/// Can this property be read?
///
public bool CanRead { get; private set; }
///
/// Can this property be written to?
///
public bool CanWrite { get; private set; }
///
/// The serialized name of the property, as it should appear in JSON.
///
public string JsonName { get; private set; }
///
/// The name of the actual member.
///
public string MemberName { get; private set; }
///
/// Is this member public?
///
public bool IsPublic { get; private set; }
///
/// Is this type readonly? We can modify readonly properties using
/// reflection, but not using generated C#.
///
public bool IsReadOnly { get; private set; }
private void CommonInitialize(fsConfig config)
{
var attr = fsPortableReflection.GetAttribute(_memberInfo);
if (attr != null)
{
JsonName = attr.Name;
OverrideConverterType = attr.Converter;
}
if (string.IsNullOrEmpty(JsonName))
{
JsonName = config.GetJsonNameFromMemberName(MemberName, _memberInfo);
}
}
///
/// Writes a value to the property that this MetaProperty represents,
/// using given object instance as the context.
///
public void Write(object context, object value)
{
var field = _memberInfo as FieldInfo;
var property = _memberInfo as PropertyInfo;
if (field != null)
{
if (PlatformUtility.supportsJit)
{
field.SetValueOptimized(context, value);
}
else
{
field.SetValue(context, value);
}
}
else if (property != null)
{
if (PlatformUtility.supportsJit)
{
if (property.CanWrite)
{
property.SetValueOptimized(context, value);
}
}
else
{
var setMethod = property.GetSetMethod(/*nonPublic:*/ true);
if (setMethod != null)
{
setMethod.Invoke(context, new[] { value });
}
}
}
}
///
/// Reads a value from the property that this MetaProperty represents,
/// using the given object instance as the context.
///
public object Read(object context)
{
if (_memberInfo is PropertyInfo)
{
#if LUDIQ_OPTIMIZE
return ((PropertyInfo)_memberInfo).GetValueOptimized(context);
#else
return ((PropertyInfo)_memberInfo).GetValue(context, null); // Attempt fix-1588
#endif
}
else
{
#if LUDIQ_OPTIMIZE
return ((FieldInfo)_memberInfo).GetValueOptimized(context);
#else
return ((FieldInfo)_memberInfo).GetValue(context);
#endif
}
}
}
}