Пример #1
0
        private static void PrepareMembersCallback(SharpYaml.Serialization.Descriptors.ObjectDescriptor objDesc, List <IMemberDescriptor> memberDescriptors)
        {
            var type = objDesc.Type;

            if (IdentifiableHelper.IsIdentifiable(type) && !typeof(IIdentifiable).IsAssignableFrom(type))
            {
                memberDescriptors.Add(CustomDynamicMemberDescriptor);
            }

            // Call custom callbacks to prepare members
            PrepareMembersEvent?.Invoke(objDesc, memberDescriptors);
        }
Пример #2
0
        private static void PrepareMembersCallback(SharpYaml.Serialization.Descriptors.ObjectDescriptor objDesc, List <IMemberDescriptor> memberDescriptors)
        {
            var type = objDesc.Type;

            // Early exit if we don't need to add a unique identifier to a type
            if (!IdentifiableHelper.IsIdentifiable(type) || typeof(IIdentifiable).IsAssignableFrom(type))
            {
                return;
            }

            // Otherwise we can add it
            memberDescriptors.Add(CustomDynamicMemberDescriptor);
        }
        public override string ReadMemberName(ref ObjectContext objectContext, string memberName, out bool skipMember)
        {
            var newMemberName = memberName.Trim(Override.PostFixSealed, Override.PostFixNew);
            var objectType    = objectContext.Instance.GetType();

            if (newMemberName.Length != memberName.Length)
            {
                var overrideType = OverrideType.Base;
                if (memberName.Contains(Override.PostFixNewSealed) || memberName.EndsWith(Override.PostFixNewSealedAlt))
                {
                    overrideType = OverrideType.New | OverrideType.Sealed;
                }
                else if (memberName.EndsWith(Override.PostFixNew))
                {
                    overrideType = OverrideType.New;
                }
                else if (memberName.EndsWith(Override.PostFixSealed))
                {
                    overrideType = OverrideType.Sealed;
                }

                if (overrideType != OverrideType.Base)
                {
                    if (cachedDescriptor == null || cachedDescriptor.Type != objectType)
                    {
                        cachedDescriptor = typeDescriptorFactory.Find(objectType);
                    }
                    var memberDescriptor = cachedDescriptor[newMemberName];
                    objectContext.Instance.SetOverride(memberDescriptor, overrideType);
                }
            }

            var resultMemberName = base.ReadMemberName(ref objectContext, newMemberName, out skipMember);

            // If ~Id was not found as a member, don't generate an error, as we may have switched an object
            // to NonIdentifiable but we don't want to write an upgrader for this
            if (!IdentifiableHelper.IsIdentifiable(objectType) && memberName == IdentifiableHelper.YamlSpecialId)
            {
                skipMember = true;
            }
            return(resultMemberName);
        }
Пример #4
0
        private void DiffValue(Diff3Node diff3, ref NodeDescription baseNodeDesc, ref NodeDescription asset1NodeDesc, ref NodeDescription asset2NodeDesc)
        {
            var node            = diff3.Asset1Node ?? diff3.Asset2Node ?? diff3.BaseNode;
            var dataVisitMember = node as DataVisitMember;

            if (dataVisitMember != null)
            {
                var diffMember = dataVisitMember.MemberDescriptor.GetCustomAttributes <DiffMemberAttribute>(true).FirstOrDefault();
                if (diffMember != null)
                {
                    if (diffMember.PreferredChange.HasValue)
                    {
                        diff3.ChangeType = diffMember.PreferredChange.Value;
                    }

                    diff3.Weight = diffMember.Weight;
                }
            }

            var instanceType = asset1NodeDesc.Instance?.GetType() ?? asset2NodeDesc.Instance?.GetType();

            object baseInstance   = baseNodeDesc.Instance;
            object asset1Instance = asset1NodeDesc.Instance;
            object asset2Instance = asset2NodeDesc.Instance;

            // If this is an identifiable type (but we are for example not visiting its member), compare only the Ids instead
            if (UseOverrideMode && instanceType != null && IdentifiableHelper.IsIdentifiable(instanceType))
            {
                baseInstance   = IdentifiableHelper.GetId(baseInstance);
                asset1Instance = IdentifiableHelper.GetId(asset1Instance);
                asset2Instance = IdentifiableHelper.GetId(asset2Instance);
            }

            var baseAsset1Equals = Equals(baseInstance, asset1Instance);
            var baseAsset2Equals = Equals(baseInstance, asset2Instance);
            var asset1And2Equals = Equals(asset1Instance, asset2Instance);

            diff3.ChangeType = baseAsset1Equals && baseAsset2Equals
                ? Diff3ChangeType.None
                : baseAsset2Equals ? Diff3ChangeType.MergeFromAsset1 : baseAsset1Equals ? Diff3ChangeType.MergeFromAsset2 : asset1And2Equals ? Diff3ChangeType.MergeFromAsset1And2 : Diff3ChangeType.Conflict;
        }
