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