// 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; } } }