Пример #5
0
        private void DiffCollection(Diff3Node diff3, DataVisitNode baseNode, DataVisitNode asset1Node, DataVisitNode asset2Node)
        {
            diff3.Type = Diff3NodeType.Collection;

            var baseItems   = baseNode != null ? baseNode.Items ?? EmptyNodes : EmptyNodes;
            var asset1Items = asset1Node != null ? asset1Node.Items ?? EmptyNodes : EmptyNodes;
            var asset2Items = asset2Node != null ? asset2Node.Items ?? EmptyNodes : EmptyNodes;

            var itemEqualityComparer = equalityComparer;

            var node = diff3.Asset1Node ?? diff3.Asset2Node ?? diff3.BaseNode;

            IEnumerable <Diff3Change> changes;
            bool recurseDiff = false;

            // Find an item in any of the list
            var firstItem = baseItems.FirstOrDefault(item => item.Instance != null) ?? asset1Items.FirstOrDefault(item => item.Instance != null) ?? asset2Items.FirstOrDefault(item => item.Instance != null);

            // For now, in the context of UseOverrideMode and we have identifiers per item, use DiffCollectionByIds instead
            if (UseOverrideMode && firstItem != null)
            {
                if (IdentifiableHelper.IsIdentifiable(firstItem.Instance.GetType()))
                {
                    DiffCollectionByIds(diff3, baseNode, asset1Node, asset2Node);
                    return;
                }
                else if (firstItem.Instance is Guid)
                {
                    DiffCollectionByGuids(diff3, baseNode, asset1Node, asset2Node);
                    return;
                }
            }

            // If we have a DiffUseAsset1Attribute, list of Asset1Node becomes authoritative.
            var dataVisitMember     = node as DataVisitMember;
            var diffMemberAttribute = dataVisitMember != null?dataVisitMember.MemberDescriptor.GetCustomAttributes <DiffMemberAttribute>(true).FirstOrDefault() : null;

            if (diffMemberAttribute != null && diffMemberAttribute.PreferredChange.HasValue)
            {
                diff3.Weight = diffMemberAttribute.Weight;
            }

            if (diffMemberAttribute != null && diffMemberAttribute.PreferredChange.HasValue)
            {
                var diffChange = diffMemberAttribute.PreferredChange.Value == Diff3ChangeType.MergeFromAsset2
                    ? new Diff3Change {
                    ChangeType = SharpDiff.Diff3ChangeType.MergeFrom2, From2 = new Span(0, asset2Items.Count - 1)
                }
                    : new Diff3Change {
                    ChangeType = SharpDiff.Diff3ChangeType.MergeFrom1, From1 = new Span(0, asset1Items.Count - 1)
                };

                changes = new[] { diffChange };
                // TODO: Try to merge back data of matching nodes
            }
            else if (firstItem != null && typeof(IDiffKey).IsAssignableFrom(firstItem.InstanceType))
            {
                // If item implement IDataDiffKey, we will use that as equality key
                changes = Diff3.Compare(
                    baseItems.Select(x => ((IDiffKey)x.Instance).GetDiffKey()).ToList(),
                    asset1Items.Select(x => ((IDiffKey)x.Instance).GetDiffKey()).ToList(),
                    asset2Items.Select(x => ((IDiffKey)x.Instance).GetDiffKey()).ToList());
                recurseDiff = true;
            }
            else
            {
                // Otherwise, do a full node comparison
                itemEqualityComparer.Reset();
                changes = Diff3.Compare(baseItems, asset1Items, asset2Items, itemEqualityComparer);
            }

            foreach (var change in changes)
            {
                switch (change.ChangeType)
                {
                case SharpDiff.Diff3ChangeType.Equal:
                    for (int i = 0; i < change.Base.Length; i++)
                    {
                        var diff3Node = recurseDiff
                                ? DiffNode(baseItems[change.Base.From + i], asset1Items[change.From1.From + i], asset2Items[change.From2.From + i])
                                : new Diff3Node(baseItems[change.Base.From + i], asset1Items[change.From1.From + i], asset2Items[change.From2.From + i])
                        {
                            ChangeType = Diff3ChangeType.None
                        };
                        AddItem(diff3, diff3Node, change.From1.From != 0);
                    }
                    break;

                case SharpDiff.Diff3ChangeType.MergeFrom1:
                    for (int i = 0; i < change.From1.Length; i++)
                    {
                        var diff3Node = new Diff3Node(null, asset1Items[change.From1.From + i], null)
                        {
                            ChangeType = Diff3ChangeType.MergeFromAsset1
                        };
                        AddItem(diff3, diff3Node, change.From1.From != 0);
                    }
                    break;

                case SharpDiff.Diff3ChangeType.MergeFrom2:
                    for (int i = 0; i < change.From2.Length; i++)
                    {
                        var diff3Node = new Diff3Node(null, null, asset2Items[change.From2.From + i])
                        {
                            ChangeType = Diff3ChangeType.MergeFromAsset2
                        };
                        AddItem(diff3, diff3Node, true);
                    }
                    break;

                case SharpDiff.Diff3ChangeType.MergeFrom1And2:
                    for (int i = 0; i < change.From2.Length; i++)
                    {
                        var diff3Node = recurseDiff
                                ? DiffNode(null, asset1Items[change.From1.From + i], asset2Items[change.From2.From + i])
                                : new Diff3Node(null, asset1Items[change.From1.From + i], asset2Items[change.From2.From + i])
                        {
                            ChangeType = Diff3ChangeType.MergeFromAsset1And2
                        };
                        AddItem(diff3, diff3Node, change.From1.From != 0);
                    }
                    break;

                case SharpDiff.Diff3ChangeType.Conflict:
                    int baseIndex  = change.Base.IsValid ? change.Base.From : -1;
                    int from1Index = change.From1.IsValid ? change.From1.From : -1;
                    int from2Index = change.From2.IsValid ? change.From2.From : -1;

                    // If there are changes only from 1 or 2 or base.Length == list1.Length == list2.Length, then try to make a diff per item
                    // else output the conflict as a full conflict
                    bool tryResolveConflict = false;
                    if (baseIndex >= 0)
                    {
                        if (from1Index >= 0 && from2Index >= 0)
                        {
                            if ((change.Base.Length == change.From1.Length && change.Base.Length == change.From2.Length) ||
                                (change.From1.Length == change.From2.Length))
                            {
                                tryResolveConflict = true;
                            }
                        }
                        else if (from1Index >= 0)
                        {
                            tryResolveConflict = change.Base.Length == change.From1.Length;
                        }
                        else if (from2Index >= 0)
                        {
                            tryResolveConflict = change.Base.Length == change.From2.Length;
                        }
                        else
                        {
                            tryResolveConflict = true;
                        }
                    }

                    // Iterate on items
                    while ((baseIndex >= 0 && baseItems.Count > 0) || (from1Index >= 0 && asset1Items.Count > 0) || (from2Index >= 0 && asset2Items.Count > 0))
                    {
                        var baseItem   = GetSafeFromList(baseItems, ref baseIndex, ref change.Base);
                        var asset1Item = GetSafeFromList(asset1Items, ref from1Index, ref change.From1);
                        var asset2Item = GetSafeFromList(asset2Items, ref from2Index, ref change.From2);

                        var diff3Node = tryResolveConflict || recurseDiff?
                                        DiffNode(baseItem, asset1Item, asset2Item) :
                                            new Diff3Node(baseItem, asset1Item, asset2Item)
                        {
                            ChangeType = Diff3ChangeType.Conflict
                        };
                        AddItem(diff3, diff3Node, true);
                    }
                    break;
                }
            }

            // Any missing item? (we can detect this only at the end)
            var newItemCount = diff3.Items != null ? diff3.Items.Count : 0;

            if (asset1Items.Count != newItemCount)
            {
                diff3.ChangeType = Diff3ChangeType.Children;
            }
        }