// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic;
using System.Reflection;
using FlaxEditor.Scripting;
using FlaxEngine;
namespace FlaxEditor.Utilities
{
///
/// Helper class used to store path made of .
///
[HideInEditor]
public struct MemberInfoPath
{
///
/// The path entry.
///
[HideInEditor]
public struct Entry
{
///
/// The member.
///
public readonly ScriptMemberInfo Member;
///
/// The collection index or key.
///
public readonly object Index;
///
/// Gets the member type (field or property type).
///
public ScriptType Type
{
get
{
var result = Member.ValueType;
// Special case for collections
if (Index != null)
result = result.GetElementType();
return result;
}
}
///
/// Initializes a new instance of the struct.
///
/// The member.
/// The collection index or key.
public Entry(ScriptMemberInfo member, object index = null)
{
Member = member;
Index = index;
}
///
/// Gets the value. Handles arrays.
///
/// The instance.
/// The result value.
public object GetValue(object instance)
{
object value;
// Special case for collections
if (Index != null)
{
if (instance is System.Collections.IList asList)
{
// Get value at index
value = asList[(int)Index];
}
else if (instance is System.Collections.IDictionary asDictionary)
{
// Get value at key
value = asDictionary[Index];
}
else
{
throw new NotSupportedException();
}
}
else
{
// Get value
value = Member.GetValue(instance);
}
return value;
}
///
/// Sets the value.
///
/// The instance.
/// The value.
public void SetValue(object instance, object value)
{
// Special case for collections
if (Index != null)
{
if (instance is System.Collections.IList asList)
{
// Set value at index
asList[(int)Index] = value;
}
else if (instance is System.Collections.IDictionary asDictionary)
{
// Set value at key
asDictionary[Index] = value;
}
else
{
throw new NotSupportedException();
}
}
else
{
// Set value
Member.SetValue(instance, value);
}
}
///
public override bool Equals(object obj)
{
if (!(obj is Entry))
{
return false;
}
var entry = (Entry)obj;
return Member == entry.Member && Index == entry.Index;
}
///
public override int GetHashCode()
{
var hashCode = 2005110182;
hashCode = hashCode * -1521134295 + Member.GetHashCode();
if (Index != null)
hashCode = hashCode * -1521134295 + Index.GetHashCode();
return hashCode;
}
///
public override string ToString()
{
if (Index != null)
return "[" + Index + "]";
return Member.Name;
}
}
private Entry[] _stack;
///
/// Initializes a new instance of the class.
///
/// The member.
/// The collection index or key.
public MemberInfoPath(ScriptMemberInfo member, object index = null)
{
if (member == null)
throw new ArgumentNullException();
_stack = new Entry[1];
_stack[0] = new Entry(member, index);
}
///
/// Initializes a new instance of the class.
///
/// The members.
public MemberInfoPath(Stack members)
: this()
{
if (members == null || members.Count == 0)
throw new ArgumentNullException();
_stack = members.ToArray();
Array.Reverse(_stack);
}
///
/// Gets the members path string.
///
public string Path
{
get
{
string result = _stack[0].ToString();
for (int i = 1; i < _stack.Length; i++)
{
result += "." + _stack[i];
}
return result;
}
}
///
/// Gets the last member (returns it) and the instance (by the ref parameter).
///
/// The instance. Also contains the result instance for the last member.
/// The last member info.
public Entry GetLastMember(ref object instance)
{
Entry finalMember = _stack[0];
for (int i = 1; i < _stack.Length; i++)
{
instance = finalMember.GetValue(instance);
finalMember = _stack[i];
}
return finalMember;
}
///
/// Gets the last member value.
///
/// The top object instance.
/// The result value.
public object GetLastValue(object instance)
{
var member = GetLastMember(ref instance);
return member.GetValue(instance);
}
///
public override string ToString()
{
return Path;
}
}
}