Ejemplo n.º 1
0
            private bool TryInvokeGetIterator(IObjectValueRole <TValue> serializedObjectRole,
                                              IValueFetchOptions options,
                                              out IObjectValueRole <TValue> returnedSerializedPropertyRole)
            {
                returnedSerializedPropertyRole = null;

                var method = MetadataTypeLiteEx.LookupInstanceMethodSafe(serializedObjectRole.ReifiedType.MetadataType,
                                                                         MethodSelectors.SerializedObject_GetIterator, false);

                if (method == null)
                {
                    myLogger.Warn("Cannot find GetIterator method on SerializedObject");
                    return(false);
                }

                returnedSerializedPropertyRole = new SimpleValueReference <TValue>(
                    serializedObjectRole.CallInstanceMethod(method),
                    serializedObjectRole.ValueReference.OriginatingFrame, myValueServices.RoleFactory)
                                                 .AsObjectSafe(options);
                if (returnedSerializedPropertyRole == null)
                {
                    myLogger.Warn("Unable to invoke GetIterator");
                    return(false);
                }

                return(true);
            }
            private bool TryCopySerializedProperty(IObjectValueRole <TValue> serializedPropertyRole,
                                                   IValueFetchOptions options,
                                                   out IObjectValueRole <TValue> copiedSerializedPropertyRole)
            {
                copiedSerializedPropertyRole = null;

                // Get a copy of the property, so we can call Next(true) without updating the current instance
                var copyMethod = MetadataTypeLiteEx.LookupInstanceMethodSafe(
                    mySerializedPropertyRole.ReifiedType.MetadataType,
                    MethodSelectors.SerializedProperty_Copy, false);

                if (copyMethod == null)
                {
                    myLogger.Warn("Cannot find Copy method on SerializedProperty");
                    return(false);
                }

                // CallInstanceMethod always returns not null (VoidValue if it fails)
                copiedSerializedPropertyRole = new SimpleValueReference <TValue>(
                    serializedPropertyRole.CallInstanceMethod(copyMethod),
                    mySerializedPropertyRole.ValueReference.OriginatingFrame, myValueServices.RoleFactory)
                                               .AsObjectSafe(options);
                if (copiedSerializedPropertyRole == null)
                {
                    myLogger.Warn("Unable to Copy serializedProperty");
                    return(false);
                }

                return(true);
            }
            private IEnumerable <IValueEntity> GetChildrenImpl(IPresentationOptions options, CancellationToken token)
            {
                myGetElementMethod = MetadataTypeLiteEx.LookupInstanceMethodSafe(mySerializedPropertyRole.ReifiedType.MetadataType,
                                                                                 myGetMethodElementSelector, false);
                if (myGetElementMethod == null)
                {
                    myLogger.Warn("Cannot find GetArrayElementAtIndex/GetFixedBufferElementAtIndex method");
                    yield break;
                }

                if (options.ClusterArrays)
                {
                    foreach (var valueEntity in GetChunkedChildren(mySerializedPropertyRole, 0, myArraySize, options, token))
                    {
                        yield return(valueEntity);
                    }
                }
                else
                {
                    for (var i = 0; i < myArraySize; i++)
                    {
                        token.ThrowIfCancellationRequested();
                        yield return(GetElementValueAt(mySerializedPropertyRole, i, options));
                    }
                }
            }
            private IEnumerable <IValueEntity> GetChildrenImpl(IValueFetchOptions options, CancellationToken token)
            {
                // SerializedProperty is a view over a serialized stream. Calling Next() or GetEnumerator().MoveNext()
                // will update this view. We need to work with copies, so that the original value isn't updated
                if (!TryCopySerializedProperty(mySerializedPropertyRole, options, out var cursor))
                {
                    yield break;
                }

                // Get the depth of this "parent" property. We'll call Next() until  children's depth changes
                if (!Util.TryEvaluatePrimitiveProperty(cursor, "depth", options, out int initialDepth))
                {
                    myLogger.Warn("Unable to evaluate initial depth on serializedProperty");
                    yield break;
                }

                var nextMethod = MetadataTypeLiteEx.LookupInstanceMethodSafe(cursor.ReifiedType.MetadataType,
                                                                             MethodSelectors.SerializedProperty_Next, false);

                if (nextMethod == null)
                {
                    myLogger.Warn("Cannot find Next method on SerializedProperty");
                    yield break;
                }

                var trueValue = myValueServices.ValueFactory.CreatePrimitive(
                    mySerializedPropertyRole.ValueReference.OriginatingFrame, options, true);
                var falseValue = myValueServices.ValueFactory.CreatePrimitive(
                    mySerializedPropertyRole.ValueReference.OriginatingFrame, options, false);

                // Call cursor.Next(true). Our cursor is now a view over the first child
                if (!TryInvokeNext(cursor, nextMethod, trueValue, options, out var nextResult))
                {
                    yield break;
                }

                var count = 0;

                while (nextResult)
                {
                    token.ThrowIfCancellationRequested();

                    if (!Util.TryEvaluatePrimitiveProperty(cursor, "depth", options, out int thisDepth))
                    {
                        myLogger.Warn("Unable to evaluate initial depth on serializedProperty");
                        yield break;
                    }

                    // SerializedProperties are a view on a stream of serialised objects (not the C# objects!). Children
                    // are simply the next node in the stream, but they have a depth set to current depth + 1. Iterating
                    // children has finished when the next node's depth is set back to current depth.
                    if (thisDepth != initialDepth + 1)
                    {
                        break;
                    }

                    // Yield a copy of the current instance
                    if (!TryCopySerializedProperty(cursor, options, out var copiedSerializedPropertyRole))
                    {
                        myLogger.Warn("Failed to copy current serialised property");
                        break;
                    }

                    var name = copiedSerializedPropertyRole.GetInstancePropertyReference("name")
                               ?.AsStringSafe(options)?.GetString() ?? $"prop{count}";

                    // Tell the value presenter to hide the name field, because we're using it for the key name. Also
                    // hide the default presentation. Of course it's a SerializedProperty, it's a child of a
                    // SerializedProperty
                    yield return(new CalculatedValueReferenceDecorator <TValue>(
                                     copiedSerializedPropertyRole.ValueReference, myValueServices.RoleFactory, name, false,
                                     false)
                                 .ToValue(myValueServices));

                    // MoveNext(false). cursor is now viewing either the next child or a sibling of the original
                    // property, or is at the end of the stream (nextResult is false). If this evaluation fails,
                    // we've already logged and nextResult is already false, so we don't need extra error handling
                    TryInvokeNext(cursor, nextMethod, falseValue, options, out nextResult);

                    count++;
                }
            }