// Parse the next path component from a SerializedProperty.propertyPath.  For simple field/property access,
        // this is just tokenizing on '.' and returning each field/property name.  Array/list access is via
        // the pseudo-property "Array.data[N]", so this method parses that and returns just the array/list index N.
        //
        // Call this method repeatedly to access all path components.  For example:
        //
        //      string propertyPath = "quests.Array.data[0].goal";
        //      int i = 0;
        //      NextPropertyPathToken(propertyPath, ref i, out var component);
        //          => component = { propertyName = "quests" };
        //      NextPropertyPathToken(propertyPath, ref i, out var component)
        //          => component = { elementIndex = 0 };
        //      NextPropertyPathToken(propertyPath, ref i, out var component)
        //          => component = { propertyName = "goal" };
        //      NextPropertyPathToken(propertyPath, ref i, out var component)
        //          => returns false
        private static bool NextPathComponent(string propertyPath, ref int index, out PropertyPathComponent component)
        {
            component = new PropertyPathComponent();

            if (index >= propertyPath.Length)
            {
                return(false);
            }

            Match arrayElementMatch = ArrayElementRegex.Match(propertyPath, index);

            if (arrayElementMatch.Success)
            {
                index += arrayElementMatch.Length + 1; // Skip past next '.'
                component.elementIndex = int.Parse(arrayElementMatch.Groups[1].Value);
                return(true);
            }

            int dot = propertyPath.IndexOf('.', index);

            if (dot == -1)
            {
                component.propertyName = propertyPath.Substring(index);
                index = propertyPath.Length;
            }
            else
            {
                component.propertyName = propertyPath.Substring(index, dot - index);
                index = dot + 1; // Skip past next '.'
            }

            return(true);
        }
 private static void SetPathComponentValue(object container, PropertyPathComponent component, object value)
 {
     if (component.propertyName == null)
     {
         ((IList)container)[component.elementIndex] = value;
     }
     else
     {
         SetMemberValue(container, component.propertyName, value);
     }
 }
 private static object GetPathComponentValue(object container, PropertyPathComponent component)
 {
     if (component.propertyName == null)
     {
         return(((IList)container)[component.elementIndex]);
     }
     else
     {
         return(GetMemberValue(container, component.propertyName));
     }
 }