Example #1
0
        /// <summary>
        /// Called on every representation to perform a normalization pass
        /// to convert many common object types to those that can be serialized
        /// in a normalized way. This provides a small safety layer as well,
        /// ensuring that we are only serializing objects that are safe/supported
        /// to do so across all agents*clients or explicitly declare themselves
        /// as an IRepresentationObject (an opt-in "contract" that says that
        /// clients should be able to deserialize it).
        /// </summary>
        /// <param name="obj">The object to normalize.</param>
        object Normalize(object obj)
        {
            if (obj == null)
            {
                return(null);
            }

            if (obj is Representation)
            {
                // an object may be boxed in a Representation object if it has metadata
                // associated with it, such as whether the representation provider supports
                // "editing" via TryConvertFromRepresentation. We must still normalize the
                // value inside to ensure we can safely serialize it. If the value differs
                // after normalization, but is serializable, we re-box it with the normalized
                // value and the canEdit flag unset.
                var originalRepresentation        = (Representation)obj;
                var normalizedRepresentationValue = Normalize(originalRepresentation.Value);

                if (Equals(originalRepresentation.Value, normalizedRepresentationValue))
                {
                    return(obj);
                }

                if (normalizedRepresentationValue == null)
                {
                    return(null);
                }

                return(originalRepresentation.With(
                           normalizedRepresentationValue,
                           canEdit: false));
            }

            if (agentRepresentationProvider != null)
            {
                try {
                    var normalized = agentRepresentationProvider.NormalizeRepresentation(obj);
                    if (normalized != null)
                    {
                        return(normalized);
                    }
                } catch (Exception e) {
                    Log.Error(TAG, "Agent-builtin normalizer raised an exception", e);
                }
            }

            if (obj is Enum)
            {
                return(new EnumValue((Enum)obj));
            }

            if (obj is IInteractiveObject)
            {
                var interactive = (IInteractiveObject)obj;
                interactive.Handle = ObjectCache.Shared.GetHandle(interactive);
                return(interactive);
            }

            if (obj is IRepresentationObject)
            {
                return(obj);
            }

            if (obj is ISerializableObject && currentPreparePassAllowsISerializableObject)
            {
                return((JsonPayload)((ISerializableObject)obj).SerializeToString());
            }

            if (obj is IFallbackRepresentationObject)
            {
                return(obj);
            }

            if (obj is Exception)
            {
                return(ExceptionNode.Create((Exception)obj));
            }

            if (obj is MemberInfo)
            {
                try {
                    var remoteMemberInfo = TypeMember.Create((MemberInfo)obj);
                    if (remoteMemberInfo != null)
                    {
                        return(remoteMemberInfo);
                    }
                } catch {
                }
            }

            if (obj is TimeSpan || obj is Guid)
            {
                return(obj);
            }

            if (obj is IntPtr)
            {
                return(new WordSizedNumber(
                           obj,
                           WordSizedNumberFlags.Pointer | WordSizedNumberFlags.Signed,
                           (ulong)(IntPtr)obj));
            }

            if (obj is UIntPtr)
            {
                return(new WordSizedNumber(
                           obj,
                           WordSizedNumberFlags.Pointer,
                           (ulong)(UIntPtr)obj));
            }

            if (Type.GetTypeCode(obj.GetType()) != TypeCode.Object)
            {
                return(obj);
            }

            if (obj is byte [])
            {
                return(obj);
            }

            return(null);
        }
        /// <summary>
        /// Called on every representation to perform a normalization pass
        /// to convert many common object types to those that can be serialized
        /// in a normalized way. This provides a small safety layer as well,
        /// ensuring that we are only serializing objects that are safe/supported
        /// to do so across all agents*clients or explicitly declare themselves
        /// as an IRepresentationObject (an opt-in "contract" that says that
        /// clients should be able to deserialize it).
        /// </summary>
        /// <param name="obj">The object to normalize.</param>
        object Normalize(object obj)
        {
            switch (obj)
            {
            case null:
                return(null);

            case Representation originalRepresentation:
                // an object may be boxed in a Representation object if it has metadata
                // associated with it, such as whether the representation provider supports
                // "editing" via TryConvertFromRepresentation. We must still normalize the
                // value inside to ensure we can safely serialize it. If the value differs
                // after normalization, but is serializable, we re-box it with the normalized
                // value and the canEdit flag unset.
                var normalizedRepresentationValue = Normalize(originalRepresentation.Value);

                if (Equals(originalRepresentation.Value, normalizedRepresentationValue))
                {
                    return(obj);
                }

                if (normalizedRepresentationValue == null)
                {
                    return(null);
                }

                return(originalRepresentation.With(
                           normalizedRepresentationValue,
                           canEdit: false));
            }

            if (agentRepresentationProvider != null)
            {
                try {
                    var normalized = agentRepresentationProvider.NormalizeRepresentation(obj);
                    if (normalized != null)
                    {
                        return(normalized);
                    }
                } catch (Exception e) {
                    Log.Error(TAG, "Agent-builtin normalizer raised an exception", e);
                }
            }

            switch (obj)
            {
            case Enum enumValue:
                return(new EnumValue(enumValue));

            case IInteractiveObject interactive:
                interactive.Handle = ObjectCache.Shared.GetHandle(interactive);
                return(interactive);

            case IRepresentationObject _:
                return(obj);

            case ISerializableObject iserializableObject when currentPreparePassAllowsISerializableObject:
                return((JsonPayload)iserializableObject.SerializeToString());

            case IFallbackRepresentationObject _:
                return(obj);

            case Exception exception:
                return(ExceptionNode.Create(exception));

            case MemberInfo memberInfo:
                try {
                    var remoteMemberInfo = TypeMember.Create(memberInfo);
                    if (remoteMemberInfo != null)
                    {
                        return(remoteMemberInfo);
                    }
                } catch (Exception e) {
                    Log.Warning(TAG, "unable to create TypeMember from MemberInfo", e);
                }
                return(null);

            case TimeSpan _:
            case Guid _:
                return(obj);

            case IntPtr intptr:
                return(new WordSizedNumber(
                           obj,
                           WordSizedNumberFlags.Pointer | WordSizedNumberFlags.Signed,
                           (ulong)intptr));

            case UIntPtr uintptr:
                return(new WordSizedNumber(
                           obj,
                           WordSizedNumberFlags.Pointer,
                           (ulong)uintptr));

            default:
                if (Type.GetTypeCode(obj.GetType()) != TypeCode.Object)
                {
                    return(obj);
                }

                if (obj is byte [])
                {
                    return(obj);
                }

                return(null);
            }
        }